[][[Kernel][common][hnat][Fix the way of recording SMAC and DMAC in get_nexthop API]]
[Description]
Fix the way of recording SMAC and DMAC in get_nexthop API.
1: After tunnel encapsulation or decapsulation,
MAC header of the skb no longer points to the correct location.
Filling SMAC/DMAC in the skb at this point may cause packet loss.
2: Filling Ethernet header should be handled by the kernel.
HNAT should avoid modifying the skb to prevent anomalies.
[Release-log]
NA
Change-Id: I45385710a31b2f80001cb1ffd02d26ea15e5cfd8
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/9682828
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
index 05f28e9..6286310 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
@@ -1163,23 +1163,9 @@
const struct in6_addr *ipv6_nexthop;
struct neighbour *neigh = NULL;
struct dst_entry *dst = skb_dst(skb);
- struct ethhdr *eth;
- u16 eth_pppoe_hlen = ETH_HLEN + PPPOE_SES_HLEN;
-
- if (hw_path->flags & FLOW_OFFLOAD_PATH_PPPOE) {
- if (ipv6_hdr(skb)->nexthdr == NEXTHDR_IPIP) {
- eth = (struct ethhdr *)(skb->data - eth_pppoe_hlen);
- eth->h_proto = skb->protocol;
- ether_addr_copy(eth->h_dest, hw_path->eth_dest);
- ether_addr_copy(eth->h_source, hw_path->eth_src);
- } else {
- eth = eth_hdr(skb);
- memcpy(eth->h_source, hw_path->eth_src, ETH_ALEN);
- memcpy(eth->h_dest, hw_path->eth_dest, ETH_ALEN);
- }
+ if (hw_path->flags & FLOW_OFFLOAD_PATH_PPPOE)
return 0;
- }
rcu_read_lock_bh();
ipv6_nexthop =
@@ -1198,16 +1184,8 @@
return -1;
}
- if (ipv6_hdr(skb)->nexthdr == NEXTHDR_IPIP) {
- /*copy ether type for DS-Lite and MapE */
- eth = (struct ethhdr *)(skb->data - ETH_HLEN);
- eth->h_proto = skb->protocol;
- } else {
- eth = eth_hdr(skb);
- }
-
- ether_addr_copy(eth->h_dest, neigh->ha);
- ether_addr_copy(eth->h_source, out->dev_addr);
+ ether_addr_copy(hw_path->eth_dest, neigh->ha);
+ ether_addr_copy(hw_path->eth_src, out->dev_addr);
rcu_read_unlock_bh();
@@ -1223,15 +1201,9 @@
struct dst_entry *dst = skb_dst(skb);
struct rtable *rt = (struct rtable *)dst;
struct net_device *dev = (__force struct net_device *)out;
- struct ethhdr *eth;
- if (hw_path->flags & FLOW_OFFLOAD_PATH_PPPOE) {
- rcu_read_lock_bh();
- memcpy(eth_hdr(skb)->h_source, hw_path->eth_src, ETH_ALEN);
- memcpy(eth_hdr(skb)->h_dest, hw_path->eth_dest, ETH_ALEN);
- rcu_read_unlock_bh();
+ if (hw_path->flags & FLOW_OFFLOAD_PATH_PPPOE)
return 0;
- }
if (!skb_hnat_cdrt(skb) && dst && dst_xfrm(dst))
return 0;
@@ -1263,15 +1235,8 @@
skb_reset_mac_header(skb);
}
- if (ip_hdr(skb)->protocol == IPPROTO_IPV6)
- /* 6RD LAN->WAN(6to4) */
- eth = (struct ethhdr *)(skb->data - ETH_HLEN);
- else
- eth = eth_hdr(skb);
-
- memcpy(eth->h_dest, neigh->ha, ETH_ALEN);
- memcpy(eth->h_source, out->dev_addr, ETH_ALEN);
- eth->h_proto = htons(ETH_P_IP);
+ memcpy(hw_path->eth_dest, neigh->ha, ETH_ALEN);
+ memcpy(hw_path->eth_src, out->dev_addr, ETH_ALEN);
if ((skb_hnat_tops(skb) && skb_hnat_is_encap(skb)) ||
(skb_hnat_cdrt(skb) && skb_hnat_is_encrypt(skb)))
@@ -1302,16 +1267,16 @@
return chksum_base;
}
-struct foe_entry ppe_fill_L2_info(struct ethhdr *eth, struct foe_entry entry,
+struct foe_entry ppe_fill_L2_info(struct foe_entry entry,
struct flow_offload_hw_path *hw_path)
{
switch ((int)entry.bfib1.pkt_type) {
case IPV4_HNAPT:
case IPV4_HNAT:
- entry.ipv4_hnapt.dmac_hi = swab32(*((u32 *)eth->h_dest));
- entry.ipv4_hnapt.dmac_lo = swab16(*((u16 *)ð->h_dest[4]));
- entry.ipv4_hnapt.smac_hi = swab32(*((u32 *)eth->h_source));
- entry.ipv4_hnapt.smac_lo = swab16(*((u16 *)ð->h_source[4]));
+ entry.ipv4_hnapt.dmac_hi = swab32(*((u32 *)hw_path->eth_dest));
+ entry.ipv4_hnapt.dmac_lo = swab16(*((u16 *)&hw_path->eth_dest[4]));
+ entry.ipv4_hnapt.smac_hi = swab32(*((u32 *)hw_path->eth_src));
+ entry.ipv4_hnapt.smac_lo = swab16(*((u16 *)&hw_path->eth_src[4]));
entry.ipv4_hnapt.pppoe_id = hw_path->pppoe_sid;
break;
case IPV4_DSLITE:
@@ -1321,18 +1286,17 @@
case IPV6_3T_ROUTE:
case IPV6_HNAPT:
case IPV6_HNAT:
- entry.ipv6_5t_route.dmac_hi = swab32(*((u32 *)eth->h_dest));
- entry.ipv6_5t_route.dmac_lo = swab16(*((u16 *)ð->h_dest[4]));
- entry.ipv6_5t_route.smac_hi = swab32(*((u32 *)eth->h_source));
- entry.ipv6_5t_route.smac_lo =
- swab16(*((u16 *)ð->h_source[4]));
+ entry.ipv6_5t_route.dmac_hi = swab32(*((u32 *)hw_path->eth_dest));
+ entry.ipv6_5t_route.dmac_lo = swab16(*((u16 *)&hw_path->eth_dest[4]));
+ entry.ipv6_5t_route.smac_hi = swab32(*((u32 *)hw_path->eth_src));
+ entry.ipv6_5t_route.smac_lo = swab16(*((u16 *)&hw_path->eth_src[4]));
entry.ipv6_5t_route.pppoe_id = hw_path->pppoe_sid;
break;
}
return entry;
}
-struct foe_entry ppe_fill_info_blk(struct ethhdr *eth, struct foe_entry entry,
+struct foe_entry ppe_fill_info_blk(struct foe_entry entry,
struct flow_offload_hw_path *hw_path)
{
entry.bfib1.psn = (hw_path->flags & FLOW_OFFLOAD_PATH_PPPOE) ? 1 : 0;
@@ -1348,7 +1312,7 @@
case IPV4_HNAPT:
case IPV4_HNAT:
if (hnat_priv->data->mcast &&
- is_multicast_ether_addr(ð->h_dest[0])) {
+ is_multicast_ether_addr(&hw_path->eth_dest[0])) {
entry.ipv4_hnapt.iblk2.mcast = 1;
if (hnat_priv->data->version == MTK_HNAT_V1_3) {
entry.bfib1.sta = 1;
@@ -1371,7 +1335,7 @@
case IPV6_HNAPT:
case IPV6_HNAT:
if (hnat_priv->data->mcast &&
- is_multicast_ether_addr(ð->h_dest[0])) {
+ is_multicast_ether_addr(&hw_path->eth_dest[0])) {
entry.ipv6_5t_route.iblk2.mcast = 1;
if (hnat_priv->data->version == MTK_HNAT_V1_3) {
entry.bfib1.sta = 1;
@@ -1391,20 +1355,6 @@
return entry;
}
-static struct ethhdr *get_ipv6_ipip_ethhdr(struct sk_buff *skb,
- struct flow_offload_hw_path *hw_path)
-{
- struct ethhdr *eth;
- u16 eth_pppoe_hlen = ETH_HLEN + PPPOE_SES_HLEN;
-
- if (hw_path->flags & FLOW_OFFLOAD_PATH_PPPOE)
- eth = (struct ethhdr *)(skb->data - eth_pppoe_hlen);
- else
- eth = (struct ethhdr *)(skb->data - ETH_HLEN);
-
- return eth;
-}
-
static inline void hnat_get_filled_unbind_entry(struct sk_buff *skb,
struct foe_entry *entry)
{
@@ -1663,7 +1613,6 @@
struct list_head *iter;
struct foe_entry entry = { 0 };
struct mtk_mac *mac;
- struct ethhdr *eth;
struct iphdr *iph;
struct ipv6hdr *ip6h;
struct tcpudphdr _ports;
@@ -1679,18 +1628,10 @@
int mape = 0;
int ret;
int i = 0;
-
- if (ipv6_hdr(skb)->nexthdr == NEXTHDR_IPIP)
- /* point to ethernet header for DS-Lite and MapE */
- eth = get_ipv6_ipip_ethhdr(skb, hw_path);
- else if (ip_hdr(skb)->protocol == IPPROTO_IPV6)
- /* 6RD LAN->WAN(6to4) */
- eth = (struct ethhdr *)(skb->data - ETH_HLEN);
- else
- eth = eth_hdr(skb);
+ u16 h_proto = 0;
/*do not bind multicast if PPE mcast not enable*/
- if (!hnat_priv->data->mcast && is_multicast_ether_addr(eth->h_dest))
+ if (!hnat_priv->data->mcast && is_multicast_ether_addr(hw_path->eth_dest))
return 0;
ret = hnat_offload_engine_done(skb, hw_path);
@@ -1711,7 +1652,14 @@
entry.bfib1.sp = foe->udib1.sp;
#endif
- switch (ntohs(eth->h_proto)) {
+ if (ip_hdr(skb)->version == IPVERSION_V4)
+ h_proto = ETH_P_IP;
+ else if (ip_hdr(skb)->version == IPVERSION_V6)
+ h_proto = ETH_P_IPV6;
+ else
+ return 0;
+
+ switch (h_proto) {
case ETH_P_IP:
iph = ip_hdr(skb);
/* Do not bind if pkt is fragmented */
@@ -2133,7 +2081,7 @@
}
/* Fill Layer2 Info.*/
- entry = ppe_fill_L2_info(eth, entry, hw_path);
+ entry = ppe_fill_L2_info(entry, hw_path);
if ((skb_hnat_tops(skb) && hw_path->flags & FLOW_OFFLOAD_PATH_TNL) ||
(!skb_hnat_cdrt(skb) && skb_hnat_is_encrypt(skb) &&
@@ -2142,7 +2090,7 @@
hnat_entry_bind:
/* Fill Info Blk*/
- entry = ppe_fill_info_blk(eth, entry, hw_path);
+ entry = ppe_fill_info_blk(entry, hw_path);
if (IS_LAN_GRP(dev) || IS_WAN(dev)) { /* Forward to GMAC Ports */
if (IS_BOND(dev)) {
@@ -2168,7 +2116,7 @@
port_id = hnat_dsa_get_port(&master_dev);
if (port_id >= 0) {
if (hnat_dsa_fill_stag(dev, &entry, hw_path,
- ntohs(eth->h_proto), mape) < 0)
+ h_proto, mape) < 0)
return 0;
}
@@ -2226,7 +2174,7 @@
qid = 0;
if (IS_PPPQ_MODE && IS_PPPQ_PATH(dev, skb)) {
- if (ntohs(eth->h_proto) == ETH_P_IP) {
+ if (h_proto == ETH_P_IP) {
iph = ip_hdr(skb);
if (iph->protocol == IPPROTO_TCP) {
skb_set_transport_header(skb, sizeof(struct iphdr));
@@ -2236,7 +2184,7 @@
if (payload_len == 0)
qid += 6;
}
- } else if (ntohs(eth->h_proto) == ETH_P_IPV6) {
+ } else if (h_proto == ETH_P_IPV6) {
ip6h = ipv6_hdr(skb);
if (ip6h->nexthdr == NEXTHDR_TCP) {
skb_set_transport_header(skb, sizeof(struct ipv6hdr));
@@ -3318,9 +3266,14 @@
if (fn && !mtk_hnat_accel_type(skb))
break;
- if (!is_virt_dev && fn && fn(skb, arp_dev, &hw_path))
- break;
-
+ if (!is_virt_dev) {
+ if (!fn) {
+ memcpy(hw_path.eth_dest, eth_hdr(skb)->h_dest, ETH_ALEN);
+ memcpy(hw_path.eth_src, eth_hdr(skb)->h_source, ETH_ALEN);
+ } else if (fn(skb, arp_dev, &hw_path)) {
+ break;
+ }
+ }
/* skb_hnat_tops(skb) is updated in mtk_tnl_offload() */
if (skb_hnat_tops(skb)) {
if (skb_hnat_is_encap(skb) && !is_virt_dev &&
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
index 4d12010..21212b7 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
@@ -193,6 +193,8 @@
#define HIT_PRE_BIND 0x1A
#define HIT_BIND_PACKET_SAMPLING 0x1B
#define HIT_BIND_EXCEED_MTU 0x1C
+#define IPVERSION_V4 0x04
+#define IPVERSION_V6 0x06
#define TPORT_ID(x) ((x) & GENMASK(3, 0))
#define TOPS_ENTRY(x) ((x) & GENMASK(5, 0))