af-packet: Add flag to distinguish VID 0 from no-vlan.
[firefly-linux-kernel-4.4.55.git] / net / packet / af_packet.c
index 91cb1d71f018d8b6b77c029dca1b99cb2855ef21..ba248d93399a95213717b8e170cfd635717b42d9 100644 (file)
@@ -164,7 +164,6 @@ struct packet_mreq_max {
 static int packet_set_ring(struct sock *sk, struct tpacket_req *req,
                int closing, int tx_ring);
 
-#define PGV_FROM_VMALLOC 1
 struct pgv {
        char *buffer;
 };
@@ -466,7 +465,7 @@ retry:
         */
 
        err = -EMSGSIZE;
-       if (len > dev->mtu + dev->hard_header_len)
+       if (len > dev->mtu + dev->hard_header_len + VLAN_HLEN)
                goto out_unlock;
 
        if (!skb) {
@@ -497,6 +496,19 @@ retry:
                goto retry;
        }
 
+       if (len > (dev->mtu + dev->hard_header_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;
+               }
+       }
 
        skb->protocol = proto;
        skb->dev = dev;
@@ -523,11 +535,11 @@ static inline unsigned int run_filter(const struct sk_buff *skb,
 {
        struct sk_filter *filter;
 
-       rcu_read_lock_bh();
-       filter = rcu_dereference_bh(sk->sk_filter);
+       rcu_read_lock();
+       filter = rcu_dereference(sk->sk_filter);
        if (filter != NULL)
-               res = sk_run_filter(skb, filter->insns);
-       rcu_read_unlock_bh();
+               res = SK_RUN_FILTER(filter, skb);
+       rcu_read_unlock();
 
        return res;
 }
@@ -786,7 +798,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
                        getnstimeofday(&ts);
                h.h2->tp_sec = ts.tv_sec;
                h.h2->tp_nsec = ts.tv_nsec;
-               h.h2->tp_vlan_tci = vlan_tx_tag_get(skb);
+               if (vlan_tx_tag_present(skb)) {
+                       h.h2->tp_vlan_tci = vlan_tx_tag_get(skb);
+                       status |= TP_STATUS_VLAN_VALID;
+               } else {
+                       h.h2->tp_vlan_tci = 0;
+               }
                hdrlen = sizeof(*h.h2);
                break;
        default:
@@ -954,7 +971,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
 
 static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
 {
-       struct socket *sock;
        struct sk_buff *skb;
        struct net_device *dev;
        __be16 proto;
@@ -966,8 +982,6 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
        int len_sum = 0;
        int status = 0;
 
-       sock = po->sk.sk_socket;
-
        mutex_lock(&po->pg_vec_lock);
 
        err = -EBUSY;
@@ -1200,7 +1214,7 @@ static int packet_snd(struct socket *sock,
        }
 
        err = -EMSGSIZE;
-       if (!gso_type && (len > dev->mtu+reserve))
+       if (!gso_type && (len > dev->mtu + reserve + VLAN_HLEN))
                goto out_unlock;
 
        err = -ENOBUFS;
@@ -1225,6 +1239,20 @@ static int packet_snd(struct socket *sock,
        if (err < 0)
                goto out_free;
 
+       if (!gso_type && (len > dev->mtu + reserve)) {
+               /* 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;
+               }
+       }
+
        skb->protocol = proto;
        skb->dev = dev;
        skb->priority = sk->sk_priority;
@@ -1702,8 +1730,12 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
                aux.tp_snaplen = skb->len;
                aux.tp_mac = 0;
                aux.tp_net = skb_network_offset(skb);
-               aux.tp_vlan_tci = vlan_tx_tag_get(skb);
-
+               if (vlan_tx_tag_present(skb)) {
+                       aux.tp_vlan_tci = vlan_tx_tag_get(skb);
+                       aux.tp_status |= TP_STATUS_VLAN_VALID;
+               } else {
+                       aux.tp_vlan_tci = 0;
+               }
                put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux);
        }
 
@@ -2683,7 +2715,7 @@ static int packet_seq_show(struct seq_file *seq, void *v)
                const struct packet_sock *po = pkt_sk(s);
 
                seq_printf(seq,
-                          "%p %-6d %-4d %04x   %-5d %1d %-6u %-6u %-6lu\n",
+                          "%pK %-6d %-4d %04x   %-5d %1d %-6u %-6u %-6lu\n",
                           s,
                           atomic_read(&s->sk_refcnt),
                           s->sk_type,