diff options
Diffstat (limited to 'drivers/net/macvtap.c')
-rw-r--r-- | drivers/net/macvtap.c | 46 |
1 files changed, 35 insertions, 11 deletions
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index abba3cc81f12..a8a94e2f6ddc 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -37,6 +37,8 @@ struct macvtap_queue { struct sock sk; struct socket sock; + struct socket_wq wq; + int vnet_hdr_sz; struct macvlan_dev *vlan; struct file *file; unsigned int flags; @@ -181,7 +183,7 @@ static int macvtap_forward(struct net_device *dev, struct sk_buff *skb) return -ENOLINK; skb_queue_tail(&q->sk.sk_receive_queue, skb); - wake_up_interruptible_poll(q->sk.sk_sleep, POLLIN | POLLRDNORM | POLLRDBAND); + wake_up_interruptible_poll(sk_sleep(&q->sk), POLLIN | POLLRDNORM | POLLRDBAND); return 0; } @@ -242,12 +244,15 @@ static struct rtnl_link_ops macvtap_link_ops __read_mostly = { static void macvtap_sock_write_space(struct sock *sk) { + wait_queue_head_t *wqueue; + if (!sock_writeable(sk) || !test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags)) return; - if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) - wake_up_interruptible_poll(sk->sk_sleep, POLLOUT | POLLWRNORM | POLLWRBAND); + wqueue = sk_sleep(sk); + if (wqueue && waitqueue_active(wqueue)) + wake_up_interruptible_poll(wqueue, POLLOUT | POLLWRNORM | POLLWRBAND); } static int macvtap_open(struct inode *inode, struct file *file) @@ -272,7 +277,8 @@ static int macvtap_open(struct inode *inode, struct file *file) if (!q) goto out; - init_waitqueue_head(&q->sock.wait); + q->sock.wq = &q->wq; + init_waitqueue_head(&q->wq.wait); q->sock.type = SOCK_RAW; q->sock.state = SS_CONNECTED; q->sock.file = file; @@ -280,6 +286,7 @@ static int macvtap_open(struct inode *inode, struct file *file) sock_init_data(&q->sock, &q->sk); q->sk.sk_write_space = macvtap_sock_write_space; q->flags = IFF_VNET_HDR | IFF_NO_PI | IFF_TAP; + q->vnet_hdr_sz = sizeof(struct virtio_net_hdr); err = macvtap_set_queue(dev, file, q); if (err) @@ -308,7 +315,7 @@ static unsigned int macvtap_poll(struct file *file, poll_table * wait) goto out; mask = 0; - poll_wait(file, &q->sock.wait, wait); + poll_wait(file, &q->wq.wait, wait); if (!skb_queue_empty(&q->sk.sk_receive_queue)) mask |= POLLIN | POLLRDNORM; @@ -440,14 +447,14 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, int vnet_hdr_len = 0; if (q->flags & IFF_VNET_HDR) { - vnet_hdr_len = sizeof(vnet_hdr); + vnet_hdr_len = q->vnet_hdr_sz; err = -EINVAL; if ((len -= vnet_hdr_len) < 0) goto err; err = memcpy_fromiovecend((void *)&vnet_hdr, iv, 0, - vnet_hdr_len); + sizeof(vnet_hdr)); if (err < 0) goto err; if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && @@ -529,7 +536,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, if (q->flags & IFF_VNET_HDR) { struct virtio_net_hdr vnet_hdr; - vnet_hdr_len = sizeof (vnet_hdr); + vnet_hdr_len = q->vnet_hdr_sz; if ((len -= vnet_hdr_len) < 0) return -EINVAL; @@ -537,7 +544,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, if (ret) return ret; - if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, vnet_hdr_len)) + if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, sizeof(vnet_hdr))) return -EFAULT; } @@ -562,7 +569,7 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q, struct kiocb *iocb, struct sk_buff *skb; ssize_t ret = 0; - add_wait_queue(q->sk.sk_sleep, &wait); + add_wait_queue(sk_sleep(&q->sk), &wait); while (len) { current->state = TASK_INTERRUPTIBLE; @@ -587,7 +594,7 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q, struct kiocb *iocb, } current->state = TASK_RUNNING; - remove_wait_queue(q->sk.sk_sleep, &wait); + remove_wait_queue(sk_sleep(&q->sk), &wait); return ret; } @@ -622,6 +629,8 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, struct ifreq __user *ifr = argp; unsigned int __user *up = argp; unsigned int u; + int __user *sp = argp; + int s; int ret; switch (cmd) { @@ -667,6 +676,21 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, q->sk.sk_sndbuf = u; return 0; + case TUNGETVNETHDRSZ: + s = q->vnet_hdr_sz; + if (put_user(s, sp)) + return -EFAULT; + return 0; + + case TUNSETVNETHDRSZ: + if (get_user(s, sp)) + return -EFAULT; + if (s < (int)sizeof(struct virtio_net_hdr)) + return -EINVAL; + + q->vnet_hdr_sz = s; + return 0; + case TUNSETOFFLOAD: /* let the user check for future flags */ if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | |