[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20240520070348.26725-1-chengen.du@canonical.com>
Date: Mon, 20 May 2024 15:03:48 +0800
From: Chengen Du <chengen.du@...onical.com>
To: willemdebruijn.kernel@...il.com
Cc: davem@...emloft.net,
edumazet@...gle.com,
kuba@...nel.org,
pabeni@...hat.com,
netdev@...r.kernel.org,
linux-kernel@...r.kernel.org,
Chengen Du <chengen.du@...onical.com>
Subject: [PATCH] af_packet: Handle outgoing VLAN packets without hardware offloading
In the outbound packet path, if hardware VLAN offloading is unavailable,
the VLAN tag is inserted into the payload but then cleared from the
metadata. Consequently, this could lead to a false negative result when
checking for the presence of a VLAN tag using skb_vlan_tag_present(),
causing the packet sniffing outcome to lack VLAN tag information. As a
result, the packet capturing tool may be unable to parse packets as
expected.
Signed-off-by: Chengen Du <chengen.du@...onical.com>
---
net/packet/af_packet.c | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index ea3ebc160e25..73e9acb1875b 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1010,12 +1010,15 @@ static void prb_fill_vlan_info(struct tpacket_kbdq_core *pkc,
if (skb_vlan_tag_present(pkc->skb)) {
ppd->hv1.tp_vlan_tci = skb_vlan_tag_get(pkc->skb);
ppd->hv1.tp_vlan_tpid = ntohs(pkc->skb->vlan_proto);
- ppd->tp_status = TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID;
+ } else if (eth_type_vlan(pkc->skb->protocol)) {
+ ppd->hv1.tp_vlan_tci = ntohs(vlan_eth_hdr(pkc->skb)->h_vlan_TCI);
+ ppd->hv1.tp_vlan_tpid = ntohs(pkc->skb->protocol);
} else {
ppd->hv1.tp_vlan_tci = 0;
ppd->hv1.tp_vlan_tpid = 0;
- ppd->tp_status = TP_STATUS_AVAILABLE;
}
+ ppd->tp_status = (ppd->hv1.tp_vlan_tci || ppd->hv1.tp_vlan_tpid) ?
+ TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID : TP_STATUS_AVAILABLE;
}
static void prb_run_all_ft_ops(struct tpacket_kbdq_core *pkc,
@@ -2427,11 +2430,15 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
if (skb_vlan_tag_present(skb)) {
h.h2->tp_vlan_tci = skb_vlan_tag_get(skb);
h.h2->tp_vlan_tpid = ntohs(skb->vlan_proto);
- status |= TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID;
+ } else if (eth_type_vlan(skb->protocol)) {
+ h.h2->tp_vlan_tci = ntohs(vlan_eth_hdr(skb)->h_vlan_TCI);
+ h.h2->tp_vlan_tpid = ntohs(skb->protocol);
} else {
h.h2->tp_vlan_tci = 0;
h.h2->tp_vlan_tpid = 0;
}
+ if (h.h2->tp_vlan_tci || h.h2->tp_vlan_tpid)
+ status |= TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID;
memset(h.h2->tp_padding, 0, sizeof(h.h2->tp_padding));
hdrlen = sizeof(*h.h2);
break;
@@ -2457,7 +2464,8 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
sll->sll_halen = dev_parse_header(skb, sll->sll_addr);
sll->sll_family = AF_PACKET;
sll->sll_hatype = dev->type;
- sll->sll_protocol = skb->protocol;
+ sll->sll_protocol = eth_type_vlan(skb->protocol) ?
+ vlan_eth_hdr(skb)->h_vlan_encapsulated_proto : skb->protocol;
sll->sll_pkttype = skb->pkt_type;
if (unlikely(packet_sock_flag(po, PACKET_SOCK_ORIGDEV)))
sll->sll_ifindex = orig_dev->ifindex;
@@ -3482,7 +3490,8 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
/* Original length was stored in sockaddr_ll fields */
origlen = PACKET_SKB_CB(skb)->sa.origlen;
sll->sll_family = AF_PACKET;
- sll->sll_protocol = skb->protocol;
+ sll->sll_protocol = eth_type_vlan(skb->protocol) ?
+ vlan_eth_hdr(skb)->h_vlan_encapsulated_proto : skb->protocol;
}
sock_recv_cmsgs(msg, sk, skb);
@@ -3538,11 +3547,15 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
if (skb_vlan_tag_present(skb)) {
aux.tp_vlan_tci = skb_vlan_tag_get(skb);
aux.tp_vlan_tpid = ntohs(skb->vlan_proto);
- aux.tp_status |= TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID;
+ } else if (eth_type_vlan(skb->protocol)) {
+ aux.tp_vlan_tci = ntohs(vlan_eth_hdr(skb)->h_vlan_TCI);
+ aux.tp_vlan_tpid = ntohs(skb->protocol);
} else {
aux.tp_vlan_tci = 0;
aux.tp_vlan_tpid = 0;
}
+ if (aux.tp_vlan_tci || aux.tp_vlan_tpid)
+ aux.tp_status |= TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID;
put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux);
}
--
2.40.1
Powered by blists - more mailing lists