Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[firefly-linux-kernel-4.4.55.git] / net / packet / af_packet.c
index bd0d14c97d412c7276504bc29d3977be93f3b067..7e387ff64465c934075993f77c4def101d2160de 100644 (file)
@@ -158,10 +158,16 @@ struct packet_mreq_max {
        unsigned char   mr_address[MAX_ADDR_LEN];
 };
 
+union tpacket_uhdr {
+       struct tpacket_hdr  *h1;
+       struct tpacket2_hdr *h2;
+       struct tpacket3_hdr *h3;
+       void *raw;
+};
+
 static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
                int closing, int tx_ring);
 
-
 #define V3_ALIGNMENT   (8)
 
 #define BLK_HDR_LEN    (ALIGN(sizeof(struct tpacket_block_desc), V3_ALIGNMENT))
@@ -290,11 +296,7 @@ static inline __pure struct page *pgv_to_page(void *addr)
 
 static void __packet_set_status(struct packet_sock *po, void *frame, int status)
 {
-       union {
-               struct tpacket_hdr *h1;
-               struct tpacket2_hdr *h2;
-               void *raw;
-       } h;
+       union tpacket_uhdr h;
 
        h.raw = frame;
        switch (po->tp_version) {
@@ -317,11 +319,7 @@ static void __packet_set_status(struct packet_sock *po, void *frame, int status)
 
 static int __packet_get_status(struct packet_sock *po, void *frame)
 {
-       union {
-               struct tpacket_hdr *h1;
-               struct tpacket2_hdr *h2;
-               void *raw;
-       } h;
+       union tpacket_uhdr h;
 
        smp_rmb();
 
@@ -347,11 +345,7 @@ static void *packet_lookup_frame(struct packet_sock *po,
                int status)
 {
        unsigned int pg_vec_pos, frame_offset;
-       union {
-               struct tpacket_hdr *h1;
-               struct tpacket2_hdr *h2;
-               void *raw;
-       } h;
+       union tpacket_uhdr h;
 
        pg_vec_pos = position / rb->frames_per_block;
        frame_offset = position % rb->frames_per_block;
@@ -1505,13 +1499,14 @@ retry:
        skb->dev = dev;
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
-       err = sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
-       if (err < 0)
-               goto out_unlock;
+
+       sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
 
        if (unlikely(extra_len == 4))
                skb->no_fcs = 1;
 
+       skb_probe_transport_header(skb, 0);
+
        dev_queue_xmit(skb);
        rcu_read_unlock();
        return len;
@@ -1662,27 +1657,40 @@ drop:
        return 0;
 }
 
+static void tpacket_get_timestamp(struct sk_buff *skb, struct timespec *ts,
+                                 unsigned int flags)
+{
+       struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
+
+       if (shhwtstamps) {
+               if ((flags & SOF_TIMESTAMPING_SYS_HARDWARE) &&
+                   ktime_to_timespec_cond(shhwtstamps->syststamp, ts))
+                       return;
+               if ((flags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
+                   ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts))
+                       return;
+       }
+
+       if (ktime_to_timespec_cond(skb->tstamp, ts))
+               return;
+
+       getnstimeofday(ts);
+}
+
 static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
                       struct packet_type *pt, struct net_device *orig_dev)
 {
        struct sock *sk;
        struct packet_sock *po;
        struct sockaddr_ll *sll;
-       union {
-               struct tpacket_hdr *h1;
-               struct tpacket2_hdr *h2;
-               struct tpacket3_hdr *h3;
-               void *raw;
-       } h;
+       union tpacket_uhdr h;
        u8 *skb_head = skb->data;
        int skb_len = skb->len;
        unsigned int snaplen, res;
        unsigned long status = TP_STATUS_USER;
        unsigned short macoff, netoff, hdrlen;
        struct sk_buff *copy_skb = NULL;
-       struct timeval tv;
        struct timespec ts;
-       struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
 
        if (skb->pkt_type == PACKET_LOOPBACK)
                goto drop;
@@ -1765,6 +1773,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
        spin_unlock(&sk->sk_receive_queue.lock);
 
        skb_copy_bits(skb, 0, h.raw + macoff, snaplen);
+       tpacket_get_timestamp(skb, &ts, po->tp_tstamp);
 
        switch (po->tp_version) {
        case TPACKET_V1:
@@ -1772,18 +1781,8 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
                h.h1->tp_snaplen = snaplen;
                h.h1->tp_mac = macoff;
                h.h1->tp_net = netoff;
-               if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
-                               && shhwtstamps->syststamp.tv64)
-                       tv = ktime_to_timeval(shhwtstamps->syststamp);
-               else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
-                               && shhwtstamps->hwtstamp.tv64)
-                       tv = ktime_to_timeval(shhwtstamps->hwtstamp);
-               else if (skb->tstamp.tv64)
-                       tv = ktime_to_timeval(skb->tstamp);
-               else
-                       do_gettimeofday(&tv);
-               h.h1->tp_sec = tv.tv_sec;
-               h.h1->tp_usec = tv.tv_usec;
+               h.h1->tp_sec = ts.tv_sec;
+               h.h1->tp_usec = ts.tv_nsec / NSEC_PER_USEC;
                hdrlen = sizeof(*h.h1);
                break;
        case TPACKET_V2:
@@ -1791,16 +1790,6 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
                h.h2->tp_snaplen = snaplen;
                h.h2->tp_mac = macoff;
                h.h2->tp_net = netoff;
-               if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
-                               && shhwtstamps->syststamp.tv64)
-                       ts = ktime_to_timespec(shhwtstamps->syststamp);
-               else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
-                               && shhwtstamps->hwtstamp.tv64)
-                       ts = ktime_to_timespec(shhwtstamps->hwtstamp);
-               else if (skb->tstamp.tv64)
-                       ts = ktime_to_timespec(skb->tstamp);
-               else
-                       getnstimeofday(&ts);
                h.h2->tp_sec = ts.tv_sec;
                h.h2->tp_nsec = ts.tv_nsec;
                if (vlan_tx_tag_present(skb)) {
@@ -1821,16 +1810,6 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
                h.h3->tp_snaplen = snaplen;
                h.h3->tp_mac = macoff;
                h.h3->tp_net = netoff;
-               if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
-                               && shhwtstamps->syststamp.tv64)
-                       ts = ktime_to_timespec(shhwtstamps->syststamp);
-               else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
-                               && shhwtstamps->hwtstamp.tv64)
-                       ts = ktime_to_timespec(shhwtstamps->hwtstamp);
-               else if (skb->tstamp.tv64)
-                       ts = ktime_to_timespec(skb->tstamp);
-               else
-                       getnstimeofday(&ts);
                h.h3->tp_sec  = ts.tv_sec;
                h.h3->tp_nsec = ts.tv_nsec;
                hdrlen = sizeof(*h.h3);
