diff options
Diffstat (limited to 'ip6t_NPTV6_common.h')
-rw-r--r-- | ip6t_NPTV6_common.h | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/ip6t_NPTV6_common.h b/ip6t_NPTV6_common.h new file mode 100644 index 0000000..86b297c --- /dev/null +++ b/ip6t_NPTV6_common.h @@ -0,0 +1,88 @@ +/* + * 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 <net/ipv6.h> + + +#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 i; + + 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); + } + + /* Fix checksum like specified in RFC 6296 */ + if (plen <= 48) { + i = 3; + } + else { + for (i = (plen+15)/16; i < 7; i++) { + if (addr->s6_addr16[i] != 0xffff) + break; + } + } + + if (addr->s6_addr16[i] == 0xffff) { + return false; + } + + addr->s6_addr16[i] = add16(addr->s6_addr16[i], csum); + if (addr->s6_addr16[i] == 0xffff) { + addr->s6_addr16[i] = 0; + } + + return true; +} + +#endif /*_IP6T_NPTV6_COMMON_H*/ |