Merge tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
[cascardo/linux.git] / net / packet / af_packet.c
index 07c04a8..6880f34 100644 (file)
@@ -785,6 +785,7 @@ static void prb_close_block(struct tpacket_kbdq_core *pkc1,
 
        struct tpacket3_hdr *last_pkt;
        struct tpacket_hdr_v1 *h1 = &pbd1->hdr.bh1;
+       struct sock *sk = &po->sk;
 
        if (po->stats.stats3.tp_drops)
                status |= TP_STATUS_LOSING;
@@ -809,6 +810,8 @@ static void prb_close_block(struct tpacket_kbdq_core *pkc1,
        /* Flush the block */
        prb_flush_block(pkc1, pbd1, status);
 
+       sk->sk_data_ready(sk);
+
        pkc1->kactive_blk_num = GET_NEXT_PRB_BLK_NUM(pkc1);
 }
 
@@ -1676,7 +1679,7 @@ retry:
                        if (len < hhlen)
                                skb_reset_network_header(skb);
                }
-               err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
+               err = memcpy_from_msg(skb_put(skb, len), msg, len);
                if (err)
                        goto out_free;
                goto retry;
@@ -2052,12 +2055,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
        smp_wmb();
 #endif
 
-       if (po->tp_version <= TPACKET_V2)
+       if (po->tp_version <= TPACKET_V2) {
                __packet_set_status(po, h.raw, status);
-       else
+               sk->sk_data_ready(sk);
+       } else {
                prb_clear_blk_fill_status(&po->rx_ring);
-
-       sk->sk_data_ready(sk);
+       }
 
 drop_n_restore:
        if (skb_head != skb->data && skb_shared(skb)) {
@@ -2095,6 +2098,18 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
        sock_wfree(skb);
 }
 
+static bool ll_header_truncated(const struct net_device *dev, int len)
+{
+       /* net device doesn't like empty head */
+       if (unlikely(len <= dev->hard_header_len)) {
+               net_warn_ratelimited("%s: packet size is too short (%d < %d)\n",
+                                    current->comm, len, dev->hard_header_len);
+               return true;
+       }
+
+       return false;
+}
+
 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)
