Chengen Du wrote:
Hi Willem,
I'm sorry, but I would like to confirm the issue further.
On Mon, Jun 10, 2024 at 4:19 AM Willem de Bruijn willemdebruijn.kernel@gmail.com wrote:
Chengen Du wrote:
The issue initially stems from libpcap. The ethertype will be overwritten as the VLAN TPID if the network interface lacks hardware VLAN 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 sk_buff struct. Consequently, this can lead to a false negative when checking for the presence of a VLAN tag, causing the packet sniffing outcome to lack VLAN tag information (i.e., TCI-TPID). As a result, the packet capturing tool may be unable to parse packets as expected.
The TCI-TPID is missing because the prb_fill_vlan_info() function does not modify the tp_vlan_tci/tp_vlan_tpid values, as the information is in the payload and not in the sk_buff struct. The skb_vlan_tag_present() function only checks vlan_all in the sk_buff struct. In cooked mode, the L2 header is stripped, preventing the packet capturing tool from determining the correct TCI-TPID value. Additionally, the protocol in SLL is incorrect, which means the packet capturing tool cannot parse the L3 header correctly.
Link: https://github.com/the-tcpdump-group/libpcap/issues/1105 Link: https://lore.kernel.org/netdev/20240520070348.26725-1-chengen.du@canonical.c... Fixes: 393e52e33c6c ("packet: deliver VLAN TCI to userspace") Cc: stable@vger.kernel.org Signed-off-by: Chengen Du chengen.du@canonical.com
Overall, solid.
net/packet/af_packet.c | 57 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index ea3ebc160e25..8cffbe1f912d 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -538,6 +538,43 @@ static void *packet_current_frame(struct packet_sock *po, return packet_lookup_frame(po, rb, rb->head, status); }
+static u16 vlan_get_tci(struct sk_buff *skb) +{
struct vlan_hdr vhdr, *vh;
u8 *skb_orig_data = skb->data;
int skb_orig_len = skb->len;
skb_push(skb, skb->data - skb_mac_header(skb));
vh = skb_header_pointer(skb, ETH_HLEN, sizeof(vhdr), &vhdr);
Don't harcode Ethernet.
According to documentation VLANs are used with other link layers.
More importantly, in practice PF_PACKET allows inserting this skb->protocol on any device.
We don't use link layer specific constants anywhere in the packet socket code for this reason. But instead dev->hard_header_len.
One caveat there is variable length link layer headers, where dev->min_header_len != dev->hard_header_len. Will just have to fail on those.
Thank you for pointing out this error. I would like to confirm if I need to use dev->hard_header_len to get the correct header length and return zero if dev->min_header_len != dev->hard_header_len to handle variable-length link layer headers. Is there something I misunderstand, or are there other aspects I need to consider further?
That's right.
The min_header_len != hard_header_len check is annoying and may seem pedantic. But it's the only way to trust that the next header starts at hard_header_len.