diff options
author | Daniel Borkmann <dborkman@redhat.com> | 2014-02-27 20:22:06 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-02-28 16:52:02 -0500 |
commit | 52f1454f629fafbfb47ad6727e0837250e1f08c0 (patch) | |
tree | 2d14ee6d76845c7b32bd8ce64a5928feea66cd06 /net/packet | |
parent | 07cb1c175e45b649daff5ec46012934904b8b07e (diff) |
packet: allow to transmit +4 byte in TX_RING slot for VLAN case
Commit 57f89bfa2140 ("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 cbd89acb9eb2 ("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 57f89bfa2140 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: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Cc: Ben Greear <greearb@candelatech.com>
Cc: Phil Sutter <phil@nwl.cc>
Tested-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/packet')
-rw-r--r-- | net/packet/af_packet.c | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 48a6a93db296..292304404fda 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -2257,8 +2257,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
2257 | if (unlikely(!(dev->flags & IFF_UP))) | 2257 | if (unlikely(!(dev->flags & IFF_UP))) |
2258 | goto out_put; | 2258 | goto out_put; |
2259 | 2259 | ||
2260 | reserve = dev->hard_header_len; | 2260 | reserve = dev->hard_header_len + VLAN_HLEN; |
2261 | |||
2262 | size_max = po->tx_ring.frame_size | 2261 | size_max = po->tx_ring.frame_size |
2263 | - (po->tp_hdrlen - sizeof(struct sockaddr_ll)); | 2262 | - (po->tp_hdrlen - sizeof(struct sockaddr_ll)); |
2264 | 2263 | ||
@@ -2285,8 +2284,19 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
2285 | goto out_status; | 2284 | goto out_status; |
2286 | 2285 | ||
2287 | tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto, | 2286 | tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto, |
2288 | addr, hlen); | 2287 | addr, hlen); |
2288 | if (tp_len > dev->mtu + dev->hard_header_len) { | ||
2289 | struct ethhdr *ehdr; | ||
2290 | /* Earlier code assumed this would be a VLAN pkt, | ||
2291 | * double-check this now that we have the actual | ||
2292 | * packet in hand. | ||
2293 | */ | ||
2289 | 2294 | ||
2295 | skb_reset_mac_header(skb); | ||
2296 | ehdr = eth_hdr(skb); | ||
2297 | if (ehdr->h_proto != htons(ETH_P_8021Q)) | ||
2298 | tp_len = -EMSGSIZE; | ||
2299 | } | ||
2290 | if (unlikely(tp_len < 0)) { | 2300 | if (unlikely(tp_len < 0)) { |
2291 | if (po->tp_loss) { | 2301 | if (po->tp_loss) { |
2292 | __packet_set_status(po, ph, | 2302 | __packet_set_status(po, ph, |