/* * NATv6: IPv6-to-IPv6 Network Prefix Translation as * proposed in RFC 6296. * Based on MAP66 (c) 2010 sven-ola()gmx.de * (c) 2011 mschiffer()universe-factory.net "I'm the one to blame for any problems with this version ;P" */ #ifndef _IP6T_NPTV6_COMMON_H #define _IP6T_NPTV6_COMMON_H #include "ip6t_NPTV6.h" #include #ifndef pr_devel # ifdef DEBUG # define pr_devel(fmt, ...) printk(fmt, ##__VA_ARGS__) # else # define pr_devel(fmt, ...) ({ if (0); }) # endif #endif #ifndef NIP6_FMT # define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" # define NIP6(addr) \ ntohs((addr).s6_addr16[0]), \ ntohs((addr).s6_addr16[1]), \ ntohs((addr).s6_addr16[2]), \ ntohs((addr).s6_addr16[3]), \ ntohs((addr).s6_addr16[4]), \ ntohs((addr).s6_addr16[5]), \ ntohs((addr).s6_addr16[6]), \ ntohs((addr).s6_addr16[7]) #endif /* Ones' complement add */ static inline u_int16_t add16(u_int16_t a, u_int16_t b) { a += b; return a + (a < b); } static bool translate_address(struct in6_addr *addr, const struct in6_addr *prefix, u_int16_t plen) { u_int16_t csum = 0; int o = plen / 16, b = plen % 16; int fix_word; int i; /* Fix checksum like specified in RFC 6296 */ if (plen <= 48) { fix_word = 3; } else { for (fix_word = 4; fix_word < 7; fix_word++) { if (addr->s6_addr16[fix_word] != 0xffff) break; } } if (addr->s6_addr16[fix_word] == 0xffff) { /* Fail before the address is translated so the ICMP error can be sent */ return false; } for (i = 0; i < o; i++) { csum = add16(csum, addr->s6_addr16[i]); csum = add16(csum, ~prefix->s6_addr16[i]); addr->s6_addr16[i] = prefix->s6_addr16[i]; } if (b != 0) { u_int16_t bmask = 0xffff << (16-b); csum = add16(csum, addr->s6_addr16[o] & bmask); csum = add16(csum, ~(prefix->s6_addr16[o] & bmask)); addr->s6_addr16[o] &= bmask; addr->s6_addr16[o] |= (prefix->s6_addr16[o] & bmask); } addr->s6_addr16[fix_word] = add16(addr->s6_addr16[fix_word], csum); if (addr->s6_addr16[fix_word] == 0xffff) { addr->s6_addr16[fix_word] = 0; } return true; } #endif /*_IP6T_NPTV6_COMMON_H*/