Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 52f1454f authored by Daniel Borkmann's avatar Daniel Borkmann Committed by David S. Miller
Browse files

packet: allow to transmit +4 byte in TX_RING slot for VLAN case



Commit 57f89bfa ("network: Allow af_packet to transmit +4 bytes
for VLAN packets.") added the possibility for non-mmaped frames to
send extra 4 byte for VLAN header so the MTU increases from 1500 to
1504 byte, for example.

Commit cbd89acb ("af_packet: fix for sending VLAN frames via
packet_mmap") attempted to fix that for the mmap part but was
reverted as it caused regressions while using eth_type_trans()
on output path.

Lets just act analogous to 57f89bfa and add a similar logic
to TX_RING. We presume size_max as overcharged with +4 bytes and
later on after skb has been built by tpacket_fill_skb() check
for ETH_P_8021Q header on packets larger than normal MTU. Can
be easily reproduced with a slightly modified trafgen in mmap(2)
mode, test cases:

 { fill(0xff, 12) const16(0x8100) fill(0xff, <1504|1505>) }
 { fill(0xff, 12) const16(0x0806) fill(0xff, <1500|1501>) }

Note that we need to do the test right after tpacket_fill_skb()
as sockets can have PACKET_LOSS set where we would not fail but
instead just continue to traverse the ring.

Reported-by: default avatarMathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
Signed-off-by: default avatarDaniel Borkmann <dborkman@redhat.com>
Cc: Ben Greear <greearb@candelatech.com>
Cc: Phil Sutter <phil@nwl.cc>
Tested-by: default avatarMathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 07cb1c17
Loading
Loading
Loading
Loading
+13 −3
Original line number Diff line number Diff line
@@ -2257,8 +2257,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
	if (unlikely(!(dev->flags & IFF_UP)))
		goto out_put;

	reserve = dev->hard_header_len;

	reserve = dev->hard_header_len + VLAN_HLEN;
	size_max = po->tx_ring.frame_size
		- (po->tp_hdrlen - sizeof(struct sockaddr_ll));

@@ -2286,7 +2285,18 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)

		tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto,
					  addr, hlen);
		if (tp_len > dev->mtu + dev->hard_header_len) {
			struct ethhdr *ehdr;
			/* Earlier code assumed this would be a VLAN pkt,
			 * double-check this now that we have the actual
			 * packet in hand.
			 */

			skb_reset_mac_header(skb);
			ehdr = eth_hdr(skb);
			if (ehdr->h_proto != htons(ETH_P_8021Q))
				tp_len = -EMSGSIZE;
		}
		if (unlikely(tp_len < 0)) {
			if (po->tp_loss) {
				__packet_set_status(po, ph,