aboutsummaryrefslogtreecommitdiffstats
path: root/net/packet
diff options
context:
space:
mode:
authorDaniel Borkmann <dborkman@redhat.com>2014-02-27 20:22:06 -0500
committerDavid S. Miller <davem@davemloft.net>2014-02-28 16:52:02 -0500
commit52f1454f629fafbfb47ad6727e0837250e1f08c0 (patch)
tree2d14ee6d76845c7b32bd8ce64a5928feea66cd06 /net/packet
parent07cb1c175e45b649daff5ec46012934904b8b07e (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.c16
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,