This reverts commits: 0f75b09c798ed00c30d7d5551b896be883bc2aeb cbd89acb9eb257ed3b2be867142583fdcf7fdc5b c483e02614551e44ced3fe6eedda8e36d3277ccc Amongst other things, it's modifies the SKB header to pull the ethernet headers off via eth_type_trans() on the output path which is bogus. It's causing serious regressions for people.
Unified · Split
| @@ -88,7 +88,6 @@ · 87 unmodified lines | ||
| 88 | 88 | #include <linux/virtio_net.h> |
| 89 | 89 | #include <linux/errqueue.h> |
| 90 | 90 | #include <linux/net_tstamp.h> |
| 91 | −#include <linux/if_arp.h> | |
| 92 | 91 | |
| 93 | 92 | #ifdef CONFIG_INET |
| 94 | 93 | #include <net/inet_common.h> |
| @@ -1924,7 +1923,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, · 1829 unmodified lines | ||
| 1924 | 1923 | __be16 proto, unsigned char *addr, int hlen) |
| 1925 | 1924 | { |
| 1926 | 1925 | union tpacket_uhdr ph; |
| 1927 | − int to_write, offset, len, tp_len, nr_frags, len_max, max_frame_len; | |
| 1926 | + int to_write, offset, len, tp_len, nr_frags, len_max; | |
| 1928 | 1927 | struct socket *sock = po->sk.sk_socket; |
| 1929 | 1928 | struct page *page; |
| 1930 | 1929 | void *data; |
| @@ -1947,6 +1946,10 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, · 16 unmodified lines | ||
| 1947 | 1946 | tp_len = ph.h1->tp_len; |
| 1948 | 1947 | break; |
| 1949 | 1948 | } |
| 1949 | + if (unlikely(tp_len > size_max)) { | |
| 1950 | + pr_err("packet size is too long (%d > %d)\n", tp_len, size_max); | |
| 1951 | + return -EMSGSIZE; | |
| 1952 | + } | |
| 1950 | 1953 | |
| 1951 | 1954 | skb_reserve(skb, hlen); |
| 1952 | 1955 | skb_reset_network_header(skb); |
| @@ -2002,25 +2005,10 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, · 49 unmodified lines | ||
| 2002 | 2005 | if (unlikely(err)) |
| 2003 | 2006 | return err; |
| 2004 | 2007 | |
| 2005 | − if (dev->type == ARPHRD_ETHER) | |
| 2006 | − skb->protocol = eth_type_trans(skb, dev); | |
| 2007 | − | |
| 2008 | 2008 | data += dev->hard_header_len; |
| 2009 | 2009 | to_write -= dev->hard_header_len; |
| 2010 | 2010 | } |
| 2011 | 2011 | |
| 2012 | − max_frame_len = dev->mtu + dev->hard_header_len; | |
| 2013 | − if (skb->protocol == htons(ETH_P_8021Q)) | |
| 2014 | − max_frame_len += VLAN_HLEN; | |
| 2015 | − | |
| 2016 | − if (size_max > max_frame_len) | |
| 2017 | − size_max = max_frame_len; | |
| 2018 | − | |
| 2019 | − if (unlikely(tp_len > size_max)) { | |
| 2020 | − pr_err("packet size is too long (%d > %d)\n", tp_len, size_max); | |
| 2021 | − return -EMSGSIZE; | |
| 2022 | − } | |
| 2023 | − | |
| 2024 | 2012 | offset = offset_in_page(data); |
| 2025 | 2013 | len_max = PAGE_SIZE - offset; |
| 2026 | 2014 | len = ((to_write > len_max) ? len_max : to_write); |
| @@ -2059,7 +2047,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) · 32 unmodified lines | ||
| 2059 | 2047 | struct net_device *dev; |
| 2060 | 2048 | __be16 proto; |
| 2061 | 2049 | bool need_rls_dev = false; |
| 2062 | − int err; | |
| 2050 | + int err, reserve = 0; | |
| 2063 | 2051 | void *ph; |
| 2064 | 2052 | struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name; |
| 2065 | 2053 | int tp_len, size_max; |
| @@ -2092,6 +2080,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) · 26 unmodified lines | ||
| 2092 | 2080 | if (unlikely(dev == NULL)) |
| 2093 | 2081 | goto out; |
| 2094 | 2082 | |
| 2083 | + reserve = dev->hard_header_len; | |
| 2084 | + | |
| 2095 | 2085 | err = -ENETDOWN; |
| 2096 | 2086 | if (unlikely(!(dev->flags & IFF_UP))) |
| 2097 | 2087 | goto out_put; |
| @@ -2099,6 +2089,9 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) · 1 unmodified line | ||
| 2099 | 2089 | size_max = po->tx_ring.frame_size |
| 2100 | 2090 | - (po->tp_hdrlen - sizeof(struct sockaddr_ll)); |
| 2101 | 2091 | |
| 2092 | + if (size_max > dev->mtu + reserve) | |
| 2093 | + size_max = dev->mtu + reserve; | |
| 2094 | + | |
| 2102 | 2095 | do { |
| 2103 | 2096 | ph = packet_current_frame(po, &po->tx_ring, |
| 2104 | 2097 | TP_STATUS_SEND_REQUEST); |
| @@ -2331,20 +2324,22 @@ static int packet_snd(struct socket *sock, · 226 unmodified lines | ||
| 2331 | 2324 | |
| 2332 | 2325 | sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags); |
| 2333 | 2326 | |
| 2334 | − if (dev->type == ARPHRD_ETHER) { | |
| 2335 | − skb->protocol = eth_type_trans(skb, dev); | |
| 2336 | − if (skb->protocol == htons(ETH_P_8021Q)) | |
| 2337 | − reserve += VLAN_HLEN; | |
| 2338 | − } else { | |
| 2339 | − skb->protocol = proto; | |
| 2340 | − skb->dev = dev; | |
| 2341 | − } | |
| 2342 | − | |
| 2343 | 2327 | if (!gso_type && (len > dev->mtu + reserve + extra_len)) { |
| 2344 | − err = -EMSGSIZE; | |
| 2345 | − goto out_free; | |
| 2328 | + /* Earlier code assumed this would be a VLAN pkt, | |
| 2329 | + * double-check this now that we have the actual | |
| 2330 | + * packet in hand. | |
| 2331 | + */ | |
| 2332 | + struct ethhdr *ehdr; | |
| 2333 | + skb_reset_mac_header(skb); | |
| 2334 | + ehdr = eth_hdr(skb); | |
| 2335 | + if (ehdr->h_proto != htons(ETH_P_8021Q)) { | |
| 2336 | + err = -EMSGSIZE; | |
| 2337 | + goto out_free; | |
| 2338 | + } | |
| 2346 | 2339 | } |
| 2347 | 2340 | |
| 2341 | + skb->protocol = proto; | |
| 2342 | + skb->dev = dev; | |
| 2348 | 2343 | skb->priority = sk->sk_priority; |
| 2349 | 2344 | skb->mark = sk->sk_mark; |
| 2350 | 2345 | |