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 abba3cc81f1..a8a94e2f6dd 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c | |||
@@ -37,6 +37,8 @@ | |||
37 | struct macvtap_queue { | 37 | struct macvtap_queue { |
38 | struct sock sk; | 38 | struct sock sk; |
39 | struct socket sock; | 39 | struct socket sock; |
40 | struct socket_wq wq; | ||
41 | int vnet_hdr_sz; | ||
40 | struct macvlan_dev *vlan; | 42 | struct macvlan_dev *vlan; |
41 | struct file *file; | 43 | struct file *file; |
42 | unsigned int flags; | 44 | unsigned int flags; |
@@ -181,7 +183,7 @@ static int macvtap_forward(struct net_device *dev, struct sk_buff *skb) | |||
181 | return -ENOLINK; | 183 | return -ENOLINK; |
182 | 184 | ||
183 | skb_queue_tail(&q->sk.sk_receive_queue, skb); | 185 | skb_queue_tail(&q->sk.sk_receive_queue, skb); |
184 | wake_up_interruptible_poll(q->sk.sk_sleep, POLLIN | POLLRDNORM | POLLRDBAND); | 186 | wake_up_interruptible_poll(sk_sleep(&q->sk), POLLIN | POLLRDNORM | POLLRDBAND); |
185 | return 0; | 187 | return 0; |
186 | } | 188 | } |
187 | 189 | ||
@@ -242,12 +244,15 @@ static struct rtnl_link_ops macvtap_link_ops __read_mostly = { | |||
242 | 244 | ||
243 | static void macvtap_sock_write_space(struct sock *sk) | 245 | static void macvtap_sock_write_space(struct sock *sk) |
244 | { | 246 | { |
247 | wait_queue_head_t *wqueue; | ||
248 | |||
245 | if (!sock_writeable(sk) || | 249 | if (!sock_writeable(sk) || |
246 | !test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags)) | 250 | !test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags)) |
247 | return; | 251 | return; |
248 | 252 | ||
249 | if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) | 253 | wqueue = sk_sleep(sk); |
250 | wake_up_interruptible_poll(sk->sk_sleep, POLLOUT | POLLWRNORM | POLLWRBAND); | 254 | if (wqueue && waitqueue_active(wqueue)) |
255 | wake_up_interruptible_poll(wqueue, POLLOUT | POLLWRNORM | POLLWRBAND); | ||
251 | } | 256 | } |
252 | 257 | ||
253 | static int macvtap_open(struct inode *inode, struct file *file) | 258 | static int macvtap_open(struct inode *inode, struct file *file) |
@@ -272,7 +277,8 @@ static int macvtap_open(struct inode *inode, struct file *file) | |||
272 | if (!q) | 277 | if (!q) |
273 | goto out; | 278 | goto out; |
274 | 279 | ||
275 | init_waitqueue_head(&q->sock.wait); | 280 | q->sock.wq = &q->wq; |
281 | init_waitqueue_head(&q->wq.wait); | ||
276 | q->sock.type = SOCK_RAW; | 282 | q->sock.type = SOCK_RAW; |
277 | q->sock.state = SS_CONNECTED; | 283 | q->sock.state = SS_CONNECTED; |
278 | q->sock.file = file; | 284 | q->sock.file = file; |
@@ -280,6 +286,7 @@ static int macvtap_open(struct inode *inode, struct file *file) | |||
280 | sock_init_data(&q->sock, &q->sk); | 286 | sock_init_data(&q->sock, &q->sk); |
281 | q->sk.sk_write_space = macvtap_sock_write_space; | 287 | q->sk.sk_write_space = macvtap_sock_write_space; |
282 | q->flags = IFF_VNET_HDR | IFF_NO_PI | IFF_TAP; | 288 | q->flags = IFF_VNET_HDR | IFF_NO_PI | IFF_TAP; |
289 | q->vnet_hdr_sz = sizeof(struct virtio_net_hdr); | ||
283 | 290 | ||
284 | err = macvtap_set_queue(dev, file, q); | 291 | err = macvtap_set_queue(dev, file, q); |
285 | if (err) | 292 | if (err) |
@@ -308,7 +315,7 @@ static unsigned int macvtap_poll(struct file *file, poll_table * wait) | |||
308 | goto out; | 315 | goto out; |
309 | 316 | ||
310 | mask = 0; | 317 | mask = 0; |
311 | poll_wait(file, &q->sock.wait, wait); | 318 | poll_wait(file, &q->wq.wait, wait); |
312 | 319 | ||
313 | if (!skb_queue_empty(&q->sk.sk_receive_queue)) | 320 | if (!skb_queue_empty(&q->sk.sk_receive_queue)) |
314 | mask |= POLLIN | POLLRDNORM; | 321 | mask |= POLLIN | POLLRDNORM; |
@@ -440,14 +447,14 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, | |||
440 | int vnet_hdr_len = 0; | 447 | int vnet_hdr_len = 0; |
441 | 448 | ||
442 | if (q->flags & IFF_VNET_HDR) { | 449 | if (q->flags & IFF_VNET_HDR) { |
443 | vnet_hdr_len = sizeof(vnet_hdr); | 450 | vnet_hdr_len = q->vnet_hdr_sz; |
444 | 451 | ||
445 | err = -EINVAL; | 452 | err = -EINVAL; |
446 | if ((len -= vnet_hdr_len) < 0) | 453 | if ((len -= vnet_hdr_len) < 0) |
447 | goto err; | 454 | goto err; |
448 | 455 | ||
449 | err = memcpy_fromiovecend((void *)&vnet_hdr, iv, 0, | 456 | err = memcpy_fromiovecend((void *)&vnet_hdr, iv, 0, |
450 | vnet_hdr_len); | 457 | sizeof(vnet_hdr)); |
451 | if (err < 0) | 458 | if (err < 0) |
452 | goto err; | 459 | goto err; |
453 | if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && | 460 | if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && |
@@ -529,7 +536,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, | |||
529 | 536 | ||
530 | if (q->flags & IFF_VNET_HDR) { | 537 | if (q->flags & IFF_VNET_HDR) { |
531 | struct virtio_net_hdr vnet_hdr; | 538 | struct virtio_net_hdr vnet_hdr; |
532 | vnet_hdr_len = sizeof (vnet_hdr); | 539 | vnet_hdr_len = q->vnet_hdr_sz; |
533 | if ((len -= vnet_hdr_len) < 0) | 540 | if ((len -= vnet_hdr_len) < 0) |
534 | return -EINVAL; | 541 | return -EINVAL; |
535 | 542 | ||
@@ -537,7 +544,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, | |||
537 | if (ret) | 544 | if (ret) |
538 | return ret; | 545 | return ret; |
539 | 546 | ||
540 | if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, vnet_hdr_len)) | 547 | if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, sizeof(vnet_hdr))) |
541 | return -EFAULT; | 548 | return -EFAULT; |
542 | } | 549 | } |
543 | 550 | ||
@@ -562,7 +569,7 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q, struct kiocb *iocb, | |||
562 | struct sk_buff *skb; | 569 | struct sk_buff *skb; |
563 | ssize_t ret = 0; | 570 | ssize_t ret = 0; |
564 | 571 | ||
565 | add_wait_queue(q->sk.sk_sleep, &wait); | 572 | add_wait_queue(sk_sleep(&q->sk), &wait); |
566 | while (len) { | 573 | while (len) { |
567 | current->state = TASK_INTERRUPTIBLE; | 574 | current->state = TASK_INTERRUPTIBLE; |
568 | 575 | ||
@@ -587,7 +594,7 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q, struct kiocb *iocb, | |||
587 | } | 594 | } |
588 | 595 | ||
589 | current->state = TASK_RUNNING; | 596 | current->state = TASK_RUNNING; |
590 | remove_wait_queue(q->sk.sk_sleep, &wait); | 597 | remove_wait_queue(sk_sleep(&q->sk), &wait); |
591 | return ret; | 598 | return ret; |
592 | } | 599 | } |
593 | 600 | ||
@@ -622,6 +629,8 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, | |||
622 | struct ifreq __user *ifr = argp; | 629 | struct ifreq __user *ifr = argp; |
623 | unsigned int __user *up = argp; | 630 | unsigned int __user *up = argp; |
624 | unsigned int u; | 631 | unsigned int u; |
632 | int __user *sp = argp; | ||
633 | int s; | ||
625 | int ret; | 634 | int ret; |
626 | 635 | ||
627 | switch (cmd) { | 636 | switch (cmd) { |
@@ -667,6 +676,21 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, | |||
667 | q->sk.sk_sndbuf = u; | 676 | q->sk.sk_sndbuf = u; |
668 | return 0; | 677 | return 0; |
669 | 678 | ||
679 | case TUNGETVNETHDRSZ: | ||
680 | s = q->vnet_hdr_sz; | ||
681 | if (put_user(s, sp)) | ||
682 | return -EFAULT; | ||
683 | return 0; | ||
684 | |||
685 | case TUNSETVNETHDRSZ: | ||
686 | if (get_user(s, sp)) | ||
687 | return -EFAULT; | ||
688 | if (s < (int)sizeof(struct virtio_net_hdr)) | ||
689 | return -EINVAL; | ||
690 | |||
691 | q->vnet_hdr_sz = s; | ||
692 | return 0; | ||
693 | |||
670 | case TUNSETOFFLOAD: | 694 | case TUNSETOFFLOAD: |
671 | /* let the user check for future flags */ | 695 | /* let the user check for future flags */ |
672 | if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | | 696 | if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | |