]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/packet/af_packet.c
packet: only allow extra vlan len on ethernet devices
[karo-tx-linux.git] / net / packet / af_packet.c
index bdecf17a15bb4cce054fb80f26fd536ef18257e6..8795b0fb1ed1c0976d3ec80b5891d8bd6099a703 100644 (file)
@@ -1741,6 +1741,20 @@ static void fanout_release(struct sock *sk)
                kfree_rcu(po->rollover, rcu);
 }
 
+static bool packet_extra_vlan_len_allowed(const struct net_device *dev,
+                                         struct sk_buff *skb)
+{
+       /* Earlier code assumed this would be a VLAN pkt, double-check
+        * this now that we have the actual packet in hand. We can only
+        * do this check on Ethernet devices.
+        */
+       if (unlikely(dev->type != ARPHRD_ETHER))
+               return false;
+
+       skb_reset_mac_header(skb);
+       return likely(eth_hdr(skb)->h_proto == htons(ETH_P_8021Q));
+}
+
 static const struct proto_ops packet_ops;
 
 static const struct proto_ops packet_ops_spkt;
@@ -1902,18 +1916,10 @@ retry:
                goto retry;
        }
 
-       if (len > (dev->mtu + dev->hard_header_len + extra_len)) {
-               /* Earlier code assumed this would be a VLAN pkt,
-                * double-check this now that we have the actual
-                * packet in hand.
-                */
-               struct ethhdr *ehdr;
-               skb_reset_mac_header(skb);
-               ehdr = eth_hdr(skb);
-               if (ehdr->h_proto != htons(ETH_P_8021Q)) {
-                       err = -EMSGSIZE;
-                       goto out_unlock;
-               }
+       if (len > (dev->mtu + dev->hard_header_len + extra_len) &&
+           !packet_extra_vlan_len_allowed(dev, skb)) {
+               err = -EMSGSIZE;
+               goto out_unlock;
        }
 
        skb->protocol = proto;
@@ -2525,18 +2531,10 @@ 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 (likely(tp_len >= 0) &&
-                   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.
-                        */
+                   tp_len > dev->mtu + dev->hard_header_len &&
+                   !packet_extra_vlan_len_allowed(dev, skb))
+                       tp_len = -EMSGSIZE;
 
-                       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,
@@ -2765,18 +2763,10 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
 
        sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
 
-       if (!gso_type && (len > dev->mtu + reserve + extra_len)) {
-               /* Earlier code assumed this would be a VLAN pkt,
-                * double-check this now that we have the actual
-                * packet in hand.
-                */
-               struct ethhdr *ehdr;
-               skb_reset_mac_header(skb);
-               ehdr = eth_hdr(skb);
-               if (ehdr->h_proto != htons(ETH_P_8021Q)) {
-                       err = -EMSGSIZE;
-                       goto out_free;
-               }
+       if (!gso_type && (len > dev->mtu + reserve + extra_len) &&
+           !packet_extra_vlan_len_allowed(dev, skb)) {
+               err = -EMSGSIZE;
+               goto out_free;
        }
 
        skb->protocol = proto;