Merge branch 'NSS-11.2-K5.15' of https://github.com/qosmio/nss-packages into NSS-11.2-K5.15

This commit is contained in:
Qosmio 2022-09-22 19:36:02 -04:00
commit 9ffb83d311
27 changed files with 2581 additions and 5 deletions

41
nat46/Makefile Normal file
View File

@ -0,0 +1,41 @@
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=nat46
PKG_MIRROR_HASH:=0627c7122ff7432aadb443e92e11a9ad7710add0ff512eebe17d7e3c041e0d2a
PKG_SOURCE_URL:=https://github.com/ayourtch/nat46.git
PKG_SOURCE_DATE:=2020-06-26
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=1182f30785e4274913f01a8c3d7e1b5437ae3819
PKG_MAINTAINER:=Hans Dedecker <dedeckeh@gmail.com>
PKG_LICENSE:=GPL-2.0
include $(INCLUDE_DIR)/package.mk
define KernelPackage/nat46
DEPENDS:=@IPV6 +kmod-nf-conntrack6
TITLE:=Stateless NAT46 translation kernel module
SECTION:=kernel
SUBMENU:=Network Support
FILES:=$(PKG_BUILD_DIR)/nat46/modules/nat46.ko
AUTOLOAD:=$(call AutoLoad,33,nat46)
endef
include $(INCLUDE_DIR)/kernel-defaults.mk
define Build/Compile
$(KERNEL_MAKE) M="$(PKG_BUILD_DIR)/nat46/modules" \
MODFLAGS="-DMODULE -mlong-calls" \
EXTRA_CFLAGS="-DNAT46_VERSION=\\\"$(PKG_SOURCE_VERSION)\\\"" \
modules
cp $(PKG_BUILD_DIR)/nat46/modules/Module.symvers $(PKG_BUILD_DIR)/Module.symvers
endef
define Build/InstallDev
mkdir -p -m 0777 $(STAGING_DIR)/usr/include/nat46
$(CP) $(PKG_BUILD_DIR)/nat46/modules/*.h $(STAGING_DIR)/usr/include/nat46/
endef
$(eval $(call KernelPackage,nat46))

View File

@ -0,0 +1,34 @@
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -17,6 +17,7 @@
*/
#include <net/route.h>
+#include <linux/version.h>
#include "nat46-glue.h"
#include "nat46-core.h"
@@ -1601,7 +1602,11 @@ void nat46_ipv6_input(struct sk_buff *ol
/* Remove any debris in the socket control block */
memset(IPCB(new_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);
+#else
+ nf_reset_ct(new_skb);
+#endif
/* modify packet: actual IPv6->IPv4 transformation */
truncSize = v6packet_l3size - sizeof(struct iphdr); /* chop first 20 bytes */
@@ -1806,7 +1811,11 @@ void nat46_ipv4_input(struct sk_buff *ol
/* Remove any debris in the socket control block */
memset(IPCB(new_skb), 0, sizeof(struct inet_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);
+#else
+ nf_reset_ct(new_skb);
+#endif
/* expand header (add 20 extra bytes at the beginning of sk_buff) */
pskb_expand_head(new_skb, IPV6V4HDRDELTA + (add_frag_header?8:0), 0, GFP_ATOMIC);

View File

@ -0,0 +1,30 @@
Author: Pavithra R <pavir@codeaurora.org>
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 <pavir@codeaurora.org>
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -1605,6 +1605,7 @@ void nat46_ipv6_input(struct sk_buff *ol
#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
@@ -1814,6 +1815,7 @@ void nat46_ipv4_input(struct sk_buff *ol
#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

View File

@ -0,0 +1,199 @@
Author: Pavithra R <pavir@codeaurora.org>
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 <pavir@codeaurora.org>
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -1491,6 +1491,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);
void nat46_ipv6_input(struct sk_buff *old_skb) {
struct ipv6hdr *ip6h = ipv6_hdr(old_skb);
@@ -1628,6 +1632,10 @@ void nat46_ipv6_input(struct sk_buff *ol
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? */
@@ -1732,6 +1740,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);
void nat46_ipv4_input(struct sk_buff *old_skb) {
nat46_instance_t *nat46 = get_nat46_instance(old_skb);
@@ -1859,10 +1871,32 @@ void nat46_ipv4_input(struct sk_buff *ol
nat46debug(5, "about to send v6 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);
done:
release_nat46_instance(nat46);
}
+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);
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 <net/ip6_route.h>
#include <net/ipv6.h>
#include <linux/version.h>
+#include <linux/radix-tree.h>
#include "nat46-core.h"
#include "nat46-module.h"
#define NETDEV_DEFAULT_NAME "nat46."
+static RADIX_TREE(netdev_tree, GFP_ATOMIC);
typedef struct {
u32 sig;
@@ -79,6 +81,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;
@@ -155,6 +169,11 @@ int nat46_netdev_create(char *basename,
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:
@@ -169,9 +188,23 @@ void nat46_netdev_destroy(struct net_dev
{
netdev_nat46_set_instance(dev, NULL);
unregister_netdev(dev);
+ radix_tree_delete(&netdev_tree, dev->ifindex);
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
@@ -24,3 +24,6 @@ void nat64_show_all_configs(struct seq_f
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);

View File

@ -0,0 +1,56 @@
Author: Pavithra R <pavir@codeaurora.org>
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 <pavir@codeaurora.org>
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -807,11 +807,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 );
@@ -1750,7 +1751,7 @@ void nat46_ipv4_input(struct sk_buff *ol
struct sk_buff *new_skb;
uint16_t sport = 0, dport = 0;
- int tclass = 0;
+ uint8_t tclass;
int flowlabel = 0;
int check_for_l4 = 0;
int having_l4 = 0;
@@ -1761,6 +1762,8 @@ void nat46_ipv4_input(struct sk_buff *ol
char v6saddr[16], v6daddr[16];
+ tclass = hdr4->tos;
+
memset(v6saddr, 1, 16);
memset(v6daddr, 2, 16);
@@ -1843,7 +1846,6 @@ void nat46_ipv4_input(struct sk_buff *ol
memset(hdr6, 0, sizeof(*hdr6) + (add_frag_header?8:0));
/* build IPv6 header */
- tclass = 0; /* traffic class */
*(__be32 *)hdr6 = htonl(0x60000000 | (tclass << 20)) | flowlabel; /* version, priority, flowlabel */
/* IPv6 length is a payload length, IPv4 is hdr+payload */

View File

@ -0,0 +1,440 @@
Author: Pavithra R <pavir@codeaurora.org>
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 <pavir@codeaurora.org>
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -22,6 +22,9 @@
#include "nat46-glue.h"
#include "nat46-core.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)
{
@@ -806,6 +809,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;
@@ -1128,34 +1139,34 @@ 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;
+ int8_t 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];
if (new_pptr >= 0) {
icmp6h->icmp6_cksum = csum16_upd(icmp6h->icmp6_cksum, (*pptr6 & 0xffff), (new_pptr << 8));
*pptr4 = 0xff & new_pptr;
- } else {
- ip6h->nexthdr = NEXTHDR_NONE;
+ update_icmp6_type_code(nat46, icmp6h, 12, 0);
+ break;
}
- } else {
- ip6h->nexthdr = NEXTHDR_NONE;
}
- break;
- case 1:
- *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 */
@@ -1211,17 +1222,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
@@ -1264,27 +1277,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
@@ -1347,16 +1366,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;
@@ -1406,14 +1430,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;
@@ -1422,22 +1447,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. */
@@ -1457,11 +1482,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;
}
}
@@ -1560,6 +1587,7 @@ void nat46_ipv6_input(struct sk_buff *ol
}
if(!pairs_xlate_v6_to_v4_outer(nat46, ip6h, proto, &v4saddr, &v4daddr)) {
+ nat46debug(0, "[nat46] Could not translate v6->v4");
goto done;
}
@@ -1713,11 +1741,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;
}
}
@@ -1746,10 +1776,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;
+}
+
void 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;
uint8_t tclass;
int flowlabel = 0;
@@ -1772,11 +1937,11 @@ void nat46_ipv4_input(struct sk_buff *ol
}
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) ) { /* Checking for MF */
check_for_l4 = 1;
} else {
add_frag_header = 1;
- if (0 == (ntohs(hdr4->frag_off) & 0x1FFF)) {
+ if (0 == (ntohs(hdr4->frag_off) & 0x1FFF)) { /* Checking for Frag Offset */
check_for_l4 = 1;
}
}
@@ -1798,9 +1963,10 @@ void nat46_ipv4_input(struct sk_buff *ol
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;
}

View File

@ -0,0 +1,639 @@
Author: Pavithra R <pavir@codeaurora.org>
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 <pavir@codeaurora.org>
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -121,6 +121,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));
@@ -134,6 +141,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));
@@ -176,11 +190,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;
@@ -210,7 +340,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) {
@@ -854,37 +995,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);
}
/*
@@ -1471,40 +1695,28 @@ 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];
+ apair = nat46_lpm(nat46, NAT46_IPV6_REMOTE, &ip6h->saddr);
+ if (!apair) {
+ return 0;
+ }
- 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;
- }
- }
- 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->local, &ip6h->daddr, pv4daddr)) {
+ nat46debug(5, "Dst addr %pI6 to %pI4 \n", &ip6h->daddr, pv4daddr);
+ xlate_dst = ipair;
+ }
+ 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;
@@ -1520,12 +1732,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);
void 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;
@@ -1586,7 +1800,7 @@ void nat46_ipv6_input(struct sk_buff *ol
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;
}
@@ -1730,56 +1944,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) {
@@ -1788,35 +1990,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;
}
@@ -1913,6 +2107,7 @@ static uint16_t xlate_pkt_in_err_v4_to_v
void 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;
@@ -1979,7 +2174,7 @@ void nat46_ipv4_input(struct sk_buff *ol
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;
void nat46_ipv6_input(struct sk_buff *old_skb);
--- a/nat46/modules/nat46-netdev.c
+++ b/nat46/modules/nat46-netdev.c
@@ -263,7 +263,13 @@ int nat46_insert(char *devname, char *bu
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);
+ 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);
if(nat46_new) {
netdev_nat46_set_instance(dev, nat46_new);
ret = nat46_set_ipair_config(nat46_new, 0, buf, strlen(buf));

View File

@ -0,0 +1,100 @@
Author: Pavithra R <pavir@codeaurora.org>
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 <pavir@codeaurora.org>
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -21,6 +21,7 @@
#include "nat46-glue.h"
#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);
@@ -2134,6 +2135,11 @@ void nat46_ipv4_input(struct sk_buff *ol
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) ) { /* Checking for MF */
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)) { /* Checking for Frag Offset */
@@ -2263,3 +2269,24 @@ bool nat46_get_rule_config(struct net_de
return true;
}
EXPORT_SYMBOL(nat46_get_rule_config);
+
+/*
+ * 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);
--- 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
@@ -57,6 +57,9 @@ MODULE_DESCRIPTION("NAT46 stateless tran
int debug = 0;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "debugging messages level (default=1)");
+bool add_dummy_header = 0;
+module_param(add_dummy_header, bool, 0);
+MODULE_PARM_DESC(add_dummy_header, "Add dummy fragment header");
static struct proc_dir_entry *nat46_proc_entry;
static struct proc_dir_entry *nat46_proc_parent;
--- a/nat46/modules/nat46-module.h
+++ b/nat46/modules/nat46-module.h
@@ -14,3 +14,4 @@
*/
extern int debug;
+extern bool add_dummy_header;

View File

@ -0,0 +1,134 @@
Author: Pavithra R <pavir@codeaurora.org>
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 <pavir@codeaurora.org>
--- a/nat46/modules/nat46-netdev.c
+++ b/nat46/modules/nat46-netdev.c
@@ -24,6 +24,7 @@
#include <net/ip6_route.h>
#include <net/ipv6.h>
#include <linux/version.h>
+#include <net/ip_tunnels.h>
#include <linux/radix-tree.h>
#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);
@@ -64,8 +89,13 @@ static int nat46_netdev_down(struct net_
static netdev_tx_t nat46_netdev_xmit(struct sk_buff *skb, struct net_device *dev)
{
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
+ struct pcpu_sw_netstats *tstats = get_cpu_ptr(dev->tstats);
+
+ u64_stats_update_begin(&tstats->syncp);
+ tstats->rx_packets++;
+ tstats->rx_bytes += skb->len;
+ u64_stats_update_end(&tstats->syncp);
+ put_cpu_ptr(tstats);
if(ETH_P_IP == ntohs(skb->protocol)) {
nat46_ipv4_input(skb);
}
@@ -77,22 +107,38 @@ 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);
+ tstats->tx_packets++;
+ 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);
+ tstats->rx_packets += rx_packets;
+ tstats->rx_bytes += rx_bytes;
+ tstats->tx_packets += tx_packets;
+ 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)
+{
+ dev_get_tstats64(dev, tot);
+}
+
void *netdev_nat46_instance(struct net_device *dev) {
nat46_netdev_priv_t *priv = netdev_priv(dev);
return priv->nat46;
@@ -116,6 +162,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;

View File

@ -0,0 +1,134 @@
Author: Pavithra R <pavir@codeaurora.org>
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 <pavir@codeaurora.org>
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -25,6 +25,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)
@@ -2106,6 +2107,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;
+}
+
void nat46_ipv4_input(struct sk_buff *old_skb) {
nat46_instance_t *nat46 = get_nat46_instance(old_skb);
nat46_xlate_rulepair_t apair;
@@ -2226,9 +2294,34 @@ void nat46_ipv4_input(struct sk_buff *ol
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);

View File

@ -0,0 +1,30 @@
Author: Pavithra R <pavir@codeaurora.org>
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 <pavir@codeaurora.org>
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -2203,10 +2203,11 @@ void nat46_ipv4_input(struct sk_buff *ol
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) ) { /* Checking for MF */
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;

View File

@ -0,0 +1,99 @@
Author: Pavithra R <pavir@codeaurora.org>
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 <pavir@codeaurora.org>
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -1697,17 +1697,19 @@ 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;
apair = nat46_lpm(nat46, NAT46_IPV6_REMOTE, &ip6h->saddr);
if (!apair) {
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;
@@ -1734,14 +1736,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);
void 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;
@@ -1803,8 +1805,37 @@ void nat46_ipv6_input(struct sk_buff *ol
}
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) {

View File

@ -0,0 +1,40 @@
Author: Pavithra R <pavir@codeaurora.org>
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 <pavir@codeaurora.org>
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -1758,6 +1758,11 @@ void nat46_ipv6_input(struct sk_buff *ol
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;
+ }
+
nat46debug(4, "nat46_ipv6_input packet");
if(ip6_input_not_interested(nat46, ip6h, old_skb)) {
@@ -2222,6 +2227,11 @@ void nat46_ipv4_input(struct sk_buff *ol
char v6saddr[16], v6daddr[16];
+ if (nat46 == NULL) {
+ printk("nat46:%p skb is dropped for no valid instance found\n", old_skb);
+ return;
+ }
+
tclass = hdr4->tos;
memset(v6saddr, 1, 16);

View File

@ -0,0 +1,40 @@
Author: Pavithra R <pavir@codeaurora.org>
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 <pavir@codeaurora.org>
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -2115,7 +2115,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 {
@@ -2128,7 +2130,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);

View File

@ -0,0 +1,52 @@
Author: Pavithra R <pavir@codeaurora.org>
Date: Wed Aug 5 21:16:50 2020 +0530
nat46: fix nat46 crash during stability test
This patch is propagated from the kernel 4.4 commit
8a2df2e4170f6f9b7eb0930d067e197bfec68129
when deleting the same device in a very close time, the first deletion
is not finished yet, the second one will hit the BUG_ON.
Change-Id: I09ec95a132e925a304b57c35d1cb51619be37229
Signed-off-by: Pavithra R <pavir@codeaurora.org>
--- a/nat46/modules/nat46-module.c
+++ b/nat46/modules/nat46-module.c
@@ -61,6 +61,7 @@ bool add_dummy_header = 0;
module_param(add_dummy_header, bool, 0);
MODULE_PARM_DESC(add_dummy_header, "Add dummy fragment header");
+static DEFINE_MUTEX(add_del_lock);
static struct proc_dir_entry *nat46_proc_entry;
static struct proc_dir_entry *nat46_proc_parent;
@@ -115,19 +116,27 @@ static ssize_t nat46_proc_write(struct f
if (0 == strcmp(arg_name, "add")) {
devname = get_devname(&tail);
printk(KERN_INFO "nat46: adding device (%s)\n", devname);
+ mutex_lock(&add_del_lock);
nat46_create(devname);
+ mutex_unlock(&add_del_lock);
} else if (0 == strcmp(arg_name, "del")) {
devname = get_devname(&tail);
printk(KERN_INFO "nat46: deleting device (%s)\n", devname);
+ mutex_lock(&add_del_lock);
nat46_destroy(devname);
+ mutex_unlock(&add_del_lock);
} else if (0 == strcmp(arg_name, "config")) {
devname = get_devname(&tail);
printk(KERN_INFO "nat46: configure device (%s) with '%s'\n", devname, tail);
+ mutex_lock(&add_del_lock);
nat46_configure(devname, tail);
+ mutex_unlock(&add_del_lock);
} else if (0 == strcmp(arg_name, "insert")) {
devname = get_devname(&tail);
printk(KERN_INFO "nat46: insert new rule into device (%s) with '%s'\n", devname, tail);
+ mutex_lock(&add_del_lock);
nat46_insert(devname, tail);
+ mutex_unlock(&add_del_lock);
}
}

View File

@ -0,0 +1,51 @@
Author: Pavithra R <pavir@codeaurora.org>
Date: Thu Aug 13 12:59:50 2020 +0530
This patch is propogated from the kernel 4.4 commit
56e2435c782e7cdb5c274ea012557f525d0a3b88
nat46: fix race condition in the get and release operation
when get and release the nat46 instance, it could run into race
condition, use spin_lock protect them.
Change-Id: I7a38164699a5b856f3407dae592a3d8fc82e7ffe
Signed-off-by: Pavithra R <pavir@codeaurora.org>
--- a/nat46/modules/nat46-glue.c
+++ b/nat46/modules/nat46-glue.c
@@ -18,6 +18,7 @@
#include "nat46-glue.h"
#include "nat46-core.h"
+static DEFINE_MUTEX(ref_lock);
int is_valid_nat46(nat46_instance_t *nat46) {
return (nat46 && (nat46->sig == NAT46_SIGNATURE));
}
@@ -46,20 +47,25 @@ nat46_instance_t *alloc_nat46_instance(i
nat46_instance_t *get_nat46_instance(struct sk_buff *sk) {
nat46_instance_t *nat46 = netdev_nat46_instance(sk->dev);
+ mutex_lock(&ref_lock);
if (is_valid_nat46(nat46)) {
nat46->refcount++;
+ mutex_unlock(&ref_lock);
return nat46;
} else {
+ mutex_unlock(&ref_lock);
printk("[nat46] get_nat46_instance: Could not find a valid NAT46 instance!");
return NULL;
}
}
void release_nat46_instance(nat46_instance_t *nat46) {
+ mutex_lock(&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;
+ printk("[nat46] release_nat46_instance: freeing nat46 instance with %d pairs\n", nat46->npairs);
kfree(nat46);
}
+ mutex_unlock(&ref_lock);
}

View File

@ -0,0 +1,33 @@
Author: Pavithra R <pavir@codeaurora.org>
Date: Tue Sep 22 10:49:35 2020 +0530
This patch is propogated from the kernel 4.4 commit
0907c30387c89bbec23f426891a756ca17e421ed
nat46: export ip6_update_csum api
export ip6_update_csum for other modules.
Change-Id: I08de067f7a2d54d687c352154f1a1ab441652445
Signed-off-by: Pavithra R <pavir@codeaurora.org>
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -1972,6 +1972,7 @@ void ip6_update_csum(struct sk_buff * sk
}
}
}
+EXPORT_SYMBOL(ip6_update_csum);
int ip4_input_not_interested(nat46_instance_t *nat46, struct iphdr *iph, struct sk_buff *old_skb) {
if (old_skb->protocol != htons(ETH_P_IP)) {
--- a/nat46/modules/nat46-core.h
+++ b/nat46/modules/nat46-core.h
@@ -111,6 +111,7 @@ void release_nat46_instance(nat46_instan
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);
+void ip6_update_csum(struct sk_buff * skb, struct ipv6hdr * ip6hdr, int do_atomic_frag);
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,

View File

@ -0,0 +1,34 @@
Author: Pavithra R <pavir@codeaurora.org>
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 <pavir@codeaurora.org>
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -1828,7 +1828,9 @@ void nat46_ipv6_input(struct sk_buff *ol
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;
@@ -2296,7 +2298,9 @@ void nat46_ipv4_input(struct sk_buff *ol
}
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;
}

View File

@ -0,0 +1,34 @@
Author: Pavithra R <pavir@codeaurora.org>
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 <pavir@codeaurora.org>
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -2137,9 +2137,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. */

View File

@ -0,0 +1,43 @@
--- a/nat46/modules/nat46-module.c
+++ b/nat46/modules/nat46-module.c
@@ -15,6 +15,7 @@
*
*/
+#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -82,7 +83,7 @@ static char *get_devname(char **ptail)
{
const int maxlen = IFNAMSIZ-1;
char *devname = get_next_arg(ptail);
- if(strlen(devname) > maxlen) {
+ if(devname && (strlen(devname) > maxlen)) {
printk(KERN_INFO "nat46: '%s' is "
"longer than %d chars, truncating\n", devname, maxlen);
devname[maxlen] = 0;
@@ -144,6 +145,7 @@ static ssize_t nat46_proc_write(struct f
return count;
}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
static const struct file_operations nat46_proc_fops = {
.owner = THIS_MODULE,
.open = nat46_proc_open,
@@ -152,6 +154,15 @@ static const struct file_operations nat4
.release = single_release,
.write = nat46_proc_write,
};
+#else
+static const struct proc_ops nat46_proc_fops = {
+ .proc_open = nat46_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+ .proc_write = nat46_proc_write,
+};
+#endif
int create_nat46_proc_entry(void) {

View File

@ -0,0 +1,80 @@
--- a/nat46/modules/nat46-module.c
+++ b/nat46/modules/nat46-module.c
@@ -138,6 +138,12 @@ static ssize_t nat46_proc_write(struct f
mutex_lock(&add_del_lock);
nat46_insert(devname, tail);
mutex_unlock(&add_del_lock);
+ } else if (0 == strcmp(arg_name, "remove")) {
+ devname = get_devname(&tail);
+ printk(KERN_INFO "nat46: remove a rule from the device (%s) with '%s'\n", devname, tail);
+ mutex_lock(&add_del_lock);
+ nat46_remove(devname, tail);
+ mutex_unlock(&add_del_lock);
}
}
--- a/nat46/modules/nat46-netdev.c
+++ b/nat46/modules/nat46-netdev.c
@@ -337,6 +337,46 @@ int nat46_configure(char *devname, char
}
}
+int nat46_remove(char *devname, char *buf) {
+ int ret = -1;
+ char config_remove[NAT46_CFG_BUFLEN];
+ struct net_device *dev;
+ nat46_instance_t *nat46;
+ nat46_instance_t *nat46_remove;
+ int result_rem;
+ int i;
+
+ if((dev = find_dev(devname)) == NULL ||
+ (nat46 = netdev_nat46_instance(dev)) == NULL ||
+ (nat46_remove = alloc_nat46_instance(1, NULL, -1, -1, -1)) == NULL) {
+ return ret;
+ }
+
+ if(nat46_set_ipair_config(nat46_remove, 0, buf, NAT46_CFG_BUFLEN) < 0) {
+ release_nat46_instance(nat46_remove);
+ return ret;
+ }
+
+ result_rem = nat46_get_ipair_config(nat46_remove, 0, config_remove, NAT46_CFG_BUFLEN);
+ for(i = 0; i < nat46->npairs; i++) {
+ char config[NAT46_CFG_BUFLEN];
+ int result = nat46_get_ipair_config(nat46, i, config, NAT46_CFG_BUFLEN);
+
+ if (result_rem == result && strncmp(config_remove, config, result_rem) == 0) {
+ nat46_instance_t *nat46_new = alloc_nat46_instance(nat46->npairs-1, nat46, 0, 0, i);
+ if(nat46_new) {
+ netdev_nat46_set_instance(dev, nat46_new);
+ ret = 0;
+ } else {
+ printk("Could not remove the rule from device %s\n", devname);
+ }
+ break;
+ }
+ }
+ release_nat46_instance(nat46_remove);
+ return ret;
+}
+
void nat64_show_all_configs(struct seq_file *m) {
struct net_device *dev;
read_lock(&dev_base_lock);
--- a/nat46/modules/nat46-netdev.h
+++ b/nat46/modules/nat46-netdev.h
@@ -14,11 +14,13 @@
*/
#define NAT46_DEVICE_SIGNATURE 0x544e36dd
+#define NAT46_CFG_BUFLEN 200
int nat46_create(char *devname);
int nat46_destroy(char *devname);
int nat46_insert(char *devname, char *buf);
int nat46_configure(char *devname, char *buf);
+int nat46_remove(char *devname, char *buf);
void nat46_destroy_all(void);
void nat64_show_all_configs(struct seq_file *m);
void nat46_netdev_count_xmit(struct sk_buff *skb, struct net_device *dev);

View File

@ -0,0 +1,56 @@
--- a/nat46/modules/nat46-core.h
+++ b/nat46/modules/nat46-core.h
@@ -106,7 +106,7 @@ int nat46_get_config(nat46_instance_t *n
char *get_next_arg(char **ptail);
nat46_instance_t *get_nat46_instance(struct sk_buff *sk);
-nat46_instance_t *alloc_nat46_instance(int npairs, nat46_instance_t *old, int from_ipair, int to_ipair);
+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);
--- a/nat46/modules/nat46-glue.c
+++ b/nat46/modules/nat46-glue.c
@@ -23,7 +23,7 @@ int is_valid_nat46(nat46_instance_t *nat
return (nat46 && (nat46->sig == NAT46_SIGNATURE));
}
-nat46_instance_t *alloc_nat46_instance(int npairs, nat46_instance_t *old, int from_ipair, int to_ipair) {
+nat46_instance_t *alloc_nat46_instance(int npairs, nat46_instance_t *old, int from_ipair, int to_ipair, int remove_ipair) {
nat46_instance_t *nat46 = kzalloc(sizeof(nat46_instance_t) + npairs*sizeof(nat46_xlate_rulepair_t), GFP_KERNEL);
if (!nat46) {
printk("[nat46] make_nat46_instance: can not alloc a nat46 instance with %d pairs\n", npairs);
@@ -37,8 +37,11 @@ nat46_instance_t *alloc_nat46_instance(i
if (old) {
nat46->debug = old->debug;
for(; (from_ipair >= 0) && (to_ipair >= 0) &&
- (from_ipair < old->npairs) && (to_ipair < nat46->npairs); from_ipair++, to_ipair++) {
- nat46->pairs[to_ipair] = old->pairs[from_ipair];
+ (from_ipair < old->npairs) && (to_ipair < nat46->npairs); from_ipair++) {
+ if (from_ipair != remove_ipair) {
+ nat46->pairs[to_ipair] = old->pairs[from_ipair];
+ to_ipair++;
+ }
}
}
return nat46;
--- a/nat46/modules/nat46-netdev.c
+++ b/nat46/modules/nat46-netdev.c
@@ -155,7 +155,7 @@ static void netdev_nat46_set_instance(st
static void nat46_netdev_setup(struct net_device *dev)
{
nat46_netdev_priv_t *priv = netdev_priv(dev);
- nat46_instance_t *nat46 = alloc_nat46_instance(1, NULL, -1, -1);
+ nat46_instance_t *nat46 = alloc_nat46_instance(1, NULL, -1, -1, -1);
memset(priv, 0, sizeof(*priv));
priv->sig = NAT46_DEVICE_SIGNATURE;
@@ -316,7 +316,7 @@ int nat46_insert(char *devname, char *bu
return ret;
}
- nat46_new = alloc_nat46_instance(nat46->npairs+1, nat46, 0, 1);
+ 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));

View File

@ -0,0 +1,144 @@
Author: Ken Zhu <guigenz@codeaurora.org>
Date: Fri Mar 26 12:27:17 2021 -0700
[nat46]: fix icmp checksum error based on the correct packet length
UDP/TCP checksum includes the pseudo header in addition to the palyload.
But in nat46 case, their length in the pseudo header could be ignored
since it keeps unchanged between IPv4/IPv6 transition.
ICMPv6 checksum includes pseudo IPV6 header in addition to packet payload
while ICMPv4 does not counter in the pseudo header.
the length of pseudo header should count in all fragmented payload.
The change get the length by reassembling the fragments.
Change-Id: I56e59958aa21eed5b595ae1a9ab02285dba2185b
Signed-off-by: Ken Zhu <guigenz@codeaurora.org>
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -18,6 +18,8 @@
#include <net/route.h>
#include <linux/version.h>
+#include <net/ipv6_frag.h>
+#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
#include "nat46-glue.h"
#include "nat46-core.h"
@@ -1751,7 +1753,8 @@ void nat46_ipv6_input(struct sk_buff *ol
struct iphdr * iph;
__u32 v4saddr, v4daddr;
- struct sk_buff * new_skb = 0;
+ struct sk_buff *new_skb = NULL;
+ struct sk_buff *reasm_skb = NULL;
int truncSize = 0;
int tailTruncSize = 0;
int v6packet_l3size = sizeof(*ip6h);
@@ -1802,6 +1805,46 @@ void nat46_ipv6_input(struct sk_buff *ol
frag_id = fold_ipv6_frag_id(fh->identification);
nat46debug(2, "Not first fragment, frag_off: %04X, frag id: %04X orig frag_off: %04X", ntohs(frag_off), frag_id, ntohs(fh->frag_off));
}
+
+ /* ICMPv6 counts the pseudo ipv6 header into its checksum, but ICMP doesn't
+ * but the length filed of the pseudo header count in all fragmented
+ * packets, so we need gather the framented packets into one packet to
+ * get the l3 payload length.
+ */
+ if (proto == NEXTHDR_ICMP) {
+ struct sk_buff *skb = skb_get(old_skb);
+ int err;
+ if (skb == NULL) {
+ goto done;
+ }
+
+ err = nf_ct_frag6_gather(dev_net(old_skb->dev), skb, IP6_DEFRAG_LOCAL_DELIVER);
+
+ /* EINPROGRESS means the skb was queued but the gather not finished yet */
+ if (err == -EINPROGRESS) {
+ goto done;
+ }
+
+ reasm_skb = skb;
+ /* other than EINPROGRESS error returned means the skb wasn't queued
+ * 0 returned means that all fragments are all gathered
+ * and the original skb was queued
+ */
+ if (err != 0) {
+ goto done;
+ }
+
+ /* Use the reassembly packet as the input */
+ ip6h = ipv6_hdr(reasm_skb);
+ proto = ip6h->nexthdr;
+ v6packet_l3size = sizeof(*ip6h);
+
+ /* No fragment header in the re-assembly packet */
+ frag_off = 0;
+ l3_infrag_payload_len = ntohs(ip6h->payload_len);
+ old_skb = reasm_skb;
+ check_for_l4 = 1;
+ }
}
} else {
frag_off = htons(IP_DF);
@@ -1850,20 +1893,28 @@ void nat46_ipv6_input(struct sk_buff *ol
/* CHECKSUMS UPDATE */
case NEXTHDR_TCP: {
struct tcphdr *th = add_offset(ip6h, v6packet_l3size);
- u16 sum1 = csum_ipv6_unmagic(nat46, &ip6h->saddr, &ip6h->daddr, l3_infrag_payload_len, NEXTHDR_TCP, th->check);
- u16 sum2 = csum_tcpudp_remagic(v4saddr, v4daddr, l3_infrag_payload_len, NEXTHDR_TCP, sum1);
+
+ /* TCP payload length won't change, needn't unmagic its value. */
+ u16 sum1 = csum_ipv6_unmagic(nat46, &ip6h->saddr, &ip6h->daddr, 0, NEXTHDR_TCP, th->check);
+ u16 sum2 = csum_tcpudp_remagic(v4saddr, v4daddr, 0, NEXTHDR_TCP, sum1);
th->check = sum2;
break;
}
case NEXTHDR_UDP: {
struct udphdr *udp = add_offset(ip6h, v6packet_l3size);
- u16 sum1 = csum_ipv6_unmagic(nat46, &ip6h->saddr, &ip6h->daddr, l3_infrag_payload_len, NEXTHDR_UDP, udp->check);
- u16 sum2 = csum_tcpudp_remagic(v4saddr, v4daddr, l3_infrag_payload_len, NEXTHDR_UDP, sum1);
+
+ /* UDP payload length won't change, needn't unmagic its value. */
+ u16 sum1 = csum_ipv6_unmagic(nat46, &ip6h->saddr, &ip6h->daddr, 0, NEXTHDR_UDP, udp->check);
+ u16 sum2 = csum_tcpudp_remagic(v4saddr, v4daddr, 0, NEXTHDR_UDP, sum1);
udp->check = sum2;
break;
}
case NEXTHDR_ICMP: {
struct icmp6hdr *icmp6h = add_offset(ip6h, v6packet_l3size);
+
+ /* ICMPv6 count the pseudo IPv6 header into its checksum, but icmp
+ * doesn't, unmagic the whole the pseudo IPv6 header from the checksum.
+ */
u16 sum1 = csum_ipv6_unmagic(nat46, &ip6h->saddr, &ip6h->daddr, l3_infrag_payload_len, NEXTHDR_ICMP, icmp6h->icmp6_cksum);
icmp6h->icmp6_cksum = sum1;
nat46debug_dump(nat46, 10, icmp6h, l3_infrag_payload_len);
@@ -1909,10 +1960,6 @@ void nat46_ipv6_input(struct sk_buff *ol
fill_v4hdr_from_v6hdr(iph, ip6h, v4saddr, v4daddr, frag_id, frag_off, proto, l3_infrag_payload_len);
new_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);
@@ -1924,11 +1971,12 @@ void nat46_ipv6_input(struct sk_buff *ol
/* TBD: should copy be released here? */
done:
+ if (reasm_skb) {
+ kfree_skb(reasm_skb);
+ }
release_nat46_instance(nat46);
}
-
-
void ip6_update_csum(struct sk_buff * skb, struct ipv6hdr * ip6hdr, int do_atomic_frag)
{
u32 sum1=0;

View File

@ -0,0 +1,32 @@
Author: Ken Zhu <guigenz@codeaurora.org>
Date: Wed Feb 17 13:37:15 2021 -0800
nat46: keep ipv4 checksum zero when incoming ipv6 UDP checksum is zero
When an incoming ipv6 UDP packet has 0 checksum, the ipv4 checksum is
kept zero after translation.
Change-Id: I8ddd0c586e5cfbd5a57dc5632e93543d6db5c312
Signed-off-by: Ken Zhu <guigenz@codeaurora.org>
--- a/nat46/modules/nat46-core.c
+++ b/nat46/modules/nat46-core.c
@@ -1903,10 +1903,14 @@ void nat46_ipv6_input(struct sk_buff *ol
case NEXTHDR_UDP: {
struct udphdr *udp = add_offset(ip6h, v6packet_l3size);
- /* UDP payload length won't change, needn't unmagic its value. */
- u16 sum1 = csum_ipv6_unmagic(nat46, &ip6h->saddr, &ip6h->daddr, 0, NEXTHDR_UDP, udp->check);
- u16 sum2 = csum_tcpudp_remagic(v4saddr, v4daddr, 0, NEXTHDR_UDP, sum1);
- udp->check = sum2;
+ /* UDP payload length won't change, needn't unmagic its value.
+ * UDP checksum zero then skip the calculation of the checksum.
+ */
+ if (udp->check) {
+ u16 sum1 = csum_ipv6_unmagic(nat46, &ip6h->saddr, &ip6h->daddr, 0, NEXTHDR_UDP, udp->check);
+ u16 sum2 = csum_tcpudp_remagic(v4saddr, v4daddr, 0, NEXTHDR_UDP, sum1);
+ udp->check = sum2;
+ }
break;
}
case NEXTHDR_ICMP: {

View File

@ -3,6 +3,7 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=libnl-nss
PKG_RELEASE:=1
PKG_BUILD_DEPENDS:=libnl
include $(INCLUDE_DIR)/package.mk

View File

@ -14,7 +14,7 @@ PKG_LICENSE:=GPL-2.0
include $(INCLUDE_DIR)/package.mk
define KernelPackage/nat46
define KernelPackage/qca-nat46
DEPENDS:=@IPV6 +kmod-nf-conntrack6
TITLE:=Stateless NAT46 translation kernel module
SECTION:=kernel
@ -40,4 +40,4 @@ define Build/InstallDev
$(CP) $(PKG_BUILD_DIR)/nat46/modules/*.h $(STAGING_DIR)/usr/include/nat46/
endef
$(eval $(call KernelPackage,nat46))
$(eval $(call KernelPackage,qca-nat46))

View File

@ -55,8 +55,9 @@ define KernelPackage/qca-nss-drv-dtlsmgr
CATEGORY:=Kernel modules
SUBMENU:=Network Devices
TITLE:=Kernel driver for NSS (connection manager) - dtlsmgr
DEPENDS:=+@NSS_DRV_DTLS_ENABLE +kmod-qca-nss-cfi-cryptoapi \
+PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv
DEPENDS:=+@NSS_DRV_DTLS_ENABLEi \
+PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv \
+PACKAGE_kmod-qca-nss-cfi-cryptoapi:kmod-qca-nss-cfi-cryptoapi
FILES:=$(PKG_BUILD_DIR)/dtls/$(DTLSMGR_DIR)/qca-nss-dtlsmgr.ko
endef
@ -323,7 +324,6 @@ define KernelPackage/qca-nss-drv-netlink
SUBMENU:=Network Devices
DEPENDS:=@TARGET_ipq806x||TARGET_ipq807x||TARGET_ipq_ipq807x_64||TARGET_ipq_ipq60xx||TARGET_ipq_ipq60xx_64||TARGET_ipq60xx||TARGET_ipq_ipq50xx||TARGET_ipq_ipq50xx_64||TARGET_ipq50xx \
+PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv \
+PACKAGE_kmod-qca-nss-drv-dtlsmgr:kmod-qca-nss-drv-dtlsmgr \
+@NSS_DRV_GRE_REDIR_ENABLE
TITLE:=NSS NETLINK Manager for QCA NSS driver
FILES:=$(PKG_BUILD_DIR)/netlink/qca-nss-netlink.ko