diff options
Diffstat (limited to 'net/packet')
-rw-r--r-- | net/packet/af_packet.c | 87 |
1 files changed, 19 insertions, 68 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 588ec202d5ba..49cd0c70a13a 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1967,17 +1967,6 @@ static unsigned int run_filter(struct sk_buff *skb, return res; } -static int __packet_rcv_vnet(const struct sk_buff *skb, - struct virtio_net_hdr *vnet_hdr) -{ - *vnet_hdr = (const struct virtio_net_hdr) { 0 }; - - if (virtio_net_hdr_from_skb(skb, vnet_hdr, vio_le())) - BUG(); - - return 0; -} - static int packet_rcv_vnet(struct msghdr *msg, const struct sk_buff *skb, size_t *len) { @@ -1987,7 +1976,7 @@ static int packet_rcv_vnet(struct msghdr *msg, const struct sk_buff *skb, return -EINVAL; *len -= sizeof(vnet_hdr); - if (__packet_rcv_vnet(skb, &vnet_hdr)) + if (virtio_net_hdr_from_skb(skb, &vnet_hdr, vio_le())) return -EINVAL; return memcpy_to_msg(msg, (void *)&vnet_hdr, sizeof(vnet_hdr)); @@ -2246,8 +2235,9 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, spin_unlock(&sk->sk_receive_queue.lock); if (po->has_vnet_hdr) { - if (__packet_rcv_vnet(skb, h.raw + macoff - - sizeof(struct virtio_net_hdr))) { + if (virtio_net_hdr_from_skb(skb, h.raw + macoff - + sizeof(struct virtio_net_hdr), + vio_le())) { spin_lock(&sk->sk_receive_queue.lock); goto drop_n_account; } @@ -2390,8 +2380,6 @@ static void tpacket_set_protocol(const struct net_device *dev, static int __packet_snd_vnet_parse(struct virtio_net_hdr *vnet_hdr, size_t len) { - unsigned short gso_type = 0; - if ((vnet_hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && (__virtio16_to_cpu(vio_le(), vnet_hdr->csum_start) + __virtio16_to_cpu(vio_le(), vnet_hdr->csum_offset) + 2 > @@ -2403,29 +2391,6 @@ static int __packet_snd_vnet_parse(struct virtio_net_hdr *vnet_hdr, size_t len) if (__virtio16_to_cpu(vio_le(), vnet_hdr->hdr_len) > len) return -EINVAL; - if (vnet_hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) { - switch (vnet_hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { - case VIRTIO_NET_HDR_GSO_TCPV4: - gso_type = SKB_GSO_TCPV4; - break; - case VIRTIO_NET_HDR_GSO_TCPV6: - gso_type = SKB_GSO_TCPV6; - break; - case VIRTIO_NET_HDR_GSO_UDP: - gso_type = SKB_GSO_UDP; - break; - default: - return -EINVAL; - } - - if (vnet_hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN) - gso_type |= SKB_GSO_TCP_ECN; - - if (vnet_hdr->gso_size == 0) - return -EINVAL; - } - - vnet_hdr->gso_type = gso_type; /* changes type, temporary storage */ return 0; } @@ -2442,27 +2407,6 @@ static int packet_snd_vnet_parse(struct msghdr *msg, size_t *len, return __packet_snd_vnet_parse(vnet_hdr, *len); } -static int packet_snd_vnet_gso(struct sk_buff *skb, - struct virtio_net_hdr *vnet_hdr) -{ - if (vnet_hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { - u16 s = __virtio16_to_cpu(vio_le(), vnet_hdr->csum_start); - u16 o = __virtio16_to_cpu(vio_le(), vnet_hdr->csum_offset); - - if (!skb_partial_csum_set(skb, s, o)) - return -EINVAL; - } - - skb_shinfo(skb)->gso_size = - __virtio16_to_cpu(vio_le(), vnet_hdr->gso_size); - skb_shinfo(skb)->gso_type = vnet_hdr->gso_type; - - /* Header must be checked, and gso_segs computed. */ - skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; - skb_shinfo(skb)->gso_segs = 0; - return 0; -} - 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, @@ -2722,7 +2666,8 @@ tpacket_error: } } - if (po->has_vnet_hdr && packet_snd_vnet_gso(skb, vnet_hdr)) { + if (po->has_vnet_hdr && virtio_net_hdr_to_skb(skb, vnet_hdr, + vio_le())) { tp_len = -EINVAL; goto tpacket_error; } @@ -2913,7 +2858,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) packet_pick_tx_queue(dev, skb); if (po->has_vnet_hdr) { - err = packet_snd_vnet_gso(skb, &vnet_hdr); + err = virtio_net_hdr_to_skb(skb, &vnet_hdr, vio_le()); if (err) goto out_free; len += sizeof(vnet_hdr); @@ -3645,19 +3590,25 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (optlen != sizeof(val)) return -EINVAL; - if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) - return -EBUSY; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; switch (val) { case TPACKET_V1: case TPACKET_V2: case TPACKET_V3: - po->tp_version = val; - return 0; + break; default: return -EINVAL; } + lock_sock(sk); + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) { + ret = -EBUSY; + } else { + po->tp_version = val; + ret = 0; + } + release_sock(sk); + return ret; } case PACKET_RESERVE: { @@ -4161,6 +4112,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, /* Added to avoid minimal code churn */ struct tpacket_req *req = &req_u->req; + lock_sock(sk); /* Opening a Tx-ring is NOT supported in TPACKET_V3 */ if (!closing && tx_ring && (po->tp_version > TPACKET_V2)) { net_warn_ratelimited("Tx-ring is not supported.\n"); @@ -4242,7 +4194,6 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, goto out; } - lock_sock(sk); /* Detach socket from network */ spin_lock(&po->bind_lock); @@ -4291,11 +4242,11 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, if (!tx_ring) prb_shutdown_retire_blk_timer(po, rb_queue); } - release_sock(sk); if (pg_vec) free_pg_vec(pg_vec, order, req->tp_block_nr); out: + release_sock(sk); return err; } |