packet: uses kfree_skb() for errors.
[cascardo/linux.git] / net / packet / af_packet.c
index 1ecfa71..4d5e699 100644 (file)
@@ -1837,6 +1837,7 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg,
        DECLARE_SOCKADDR(struct sockaddr_pkt *, saddr, msg->msg_name);
        struct sk_buff *skb = NULL;
        struct net_device *dev;
+       struct sockcm_cookie sockc;
        __be16 proto = 0;
        int err;
        int extra_len = 0;
@@ -1925,12 +1926,21 @@ retry:
                goto out_unlock;
        }
 
+       sockc.tsflags = 0;
+       if (msg->msg_controllen) {
+               err = sock_cmsg_send(sk, msg, &sockc);
+               if (unlikely(err)) {
+                       err = -EINVAL;
+                       goto out_unlock;
+               }
+       }
+
        skb->protocol = proto;
        skb->dev = dev;
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
 
-       sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
+       sock_tx_timestamp(sk, sockc.tsflags, &skb_shinfo(skb)->tx_flags);
 
        if (unlikely(extra_len == 4))
                skb->no_fcs = 1;
@@ -2042,6 +2052,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
        u8 *skb_head = skb->data;
        int skb_len = skb->len;
        unsigned int snaplen, res;
+       bool is_drop_n_account = false;
 
        if (skb->pkt_type == PACKET_LOOPBACK)
                goto drop;
@@ -2130,6 +2141,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
        return 0;
 
 drop_n_acct:
+       is_drop_n_account = true;
        spin_lock(&sk->sk_receive_queue.lock);
        po->stats.stats1.tp_drops++;
        atomic_inc(&sk->sk_drops);
@@ -2141,7 +2153,10 @@ drop_n_restore:
                skb->len = skb_len;
        }
 drop:
-       consume_skb(skb);
+       if (!is_drop_n_account)
+               consume_skb(skb);
+       else
+               kfree_skb(skb);
        return 0;
 }
 
@@ -2160,6 +2175,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
        struct sk_buff *copy_skb = NULL;
        struct timespec ts;
        __u32 ts_status;
+       bool is_drop_n_account = false;
 
        /* struct tpacket{2,3}_hdr is aligned to a multiple of TPACKET_ALIGNMENT.
         * We may add members to them until current aligned size without forcing
@@ -2367,10 +2383,14 @@ drop_n_restore:
                skb->len = skb_len;
        }
 drop:
-       kfree_skb(skb);
+       if (!is_drop_n_account)
+               consume_skb(skb);
+       else
+               kfree_skb(skb);
        return 0;
 
 drop_n_account:
+       is_drop_n_account = true;
        po->stats.stats1.tp_drops++;
        spin_unlock(&sk->sk_receive_queue.lock);
 
@@ -2486,7 +2506,8 @@ static int packet_snd_vnet_gso(struct sk_buff *skb,
 
 static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
                void *frame, struct net_device *dev, void *data, int tp_len,
-               __be16 proto, unsigned char *addr, int hlen, int copylen)
+               __be16 proto, unsigned char *addr, int hlen, int copylen,
+               const struct sockcm_cookie *sockc)
 {
        union tpacket_uhdr ph;
        int to_write, offset, len, nr_frags, len_max;
@@ -2500,7 +2521,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
        skb->dev = dev;
        skb->priority = po->sk.sk_priority;
        skb->mark = po->sk.sk_mark;
-       sock_tx_timestamp(&po->sk, &skb_shinfo(skb)->tx_flags);
+       sock_tx_timestamp(&po->sk, sockc->tsflags, &skb_shinfo(skb)->tx_flags);
        skb_shinfo(skb)->destructor_arg = ph.raw;
 
        skb_reserve(skb, hlen);
@@ -2624,6 +2645,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
        struct sk_buff *skb;
        struct net_device *dev;
        struct virtio_net_hdr *vnet_hdr = NULL;
+       struct sockcm_cookie sockc;
        __be16 proto;
        int err, reserve = 0;
        void *ph;
@@ -2655,6 +2677,13 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
                dev = dev_get_by_index(sock_net(&po->sk), saddr->sll_ifindex);
        }
 
+       sockc.tsflags = 0;
+       if (msg->msg_controllen) {
+               err = sock_cmsg_send(&po->sk, msg, &sockc);
+               if (unlikely(err))
+                       goto out;
+       }
+
        err = -ENXIO;
        if (unlikely(dev == NULL))
                goto out;
@@ -2712,7 +2741,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
                        goto out_status;
                }
                tp_len = tpacket_fill_skb(po, skb, ph, dev, data, tp_len, proto,
-                                         addr, hlen, copylen);
+                                         addr, hlen, copylen, &sockc);
                if (likely(tp_len >= 0) &&
                    tp_len > dev->mtu + reserve &&
                    !po->has_vnet_hdr &&
@@ -2851,6 +2880,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
        if (unlikely(!(dev->flags & IFF_UP)))
                goto out_unlock;
 
+       sockc.tsflags = 0;
        sockc.mark = sk->sk_mark;
        if (msg->msg_controllen) {
                err = sock_cmsg_send(sk, msg, &sockc);
@@ -2908,7 +2938,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
                goto out_free;
        }
 
-       sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
+       sock_tx_timestamp(sk, sockc.tsflags, &skb_shinfo(skb)->tx_flags);
 
        if (!vnet_hdr.gso_type && (len > dev->mtu + reserve + extra_len) &&
            !packet_extra_vlan_len_allowed(dev, skb)) {
@@ -4151,7 +4181,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
 
        /* Opening a Tx-ring is NOT supported in TPACKET_V3 */
        if (!closing && tx_ring && (po->tp_version > TPACKET_V2)) {
-               WARN(1, "Tx-ring is not supported.\n");
+               net_warn_ratelimited("Tx-ring is not supported.\n");
                goto out;
        }