summaryrefslogtreecommitdiffstats
path: root/ip6t_NPTV6_common.h
diff options
context:
space:
mode:
Diffstat (limited to 'ip6t_NPTV6_common.h')
-rw-r--r--ip6t_NPTV6_common.h88
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*/