@@ -2170,12 +2185,8 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
                if (unlikely(err < 0))
                        return -EINVAL;
        } else if (dev->hard_header_len) {
-               /* net device doesn't like empty head */
-               if (unlikely(tp_len <= dev->hard_header_len)) {
-                       pr_err("packet size is too short (%d < %d)\n",
-                              tp_len, dev->hard_header_len);
+               if (ll_header_truncated(dev, tp_len))
                        return -EINVAL;
-               }
 
                skb_push(skb, dev->hard_header_len);
                err = skb_store_bits(skb, 0, data,
@@ -2400,6 +2411,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
        unsigned short gso_type = 0;
        int hlen, tlen;
        int extra_len = 0;
+       ssize_t n;
 
        /*
         *      Get and verify the address.
@@ -2438,19 +2450,21 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
 
                len -= vnet_hdr_len;
 
-               err = memcpy_fromiovec((void *)&vnet_hdr, msg->msg_iov,
-                                      vnet_hdr_len);
-               if (err < 0)
+               err = -EFAULT;
+               n = copy_from_iter(&vnet_hdr, vnet_hdr_len, &msg->msg_iter);
+               if (n != vnet_hdr_len)
                        goto out_unlock;
 
                if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
-                   (vnet_hdr.csum_start + vnet_hdr.csum_offset + 2 >
-                     vnet_hdr.hdr_len))
-                       vnet_hdr.hdr_len = vnet_hdr.csum_start +
-                                                vnet_hdr.csum_offset + 2;
+                   (__virtio16_to_cpu(false, vnet_hdr.csum_start) +
+                    __virtio16_to_cpu(false, vnet_hdr.csum_offset) + 2 >
+                     __virtio16_to_cpu(false, vnet_hdr.hdr_len)))
+                       vnet_hdr.hdr_len = __cpu_to_virtio16(false,
+                                __virtio16_to_cpu(false, vnet_hdr.csum_start) +
+                               __virtio16_to_cpu(false, vnet_hdr.csum_offset) + 2);
 
                err = -EINVAL;
-               if (vnet_hdr.hdr_len > len)
+               if (__virtio16_to_cpu(false, vnet_hdr.hdr_len) > len)
                        goto out_unlock;
 
                if (vnet_hdr.gso_type != VIRTIO_NET_HDR_GSO_NONE) {
@@ -2492,7 +2506,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
        err = -ENOBUFS;
        hlen = LL_RESERVED_SPACE(dev);
        tlen = dev->needed_tailroom;
-       skb = packet_alloc_skb(sk, hlen + tlen, hlen, len, vnet_hdr.hdr_len,
+       skb = packet_alloc_skb(sk, hlen + tlen, hlen, len,
+                              __virtio16_to_cpu(false, vnet_hdr.hdr_len),
                               msg->msg_flags & MSG_DONTWAIT, &err);
        if (skb == NULL)
                goto out_unlock;
@@ -2500,12 +2515,17 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
        skb_set_network_header(skb, reserve);
 
        err = -EINVAL;
-       if (sock->type == SOCK_DGRAM &&
-           (offset = dev_hard_header(skb, dev, ntohs(proto), addr, NULL, len)) < 0)
-               goto out_free;
+       if (sock->type == SOCK_DGRAM) {
+               offset = dev_hard_header(skb, dev, ntohs(proto), addr, NULL, len);
+               if (unlikely(offset) < 0)
+                       goto out_free;
+       } else {
+               if (ll_header_truncated(dev, len))
+                       goto out_free;
+       }
 
        /* Returns -EFAULT on error */
-       err = skb_copy_datagram_from_iovec(skb, offset, msg->msg_iov, 0, len);
+       err = skb_copy_datagram_from_iter(skb, offset, &msg->msg_iter, len);
        if (err)
                goto out_free;
 
@@ -2534,14 +2554,16 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
 
        if (po->has_vnet_hdr) {
                if (vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
-                       if (!skb_partial_csum_set(skb, vnet_hdr.csum_start,
-                                                 vnet_hdr.csum_offset)) {
+                       u16 s = __virtio16_to_cpu(false, vnet_hdr.csum_start);
+                       u16 o = __virtio16_to_cpu(false, vnet_hdr.csum_offset);
+                       if (!skb_partial_csum_set(skb, s, o)) {
                                err = -EINVAL;
                                goto out_free;
                        }
                }
 
-               skb_shinfo(skb)->gso_size = vnet_hdr.gso_size;
+               skb_shinfo(skb)->gso_size =
+                       __virtio16_to_cpu(false, vnet_hdr.gso_size);
                skb_shinfo(skb)->gso_type = gso_type;
 
                /* Header must be checked, and gso_segs computed. */
@@ -2912,8 +2934,10 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
                        struct skb_shared_info *sinfo = skb_shinfo(skb);
 
                        /* This is a hint as to how much should be linear. */
-                       vnet_hdr.hdr_len = skb_headlen(skb);
-                       vnet_hdr.gso_size = sinfo->gso_size;
+                       vnet_hdr.hdr_len =
+                               __cpu_to_virtio16(false, skb_headlen(skb));
+                       vnet_hdr.gso_size =
+                               __cpu_to_virtio16(false, sinfo->gso_size);
                        if (sinfo->gso_type & SKB_GSO_TCPV4)
                                vnet_hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
                        else if (sinfo->gso_type & SKB_GSO_TCPV6)
@@ -2931,14 +2955,15 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
 
                if (skb->ip_summed == CHECKSUM_PARTIAL) {
                        vnet_hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
-                       vnet_hdr.csum_start = skb_checksum_start_offset(skb);
-                       vnet_hdr.csum_offset = skb->csum_offset;
+                       vnet_hdr.csum_start = __cpu_to_virtio16(false,
+                                         skb_checksum_start_offset(skb));
+                       vnet_hdr.csum_offset = __cpu_to_virtio16(false,
+                                                        skb->csum_offset);
                } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
                        vnet_hdr.flags = VIRTIO_NET_HDR_F_DATA_VALID;
                } /* else everything is zero */
 
-               err = memcpy_toiovec(msg->msg_iov, (void *)&vnet_hdr,
-                                    vnet_hdr_len);
+               err = memcpy_to_msg(msg, (void *)&vnet_hdr, vnet_hdr_len);
                if (err < 0)
                        goto out_free;
        }
@@ -2953,7 +2978,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
                msg->msg_flags |= MSG_TRUNC;
        }
 
-       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+       err = skb_copy_datagram_msg(skb, 0, msg, copied);
        if (err)
                goto out_free;