@@ -1908,11 +1887,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
                void *frame, struct net_device *dev, int size_max,
                __be16 proto, unsigned char *addr, int hlen)
 {
-       union {
-               struct tpacket_hdr *h1;
-               struct tpacket2_hdr *h2;
-               void *raw;
-       } ph;
+       union tpacket_uhdr ph;
        int to_write, offset, len, tp_len, nr_frags, len_max;
        struct socket *sock = po->sk.sk_socket;
        struct page *page;
@@ -1942,6 +1917,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
 
        skb_reserve(skb, hlen);
        skb_reset_network_header(skb);
+       skb_probe_transport_header(skb, 0);
 
        if (po->tp_tx_has_off) {
                int off_min, off_max, off;
@@ -2309,9 +2285,8 @@ static int packet_snd(struct socket *sock,
        err = skb_copy_datagram_from_iovec(skb, offset, msg->msg_iov, 0, len);
        if (err)
                goto out_free;
-       err = sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
-       if (err < 0)
-               goto out_free;
+
+       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,
@@ -2351,6 +2326,8 @@ static int packet_snd(struct socket *sock,
                len += vnet_hdr_len;
        }
 
+       skb_probe_transport_header(skb, reserve);
+
        if (unlikely(extra_len == 4))
                skb->no_fcs = 1;