diff --git a/package/kernel/nat46/Makefile b/package/kernel/nat46/Makefile index 296ef5a058e83e..bcd0cbd9f6a2f0 100644 --- a/package/kernel/nat46/Makefile +++ b/package/kernel/nat46/Makefile @@ -3,15 +3,17 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=nat46 -PKG_MIRROR_HASH:=09b93f31d10030d3b4f326066b544b70b1f60236d0482f27c384ed93b298c0a6 PKG_SOURCE_URL:=https://github.com/ayourtch/nat46.git -PKG_SOURCE_DATE:=2022-09-19 +PKG_SOURCE_DATE:=2024-08-12 PKG_SOURCE_PROTO:=git -PKG_SOURCE_VERSION:=4c5beee236841724219598fabb1edc93d4f08ce5 +PKG_SOURCE_VERSION:=b42c37d5c6dee4593df0fc60b37bc7ec4ee243a4 +PKG_MIRROR_HASH:=2d7bbb6cc22808f7e81d716e6bd7a27d9978fb802496304851946627e21534a5 PKG_MAINTAINER:=Hans Dedecker PKG_LICENSE:=GPL-2.0 +PKG_BUILD_PARALLEL:=1 + include $(INCLUDE_DIR)/package.mk define KernelPackage/nat46 @@ -25,11 +27,17 @@ endef include $(INCLUDE_DIR)/kernel-defaults.mk +define Build/InstallDev + $(INSTALL_DIR) $(STAGING_DIR)/usr/include/nat46 + $(INSTALL_DATA) $(PKG_BUILD_DIR)/nat46/modules/*.h $(STAGING_DIR)/usr/include/nat46/ +endef + define Build/Compile - $(KERNEL_MAKE) M="$(PKG_BUILD_DIR)/nat46/modules" \ + +$(KERNEL_MAKE) M="$(PKG_BUILD_DIR)/nat46/modules" \ MODFLAGS="-DMODULE -mlong-calls" \ EXTRA_CFLAGS="-DNAT46_VERSION=\\\"$(PKG_SOURCE_VERSION)\\\"" \ modules + $(INSTALL_DATA) $(PKG_BUILD_DIR)/nat46/modules/Module.symvers $(PKG_BUILD_DIR)/Module.symvers endef $(eval $(call KernelPackage,nat46)) diff --git a/package/kernel/nat46/patches/101-skb-reset.patch b/package/kernel/nat46/patches/101-skb-reset.patch new file mode 100644 index 00000000000000..14cf2d75a07d88 --- /dev/null +++ b/package/kernel/nat46/patches/101-skb-reset.patch @@ -0,0 +1,30 @@ +Author: Pavithra R +Date: Sun Sep 20 13:33:42 2020 +0530 + +nat46: Add skb_ext_reset to reset skb extensions + +This patch adds support to reset the skb extensions before +resetting the netfilter. Without the change, conntrack +is in invalid state and traffic gets dropped. + +Change-Id: I24ee6fe8a9a9dec09d61d8e716fff587f65e4e4f +Signed-off-by: Pavithra R + +--- a/nat46/modules/nat46-core.c ++++ b/nat46/modules/nat46-core.c +@@ -1710,6 +1710,7 @@ int nat46_ipv6_input(struct sk_buff *old + #if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) + nf_reset(new_skb); + #else ++ skb_ext_reset(new_skb); + nf_reset_ct(new_skb); + #endif + +@@ -1936,6 +1937,7 @@ int nat46_ipv4_input(struct sk_buff *old + #if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) + nf_reset(new_skb); + #else ++ skb_ext_reset(new_skb); + nf_reset_ct(new_skb); + #endif + diff --git a/package/kernel/nat46/patches/102-mapt.patch b/package/kernel/nat46/patches/102-mapt.patch new file mode 100644 index 00000000000000..072d0cc44715fc --- /dev/null +++ b/package/kernel/nat46/patches/102-mapt.patch @@ -0,0 +1,209 @@ +Author: Pavithra R +Date: Sat Aug 1 13:27:20 2020 +0530 + +nat46: Export APIs for acceleration engine support in nat46 for kernel 5.4 + +This patch is propagated from kernel 4.4 commit +861e64a607fd22d5af089cf56539f42a2e31d581 + +The patch defines and exports APIs in nat46 to be used for accelaration. + +Change-Id: I7934b15544953f870d3595b8b359433b4fff7c30 +Signed-off-by: Pavithra R + +--- a/nat46/modules/nat46-core.c ++++ b/nat46/modules/nat46-core.c +@@ -1497,7 +1497,6 @@ static uint16_t nat46_fixup_icmp_dest_un + return 0; + } + +- + /* Fixup ICMP->ICMP6 before IP header translation, according to http://tools.ietf.org/html/rfc6145 */ + + static uint16_t nat46_fixup_icmp(nat46_instance_t *nat46, struct iphdr *iph, struct sk_buff *old_skb) { +@@ -1579,6 +1578,10 @@ int pairs_xlate_v6_to_v4_outer(nat46_ins + return ( (xlate_src >= 0) && (xlate_dst >= 0) ); + } + ++int xlate_6_to_4(struct net_device *dev, struct ipv6hdr *ip6h, uint16_t proto, __u32 *pv4saddr, __u32 *pv4daddr) { ++ return pairs_xlate_v6_to_v4_outer(netdev_nat46_instance(dev), ip6h, proto, pv4saddr, pv4daddr); ++} ++EXPORT_SYMBOL(xlate_6_to_4); + + int nat46_ipv6_input(struct sk_buff *old_skb) { + struct ipv6hdr *ip6h = ipv6_hdr(old_skb); +@@ -1733,6 +1736,10 @@ int nat46_ipv6_input(struct sk_buff *old + + nat46debug(5, "about to send v4 packet, flags: %02x", IPCB(new_skb)->flags); + nat46_netdev_count_xmit(new_skb, old_skb->dev); ++ ++ /* set skb->iif */ ++ new_skb->skb_iif = old_skb->skb_iif; ++ + netif_rx(new_skb); + + /* TBD: should copy be released here? */ +@@ -1841,6 +1848,10 @@ int pairs_xlate_v4_to_v6_outer(nat46_ins + return 0; + } + ++int xlate_4_to_6(struct net_device *dev, struct iphdr *hdr4, uint16_t sport, uint16_t dport, void *v6saddr, void *v6daddr) { ++ return pairs_xlate_v4_to_v6_outer(netdev_nat46_instance(dev), hdr4, &sport, &dport, v6saddr, v6daddr); ++} ++EXPORT_SYMBOL(xlate_4_to_6); + + int nat46_ipv4_input(struct sk_buff *old_skb) { + nat46_instance_t *nat46 = get_nat46_instance(old_skb); +@@ -1981,6 +1992,10 @@ int nat46_ipv4_input(struct sk_buff *old + + nat46debug(5, "about to send v6 packet, flags: %02x", IP6CB(new_skb)->flags); + nat46_netdev_count_xmit(new_skb, old_skb->dev); ++ ++ /* set skb->iif */ ++ new_skb->skb_iif = old_skb->skb_iif; ++ + netif_rx(new_skb); + + done: +@@ -1988,4 +2003,22 @@ done: + return err; + } + ++int nat46_get_npairs(struct net_device *dev) { ++ nat46_instance_t *nat46 = netdev_nat46_instance(dev); ++ return nat46->npairs; ++} ++EXPORT_SYMBOL(nat46_get_npairs); + ++bool nat46_get_rule_config(struct net_device *dev, nat46_xlate_rulepair_t **nat46_rule_pair, int *count) { ++ nat46_instance_t *nat46 = netdev_nat46_instance(dev); ++ if (nat46->npairs < 1) { ++ /* ++ * no rules ? ++ */ ++ return false; ++ } ++ *count = nat46->npairs; ++ *nat46_rule_pair = nat46->pairs; ++ return true; ++} ++EXPORT_SYMBOL(nat46_get_rule_config); +--- a/nat46/modules/nat46-core.h ++++ b/nat46/modules/nat46-core.h +@@ -42,18 +42,18 @@ typedef enum { + #define NAT46_SIGNATURE 0x544e3634 + #define FREED_NAT46_SIGNATURE 0xdead544e + +-typedef struct { ++typedef struct nat46_xlate_rule { + nat46_xlate_style_t style; + struct in6_addr v6_pref; +- int v6_pref_len; +- u32 v4_pref; +- int v4_pref_len; +- int ea_len; +- int psid_offset; +- int fmr_flag; ++ int v6_pref_len; ++ u32 v4_pref; ++ int v4_pref_len; ++ int ea_len; ++ int psid_offset; ++ int fmr_flag; + } nat46_xlate_rule_t; + +-typedef struct { ++typedef struct nat46_xlate_rulepair { + nat46_xlate_rule_t local; + nat46_xlate_rule_t remote; + } nat46_xlate_rulepair_t; +@@ -82,4 +82,9 @@ nat46_instance_t *get_nat46_instance(str + nat46_instance_t *alloc_nat46_instance(int npairs, nat46_instance_t *old, int from_ipair, int to_ipair, int remove_ipair); + void release_nat46_instance(nat46_instance_t *nat46); + ++int xlate_6_to_4(struct net_device *dev, struct ipv6hdr *ip6h, uint16_t proto, __u32 *pv4saddr, __u32 *pv4daddr); ++int xlate_4_to_6(struct net_device *dev, struct iphdr *hdr4, uint16_t sport, uint16_t dport, void *v6saddr, void *v6daddr); ++bool nat46_get_rule_config(struct net_device *dev, nat46_xlate_rulepair_t **nat46_rule_pair, int *count); ++int nat46_get_npairs(struct net_device *dev); ++ + #endif +--- a/nat46/modules/nat46-netdev.c ++++ b/nat46/modules/nat46-netdev.c +@@ -24,10 +24,12 @@ + #include + #include + #include ++#include + #include "nat46-core.h" + #include "nat46-module.h" + + #define NETDEV_DEFAULT_NAME "nat46." ++static RADIX_TREE(netdev_tree, GFP_ATOMIC); + + typedef struct { + u32 sig; +@@ -83,6 +85,18 @@ void nat46_netdev_count_xmit(struct sk_b + dev->stats.tx_bytes += skb->len; + } + ++void nat46_update_stats(struct net_device *dev, uint32_t rx_packets, uint32_t rx_bytes, ++ uint32_t tx_packets, uint32_t tx_bytes, uint32_t rx_dropped, uint32_t tx_dropped) ++{ ++ dev->stats.rx_packets += rx_packets; ++ dev->stats.rx_bytes += rx_bytes; ++ dev->stats.tx_packets += tx_packets; ++ dev->stats.tx_bytes += tx_bytes; ++ dev->stats.rx_dropped += rx_dropped; ++ dev->stats.tx_dropped += tx_dropped; ++} ++EXPORT_SYMBOL(nat46_update_stats); ++ + void *netdev_nat46_instance(struct net_device *dev) { + nat46_netdev_priv_t *priv = netdev_priv(dev); + return priv->nat46; +@@ -160,6 +174,11 @@ int nat46_netdev_create(struct net *net, + printk("nat46: netdevice nat46 '%s' created successfully.\n", devname); + kfree(devname); + ++ /* ++ * add this netdevice to list ++ */ ++ radix_tree_insert(&netdev_tree, (*dev)->ifindex, (void *)*dev); ++ + return 0; + + err_register_dev: +@@ -176,10 +195,24 @@ void nat46_netdev_destroy(struct net_dev + netif_stop_queue(dev); + netdev_nat46_set_instance(dev, NULL); + unregister_netdev(dev); ++ radix_tree_delete(&netdev_tree, dev->ifindex); + free_netdev(dev); + printk("nat46: Destroying nat46 device.\n"); + } + ++bool is_map_t_dev(struct net_device *dev) ++{ ++ if(!dev) { ++ return false; ++ } ++ ++ if(radix_tree_lookup(&netdev_tree, dev->ifindex)) { ++ return true; ++ } ++ return false; ++} ++EXPORT_SYMBOL(is_map_t_dev); ++ + static int is_nat46(struct net_device *dev) { + nat46_netdev_priv_t *priv = netdev_priv(dev); + return (priv && (NAT46_DEVICE_SIGNATURE == priv->sig)); +--- a/nat46/modules/nat46-netdev.h ++++ b/nat46/modules/nat46-netdev.h +@@ -26,3 +26,6 @@ void nat64_show_all_configs(struct net * + void nat46_netdev_count_xmit(struct sk_buff *skb, struct net_device *dev); + void *netdev_nat46_instance(struct net_device *dev); + ++void nat46_update_stats(struct net_device *dev, uint32_t rx_packets, uint32_t rx_bytes, uint32_t tx_packets, uint32_t tx_bytes, ++ uint32_t rx_dropped, uint32_t tx_dropped); ++bool is_map_t_dev(struct net_device *dev); diff --git a/package/kernel/nat46/patches/103-tos.patch b/package/kernel/nat46/patches/103-tos.patch new file mode 100644 index 00000000000000..60ffcb2fae802a --- /dev/null +++ b/package/kernel/nat46/patches/103-tos.patch @@ -0,0 +1,39 @@ +Author: Pavithra R +Date: Sat Aug 1 13:55:33 2020 +0530 + +nat46: Set IPv6 traffic class from IPv4 ToS value + +Set IPv6 traffic class from IPv4 ToS value during +IPv4 to IPv6 translation and vice-versa. + +This patch is propagated from kernel 4.4 commit +1cd3b55b059d4513649bb73bc69da931ed3beb7b + +Change-Id: Ia14e53447e829c8648c01656237ac902ad8674ec +Signed-off-by: Pavithra R + +--- a/nat46/modules/nat46-core.c ++++ b/nat46/modules/nat46-core.c +@@ -886,11 +886,12 @@ void *get_next_header_ptr6(void *pv6, in + } + + void fill_v4hdr_from_v6hdr(struct iphdr * iph, struct ipv6hdr *ip6h, __u32 v4saddr, __u32 v4daddr, __u16 id, __u16 frag_off, __u16 proto, int l3_payload_len) { ++ uint32_t ver_class_flow = ntohl(*(__be32 *)ip6h); + iph->ttl = ip6h->hop_limit; + iph->saddr = v4saddr; + iph->daddr = v4daddr; + iph->protocol = proto; +- *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (0x00/*tos*/ & 0xff)); ++ *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | ((ver_class_flow >> 20) & 0xff)); + iph->frag_off = frag_off; + iph->id = id; + iph->tot_len = htons( l3_payload_len + IPV4HDRSIZE ); +@@ -1859,7 +1860,7 @@ int nat46_ipv4_input(struct sk_buff *old + uint16_t sport = 0, dport = 0; + + int err = 0; +- int tclass = 0; ++ uint8_t tclass = 0; + int flowlabel = 0; + int check_for_l4 = 0; + int having_l4 = 0; diff --git a/package/kernel/nat46/patches/104-icmp.patch b/package/kernel/nat46/patches/104-icmp.patch new file mode 100644 index 00000000000000..7907a66726005b --- /dev/null +++ b/package/kernel/nat46/patches/104-icmp.patch @@ -0,0 +1,439 @@ +Author: Pavithra R +Date: Mon Aug 3 17:03:37 2020 +0530 + +nat46: Fix for icmp translation issues. + +This patch is propagated from kernel 4.4 commit +45fce10ba0105515289930b3e3f9df57bf3c22b6. + +Fixed icmpv4 to icmpv6 and vice-versa translation issues, in accordance with RFC6145. + +The change covers: +1. Translation of ICMP errors from IPv4 to IPv6 and vice-versa. +2. Translation of inner L3 packet header {Eth:IPv4:ICMP:IPv4:ICMP} in ICMP error messages. +3. Address translation for packets not having port numbers, hence CE/BR needs to fetch this + information from inner header (atleast 28 bytes (IP hdr + 8 bytes) of orignal packet received + that is transmitted back will be there in response). + +Change-Id: I677474728aeaee656376fdb1edcb9476783d5b40 +Signed-off-by: Pavithra R + +--- a/nat46/modules/nat46-core.c ++++ b/nat46/modules/nat46-core.c +@@ -29,6 +29,9 @@ + #include "nat46-core.h" + #include "nat46-module.h" + ++static uint16_t xlate_pkt_in_err_v4_to_v6(nat46_instance_t *nat46, struct iphdr *iph, ++ struct sk_buff *old_skb, uint16_t *sport, uint16_t *dport); ++ + void + nat46debug_dump(nat46_instance_t *nat46, int level, void *addr, int len) + { +@@ -885,6 +888,14 @@ void *get_next_header_ptr6(void *pv6, in + return ret; + } + ++void fill_v6hdr_from_v4hdr(struct iphdr *iph, struct ipv6hdr *ip6h) { ++ *((__be16 *)ip6h) = htons((6 << 12) | (iph->tos << 4)); /* Version, Traffic Class */ ++ memset(&(ip6h->flow_lbl), 0, sizeof(ip6h->flow_lbl)); /* Flowlabel */ ++ ip6h->payload_len = htons(ntohs(iph->tot_len) - IPV4HDRSIZE); ++ ip6h->nexthdr = iph->protocol; ++ ip6h->hop_limit = iph->ttl; ++} ++ + void fill_v4hdr_from_v6hdr(struct iphdr * iph, struct ipv6hdr *ip6h, __u32 v4saddr, __u32 v4daddr, __u16 id, __u16 frag_off, __u16 proto, int l3_payload_len) { + uint32_t ver_class_flow = ntohl(*(__be32 *)ip6h); + iph->ttl = ip6h->hop_limit; +@@ -1212,10 +1223,14 @@ static void nat46_fixup_icmp6_paramprob( + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, -1 }; + u32 *pptr6 = icmp6_parameter_ptr(icmp6h); + u8 *pptr4 = icmp_parameter_ptr((struct icmphdr *)icmp6h); +- int new_pptr = -1; ++ u8 new_pptr = -1; + int len = ntohs(ip6h->payload_len)-sizeof(*icmp6h); + + switch(icmp6h->icmp6_code) { ++ case 1: ++ update_icmp6_type_code(nat46, icmp6h, 3, 2); ++ break; ++ + case 0: + if(*pptr6 < sizeof(ptr6_4)/sizeof(ptr6_4[0])) { + new_pptr = ptr6_4[*pptr6]; +@@ -1224,27 +1239,21 @@ static void nat46_fixup_icmp6_paramprob( + *pptr4 = 0xff & new_pptr; + update_icmp6_type_code(nat46, icmp6h, 12, 0); + len = xlate_payload6_to4(nat46, (icmp6h + 1), get_next_header_ptr6((icmp6h + 1), len), len, &icmp6h->icmp6_cksum, ptailTruncSize); +- } else { +- ip6h->nexthdr = NEXTHDR_NONE; ++ update_icmp6_type_code(nat46, icmp6h, 12, 0); ++ break; + } +- } else { +- ip6h->nexthdr = NEXTHDR_NONE; + } +- break; +- case 1: +- icmp6h->icmp6_cksum = csum16_upd(icmp6h->icmp6_cksum, ((*pptr6 >> 16) & 0xffff), 0); +- icmp6h->icmp6_cksum = csum16_upd(icmp6h->icmp6_cksum, (*pptr6 & 0xffff), 0); +- *pptr6 = 0; +- update_icmp6_type_code(nat46, icmp6h, 3, 2); +- len = xlate_payload6_to4(nat46, (icmp6h + 1), get_next_header_ptr6((icmp6h + 1), len), len, &icmp6h->icmp6_cksum, ptailTruncSize); +- break; ++#if __has_attribute(__fallthrough__) ++ __attribute__((__fallthrough__)); ++#endif + case 2: /* fallthrough to default */ + default: + ip6h->nexthdr = NEXTHDR_NONE; ++ return; + } ++ len = xlate_payload6_to4(nat46, (icmp6h + 1), get_next_header_ptr6((icmp6h + 1), len), len, &icmp6h->icmp6_cksum, ptailTruncSize); + } + +- + /* Fixup ICMP6->ICMP before IP header translation, according to http://tools.ietf.org/html/rfc6145 */ + + static void nat46_fixup_icmp6(nat46_instance_t *nat46, struct ipv6hdr *ip6h, struct icmp6hdr *icmp6h, struct sk_buff *old_skb, int *ptailTruncSize) { +@@ -1299,17 +1308,19 @@ int ip6_input_not_interested(nat46_insta + return 0; + } + +-static uint16_t nat46_fixup_icmp_time_exceeded(nat46_instance_t *nat46, struct iphdr *iph, struct icmphdr *icmph, struct sk_buff *old_skb) { ++static uint16_t nat46_fixup_icmp_time_exceeded(nat46_instance_t *nat46, struct iphdr *iph, ++ struct icmphdr *icmph, struct sk_buff *old_skb, uint16_t *sport, uint16_t *dport) { + /* + * Set the Type to 3, and adjust the + * ICMP checksum both to take the type change into account and + * to include the ICMPv6 pseudo-header. The Code is unchanged. + */ + icmph->type = 3; +- return 0; ++ return xlate_pkt_in_err_v4_to_v6(nat46, iph, old_skb, sport, dport); + } + +-static uint16_t nat46_fixup_icmp_parameterprob(nat46_instance_t *nat46, struct iphdr *iph, struct icmphdr *icmph, struct sk_buff *old_skb) { ++static uint16_t nat46_fixup_icmp_parameterprob(nat46_instance_t *nat46, struct iphdr *iph, ++ struct icmphdr *icmph, struct sk_buff *old_skb, uint16_t *sport, uint16_t *dport) { + /* + * Set the Type to 4, and adjust the + * ICMP checksum both to take the type/code change into account +@@ -1352,27 +1363,33 @@ static uint16_t nat46_fixup_icmp_paramet + */ + static int ptr4_6[] = { 0, 1, 4, 4, -1, -1, -1, -1, 7, 6, -1, -1, 8, 8, 8, 8, 24, 24, 24, 24, -1 }; + u8 *icmp_pptr = icmp_parameter_ptr(icmph); +- int new_pptr = -1; ++ u32 *icmp6_pptr = icmp6_parameter_ptr((struct icmp6hdr *)icmph); ++ int8_t new_pptr = -1; ++ ++ icmph->type = 4; ++ + switch (icmph->code) { + case 0: + case 2: + if (*icmp_pptr < (sizeof(ptr4_6)/sizeof(ptr4_6[0]))) { + icmph->code = 0; + new_pptr = ptr4_6[*icmp_pptr]; +- if(new_pptr >= 0) { +- /* FIXME: update the parameter pointer in ICMPv6 with new_pptr value */ ++ if (new_pptr >= 0) { ++ *icmp6_pptr = new_pptr; ++ return xlate_pkt_in_err_v4_to_v6(nat46, iph, old_skb, sport, dport); + } +- } else { +- iph->protocol = NEXTHDR_NONE; + } +- break; ++#if __has_attribute(__fallthrough__) ++ __attribute__((__fallthrough__)); ++#endif + default: + iph->protocol = NEXTHDR_NONE; + } + return 0; + } + +-static uint16_t nat46_fixup_icmp_dest_unreach(nat46_instance_t *nat46, struct iphdr *iph, struct icmphdr *icmph, struct sk_buff *old_skb) { ++static uint16_t nat46_fixup_icmp_dest_unreach(nat46_instance_t *nat46, struct iphdr *iph, ++ struct icmphdr *icmph, struct sk_buff *old_skb, uint16_t *sport, uint16_t *dport) { + /* + * Translate the Code as + * described below, set the Type to 1, and adjust the ICMP +@@ -1435,16 +1452,21 @@ static uint16_t nat46_fixup_icmp_dest_un + + u16 *pmtu = ((u16 *)icmph) + 3; /* IPv4-compatible MTU value is 16 bit */ + ++ icmph->type = 1; ++ + switch (icmph->code) { + case 0: + case 1: + icmph->code = 0; + break; +- case 2: +- /* FIXME: set ICMPv6 parameter pointer to 6 */ ++ case 2: { ++ u32 *icmp6_pptr = icmp6_parameter_ptr((struct icmp6hdr *)icmph); ++ *icmp6_pptr = 6; /* Offset to Next Proto field in IPv6 header. */ + icmph->type = 4; + icmph->code = 1; ++ nat46debug(3, "ICMP Proto Unreachable translated into IPv6 Param Prob.\n"); + break; ++ } + case 3: + icmph->code = 4; + break; +@@ -1494,13 +1516,15 @@ static uint16_t nat46_fixup_icmp_dest_un + break; + default: + iph->protocol = NEXTHDR_NONE; ++ return 0; + } +- return 0; ++ return xlate_pkt_in_err_v4_to_v6(nat46, iph, old_skb, sport, dport); + } + + /* Fixup ICMP->ICMP6 before IP header translation, according to http://tools.ietf.org/html/rfc6145 */ +- +-static uint16_t nat46_fixup_icmp(nat46_instance_t *nat46, struct iphdr *iph, struct sk_buff *old_skb) { ++static uint16_t nat46_fixup_icmp(nat46_instance_t *nat46, struct iphdr *iph, ++ struct sk_buff *old_skb, uint16_t *sport, uint16_t *dport) ++{ + struct icmphdr *icmph = (struct icmphdr *)(iph+1); + uint16_t ret = 0; + +@@ -1509,22 +1533,22 @@ static uint16_t nat46_fixup_icmp(nat46_i + switch(icmph->type) { + case ICMP_ECHO: + icmph->type = ICMPV6_ECHO_REQUEST; +- ret = icmph->un.echo.id; ++ *sport = *dport = icmph->un.echo.id; + nat46debug(3, "ICMP echo request translated into IPv6, id: %d", ntohs(ret)); + break; + case ICMP_ECHOREPLY: + icmph->type = ICMPV6_ECHO_REPLY; +- ret = icmph->un.echo.id; ++ *sport = *dport = icmph->un.echo.id; + nat46debug(3, "ICMP echo reply translated into IPv6, id: %d", ntohs(ret)); + break; + case ICMP_TIME_EXCEEDED: +- ret = nat46_fixup_icmp_time_exceeded(nat46, iph, icmph, old_skb); ++ ret = nat46_fixup_icmp_time_exceeded(nat46, iph, icmph, old_skb, sport, dport); + break; + case ICMP_PARAMETERPROB: +- ret = nat46_fixup_icmp_parameterprob(nat46, iph, icmph, old_skb); ++ ret = nat46_fixup_icmp_parameterprob(nat46, iph, icmph, old_skb, sport, dport); + break; + case ICMP_DEST_UNREACH: +- ret = nat46_fixup_icmp_dest_unreach(nat46, iph, icmph, old_skb); ++ ret = nat46_fixup_icmp_dest_unreach(nat46, iph, icmph, old_skb, sport, dport); + break; + default: + /* Silently drop. */ +@@ -1544,11 +1568,13 @@ int pairs_xlate_v6_to_v4_outer(nat46_ins + + if(-1 == xlate_dst) { + if (xlate_v6_to_v4(nat46, &apair->local, &ip6h->daddr, pv4daddr)) { ++ nat46debug(5, "Dst addr %pI6 to %pI4 \n", &ip6h->daddr, pv4daddr); + xlate_dst = ipair; + } + } + if(-1 == xlate_src) { + if (xlate_v6_to_v4(nat46, &apair->remote, &ip6h->saddr, pv4saddr)) { ++ nat46debug(5, "Src addr %pI6 to %pI4 \n", &ip6h->saddr, pv4saddr); + xlate_src = ipair; + } + } +@@ -1659,6 +1685,7 @@ int nat46_ipv6_input(struct sk_buff *old + } + + if(!pairs_xlate_v6_to_v4_outer(nat46, ip6h, proto, &v4saddr, &v4daddr)) { ++ nat46debug(0, "[nat46] Could not translate v6->v4"); + goto done; + } + +@@ -1821,11 +1848,13 @@ int pairs_xlate_v4_to_v6_outer(nat46_ins + + if(-1 == xlate_src) { + if(xlate_v4_to_v6(nat46, &apair->local, &hdr4->saddr, v6saddr, sport)) { ++ nat46debug(5, "Src addr %pI4 to %pI6 \n", &hdr4->saddr, v6saddr); + xlate_src = ipair; + } + } + if(-1 == xlate_dst) { + if(xlate_v4_to_v6(nat46, &apair->remote, &hdr4->daddr, v6daddr, dport)) { ++ nat46debug(5, "Dst addr %pI4 to %pI6 \n", &hdr4->daddr, v6daddr); + xlate_dst = ipair; + } + } +@@ -1854,10 +1883,145 @@ int xlate_4_to_6(struct net_device *dev, + } + EXPORT_SYMBOL(xlate_4_to_6); + ++/* FIXME: This is a workaround, till the LPM is not added. The sport & dport in inner header will be dport & sport of the outer ++ * header, respectively. Hence, dest. and source ips of inner header will be found in local & remote rules, respectively. ++ * Will work only for a pair of local & remote rules. Once LPM is brought in, this method can be removed and ++ * pairs_xlate_v4_to_v6_outer be used instead. ++ */ ++int pairs_xlate_v4_to_v6_inner(nat46_instance_t *nat46, struct iphdr *iph, ++ uint16_t sport, uint16_t dport, void *v6saddr, void *v6daddr) { ++ int ipair = 0; ++ nat46_xlate_rulepair_t *apair = NULL; ++ int xlate_src = -1; ++ int xlate_dst = -1; ++ ++ for (ipair = 0; ipair < nat46->npairs; ipair++) { ++ apair = &nat46->pairs[ipair]; ++ ++ if (-1 == xlate_dst) { ++ if (xlate_v4_to_v6(nat46, &apair->local, &iph->daddr, v6daddr, &dport)) { ++ nat46debug(3, "Dst addr %pI4 to %pI6 \n", &iph->daddr, v6daddr); ++ xlate_dst = ipair; ++ } ++ } ++ if (-1 == xlate_src) { ++ if(xlate_v4_to_v6(nat46, &apair->remote, &iph->saddr, v6saddr, &sport)) { ++ nat46debug(3, "Src addr %pI4 to %pI6 \n", &iph->saddr, v6saddr); ++ xlate_src = ipair; ++ } ++ } ++ if ((xlate_src >= 0) && (xlate_dst >= 0)) { ++ /* we did manage to translate it */ ++ nat46debug(5, "[nat46] Inner header xlate results: src %d dst %d", xlate_src, xlate_dst); ++ return 1; ++ } else { ++ /* We did not match fully and there are more rules */ ++ if((ipair+1 < nat46->npairs) && is_last_pair_in_group(apair)) { ++ xlate_src = -1; ++ xlate_dst = -1; ++ } ++ } ++} ++ ++ nat46debug(1, "[nat46] Could not find a translation pair v4->v6"); ++ return 0; ++} ++ ++static uint16_t xlate_pkt_in_err_v4_to_v6(nat46_instance_t *nat46, struct iphdr *iph, ++ struct sk_buff *old_skb, uint16_t *sport, uint16_t *dport) { ++ struct ipv6hdr ip6h; ++ char v6saddr[16], v6daddr[16]; ++ uint16_t temp_port = 0; ++ int ret = 0; ++ struct icmphdr *icmph = (struct icmphdr *)(iph + 1); ++ struct iphdr *iiph = (struct iphdr *)(icmph + 1); ++ ++ switch (iiph->protocol) { ++ case IPPROTO_TCP: { ++ struct tcphdr *th = (struct tcphdr *)(iiph + 1); ++ *sport = th->source; ++ *dport = th->dest; ++ iiph->protocol = NEXTHDR_TCP; ++ break; ++ } ++ case IPPROTO_UDP: { ++ struct udphdr *udp = (struct udphdr *)(iiph + 1); ++ *sport = udp->source; ++ *dport = udp->dest; ++ iiph->protocol = NEXTHDR_UDP; ++ break; ++ } ++ case IPPROTO_ICMP: { ++ struct icmphdr *icmph = (struct icmphdr *)(iiph + 1); ++ iiph->protocol = NEXTHDR_ICMP; ++ switch (icmph->type) { ++ case ICMP_ECHO: ++ icmph->type = ICMPV6_ECHO_REQUEST; ++ *sport = *dport = icmph->un.echo.id; ++ break; ++ case ICMP_ECHOREPLY: ++ icmph->type = ICMPV6_ECHO_REPLY; ++ *sport = *dport = icmph->un.echo.id; ++ break; ++ default: ++ nat46debug(3, "ICMP Error message can't be inside another ICMP Error messgae."); ++ *sport = *dport = 0; ++ return 0; ++ } ++ break; ++ } ++ default: ++ nat46debug(3, "[ICMPv4] Next header: %u. Only TCP, UDP, and ICMP are supported.", iiph->protocol); ++ *sport = *dport = 0; ++ return 0; ++ } ++ ++ nat46debug(3, "Retrieved from pkt in error: dest port %d, and src port %d.", ntohs(*dport), ntohs(*sport)); ++ ++ if (!pairs_xlate_v4_to_v6_inner(nat46, iiph, *sport, *dport, v6saddr, v6daddr)) { ++ nat46debug(0, "[nat46] Could not translate inner header v4->v6"); ++ *sport = *dport = 0; ++ return 0; ++ } ++ ++ fill_v6hdr_from_v4hdr (iiph, &ip6h); ++ memcpy(&ip6h.saddr, v6saddr, sizeof(ip6h.saddr)); ++ memcpy(&ip6h.daddr, v6daddr, sizeof(ip6h.daddr)); ++ ++ if (skb_tailroom(old_skb) >= IPV6V4HDRDELTA){ ++ skb_put(old_skb, IPV6V4HDRDELTA); ++ memmove(((char *)iiph + IPV6HDRSIZE), (iiph + 1), ntohs(iiph->tot_len) - IPV4HDRSIZE); ++ memcpy(iiph, &ip6h, IPV6HDRSIZE); ++ } ++ else { ++ ret = pskb_expand_head(old_skb, 0, IPV6V4HDRDELTA, GFP_ATOMIC); ++ if (unlikely(ret)) { ++ nat46debug(0, "[nat46] Could not copy v4 skb"); ++ *sport = *dport = 0; ++ return 0; ++ } ++ ++ skb_put(old_skb, IPV6V4HDRDELTA); ++ iiph = (struct iphdr *)(icmp_hdr(old_skb) + 1); ++ memmove(((char *)iiph + IPV6HDRSIZE), (iiph + 1), ntohs(iiph->tot_len) - IPV4HDRSIZE); ++ memcpy(iiph, &ip6h, IPV6HDRSIZE); ++ nat46 = get_nat46_instance(old_skb); ++ iph = ip_hdr(old_skb); ++ } ++ ++ /* Swapping Ports for outer header */ ++ /* Another work-around till LPM is not present. */ ++ temp_port = *sport; ++ *sport = *dport; ++ *dport = temp_port; ++ ++ return 1; ++} ++ + int nat46_ipv4_input(struct sk_buff *old_skb) { + nat46_instance_t *nat46 = get_nat46_instance(old_skb); + struct sk_buff *new_skb; +- uint16_t sport = 0, dport = 0; ++ uint16_t sport = 0, dport = 0, ret = 0; + + int err = 0; + uint8_t tclass = 0; +@@ -1879,7 +2043,7 @@ int nat46_ipv4_input(struct sk_buff *old + } + nat46debug(1, "nat46_ipv4_input packet"); + nat46debug(5, "nat46_ipv4_input protocol: %d, len: %d, flags: %02x", hdr4->protocol, old_skb->len, IPCB(old_skb)->flags); +- if(0 == (ntohs(hdr4->frag_off) & 0x3FFF) ) { ++ if (0 == (ntohs(hdr4->frag_off) & 0x3FFF)) { + check_for_l4 = 1; + } else if (IPPROTO_ICMP == hdr4->protocol) { + /* +@@ -1916,9 +2080,10 @@ int nat46_ipv4_input(struct sk_buff *old + break; + } + case IPPROTO_ICMP: +- sport = dport = nat46_fixup_icmp(nat46, hdr4, old_skb); +- having_l4 = 1; +- break; ++ ret = nat46_fixup_icmp(nat46, hdr4, old_skb, &sport, &dport); ++ nat46debug(3, "ICMP translated to dest port %d, and src port %d.", ntohs(dport), ntohs(sport)); ++ having_l4 = 1; ++ break; + default: + break; + } diff --git a/package/kernel/nat46/patches/105-longest-prefix-match.patch b/package/kernel/nat46/patches/105-longest-prefix-match.patch new file mode 100644 index 00000000000000..af7f2c770b2902 --- /dev/null +++ b/package/kernel/nat46/patches/105-longest-prefix-match.patch @@ -0,0 +1,640 @@ +Author: Pavithra R +Date: Tue Aug 4 10:33:59 2020 +0530 + +nat46: Adding support for multiple MAP-T rules. + +This patch is propagated from kernel 4.4 commit +05a122b0cb0d3a99f040c94b3f626e7350f1445b + +This change covers: +1. Support for adding maximum of 32 MAP-T rules (DMR + FMRs). +2. Support for rule lookup based on Longest Prefix Match method. +3. Support for validation of new rules being inserted. + +Change-Id: Id87448a8f544273b40c20aaab6e5c63b0dbd72e +Signed-off-by: Pavithra R + +--- a/nat46/modules/nat46-core.c ++++ b/nat46/modules/nat46-core.c +@@ -128,6 +128,13 @@ int try_parse_ipv6_prefix(struct in6_add + *arg_plen++ = 0; + if (pref_len) { + *pref_len = simple_strtol(arg_plen, NULL, 10); ++ ++ /* ++ * ipv6 prefix should be <= 128 ++ */ ++ if (*pref_len > IPV6_BITS_MAX) { ++ return -1; ++ } + } + } + err = (1 != in6_pton(arg, -1, (u8 *)pref, '\0', NULL)); +@@ -141,6 +148,13 @@ int try_parse_ipv4_prefix(u32 *v4addr, i + *arg_plen++ = 0; + if (pref_len) { + *pref_len = simple_strtol(arg_plen, NULL, 10); ++ ++ /* ++ * ipv4 prefix len should be <= 32 ++ */ ++ if (*pref_len > IPV4_BITS_MAX) { ++ return -1; ++ } + } + } + err = (1 != in4_pton(arg, -1, (u8 *)v4addr, '/', NULL)); +@@ -183,11 +197,127 @@ int try_parse_rule_arg(nat46_xlate_rule_ + return err; + } + +-/* +- * Parse the config commands in the buffer, +- * destructive (puts zero between the args) ++static inline void nat46_swap(nat46_xlate_rulepair_t *var1, nat46_xlate_rulepair_t *var2) { ++ nat46_xlate_rulepair_t temp; ++ temp = *var1; ++ *var1 = *var2; ++ *var2 = temp; ++} ++ ++/* ++ * Sort rule pairs based on prefix length. + */ ++void nat46_sort_rule_array(nat46_instance_t *nat46) { ++ int i, j; ++ int nelem = nat46->npairs; ++ nat46_xlate_rulepair_t *array = NULL; ++ ++ memcpy(nat46->sorted_ipv4_local_pairs, nat46->pairs, nelem * sizeof(nat46_xlate_rulepair_t)); ++ memcpy(nat46->sorted_ipv4_remote_pairs, nat46->pairs, nelem * sizeof(nat46_xlate_rulepair_t)); ++ memcpy(nat46->sorted_ipv6_local_pairs, nat46->pairs, nelem * sizeof(nat46_xlate_rulepair_t)); ++ memcpy(nat46->sorted_ipv6_remote_pairs, nat46->pairs, nelem * sizeof(nat46_xlate_rulepair_t)); ++ ++ array = &nat46->sorted_ipv4_local_pairs[0]; ++ for (i = 0; i < nelem - 1; i++) { ++ for (j = 0; j < nelem - i - 1; j++) { ++ if (array[j].local.v4_pref_len < array[j+1].local.v4_pref_len) { ++ nat46_swap (&array[j], &array[j+1]); ++ } ++ } ++ } ++ ++ array = &nat46->sorted_ipv4_remote_pairs[0]; ++ for (i = 0; i < nelem - 1; i++) { ++ for (j = 0; j < nelem - i - 1; j++) { ++ if (array[j].remote.v4_pref_len < array[j+1].remote.v4_pref_len) { ++ nat46_swap (&array[j], &array[j+1]); ++ } ++ } ++ } + ++ array = &nat46->sorted_ipv6_local_pairs[0]; ++ for (i = 0; i < nelem - 1; i++) { ++ for (j = 0; j < nelem - i - 1; j++) { ++ if (array[j].local.v6_pref_len < array[j+1].local.v6_pref_len) { ++ nat46_swap (&array[j], &array[j+1]); ++ } ++ } ++ } ++ ++ array = &nat46->sorted_ipv6_remote_pairs[0]; ++ for (i = 0; i < nelem - 1; i++) { ++ for (j = 0; j < nelem - i - 1; j++) { ++ if (array[j].remote.v6_pref_len < array[j+1].remote.v6_pref_len) { ++ nat46_swap (&array[j], &array[j+1]); ++ } ++ } ++ } ++} ++ ++bool nat46_validate_RFC6052_style(nat46_instance_t *nat46, nat46_xlate_rule_t rule) ++{ ++ if (rule.style == NAT46_XLATE_RFC6052) { ++ if (!((rule.v6_pref_len == 32) || (rule.v6_pref_len == 40) || ++ (rule.v6_pref_len == 48) || (rule.v6_pref_len == 56) || ++ (rule.v6_pref_len == 64) || (rule.v6_pref_len == 96))) { ++ nat46debug(3, "IPv6 prefix len is invalid"); ++ return false; ++ } ++ } ++ return true; ++} ++ ++bool nat46_validate_MAP_style(nat46_instance_t *nat46, nat46_xlate_rule_t rule) ++{ ++ int psid_len; ++ if (rule.style == NAT46_XLATE_MAP) { ++ ++ /* ++ * max ea_len is 48 ++ */ ++ if (rule.ea_len > EA_LEN_MAX) { ++ nat46debug(3, "EA-length should not exceed 48"); ++ return false; ++ } ++ ++ if (rule.v4_pref_len + rule.ea_len > IPV4_BITS_MAX) { ++ psid_len = rule.ea_len - (IPV4_BITS_MAX - rule.v4_pref_len); ++ } else { ++ psid_len = 0; ++ } ++ ++ if (psid_len + rule.psid_offset > PSID_LEN_MAX) { ++ nat46debug(3, "psid_len + psid_offset should not exceed 16"); ++ return false; ++ } ++ } ++ return true; ++} ++ ++int nat46_validate_ipair_config(nat46_instance_t *nat46, nat46_xlate_rulepair_t *apair) ++{ ++ if (!nat46_validate_RFC6052_style(nat46, apair->local)) { ++ return -1; ++ } ++ ++ if (!nat46_validate_RFC6052_style(nat46, apair->remote)) { ++ return -1; ++ } ++ ++ if (!nat46_validate_MAP_style(nat46, apair->local)) { ++ return -1; ++ } ++ ++ if (!nat46_validate_MAP_style(nat46, apair->remote)) { ++ return -1; ++ } ++ return 0; ++} ++ ++/* ++ * Parse the config commands in the buffer, ++ * destructive (puts zero between the args) ++ */ + int nat46_set_ipair_config(nat46_instance_t *nat46, int ipair, char *buf, int count) { + char *tail = buf; + char *arg_name; +@@ -217,7 +347,18 @@ int nat46_set_ipair_config(nat46_instanc + err = try_parse_rule_arg(&apair->remote, arg_name, &tail); + } + } +- return err; ++ ++ err = nat46_validate_ipair_config(nat46, apair); ++ if (err) { ++ return err; ++ } ++ ++ /* ++ * sort nat46->pairs based on prefix length. ++ */ ++ nat46_sort_rule_array(nat46); ++ ++ return 0; + } + + int nat46_set_config(nat46_instance_t *nat46, char *buf, int count) { +@@ -933,37 +1074,120 @@ int is_last_pair_in_group(nat46_xlate_ru + return ( (apair->local.style != NAT46_XLATE_NONE) && (apair->remote.style != NAT46_XLATE_NONE) ); + } + ++nat46_xlate_rulepair_t *nat46_lpm(nat46_instance_t *nat46, nat46_rule_type_t type, void *paddr) { ++ int ipair = 0; ++ nat46_xlate_rulepair_t *apair = NULL; ++ uint32_t mask = 0; ++ uint8_t *pa1; ++ uint8_t *pa2; ++ ++ if(!nat46 || !paddr) { ++ return NULL; ++ } ++ ++ switch (type) { ++ case NAT46_IPV4_LOCAL: ++ for (ipair = 0; ipair < nat46->npairs; ipair++) { ++ apair = &nat46->sorted_ipv4_local_pairs[ipair]; ++ ++ /* ++ * For a 32-bit number, if the shift count is 32, then the ++ * result of the left shift operation is always 0. ++ */ ++ if (apair->local.v4_pref_len) { ++ mask = htonl(U32_MASK << (IPV4_BITS_MAX - apair->local.v4_pref_len)); ++ } ++ ++ if((*(uint32_t *)paddr & mask) == (apair->local.v4_pref & mask)) { ++ return apair; ++ } ++ } ++ break; ++ case NAT46_IPV4_REMOTE: ++ for (ipair = 0; ipair < nat46->npairs; ipair++) { ++ apair = &nat46->sorted_ipv4_remote_pairs[ipair]; ++ ++ /* ++ * For a 32-bit number, if the shift count is 32, then the ++ * result of the left shift operation is always 0. ++ */ ++ if (apair->remote.v4_pref_len) { ++ mask = htonl(U32_MASK << (IPV4_BITS_MAX - apair->remote.v4_pref_len)); ++ } ++ ++ if((*(uint32_t *)paddr & mask) == (apair->remote.v4_pref & mask)) { ++ return apair; ++ } ++ } ++ break; ++ case NAT46_IPV6_LOCAL: ++ for (ipair = 0; ipair < nat46->npairs; ipair++) { ++ apair = &nat46->sorted_ipv6_local_pairs[ipair]; ++ if(memcmp(paddr, &apair->local.v6_pref, apair->local.v6_pref_len / BITS_PER_BYTE)) { ++ continue; ++ } ++ if(apair->local.v6_pref_len % BITS_PER_BYTE) { ++ mask = U8_MASK << (BITS_PER_BYTE - (apair->local.v6_pref_len % BITS_PER_BYTE)); ++ pa1 = (uint8_t *)paddr + (apair->local.v6_pref_len / BITS_PER_BYTE); ++ pa2 = (uint8_t *)&apair->local.v6_pref + (apair->local.v6_pref_len / BITS_PER_BYTE); ++ ++ if ((*pa1 & mask) == (*pa2 & mask)) { ++ return apair; ++ } ++ } ++ else ++ return apair; ++ } ++ break; ++ case NAT46_IPV6_REMOTE: ++ for (ipair = 0; ipair < nat46->npairs; ipair++) { ++ apair = &nat46->sorted_ipv6_remote_pairs[ipair]; ++ if(memcmp(paddr, &apair->remote.v6_pref, apair->remote.v6_pref_len / BITS_PER_BYTE)) { ++ continue; ++ } ++ if(apair->remote.v6_pref_len % BITS_PER_BYTE) { ++ mask = U8_MASK << (BITS_PER_BYTE - (apair->remote.v6_pref_len % BITS_PER_BYTE)); ++ pa1 = (uint8_t *)paddr + (apair->remote.v6_pref_len / BITS_PER_BYTE); ++ pa2 = (uint8_t *)&apair->remote.v6_pref + (apair->remote.v6_pref_len / BITS_PER_BYTE); ++ ++ if((*pa1 & mask) == (*pa2 & mask)) { ++ return apair; ++ } ++ } ++ else ++ return apair; ++ } ++ break; ++ default: ++ nat46debug(0, "%s : Invalid prefix type.\n", __func__); ++ } ++ return NULL; ++} ++ + void pairs_xlate_v6_to_v4_inner(nat46_instance_t *nat46, struct ipv6hdr *ip6h, __u32 *pv4saddr, __u32 *pv4daddr) { + int ipair = 0; + nat46_xlate_rulepair_t *apair = NULL; + int xlate_src = -1; + int xlate_dst = -1; + +- for(ipair = 0; ipair < nat46->npairs; ipair++) { +- apair = &nat46->pairs[ipair]; ++ apair = nat46_lpm(nat46, NAT46_IPV6_REMOTE, &ip6h->daddr); ++ if (!apair) { ++ return; ++ } + +- if(-1 == xlate_dst) { +- if(xlate_v6_to_v4(nat46, &apair->remote, &ip6h->daddr, pv4daddr)) { +- xlate_dst = ipair; +- } +- } +- if(-1 == xlate_src) { +- if(xlate_v6_to_v4(nat46, &apair->local, &ip6h->saddr, pv4saddr)) { +- xlate_src = ipair; +- } +- } +- if((xlate_src >= 0) && (xlate_dst >= 0)) { +- /* we did manage to translate it */ +- break; +- } else { +- /* We did not match fully and there are more rules */ +- if((ipair+1 < nat46->npairs) && is_last_pair_in_group(apair)) { +- xlate_src = -1; +- xlate_dst = -1; +- } +- } ++ if (xlate_v6_to_v4(nat46, &apair->remote, &ip6h->daddr, pv4daddr)) { ++ xlate_dst = ipair; ++ } ++ if (xlate_v6_to_v4(nat46, &apair->local, &ip6h->saddr, pv4saddr)) { ++ xlate_src = ipair; ++ } ++ ++ if ((xlate_src >= 0) && (xlate_dst >= 0)) { ++ /* we did manage to translate it */ ++ nat46debug(5, "[nat46payload] xlate results: src %d dst %d", xlate_src, xlate_dst); ++ } else { ++ nat46debug(1, "[nat46] Could not find a translation pair v6->v4 src %pI6c dst %pI6c", &ip6h->saddr, &ip6h->daddr); + } +- nat46debug(5, "[nat46payload] xlate results: src %d dst %d", xlate_src, xlate_dst); + } + + /* +@@ -1557,40 +1781,31 @@ static uint16_t nat46_fixup_icmp(nat46_i + return ret; + } + +-int pairs_xlate_v6_to_v4_outer(nat46_instance_t *nat46, struct ipv6hdr *ip6h, uint16_t proto, __u32 *pv4saddr, __u32 *pv4daddr) { ++int pairs_xlate_v6_to_v4_outer(nat46_instance_t *nat46, nat46_xlate_rulepair_t *apair, ++ struct ipv6hdr *ip6h, uint16_t proto, __u32 *pv4saddr, __u32 *pv4daddr) { + int ipair = 0; +- nat46_xlate_rulepair_t *apair = NULL; + int xlate_src = -1; + int xlate_dst = -1; + + for(ipair = 0; ipair < nat46->npairs; ipair++) { +- apair = &nat46->pairs[ipair]; +- +- if(-1 == xlate_dst) { +- if (xlate_v6_to_v4(nat46, &apair->local, &ip6h->daddr, pv4daddr)) { +- nat46debug(5, "Dst addr %pI6 to %pI4 \n", &ip6h->daddr, pv4daddr); +- xlate_dst = ipair; +- } ++ apair = nat46_lpm(nat46, NAT46_IPV6_REMOTE, &ip6h->saddr); ++ if (!apair) { ++ return 0; + } +- if(-1 == xlate_src) { +- if (xlate_v6_to_v4(nat46, &apair->remote, &ip6h->saddr, pv4saddr)) { +- nat46debug(5, "Src addr %pI6 to %pI4 \n", &ip6h->saddr, pv4saddr); +- xlate_src = ipair; +- } ++ ++ if (xlate_v6_to_v4(nat46, &apair->local, &ip6h->daddr, pv4daddr)) { ++ nat46debug(5, "Dst addr %pI6 to %pI4 \n", &ip6h->daddr, pv4daddr); ++ xlate_dst = ipair; + } +- if( (xlate_src >= 0) && (xlate_dst >= 0) ) { +- break; +- } else { +- /* We did not match fully and there are more rules */ +- if((ipair+1 < nat46->npairs) && is_last_pair_in_group(apair)) { +- xlate_src = -1; +- xlate_dst = -1; +- } ++ ++ if (xlate_v6_to_v4(nat46, &apair->remote, &ip6h->saddr, pv4saddr)) { ++ nat46debug(5, "Src addr %pI6 to %pI4 \n", &ip6h->saddr, pv4saddr); ++ xlate_src = ipair; + } + } + if (xlate_dst >= 0) { + if (xlate_src < 0) { +- if(proto == NEXTHDR_ICMP) { ++ if (proto == NEXTHDR_ICMP) { + nat46debug(1, "[nat46] Could not translate remote address v6->v4, ipair %d, for ICMP6 use dest addr", ipair); + *pv4saddr = *pv4daddr; + xlate_src = xlate_dst; +@@ -1606,12 +1821,14 @@ int pairs_xlate_v6_to_v4_outer(nat46_ins + } + + int xlate_6_to_4(struct net_device *dev, struct ipv6hdr *ip6h, uint16_t proto, __u32 *pv4saddr, __u32 *pv4daddr) { +- return pairs_xlate_v6_to_v4_outer(netdev_nat46_instance(dev), ip6h, proto, pv4saddr, pv4daddr); ++ nat46_xlate_rulepair_t apair; ++ return pairs_xlate_v6_to_v4_outer(netdev_nat46_instance(dev), &apair, ip6h, proto, pv4saddr, pv4daddr); + } + EXPORT_SYMBOL(xlate_6_to_4); + + int nat46_ipv6_input(struct sk_buff *old_skb) { + struct ipv6hdr *ip6h = ipv6_hdr(old_skb); ++ nat46_xlate_rulepair_t apair; + nat46_instance_t *nat46 = get_nat46_instance(old_skb); + uint16_t proto; + uint16_t frag_off; +@@ -1684,7 +1901,7 @@ int nat46_ipv6_input(struct sk_buff *old + check_for_l4 = 1; + } + +- if(!pairs_xlate_v6_to_v4_outer(nat46, ip6h, proto, &v4saddr, &v4daddr)) { ++ if (!pairs_xlate_v6_to_v4_outer(nat46, &apair, ip6h, proto, &v4saddr, &v4daddr)) { + nat46debug(0, "[nat46] Could not translate v6->v4"); + goto done; + } +@@ -1837,56 +2054,44 @@ int ip4_input_not_interested(nat46_insta + return 0; + } + +-int pairs_xlate_v4_to_v6_outer(nat46_instance_t *nat46, struct iphdr *hdr4, uint16_t *sport, uint16_t *dport, void *v6saddr, void *v6daddr) { ++int pairs_xlate_v4_to_v6_outer(nat46_instance_t *nat46, nat46_xlate_rulepair_t *apair, ++ struct iphdr *hdr4, uint16_t *sport, uint16_t *dport, void *v6saddr, void *v6daddr) { + int ipair = 0; +- nat46_xlate_rulepair_t *apair = NULL; + int xlate_src = -1; + int xlate_dst = -1; ++ int ret = 0; + +- for(ipair = 0; ipair < nat46->npairs; ipair++) { +- apair = &nat46->pairs[ipair]; ++ apair = nat46_lpm(nat46, NAT46_IPV4_REMOTE, &hdr4->daddr); ++ if (!apair) { ++ return 0; ++ } + +- if(-1 == xlate_src) { +- if(xlate_v4_to_v6(nat46, &apair->local, &hdr4->saddr, v6saddr, sport)) { +- nat46debug(5, "Src addr %pI4 to %pI6 \n", &hdr4->saddr, v6saddr); +- xlate_src = ipair; +- } +- } +- if(-1 == xlate_dst) { +- if(xlate_v4_to_v6(nat46, &apair->remote, &hdr4->daddr, v6daddr, dport)) { +- nat46debug(5, "Dst addr %pI4 to %pI6 \n", &hdr4->daddr, v6daddr); +- xlate_dst = ipair; +- } +- } +- if( (xlate_src >= 0) && (xlate_dst >= 0) ) { +- break; +- } else { +- /* We did not match fully and there are more rules */ +- if((ipair+1 < nat46->npairs) && is_last_pair_in_group(apair)) { +- xlate_src = -1; +- xlate_dst = -1; +- } +- } ++ if (xlate_v4_to_v6(nat46, &apair->local, &hdr4->saddr, v6saddr, sport)) { ++ nat46debug(5, "Src addr %pI4 to %pI6 \n", &hdr4->saddr, v6saddr); ++ xlate_src = ipair; ++ } ++ if (xlate_v4_to_v6(nat46, &apair->remote, &hdr4->daddr, v6daddr, dport)) { ++ nat46debug(5, "Dst addr %pI4 to %pI6 \n", &hdr4->daddr, v6daddr); ++ xlate_dst = ipair; + } + nat46debug(5, "[nat46] pairs_xlate_v4_to_v6_outer result: src %d dst %d", xlate_src, xlate_dst); + if ( (xlate_src >= 0) && (xlate_dst >= 0) ) { +- return 1; ++ ret = 1; ++ } else { ++ nat46debug(1, "[nat46] Could not find a translation pair v4->v6"); + } +- +- nat46debug(1, "[nat46] Could not find a translation pair v4->v6"); +- +- return 0; ++ return ret; + } + + int xlate_4_to_6(struct net_device *dev, struct iphdr *hdr4, uint16_t sport, uint16_t dport, void *v6saddr, void *v6daddr) { +- return pairs_xlate_v4_to_v6_outer(netdev_nat46_instance(dev), hdr4, &sport, &dport, v6saddr, v6daddr); ++ nat46_xlate_rulepair_t apair; ++ return pairs_xlate_v4_to_v6_outer(netdev_nat46_instance(dev), &apair, hdr4, &sport, &dport, v6saddr, v6daddr); + } + EXPORT_SYMBOL(xlate_4_to_6); + +-/* FIXME: This is a workaround, till the LPM is not added. The sport & dport in inner header will be dport & sport of the outer +- * header, respectively. Hence, dest. and source ips of inner header will be found in local & remote rules, respectively. +- * Will work only for a pair of local & remote rules. Once LPM is brought in, this method can be removed and +- * pairs_xlate_v4_to_v6_outer be used instead. ++/* ++ * The sport & dport in inner header will be dport & sport of the outer header, respectively. ++ * Hence, dest. and source ips of inner header will be found in local & remote rules, respectively. + */ + int pairs_xlate_v4_to_v6_inner(nat46_instance_t *nat46, struct iphdr *iph, + uint16_t sport, uint16_t dport, void *v6saddr, void *v6daddr) { +@@ -1895,35 +2100,27 @@ int pairs_xlate_v4_to_v6_inner(nat46_ins + int xlate_src = -1; + int xlate_dst = -1; + +- for (ipair = 0; ipair < nat46->npairs; ipair++) { +- apair = &nat46->pairs[ipair]; ++ apair = nat46_lpm(nat46, NAT46_IPV4_REMOTE, &iph->saddr); ++ if (!apair) { ++ return 0; ++ } + +- if (-1 == xlate_dst) { +- if (xlate_v4_to_v6(nat46, &apair->local, &iph->daddr, v6daddr, &dport)) { +- nat46debug(3, "Dst addr %pI4 to %pI6 \n", &iph->daddr, v6daddr); +- xlate_dst = ipair; +- } +- } +- if (-1 == xlate_src) { +- if(xlate_v4_to_v6(nat46, &apair->remote, &iph->saddr, v6saddr, &sport)) { +- nat46debug(3, "Src addr %pI4 to %pI6 \n", &iph->saddr, v6saddr); +- xlate_src = ipair; +- } +- } +- if ((xlate_src >= 0) && (xlate_dst >= 0)) { +- /* we did manage to translate it */ +- nat46debug(5, "[nat46] Inner header xlate results: src %d dst %d", xlate_src, xlate_dst); +- return 1; +- } else { +- /* We did not match fully and there are more rules */ +- if((ipair+1 < nat46->npairs) && is_last_pair_in_group(apair)) { +- xlate_src = -1; +- xlate_dst = -1; +- } +- } +-} ++ if (xlate_v4_to_v6(nat46, &apair->local, &iph->daddr, v6daddr, &dport)) { ++ nat46debug(3, "Dst addr %pI4 to %pI6 \n", &iph->daddr, v6daddr); ++ xlate_dst = ipair; ++ } ++ if (xlate_v4_to_v6(nat46, &apair->remote, &iph->saddr, v6saddr, &sport)) { ++ nat46debug(3, "Src addr %pI4 to %pI6 \n", &iph->saddr, v6saddr); ++ xlate_src = ipair; ++ } ++ if ((xlate_src >= 0) && (xlate_dst >= 0)) { ++ /* we did manage to translate it */ ++ nat46debug(5, "[nat46] Inner header xlate results: src %d dst %d", xlate_src, xlate_dst); ++ return 1; ++ } else { ++ nat46debug(1, "[nat46] Could not find a translation pair v4->v6"); ++ } + +- nat46debug(1, "[nat46] Could not find a translation pair v4->v6"); + return 0; + } + +@@ -2020,6 +2217,7 @@ static uint16_t xlate_pkt_in_err_v4_to_v + + int nat46_ipv4_input(struct sk_buff *old_skb) { + nat46_instance_t *nat46 = get_nat46_instance(old_skb); ++ nat46_xlate_rulepair_t apair; + struct sk_buff *new_skb; + uint16_t sport = 0, dport = 0, ret = 0; + +@@ -2097,7 +2295,7 @@ int nat46_ipv4_input(struct sk_buff *old + having_l4 = 1; + } + +- if(!pairs_xlate_v4_to_v6_outer(nat46, hdr4, having_l4 ? &sport : NULL, having_l4 ? &dport : NULL, v6saddr, v6daddr)) { ++ if(!pairs_xlate_v4_to_v6_outer(nat46, &apair, hdr4, having_l4 ? &sport : NULL, having_l4 ? &dport : NULL, v6saddr, v6daddr)) { + nat46debug(0, "[nat46] Could not translate v4->v6"); + goto done; + } +--- a/nat46/modules/nat46-core.h ++++ b/nat46/modules/nat46-core.h +@@ -23,6 +23,15 @@ + // #define nat46debug(level, format, ...) + #define nat46debug(level, format, ...) do { if(nat46->debug >= level) { printk(format "\n", ##__VA_ARGS__); } } while (0) + ++#define U8_MASK (uint8_t)(0xFF) ++#define U32_MASK (uint32_t)(~0U) ++#define BITS_PER_BYTE 8 ++#define PSID_LEN_MAX 16 ++#define NUM_RULE_PAIRS_MAX 32 ++#define IPV4_BITS_MAX 32 ++#define EA_LEN_MAX 48 ++#define IPV6_BITS_MAX 128 ++ + #define IPV6HDRSIZE 40 + #define IPV4HDRSIZE 20 + #define IPV6V4HDRDELTA (IPV6HDRSIZE - IPV4HDRSIZE) +@@ -39,6 +48,17 @@ typedef enum { + NAT46_XLATE_RFC6052 + } nat46_xlate_style_t; + ++/* ++ * Enumeration for sorting pairs based on ++ * type of prefix length. ++ */ ++typedef enum { ++ NAT46_IPV4_LOCAL = 0, ++ NAT46_IPV4_REMOTE, ++ NAT46_IPV6_LOCAL, ++ NAT46_IPV6_REMOTE ++} nat46_rule_type_t; ++ + #define NAT46_SIGNATURE 0x544e3634 + #define FREED_NAT46_SIGNATURE 0xdead544e + +@@ -64,7 +84,11 @@ typedef struct { + int debug; + + int npairs; +- nat46_xlate_rulepair_t pairs[0]; /* npairs */ ++ nat46_xlate_rulepair_t pairs[NUM_RULE_PAIRS_MAX]; /* npairs */ ++ nat46_xlate_rulepair_t sorted_ipv4_local_pairs[NUM_RULE_PAIRS_MAX]; /* npairs */ ++ nat46_xlate_rulepair_t sorted_ipv4_remote_pairs[NUM_RULE_PAIRS_MAX]; /* npairs */ ++ nat46_xlate_rulepair_t sorted_ipv6_local_pairs[NUM_RULE_PAIRS_MAX]; /* npairs */ ++ nat46_xlate_rulepair_t sorted_ipv6_remote_pairs[NUM_RULE_PAIRS_MAX]; /* npairs */ + } nat46_instance_t; + + int nat46_ipv6_input(struct sk_buff *old_skb); +--- a/nat46/modules/nat46-netdev.c ++++ b/nat46/modules/nat46-netdev.c +@@ -270,7 +270,14 @@ int nat46_insert(struct net *net, char * + int ret = -1; + if(dev) { + nat46_instance_t *nat46 = netdev_nat46_instance(dev); +- nat46_instance_t *nat46_new = alloc_nat46_instance(nat46->npairs+1, nat46, 0, 1, -1); ++ nat46_instance_t *nat46_new; ++ ++ if(nat46->npairs == NUM_RULE_PAIRS_MAX) { ++ printk("Could not insert a new rule on device %s\n", devname); ++ return ret; ++ } ++ ++ nat46_new = alloc_nat46_instance(nat46->npairs+1, nat46, 0, 1, -1); + if(nat46_new) { + netdev_nat46_set_instance(dev, nat46_new); + ret = nat46_set_ipair_config(nat46_new, 0, buf, strlen(buf)); diff --git a/package/kernel/nat46/patches/106-dummy_header.patch b/package/kernel/nat46/patches/106-dummy_header.patch new file mode 100644 index 00000000000000..bad08339e6afcf --- /dev/null +++ b/package/kernel/nat46/patches/106-dummy_header.patch @@ -0,0 +1,104 @@ +Author: Pavithra R +Date: Wed Aug 5 10:09:45 2020 +0530 + +nat46: Add dummy fragment header for DF=0 IPv4 packet. + +This patch is propagated from 4.4 kernel commit +b45f19e86ebcc19ea26d5e014bfdcb837148f99e. + +Add dummy fragment header to IPv6 translated packet for +every DF=0 IPv4 packet. + +Change-Id: Id72945eefac030e95e4fd18305e48c46e525def3 +Signed-off-by: Pavithra R + +--- a/nat46/modules/nat46-core.c ++++ b/nat46/modules/nat46-core.c +@@ -1996,6 +1996,27 @@ done: + + + ++/* ++ * Function to get MAP-T rules and flags. ++ */ ++bool nat46_get_info(struct net_device *dev, nat46_xlate_rulepair_t **nat46_rule_pair, ++ int *count, u8 *flag) { ++ if ((!dev) || (!nat46_rule_pair) || (!count) || (!flag)) { ++ return false; ++ } ++ ++ if (!nat46_get_rule_config(dev, nat46_rule_pair, count)) { ++ return false; ++ } ++ ++ /* Check add dummy header flag */ ++ if (add_dummy_header) { ++ *flag = ADD_DUMMY_HEADER; ++ } ++ return true; ++} ++EXPORT_SYMBOL(nat46_get_info); ++ + void ip6_update_csum(struct sk_buff * skb, struct ipv6hdr * ip6hdr, int do_atomic_frag) + { + u32 sum1=0; +@@ -2254,6 +2275,11 @@ int nat46_ipv4_input(struct sk_buff *old + } + hdr4 = ip_hdr(old_skb); + check_for_l4 = 1; ++ if (add_dummy_header) { ++ if (0 == (ntohs(hdr4->frag_off) & IP_DF)) { ++ add_frag_header = 1; ++ } ++ } + } else { + add_frag_header = 1; + if (0 == (ntohs(hdr4->frag_off) & 0x1FFF)) { +--- a/nat46/modules/nat46-core.h ++++ b/nat46/modules/nat46-core.h +@@ -32,6 +32,9 @@ + #define EA_LEN_MAX 48 + #define IPV6_BITS_MAX 128 + ++/* Flag definations for MAP-T */ ++#define ADD_DUMMY_HEADER 0x01 ++ + #define IPV6HDRSIZE 40 + #define IPV4HDRSIZE 20 + #define IPV6V4HDRDELTA (IPV6HDRSIZE - IPV4HDRSIZE) +@@ -110,5 +113,6 @@ int xlate_6_to_4(struct net_device *dev, + int xlate_4_to_6(struct net_device *dev, struct iphdr *hdr4, uint16_t sport, uint16_t dport, void *v6saddr, void *v6daddr); + bool nat46_get_rule_config(struct net_device *dev, nat46_xlate_rulepair_t **nat46_rule_pair, int *count); + int nat46_get_npairs(struct net_device *dev); +- ++bool nat46_get_info(struct net_device *dev, nat46_xlate_rulepair_t **nat46_rule_pair, ++ int *count, u8 *flag); + #endif +--- a/nat46/modules/nat46-module.c ++++ b/nat46/modules/nat46-module.c +@@ -59,12 +59,16 @@ MODULE_AUTHOR("Andrew Yourtchenko +Date: Wed Aug 5 10:57:25 2020 +0530 + +nat46: Add support for 64-bits stats. + +This patch is propagated from 4.4 kernel commit +4a2d1dd9bc9331392c7a4947126c361217c82e0c + +Add 64-bits stats functionality for MAP-T interface. + +Change-Id: I4a6f9c7ed3554ac0ec672aa5fa283be2e95cfdc0 +Signed-off-by: Pavithra R + +--- a/nat46/modules/nat46-netdev.c ++++ b/nat46/modules/nat46-netdev.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include "nat46-core.h" + #include "nat46-module.h" +@@ -40,16 +41,40 @@ static u8 netdev_count = 0; + + static int nat46_netdev_up(struct net_device *dev); + static int nat46_netdev_down(struct net_device *dev); +- ++static int nat46_netdev_init(struct net_device *dev); ++static void nat46_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *tot); + static netdev_tx_t nat46_netdev_xmit(struct sk_buff *skb, struct net_device *dev); + + + static const struct net_device_ops nat46_netdev_ops = { ++ .ndo_init = nat46_netdev_init, /* device specific initialization */ + .ndo_open = nat46_netdev_up, /* Called at ifconfig nat46 up */ + .ndo_stop = nat46_netdev_down, /* Called at ifconfig nat46 down */ + .ndo_start_xmit = nat46_netdev_xmit, /* REQUIRED, must return NETDEV_TX_OK */ ++ .ndo_get_stats64 = nat46_get_stats64, /* 64 bit device stats */ + }; + ++static int nat46_netdev_init(struct net_device *dev) ++{ ++ int i; ++ dev->tstats = alloc_percpu(struct pcpu_sw_netstats); ++ if (!dev->tstats) { ++ return -ENOMEM; ++ } ++ ++ for_each_possible_cpu(i) { ++ struct pcpu_sw_netstats *ipt_stats; ++ ipt_stats = per_cpu_ptr(dev->tstats, i); ++ u64_stats_init(&ipt_stats->syncp); ++ } ++ return 0; ++} ++ ++static void nat46_netdev_resource_free(struct net_device *dev) ++{ ++ free_percpu(dev->tstats); ++} ++ + static int nat46_netdev_up(struct net_device *dev) + { + netif_start_queue(dev); +@@ -65,9 +90,14 @@ static int nat46_netdev_down(struct net_ + static netdev_tx_t nat46_netdev_xmit(struct sk_buff *skb, struct net_device *dev) + { + int ret = 0; ++ struct pcpu_sw_netstats *tstats = get_cpu_ptr(dev->tstats); ++ ++ u64_stats_update_begin(&tstats->syncp); ++ u64_stats_inc(&tstats->rx_packets); ++ u64_stats_add(&tstats->rx_bytes, skb->len); ++ u64_stats_update_end(&tstats->syncp); ++ put_cpu_ptr(tstats); + +- dev->stats.rx_packets++; +- dev->stats.rx_bytes += skb->len; + if(ETH_P_IP == ntohs(skb->protocol)) { + ret = nat46_ipv4_input(skb); + } +@@ -81,22 +111,39 @@ static netdev_tx_t nat46_netdev_xmit(str + } + + void nat46_netdev_count_xmit(struct sk_buff *skb, struct net_device *dev) { +- dev->stats.tx_packets++; +- dev->stats.tx_bytes += skb->len; ++ struct pcpu_sw_netstats *tstats = get_cpu_ptr(dev->tstats); ++ ++ u64_stats_update_begin(&tstats->syncp); ++ u64_stats_inc(&tstats->tx_packets); ++ u64_stats_add(&tstats->tx_bytes, skb->len); ++ u64_stats_update_end(&tstats->syncp); ++ put_cpu_ptr(tstats); + } + + void nat46_update_stats(struct net_device *dev, uint32_t rx_packets, uint32_t rx_bytes, + uint32_t tx_packets, uint32_t tx_bytes, uint32_t rx_dropped, uint32_t tx_dropped) + { +- dev->stats.rx_packets += rx_packets; +- dev->stats.rx_bytes += rx_bytes; +- dev->stats.tx_packets += tx_packets; +- dev->stats.tx_bytes += tx_bytes; ++ struct pcpu_sw_netstats *tstats = get_cpu_ptr(dev->tstats); ++ ++ u64_stats_update_begin(&tstats->syncp); ++ u64_stats_add(&tstats->rx_packets, rx_packets); ++ u64_stats_add(&tstats->rx_bytes, rx_bytes); ++ u64_stats_add(&tstats->tx_packets, tx_packets); ++ u64_stats_add(&tstats->tx_bytes, tx_bytes); + dev->stats.rx_dropped += rx_dropped; + dev->stats.tx_dropped += tx_dropped; ++ u64_stats_update_end(&tstats->syncp); ++ put_cpu_ptr(tstats); + } + EXPORT_SYMBOL(nat46_update_stats); + ++static void nat46_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *tot) ++{ ++ netdev_stats_to_stats64(tot, &dev->stats); ++ dev_fetch_sw_netstats(tot, dev->tstats); ++} ++ + void *netdev_nat46_instance(struct net_device *dev) { + nat46_netdev_priv_t *priv = netdev_priv(dev); + return priv->nat46; +@@ -120,6 +167,7 @@ static void nat46_netdev_setup(struct ne + priv->nat46 = nat46; + + dev->netdev_ops = &nat46_netdev_ops; ++ dev->priv_destructor = nat46_netdev_resource_free; + dev->type = ARPHRD_NONE; + dev->hard_header_len = 0; + dev->addr_len = 0; diff --git a/package/kernel/nat46/patches/108-ce_port.patch b/package/kernel/nat46/patches/108-ce_port.patch new file mode 100644 index 00000000000000..ab6ab37b986e07 --- /dev/null +++ b/package/kernel/nat46/patches/108-ce_port.patch @@ -0,0 +1,134 @@ +Author: Pavithra R +Date: Wed Aug 5 18:59:20 2020 +0530 + +nat46: Copy CE's port number to IPv6 fragment header. + +This patch is propagated from kernel 4.4 commit +7886fd3eb081c7767b02685593bc1d19deaecba8 + +Copy CE's port number to the lower 16-bits of IPv6 identification +number. + +Change-Id: I6946e93bf8bed4c1378d19e75db0729097e0d9eb +Signed-off-by: Pavithra R + +--- a/nat46/modules/nat46-core.c ++++ b/nat46/modules/nat46-core.c +@@ -31,6 +31,7 @@ + + static uint16_t xlate_pkt_in_err_v4_to_v6(nat46_instance_t *nat46, struct iphdr *iph, + struct sk_buff *old_skb, uint16_t *sport, uint16_t *dport); ++static DEFINE_SPINLOCK(port_id_lock); + + void + nat46debug_dump(nat46_instance_t *nat46, int level, void *addr, int len) +@@ -2236,6 +2237,73 @@ static uint16_t xlate_pkt_in_err_v4_to_v + return 1; + } + ++/* Return the port number from CE's port set */ ++static uint16_t nat46_get_ce_port(nat46_xlate_rulepair_t *pair, uint16_t sport) ++{ ++ /* ++ * 'psid_bits_len' represents number of bits in PSID. ++ * 'offset' represents offset of PSID in a port number. ++ */ ++ uint8_t psid_bits_len, offset, port_set_bitmask; ++ ++ /* ++ * 'psid16' represent PSID value. ++ * 'm' represents number of bits in excluded port set. ++ * 'a' represents number of bits in a 16-bit port number after PSID. ++ * It is used to control number of port in one contiguous port set. ++ * ++ * Name of a variable 'a' and 'm' is as per Appendix B of [RFC7597]. ++ */ ++ uint16_t psid16, value, m, a; ++ nat46_xlate_rule_t *rule; ++ ++ /* stores to last port number from CE's port set */ ++ static uint16_t port_num; ++ ++ rule = &pair->local; ++ offset = rule->psid_offset; ++ ++ if (rule->ea_len + rule->v4_pref_len > IPV4_BITS_MAX) { ++ psid_bits_len = rule->ea_len - (IPV4_BITS_MAX - rule->v4_pref_len); ++ } else { ++ return 0; ++ } ++ a = PSID_LEN_MAX - offset - psid_bits_len; ++ psid16 = (ntohs(sport) >> a) & (0xffff >> (PSID_LEN_MAX - psid_bits_len)); ++ ++ spin_lock(&port_id_lock); ++ ++ /* Start case */ ++ if (0 == port_num) { ++ m = (offset) ? 1 : 0; ++ port_num = (m << (PSID_LEN_MAX - offset)) | (psid16 << a); ++ value = port_num; ++ spin_unlock(&port_id_lock); ++ return value; ++ } ++ ++ /* End of one port set */ ++ port_set_bitmask = (1 << a) - 1; ++ value = port_num & port_set_bitmask; ++ if (0 == (value ^ port_set_bitmask)) { ++ m = port_num >> (PSID_LEN_MAX - offset); ++ m++; ++ /* End case */ ++ if (m >= (1 << offset)) { ++ m = (offset) ? 1 : 0; ++ } ++ port_num = (m << (PSID_LEN_MAX - offset)) | (psid16 << a); ++ value = port_num; ++ spin_unlock(&port_id_lock); ++ return value; ++ } ++ ++ port_num++; ++ value = port_num; ++ spin_unlock(&port_id_lock); ++ return value; ++} ++ + int nat46_ipv4_input(struct sk_buff *old_skb) { + nat46_instance_t *nat46 = get_nat46_instance(old_skb); + nat46_xlate_rulepair_t apair; +@@ -2368,9 +2436,34 @@ int nat46_ipv4_input(struct sk_buff *old + + if (add_frag_header) { + struct frag_hdr *fh = (struct frag_hdr*)(hdr6 + 1); ++ uint16_t ce_port_num = 0; ++ ++ /* Flag to represent whether PSID is assigned to MAP-T node or not */ ++ bool is_psid = false; ++ + fh->frag_off = htons(((ntohs(hdr4->frag_off) >> 13) & 7) + ((ntohs(hdr4->frag_off) & 0x1FFF) << 3)); + fh->nexthdr = hdr4->protocol; +- fh->identification = htonl(ntohs(hdr4->id)); ++ ++ /* ++ * PSID assigned MAP-T node will have non-zero ea_len and we are currently ++ * only supporting NAT46_XLATE_MAP as the CE's rule style. ++ */ ++ is_psid = (apair.local.style == NAT46_XLATE_MAP) && apair.local.ea_len; ++ if (is_psid) { ++ ce_port_num = nat46_get_ce_port(nat46->pairs, sport); ++ nat46debug(10, "\n ce port number is %02x\n", ce_port_num); ++ ++ /* Assign CE's port number as the fragment identifier */ ++ if (ce_port_num) { ++ fh->identification = htonl(ce_port_num); ++ } else { ++ fh->identification = htonl(ntohs(hdr4->id)); ++ } ++ } else { ++ fh->identification = htonl(ntohs(hdr4->id)); ++ } ++ ++ + } + ip6_update_csum(new_skb, hdr6, add_frag_header); + diff --git a/package/kernel/nat46/patches/109-fragment_if_not_df_and_larger_than_mtu.patch b/package/kernel/nat46/patches/109-fragment_if_not_df_and_larger_than_mtu.patch new file mode 100644 index 00000000000000..333228a97496c3 --- /dev/null +++ b/package/kernel/nat46/patches/109-fragment_if_not_df_and_larger_than_mtu.patch @@ -0,0 +1,30 @@ +Author: Pavithra R +Date: Wed Aug 5 19:26:48 2020 +0530 + +nat46: Fix the issue of packets not fragmented + +This patch is propagated from the kernel 4.4 commit +e598f9c249092abd7c7978fe99b6690884f225c9 + +when packets size is larger than the MTU of dst, if DF flag is not set, +fragment it instead of dropping it with PktTooBig ICMPv6 message. + +Change-Id: I380d42f59bb4f46a45e542f251f5710f2cca8b62 +Signed-off-by: Pavithra R + +--- a/nat46/modules/nat46-core.c ++++ b/nat46/modules/nat46-core.c +@@ -2343,10 +2343,11 @@ int nat46_ipv4_input(struct sk_buff *old + } + hdr4 = ip_hdr(old_skb); + check_for_l4 = 1; +- if (add_dummy_header) { +- if (0 == (ntohs(hdr4->frag_off) & IP_DF)) { ++ if (0 == (ntohs(hdr4->frag_off) & IP_DF)) { ++ if (add_dummy_header) { + add_frag_header = 1; + } ++ old_skb->ignore_df = 1; + } + } else { + add_frag_header = 1; diff --git a/package/kernel/nat46/patches/110-icmp_error_not_handled.patch b/package/kernel/nat46/patches/110-icmp_error_not_handled.patch new file mode 100644 index 00000000000000..5697c609732ccf --- /dev/null +++ b/package/kernel/nat46/patches/110-icmp_error_not_handled.patch @@ -0,0 +1,100 @@ +Author: Pavithra R +Date: Wed Aug 5 20:16:27 2020 +0530 + +nat46: fix ICMPv6 error message dropped locally + +This patch is propagated from the kernel 4.4 commit +1b96bd0e9ee9182566b119741854c03bf4b94a99 + +While routing IPv6 packets from a customer-side translated device (CLAT) +to a provider-side translated device (PLAT), it is possible that the IPv6 +destination is unknown. In such a scenario, the IPv6 stack must send back +an ICMP error. However, the source IPv6 address of this error message does +not have a MAP-T translation. According to RFC2473, the translation layer +should use the tunnel's own IPv4 address for the IPv6 ICMP packet's source +address. + +Change-Id: I784473cddf9214843c466d10763cb66852139ef6 +Signed-off-by: Pavithra R + +--- a/nat46/modules/nat46-core.c ++++ b/nat46/modules/nat46-core.c +@@ -1782,11 +1782,12 @@ static uint16_t nat46_fixup_icmp(nat46_i + return ret; + } + +-int pairs_xlate_v6_to_v4_outer(nat46_instance_t *nat46, nat46_xlate_rulepair_t *apair, ++int pairs_xlate_v6_to_v4_outer(nat46_instance_t *nat46, nat46_xlate_rulepair_t **papair, + struct ipv6hdr *ip6h, uint16_t proto, __u32 *pv4saddr, __u32 *pv4daddr) { + int ipair = 0; + int xlate_src = -1; + int xlate_dst = -1; ++ nat46_xlate_rulepair_t *apair; + + for(ipair = 0; ipair < nat46->npairs; ipair++) { + apair = nat46_lpm(nat46, NAT46_IPV6_REMOTE, &ip6h->saddr); +@@ -1794,6 +1795,7 @@ int pairs_xlate_v6_to_v4_outer(nat46_ins + return 0; + } + ++ *papair = apair; + if (xlate_v6_to_v4(nat46, &apair->local, &ip6h->daddr, pv4daddr)) { + nat46debug(5, "Dst addr %pI6 to %pI4 \n", &ip6h->daddr, pv4daddr); + xlate_dst = ipair; +@@ -1822,14 +1824,14 @@ int pairs_xlate_v6_to_v4_outer(nat46_ins + } + + int xlate_6_to_4(struct net_device *dev, struct ipv6hdr *ip6h, uint16_t proto, __u32 *pv4saddr, __u32 *pv4daddr) { +- nat46_xlate_rulepair_t apair; ++ nat46_xlate_rulepair_t *apair; + return pairs_xlate_v6_to_v4_outer(netdev_nat46_instance(dev), &apair, ip6h, proto, pv4saddr, pv4daddr); + } + EXPORT_SYMBOL(xlate_6_to_4); + + int nat46_ipv6_input(struct sk_buff *old_skb) { + struct ipv6hdr *ip6h = ipv6_hdr(old_skb); +- nat46_xlate_rulepair_t apair; ++ nat46_xlate_rulepair_t *apair; + nat46_instance_t *nat46 = get_nat46_instance(old_skb); + uint16_t proto; + uint16_t frag_off; +@@ -1903,8 +1905,37 @@ int nat46_ipv6_input(struct sk_buff *old + } + + if (!pairs_xlate_v6_to_v4_outer(nat46, &apair, ip6h, proto, &v4saddr, &v4daddr)) { +- nat46debug(0, "[nat46] Could not translate v6->v4"); +- goto done; ++ if (proto == NEXTHDR_ICMP) { ++ struct icmp6hdr *icmp6h = add_offset(ip6h, v6packet_l3size); ++ struct ipv6hdr *ip6h_inner = (struct ipv6hdr *) (icmp6h + 1); ++ struct ipv6hdr hdr6; ++ switch(icmp6h->icmp6_type) { ++ case ICMPV6_DEST_UNREACH: ++ case ICMPV6_PKT_TOOBIG: ++ case ICMPV6_TIME_EXCEED: ++ case ICMPV6_PARAMPROB: ++ /* ++ * For icmpv6 error message, using the original message ++ * address to locate the apair one more time according ++ * to the RFC 2473, and use the ipv4 address of the ++ * tunnel as SRC ipv4 address ++ */ ++ memcpy(&hdr6.saddr, &ip6h_inner->daddr, 16); ++ memcpy(&hdr6.daddr, &ip6h_inner->saddr, 16); ++ if (!pairs_xlate_v6_to_v4_outer(nat46, &apair, &hdr6, proto, &v4saddr, &v4daddr)) { ++ nat46debug(0, "[nat46] Could not translate v6->v4"); ++ goto done; ++ } ++ v4saddr = apair->local.v4_pref; ++ break; ++ default: ++ nat46debug(0, "[nat46] Could not translate v6->v4"); ++ goto done; ++ } ++ } else { ++ nat46debug(0, "[nat46] Could not translate v6->v4"); ++ goto done; ++ } + } + + if (check_for_l4) { diff --git a/package/kernel/nat46/patches/111-fix_null_point_reference.patch b/package/kernel/nat46/patches/111-fix_null_point_reference.patch new file mode 100644 index 00000000000000..4cef9db199d639 --- /dev/null +++ b/package/kernel/nat46/patches/111-fix_null_point_reference.patch @@ -0,0 +1,40 @@ +Author: Pavithra R +Date: Wed Aug 5 20:35:00 2020 +0530 + +nat46: Fix null pointer dereference issue + +This patch is propagated from the kernel 4.4 commit +5bdf9bd5500c45ab5a3fd43e60c40a09d5e5a13d + +get_nat46_instance possibly returns null point, before using the returning +point, caller needs to check if it is null. + +Change-Id: Id407a71ca8eccd60a713c34429e7e3f16e2cdd12 +Signed-off-by: Pavithra R + +--- a/nat46/modules/nat46-core.c ++++ b/nat46/modules/nat46-core.c +@@ -1847,6 +1847,11 @@ int nat46_ipv6_input(struct sk_buff *old + int l3_infrag_payload_len = ntohs(ip6h->payload_len); + int check_for_l4 = 0; + ++ if (nat46 == NULL) { ++ printk("nat46:%p skb is dropped for no valid instance found\n", old_skb); ++ return err; ++ } ++ + nat46debug(4, "nat46_ipv6_input packet"); + + if(ip6_input_not_interested(nat46, ip6h, old_skb)) { +@@ -2353,6 +2358,11 @@ int nat46_ipv4_input(struct sk_buff *old + + char v6saddr[16], v6daddr[16]; + ++ if (nat46 == NULL) { ++ printk("nat46:%p skb is dropped for no valid instance found\n", old_skb); ++ return err; ++ } ++ + memset(v6saddr, 1, 16); + memset(v6daddr, 2, 16); + diff --git a/package/kernel/nat46/patches/112-fix_icmp_crash.patch b/package/kernel/nat46/patches/112-fix_icmp_crash.patch new file mode 100644 index 00000000000000..5d34697a45b84d --- /dev/null +++ b/package/kernel/nat46/patches/112-fix_icmp_crash.patch @@ -0,0 +1,40 @@ +Author: Pavithra R +Date: Wed Aug 5 20:57:33 2020 +0530 + +Fix crash of free skb + +This patch is propagated from the 4.4 kernel commit +b959b0d45c66ae004a5bfc1687980093fa5b8cc3. + +This is caused by the translation of the inner ipv6 header, it +move memory by the inner head's tot_len which is not exact that +inner packet will be trimmed for icmp error packets size no more +than 576. + +Change-Id: Id5d41fa0721acdf6ea76721c45415fe3be432207 +Signed-off-by: Pavithra R + +--- a/nat46/modules/nat46-core.c ++++ b/nat46/modules/nat46-core.c +@@ -2245,7 +2245,9 @@ static uint16_t xlate_pkt_in_err_v4_to_v + + if (skb_tailroom(old_skb) >= IPV6V4HDRDELTA){ + skb_put(old_skb, IPV6V4HDRDELTA); +- memmove(((char *)iiph + IPV6HDRSIZE), (iiph + 1), ntohs(iiph->tot_len) - IPV4HDRSIZE); ++ /* ErrorICMP size is less than 576, the inner ipv4 packet will be trimmed */ ++ memmove(((char *)iiph + IPV6HDRSIZE), (iiph + 1), ++ ntohs(iph->tot_len) - 2 * IPV4HDRSIZE - sizeof(struct icmphdr)); + memcpy(iiph, &ip6h, IPV6HDRSIZE); + } + else { +@@ -2258,7 +2260,9 @@ static uint16_t xlate_pkt_in_err_v4_to_v + + skb_put(old_skb, IPV6V4HDRDELTA); + iiph = (struct iphdr *)(icmp_hdr(old_skb) + 1); +- memmove(((char *)iiph + IPV6HDRSIZE), (iiph + 1), ntohs(iiph->tot_len) - IPV4HDRSIZE); ++ /* ErrorICMP size is less than 576, the inner ipv4 packet will be trimmed */ ++ memmove(((char *)iiph + IPV6HDRSIZE), (iiph + 1), ++ ntohs(iph->tot_len) - 2 * IPV4HDRSIZE - sizeof(struct icmphdr)); + memcpy(iiph, &ip6h, IPV6HDRSIZE); + nat46 = get_nat46_instance(old_skb); + iph = ip_hdr(old_skb); diff --git a/package/kernel/nat46/patches/116-rate-limit-the-print.patch b/package/kernel/nat46/patches/116-rate-limit-the-print.patch new file mode 100644 index 00000000000000..d857d0e6cb0a05 --- /dev/null +++ b/package/kernel/nat46/patches/116-rate-limit-the-print.patch @@ -0,0 +1,34 @@ +Author: Pavithra R +Date: Wed Sep 30 14:05:50 2020 +0530 + +nat46: Add rate limit to a print. + +This patch is propagated from the kernel 4.4 commit +d47f62508d2c105f236470e56bedbe279db0e6f1 + +Change-Id: I2119fbe54d630c3ed39535f1cb1b8a0d9d3199b4 +Signed-off-by: Pavithra R +--- a/nat46/modules/nat46-core.c ++++ b/nat46/modules/nat46-core.c +@@ -1928,7 +1928,9 @@ int nat46_ipv6_input(struct sk_buff *old + memcpy(&hdr6.saddr, &ip6h_inner->daddr, 16); + memcpy(&hdr6.daddr, &ip6h_inner->saddr, 16); + if (!pairs_xlate_v6_to_v4_outer(nat46, &apair, &hdr6, proto, &v4saddr, &v4daddr)) { +- nat46debug(0, "[nat46] Could not translate v6->v4"); ++ if (net_ratelimit()) { ++ nat46debug(0, "[nat46] Could not translate v6->v4"); ++ } + goto done; + } + v4saddr = apair->local.v4_pref; +@@ -2436,7 +2438,9 @@ int nat46_ipv4_input(struct sk_buff *old + } + + if(!pairs_xlate_v4_to_v6_outer(nat46, &apair, hdr4, having_l4 ? &sport : NULL, having_l4 ? &dport : NULL, v6saddr, v6daddr)) { +- nat46debug(0, "[nat46] Could not translate v4->v6"); ++ if (net_ratelimit()) { ++ nat46debug(0, "[nat46] Could not translate v4->v6"); ++ } + goto done; + } + diff --git a/package/kernel/nat46/patches/117-fix-icmp-no-payload-bug.patch b/package/kernel/nat46/patches/117-fix-icmp-no-payload-bug.patch new file mode 100644 index 00000000000000..a8bff4a945457c --- /dev/null +++ b/package/kernel/nat46/patches/117-fix-icmp-no-payload-bug.patch @@ -0,0 +1,34 @@ +Author: Pavithra R +Date: Wed Sep 30 14:27:37 2020 +0530 + +nat46: Fix for ICMP error packets with no payload. + +This patch is propagated from the kernel 4.4 commit +d8b29a8e31f948a5d7338aa69c36e0f654fcb9e4 + +When no payload is attached to the original packet, any +ICMP error message generated in response to such packets +gets dropped due to malformed packet at CE. + +During the translation of packet-in-error in ICMP, +the IPv6 header in ICMPv6 payload gets corrupted. +Hence, the translated packet gets dropped at CE. + +This fix updates the outer IPv4 header's total length +before translating to IPv6 header. + +Change-Id: Ifd9802afb50771de39b4c6fb734d36b0801613ec +Signed-off-by: Pavithra R +--- a/nat46/modules/nat46-core.c ++++ b/nat46/modules/nat46-core.c +@@ -2266,9 +2266,8 @@ static uint16_t xlate_pkt_in_err_v4_to_v + memmove(((char *)iiph + IPV6HDRSIZE), (iiph + 1), + ntohs(iph->tot_len) - 2 * IPV4HDRSIZE - sizeof(struct icmphdr)); + memcpy(iiph, &ip6h, IPV6HDRSIZE); +- nat46 = get_nat46_instance(old_skb); +- iph = ip_hdr(old_skb); + } ++ iph->tot_len = htons(ntohs(iph->tot_len) + IPV6V4HDRDELTA); + + /* Swapping Ports for outer header */ + /* Another work-around till LPM is not present. */ diff --git a/package/kernel/nat46/patches/118-performance_fix.patch b/package/kernel/nat46/patches/118-performance_fix.patch new file mode 100644 index 00000000000000..5f10ca10bb67bd --- /dev/null +++ b/package/kernel/nat46/patches/118-performance_fix.patch @@ -0,0 +1,415 @@ +Author: Suruchi Agarwal +Date: Fri Dec 17 13:37:15 2021 -0800 + + nat46: Performance fix + + Avoid allocating new skb and copy for map-t translation + + Change-Id: I621b90609b4642d64b6e4cfb98b105b3fcbb0365 + Signed-off-by: Suruchi Agarwal + +--- a/nat46/modules/nat46-core.c ++++ b/nat46/modules/nat46-core.c +@@ -118,7 +118,7 @@ char *get_next_arg(char **ptail) { + return pc; + } + +-/* ++/* + * Parse an IPv6 address (if pref_len is NULL), or prefix (if it isn't). + * parses destructively (places \0 between address and prefix len) + */ +@@ -163,7 +163,7 @@ int try_parse_ipv4_prefix(u32 *v4addr, i + } + + +-/* ++/* + * parse a rule argument and put config into a rule. + * advance the tail to prepare for the next arg parsing. + * destructive. +@@ -384,7 +384,7 @@ char *xlate_style_to_string(nat46_xlate_ + return "unknown"; + } + +-/* ++/* + * Get the nat46 configuration into a supplied buffer (if non-null). + */ + int nat46_get_ipair_config(nat46_instance_t *nat46, int ipair, char *buf, int count) { +@@ -985,6 +985,28 @@ __sum16 csum_ipv6_unmagic(nat46_instance + return csum; + } + ++/* Update UDP with incremental checksum */ ++__sum16 csum_ipv6_udp_remagic(struct ipv6hdr *ip6hdr, u32 csum) { ++ uint32_t sum; ++ sum = csum_partial(ip6hdr->saddr.s6_addr16, 2 * sizeof(ip6hdr->saddr), ~csum); ++ sum = ((sum >> 16) & 0xffff) + (sum & 0xffff); ++ sum += ((sum >> 16) & 0xffff); ++ return (u16)(~sum); ++} ++ ++/* Undo the IPv4 pseudoheader inclusion into the checksum */ ++__sum16 csum_ipv4_unmagic(__be32 saddr, __be32 daddr, ++ u32 csum) { ++ u32 s; ++ uint32_t addr_csum; ++ csum = ntohs(~csum); ++ addr_csum = (saddr & 0xffff) + (saddr >> 16) + (daddr & 0xffff) + (daddr >> 16); ++ s= csum + ntohs(~addr_csum); ++ s = ((s >> 16) & 0xffff) + (s & 0xffff); ++ s += ((s >> 16) & 0xffff); ++ return htons((u16)(~s)); ++} ++ + /* Update ICMPv6 type/code with incremental checksum adjustment */ + void update_icmp6_type_code(nat46_instance_t *nat46, struct icmp6hdr *icmp6h, u8 type, u8 code) { + u16 old_tc = *((u16 *)icmp6h); +@@ -1038,9 +1060,8 @@ void fill_v6hdr_from_v4hdr(struct iphdr + ip6h->hop_limit = iph->ttl; + } + +-void fill_v4hdr_from_v6hdr(struct iphdr * iph, struct ipv6hdr *ip6h, __u32 v4saddr, __u32 v4daddr, __u16 id, __u16 frag_off, __u16 proto, int l3_payload_len) { +- uint32_t ver_class_flow = ntohl(*(__be32 *)ip6h); +- iph->ttl = ip6h->hop_limit; ++void fill_v4hdr_from_v6hdr(struct iphdr * iph, uint32_t ver_class_flow, uint8_t hop_limit, __u32 v4saddr, __u32 v4daddr, __u16 id, __u16 frag_off, __u16 proto, int l3_payload_len) { ++ iph->ttl = hop_limit; + iph->saddr = v4saddr; + iph->daddr = v4daddr; + iph->protocol = proto; +@@ -1198,6 +1219,8 @@ void pairs_xlate_v6_to_v4_inner(nat46_in + */ + int xlate_payload6_to4(nat46_instance_t *nat46, void *pv6, void *ptrans_hdr, int v6_len, u16 *ul_sum, int *ptailTruncSize) { + struct ipv6hdr *ip6h = pv6; ++ uint32_t ver_class_flow; ++ uint8_t hop_limit; + __u32 v4saddr, v4daddr; + struct iphdr new_ipv4; + struct iphdr *iph = &new_ipv4; +@@ -1274,7 +1297,10 @@ int xlate_payload6_to4(nat46_instance_t + } + } + +- fill_v4hdr_from_v6hdr(iph, ip6h, v4saddr, v4daddr, ipid, ipflags, proto, infrag_payload_len); ++ ver_class_flow = ntohl(*(__be32 *)ip6h); ++ hop_limit = ip6h->hop_limit; ++ ++ fill_v4hdr_from_v6hdr(iph, ver_class_flow, hop_limit, v4saddr, v4daddr, ipid, ipflags, proto, infrag_payload_len); + if(ul_sum) { + *ul_sum = unchecksum16(pv6, (((u8 *)ptrans_hdr)-((u8 *)pv6))/2, *ul_sum); + *ul_sum = rechecksum16(iph, 10, *ul_sum); +@@ -1831,6 +1857,8 @@ EXPORT_SYMBOL(xlate_6_to_4); + + int nat46_ipv6_input(struct sk_buff *old_skb) { + struct ipv6hdr *ip6h = ipv6_hdr(old_skb); ++ uint32_t ver_class_flow; ++ uint8_t hop_limit; + nat46_xlate_rulepair_t *apair; + nat46_instance_t *nat46 = get_nat46_instance(old_skb); + uint16_t proto; +@@ -1839,22 +1867,20 @@ int nat46_ipv6_input(struct sk_buff *old + + struct iphdr * iph; + __u32 v4saddr, v4daddr; +- struct sk_buff * new_skb = 0; + int err = 0; +- int truncSize = 0; + int tailTruncSize = 0; + int v6packet_l3size = sizeof(*ip6h); + int l3_infrag_payload_len = ntohs(ip6h->payload_len); + int check_for_l4 = 0; + +- if (nat46 == NULL) { ++ if (unlikely(nat46 == NULL)) { + printk("nat46:%p skb is dropped for no valid instance found\n", old_skb); + return err; + } + + nat46debug(4, "nat46_ipv6_input packet"); + +- if(ip6_input_not_interested(nat46, ip6h, old_skb)) { ++ if(unlikely(ip6_input_not_interested(nat46, ip6h, old_skb))) { + nat46debug(1, "nat46_ipv6_input not interested"); + goto done; + } +@@ -1985,47 +2011,45 @@ int nat46_ipv6_input(struct sk_buff *old + } + } + +- new_skb = skb_copy(old_skb, GFP_ATOMIC); // other possible option: GFP_ATOMIC +- if (!new_skb) { +- nat46debug(0, "[nat46] Could not copy v6 skb"); +- goto done; +- } ++ ver_class_flow = ntohl(*(__be32 *)ip6h); ++ hop_limit = ip6h->hop_limit; + + /* Remove any debris in the socket control block */ +- memset(IPCB(new_skb), 0, sizeof(struct inet_skb_parm)); ++ memset(IPCB(old_skb), 0, sizeof(struct inet_skb_parm)); ++ + /* Remove netfilter references to IPv6 packet, new netfilter references will be created based on IPv4 packet */ + #if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) +- nf_reset(new_skb); ++ nf_reset(old_skb); + #else +- skb_ext_reset(new_skb); +- nf_reset_ct(new_skb); ++ skb_ext_reset(old_skb); ++ nf_reset_ct(old_skb); + #endif + + /* modify packet: actual IPv6->IPv4 transformation */ +- truncSize = v6packet_l3size - sizeof(struct iphdr); /* chop first 20 bytes */ +- skb_pull(new_skb, truncSize); +- skb_put(new_skb, -tailTruncSize); ++ skb_pull(old_skb, sizeof(struct iphdr)); + l3_infrag_payload_len -= tailTruncSize; +- skb_reset_network_header(new_skb); +- skb_set_transport_header(new_skb,IPV4HDRSIZE); /* transport (TCP/UDP/ICMP/...) header starts after 20 bytes */ ++ skb_reset_mac_header(old_skb); ++ skb_reset_network_header(old_skb); ++ skb_set_transport_header(old_skb,IPV4HDRSIZE); /* transport (TCP/UDP/ICMP/...) header starts after 20 bytes */ + + /* build IPv4 header */ +- iph = ip_hdr(new_skb); +- fill_v4hdr_from_v6hdr(iph, ip6h, v4saddr, v4daddr, frag_id, frag_off, proto, l3_infrag_payload_len); +- new_skb->protocol = htons(ETH_P_IP); ++ iph = ip_hdr(old_skb); ++ fill_v4hdr_from_v6hdr(iph, ver_class_flow, hop_limit, v4saddr, v4daddr, frag_id, frag_off, proto, l3_infrag_payload_len); ++ old_skb->protocol = htons(ETH_P_IP); + + if (ntohs(iph->tot_len) >= 2000) { + nat46debug(0, "Too big IP len: %d", ntohs(iph->tot_len)); + } + +- nat46debug(5, "about to send v4 packet, flags: %02x", IPCB(new_skb)->flags); +- nat46_netdev_count_xmit(new_skb, old_skb->dev); ++ nat46debug(5, "about to send v4 packet, flags: %02x", IPCB(old_skb)->flags); ++ nat46_netdev_count_xmit(old_skb, old_skb->dev); + +- /* set skb->iif */ +- new_skb->skb_iif = old_skb->skb_iif; +- +- netif_rx(new_skb); ++ netif_rx(old_skb); + ++ /* ++ * skb was consumed in the ipv4 format, don't release later. ++ */ ++ err = 1; + /* TBD: should copy be released here? */ + + done: +@@ -2056,7 +2080,7 @@ bool nat46_get_info(struct net_device *d + } + EXPORT_SYMBOL(nat46_get_info); + +-void ip6_update_csum(struct sk_buff * skb, struct ipv6hdr * ip6hdr, int do_atomic_frag) ++void ip6_update_csum(struct sk_buff * skb, struct ipv6hdr * ip6hdr, uint32_t v4saddr, uint32_t v4daddr, int do_atomic_frag) + { + u32 sum1=0; + u16 sum2=0; +@@ -2079,12 +2103,13 @@ void ip6_update_csum(struct sk_buff * sk + struct udphdr *udp = udp_hdr(skb); + unsigned udplen = ntohs(ip6hdr->payload_len) - (do_atomic_frag?8:0); /* UDP hdr + payload */ + +- oldsum = udp->check; +- udp->check = 0; +- +- sum1 = csum_partial((char*)udp, udplen, 0); /* calculate checksum for UDP hdr+payload */ +- sum2 = csum_ipv6_magic(&ip6hdr->saddr, &ip6hdr->daddr, udplen, ip6hdr->nexthdr, sum1); /* add pseudoheader */ +- ++ if (!udp->check) { ++ sum1 = csum_partial((char*)udp, udplen, 0); /* calculate checksum for UDP hdr+payload */ ++ sum2 = csum_ipv6_magic(&ip6hdr->saddr, &ip6hdr->daddr, udplen, ip6hdr->nexthdr, sum1); /* add pseudoheader */ ++ } else { ++ sum1 = csum_ipv4_unmagic(v4saddr, v4daddr, udp->check); ++ sum2 = csum_ipv6_udp_remagic(ip6hdr, sum1); ++ } + udp->check = sum2; + + break; +@@ -2348,7 +2373,6 @@ static uint16_t nat46_get_ce_port(nat46_ + int nat46_ipv4_input(struct sk_buff *old_skb) { + nat46_instance_t *nat46 = get_nat46_instance(old_skb); + nat46_xlate_rulepair_t apair; +- struct sk_buff *new_skb; + uint16_t sport = 0, dport = 0, ret = 0; + + int err = 0; +@@ -2360,10 +2384,15 @@ int nat46_ipv4_input(struct sk_buff *old + + struct ipv6hdr * hdr6; + struct iphdr * hdr4 = ip_hdr(old_skb); ++ uint32_t v4saddr, v4daddr; ++ uint8_t ttl; ++ uint16_t tot_len; ++ uint8_t protocol; ++ uint16_t frag_off, id; + + char v6saddr[16], v6daddr[16]; + +- if (nat46 == NULL) { ++ if (unlikely(nat46 == NULL)) { + printk("nat46:%p skb is dropped for no valid instance found\n", old_skb); + return err; + } +@@ -2443,31 +2472,39 @@ int nat46_ipv4_input(struct sk_buff *old + goto done; + } + +- new_skb = skb_copy(old_skb, GFP_ATOMIC); +- if (!new_skb) { +- nat46debug(0, "[nat46] Could not copy v4 skb"); +- goto done; +- } ++ v4saddr = hdr4->saddr; ++ v4daddr = hdr4->daddr; ++ protocol = hdr4->protocol; ++ tot_len = hdr4->tot_len; ++ ttl = hdr4->ttl; ++ frag_off = hdr4->frag_off; ++ id = hdr4->id; + + /* Remove any debris in the socket control block */ +- memset(IP6CB(new_skb), 0, sizeof(struct inet6_skb_parm)); ++ memset(IP6CB(old_skb), 0, sizeof(struct inet6_skb_parm)); + /* Remove netfilter references to IPv4 packet, new netfilter references will be created based on IPv6 packet */ + #if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) +- nf_reset(new_skb); ++ nf_reset(old_skb); + #else +- skb_ext_reset(new_skb); +- nf_reset_ct(new_skb); ++ skb_ext_reset(old_skb); ++ nf_reset_ct(old_skb); + #endif + + /* expand header (add 20 extra bytes at the beginning of sk_buff) */ +- pskb_expand_head(new_skb, IPV6HDRSIZE - (hdr4->ihl << 2) + (add_frag_header?8:0), 0, GFP_ATOMIC); ++ if (skb_headroom(old_skb) < IPV6V4HDRDELTA) { ++ ret = pskb_expand_head(old_skb, IPV6V4HDRDELTA + (add_frag_header?8:0), 0, GFP_ATOMIC); ++ if (unlikely(ret)) { ++ nat46debug(0, "[nat46] Could not expand skb header"); ++ goto done; ++ } ++ } + +- skb_push(new_skb, IPV6HDRSIZE - (hdr4->ihl << 2) + (add_frag_header?8:0)); /* push boundary by extra 20 bytes */ ++ skb_push(old_skb, IPV6HDRSIZE - (hdr4->ihl << 2) + (add_frag_header?8:0)); /* push boundary by extra 20 bytes */ + +- skb_reset_network_header(new_skb); +- skb_set_transport_header(new_skb, IPV6HDRSIZE + (add_frag_header?8:0) ); /* transport (TCP/UDP/ICMP/...) header starts after 40 bytes */ ++ skb_reset_network_header(old_skb); ++ skb_set_transport_header(old_skb, IPV6HDRSIZE + (add_frag_header?8:0) ); /* transport (TCP/UDP/ICMP/...) header starts after 40 bytes */ + +- hdr6 = ipv6_hdr(new_skb); ++ hdr6 = ipv6_hdr(old_skb); + memset(hdr6, 0, sizeof(*hdr6) + (add_frag_header?8:0)); + + /* build IPv6 header */ +@@ -2475,13 +2512,14 @@ int nat46_ipv4_input(struct sk_buff *old + *(__be32 *)hdr6 = htonl(0x60000000 | (tclass << 20)) | flowlabel; /* version, priority, flowlabel */ + + /* IPv6 length is a payload length, IPv4 is hdr+payload */ +- hdr6->payload_len = htons(ntohs(hdr4->tot_len) - (hdr4->ihl << 2) + (add_frag_header?8:0)); +- hdr6->nexthdr = hdr4->protocol; +- hdr6->hop_limit = hdr4->ttl; ++ hdr6->payload_len = htons(ntohs(tot_len) - sizeof(struct iphdr) + (add_frag_header?8:0)); ++ hdr6->nexthdr = protocol; ++ hdr6->hop_limit = ttl; ++ + memcpy(&hdr6->saddr, v6saddr, 16); + memcpy(&hdr6->daddr, v6daddr, 16); + +- new_skb->protocol = htons(ETH_P_IPV6); ++ old_skb->protocol = htons(ETH_P_IPV6); + + if (add_frag_header) { + struct frag_hdr *fh = (struct frag_hdr*)(hdr6 + 1); +@@ -2490,8 +2528,8 @@ int nat46_ipv4_input(struct sk_buff *old + /* Flag to represent whether PSID is assigned to MAP-T node or not */ + bool is_psid = false; + +- fh->frag_off = htons(((ntohs(hdr4->frag_off) >> 13) & 7) + ((ntohs(hdr4->frag_off) & 0x1FFF) << 3)); +- fh->nexthdr = hdr4->protocol; ++ fh->frag_off = htons(((ntohs(frag_off) >> 13) & 7) + ((ntohs(frag_off) & 0x1FFF) << 3)); ++ fh->nexthdr = protocol; + + /* + * PSID assigned MAP-T node will have non-zero ea_len and we are currently +@@ -2506,29 +2544,30 @@ int nat46_ipv4_input(struct sk_buff *old + if (ce_port_num) { + fh->identification = htonl(ce_port_num); + } else { +- fh->identification = htonl(ntohs(hdr4->id)); ++ fh->identification = htonl(ntohs(id)); + } + } else { +- fh->identification = htonl(ntohs(hdr4->id)); ++ fh->identification = htonl(ntohs(id)); + } + + + } +- ip6_update_csum(new_skb, hdr6, add_frag_header); ++ ip6_update_csum(old_skb, hdr6, v4saddr, v4daddr, add_frag_header); + +- hdr6->nexthdr = add_frag_header ? NEXTHDR_FRAGMENT : hdr4->protocol; ++ hdr6->nexthdr = add_frag_header ? NEXTHDR_FRAGMENT : protocol; + + + // FIXME: check if you can not fit the packet into the cached MTU +- // if (dst_mtu(skb_dst(new_skb))==0) { } +- +- nat46debug(5, "about to send v6 packet, flags: %02x", IP6CB(new_skb)->flags); +- nat46_netdev_count_xmit(new_skb, old_skb->dev); ++ // if (dst_mtu(skb_dst(old_skb))==0) { } + +- /* set skb->iif */ +- new_skb->skb_iif = old_skb->skb_iif; ++ nat46debug(5, "about to send v6 packet, flags: %02x", IPCB(old_skb)->flags); ++ nat46_netdev_count_xmit(old_skb, old_skb->dev); ++ netif_rx(old_skb); + +- netif_rx(new_skb); ++ /* ++ * skb was reused, needn't free it later. ++ */ ++ err = 1; + + done: + release_nat46_instance(nat46); +--- a/nat46/modules/nat46-core.h ++++ b/nat46/modules/nat46-core.h +@@ -39,7 +39,7 @@ + #define IPV4HDRSIZE 20 + #define IPV6V4HDRDELTA (IPV6HDRSIZE - IPV4HDRSIZE) + +-/* ++/* + * A generic v4<->v6 translation structure. + * The currently supported translation styles: + */ +--- a/nat46/modules/nat46-netdev.c ++++ b/nat46/modules/nat46-netdev.c +@@ -100,8 +100,7 @@ static netdev_tx_t nat46_netdev_xmit(str + + if(ETH_P_IP == ntohs(skb->protocol)) { + ret = nat46_ipv4_input(skb); +- } +- if(ETH_P_IPV6 == ntohs(skb->protocol)) { ++ }else if(ETH_P_IPV6 == ntohs(skb->protocol)) { + ret = nat46_ipv6_input(skb); + } + if(0 == ret) { +@@ -174,6 +173,7 @@ static void nat46_netdev_setup(struct ne + dev->mtu = 16384; /* iptables does reassembly. Rather than using ETH_DATA_LEN, let's try to get as much mileage as we can with the Linux stack */ + dev->features = NETIF_F_NETNS_LOCAL; + dev->flags = IFF_NOARP | IFF_POINTOPOINT; ++ dev->priv_flags_ext = IFF_EXT_MAPT; + } + + int nat46_netdev_create(struct net *net, char *basename, struct net_device **dev) diff --git a/package/kernel/nat46/patches/120-sleeping_backtrace.patch b/package/kernel/nat46/patches/120-sleeping_backtrace.patch new file mode 100644 index 00000000000000..5963af2b0365d7 --- /dev/null +++ b/package/kernel/nat46/patches/120-sleeping_backtrace.patch @@ -0,0 +1,57 @@ +commit 9457a8be6e700f39e6b545f8db0edd30c0693700 +Author: Ken Zhu +Date: Tue Sep 6 11:11:20 2022 -0700 + + nat46: fix sleeping warning back trace + + use spin_lock instead of mutex_lock since + mutex_lock could sleep in the kernel packet process. + + Change-Id: I65c15a9f618ef296159884a0d6d742e66aaf6623 + Signed-off-by: Ken Zhu + +--- a/nat46/modules/nat46-glue.c ++++ b/nat46/modules/nat46-glue.c +@@ -18,7 +18,7 @@ + #include "nat46-glue.h" + #include "nat46-core.h" + +-static DEFINE_MUTEX(ref_lock); ++static DEFINE_SPINLOCK(ref_lock); + int is_valid_nat46(nat46_instance_t *nat46) { + return (nat46 && (nat46->sig == NAT46_SIGNATURE)); + } +@@ -47,28 +47,27 @@ nat46_instance_t *alloc_nat46_instance(i + return nat46; + } + +- + nat46_instance_t *get_nat46_instance(struct sk_buff *sk) { + nat46_instance_t *nat46 = netdev_nat46_instance(sk->dev); +- mutex_lock(&ref_lock); ++ spin_lock_bh(&ref_lock); + if (is_valid_nat46(nat46)) { + nat46->refcount++; +- mutex_unlock(&ref_lock); ++ spin_unlock_bh(&ref_lock); + return nat46; + } else { + printk("[nat46] get_nat46_instance: Could not find a valid NAT46 instance!"); +- mutex_unlock(&ref_lock); ++ spin_unlock_bh(&ref_lock); + return NULL; + } + } + + void release_nat46_instance(nat46_instance_t *nat46) { +- mutex_lock(&ref_lock); ++ spin_lock_bh(&ref_lock); + nat46->refcount--; + if(0 == nat46->refcount) { + printk("[nat46] release_nat46_instance: freeing nat46 instance with %d pairs\n", nat46->npairs); + nat46->sig = FREED_NAT46_SIGNATURE; + kfree(nat46); + } +- mutex_unlock(&ref_lock); ++ spin_unlock_bh(&ref_lock); + } diff --git a/package/kernel/nat46/patches/121-tos-fix.patch b/package/kernel/nat46/patches/121-tos-fix.patch new file mode 100644 index 00000000000000..6b265886f5b70b --- /dev/null +++ b/package/kernel/nat46/patches/121-tos-fix.patch @@ -0,0 +1,27 @@ +Author: Ramkishan Gurjar +Date: Thu Nov 16 15:30:04 2023 +0530 + + nat46: Fix traffic class is not set in ipv6 Header from ipv4 tos value. + + Change-Id: I781d7af8bc9751dd23f6c3f4195644b3f9025fcb + Signed-off-by: Ramkishan Gurjar + +--- a/nat46/modules/nat46-core.c ++++ b/nat46/modules/nat46-core.c +@@ -2397,6 +2397,8 @@ int nat46_ipv4_input(struct sk_buff *old + return err; + } + ++ tclass = ip_tos_ignore ? 0 : hdr4->tos; /* traffic class */ ++ + memset(v6saddr, 1, 16); + memset(v6daddr, 2, 16); + +@@ -2508,7 +2510,6 @@ int nat46_ipv4_input(struct sk_buff *old + memset(hdr6, 0, sizeof(*hdr6) + (add_frag_header?8:0)); + + /* build IPv6 header */ +- tclass = ip_tos_ignore ? 0 : hdr4->tos; /* traffic class */ + *(__be32 *)hdr6 = htonl(0x60000000 | (tclass << 20)) | flowlabel; /* version, priority, flowlabel */ + + /* IPv6 length is a payload length, IPv4 is hdr+payload */