diff options
Diffstat (limited to 'drivers/net')
| -rw-r--r-- | drivers/net/macvtap.c | 27 | ||||
| -rw-r--r-- | drivers/net/tun.c | 32 |
2 files changed, 51 insertions, 8 deletions
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 1c4110df343e..a8a94e2f6ddc 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c | |||
| @@ -38,6 +38,7 @@ struct macvtap_queue { | |||
| 38 | struct sock sk; | 38 | struct sock sk; |
| 39 | struct socket sock; | 39 | struct socket sock; |
| 40 | struct socket_wq wq; | 40 | struct socket_wq wq; |
| 41 | int vnet_hdr_sz; | ||
| 41 | struct macvlan_dev *vlan; | 42 | struct macvlan_dev *vlan; |
| 42 | struct file *file; | 43 | struct file *file; |
| 43 | unsigned int flags; | 44 | unsigned int flags; |
| @@ -285,6 +286,7 @@ static int macvtap_open(struct inode *inode, struct file *file) | |||
| 285 | sock_init_data(&q->sock, &q->sk); | 286 | sock_init_data(&q->sock, &q->sk); |
| 286 | q->sk.sk_write_space = macvtap_sock_write_space; | 287 | q->sk.sk_write_space = macvtap_sock_write_space; |
| 287 | 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); | ||
| 288 | 290 | ||
| 289 | err = macvtap_set_queue(dev, file, q); | 291 | err = macvtap_set_queue(dev, file, q); |
| 290 | if (err) | 292 | if (err) |
| @@ -445,14 +447,14 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, | |||
| 445 | int vnet_hdr_len = 0; | 447 | int vnet_hdr_len = 0; |
| 446 | 448 | ||
| 447 | if (q->flags & IFF_VNET_HDR) { | 449 | if (q->flags & IFF_VNET_HDR) { |
| 448 | vnet_hdr_len = sizeof(vnet_hdr); | 450 | vnet_hdr_len = q->vnet_hdr_sz; |
| 449 | 451 | ||
| 450 | err = -EINVAL; | 452 | err = -EINVAL; |
| 451 | if ((len -= vnet_hdr_len) < 0) | 453 | if ((len -= vnet_hdr_len) < 0) |
| 452 | goto err; | 454 | goto err; |
| 453 | 455 | ||
| 454 | err = memcpy_fromiovecend((void *)&vnet_hdr, iv, 0, | 456 | err = memcpy_fromiovecend((void *)&vnet_hdr, iv, 0, |
| 455 | vnet_hdr_len); | 457 | sizeof(vnet_hdr)); |
| 456 | if (err < 0) | 458 | if (err < 0) |
| 457 | goto err; | 459 | goto err; |
| 458 | if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && | 460 | if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && |
| @@ -534,7 +536,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, | |||
| 534 | 536 | ||
| 535 | if (q->flags & IFF_VNET_HDR) { | 537 | if (q->flags & IFF_VNET_HDR) { |
| 536 | struct virtio_net_hdr vnet_hdr; | 538 | struct virtio_net_hdr vnet_hdr; |
| 537 | vnet_hdr_len = sizeof (vnet_hdr); | 539 | vnet_hdr_len = q->vnet_hdr_sz; |
| 538 | if ((len -= vnet_hdr_len) < 0) | 540 | if ((len -= vnet_hdr_len) < 0) |
| 539 | return -EINVAL; | 541 | return -EINVAL; |
| 540 | 542 | ||
| @@ -542,7 +544,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, | |||
| 542 | if (ret) | 544 | if (ret) |
| 543 | return ret; | 545 | return ret; |
| 544 | 546 | ||
| 545 | if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, vnet_hdr_len)) | 547 | if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, sizeof(vnet_hdr))) |
| 546 | return -EFAULT; | 548 | return -EFAULT; |
| 547 | } | 549 | } |
| 548 | 550 | ||
| @@ -627,6 +629,8 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, | |||
| 627 | struct ifreq __user *ifr = argp; | 629 | struct ifreq __user *ifr = argp; |
| 628 | unsigned int __user *up = argp; | 630 | unsigned int __user *up = argp; |
| 629 | unsigned int u; | 631 | unsigned int u; |
| 632 | int __user *sp = argp; | ||
| 633 | int s; | ||
| 630 | int ret; | 634 | int ret; |
| 631 | 635 | ||
| 632 | switch (cmd) { | 636 | switch (cmd) { |
| @@ -672,6 +676,21 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, | |||
| 672 | q->sk.sk_sndbuf = u; | 676 | q->sk.sk_sndbuf = u; |
| 673 | return 0; | 677 | return 0; |
| 674 | 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 | |||
| 675 | case TUNSETOFFLOAD: | 694 | case TUNSETOFFLOAD: |
| 676 | /* let the user check for future flags */ | 695 | /* let the user check for future flags */ |
| 677 | if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | | 696 | if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | |
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index e525a6cf5587..6b150c072a41 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
| @@ -110,6 +110,9 @@ struct tun_struct { | |||
| 110 | struct tap_filter txflt; | 110 | struct tap_filter txflt; |
| 111 | struct socket socket; | 111 | struct socket socket; |
| 112 | struct socket_wq wq; | 112 | struct socket_wq wq; |
| 113 | |||
| 114 | int vnet_hdr_sz; | ||
| 115 | |||
| 113 | #ifdef TUN_DEBUG | 116 | #ifdef TUN_DEBUG |
| 114 | int debug; | 117 | int debug; |
| 115 | #endif | 118 | #endif |
| @@ -563,7 +566,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, | |||
| 563 | } | 566 | } |
| 564 | 567 | ||
| 565 | if (tun->flags & TUN_VNET_HDR) { | 568 | if (tun->flags & TUN_VNET_HDR) { |
| 566 | if ((len -= sizeof(gso)) > count) | 569 | if ((len -= tun->vnet_hdr_sz) > count) |
| 567 | return -EINVAL; | 570 | return -EINVAL; |
| 568 | 571 | ||
| 569 | if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso))) | 572 | if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso))) |
| @@ -575,7 +578,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, | |||
| 575 | 578 | ||
| 576 | if (gso.hdr_len > len) | 579 | if (gso.hdr_len > len) |
| 577 | return -EINVAL; | 580 | return -EINVAL; |
| 578 | offset += sizeof(gso); | 581 | offset += tun->vnet_hdr_sz; |
| 579 | } | 582 | } |
| 580 | 583 | ||
| 581 | if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { | 584 | if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { |
| @@ -718,7 +721,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, | |||
| 718 | 721 | ||
| 719 | if (tun->flags & TUN_VNET_HDR) { | 722 | if (tun->flags & TUN_VNET_HDR) { |
| 720 | struct virtio_net_hdr gso = { 0 }; /* no info leak */ | 723 | struct virtio_net_hdr gso = { 0 }; /* no info leak */ |
| 721 | if ((len -= sizeof(gso)) < 0) | 724 | if ((len -= tun->vnet_hdr_sz) < 0) |
| 722 | return -EINVAL; | 725 | return -EINVAL; |
| 723 | 726 | ||
| 724 | if (skb_is_gso(skb)) { | 727 | if (skb_is_gso(skb)) { |
| @@ -749,7 +752,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, | |||
| 749 | if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, | 752 | if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, |
| 750 | sizeof(gso)))) | 753 | sizeof(gso)))) |
| 751 | return -EFAULT; | 754 | return -EFAULT; |
| 752 | total += sizeof(gso); | 755 | total += tun->vnet_hdr_sz; |
| 753 | } | 756 | } |
| 754 | 757 | ||
| 755 | len = min_t(int, skb->len, len); | 758 | len = min_t(int, skb->len, len); |
| @@ -1035,6 +1038,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
| 1035 | tun->dev = dev; | 1038 | tun->dev = dev; |
| 1036 | tun->flags = flags; | 1039 | tun->flags = flags; |
| 1037 | tun->txflt.count = 0; | 1040 | tun->txflt.count = 0; |
| 1041 | tun->vnet_hdr_sz = sizeof(struct virtio_net_hdr); | ||
| 1038 | 1042 | ||
| 1039 | err = -ENOMEM; | 1043 | err = -ENOMEM; |
| 1040 | sk = sk_alloc(net, AF_UNSPEC, GFP_KERNEL, &tun_proto); | 1044 | sk = sk_alloc(net, AF_UNSPEC, GFP_KERNEL, &tun_proto); |
| @@ -1177,6 +1181,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
| 1177 | struct sock_fprog fprog; | 1181 | struct sock_fprog fprog; |
| 1178 | struct ifreq ifr; | 1182 | struct ifreq ifr; |
| 1179 | int sndbuf; | 1183 | int sndbuf; |
| 1184 | int vnet_hdr_sz; | ||
| 1180 | int ret; | 1185 | int ret; |
| 1181 | 1186 | ||
| 1182 | if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) | 1187 | if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) |
| @@ -1322,6 +1327,25 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
| 1322 | tun->socket.sk->sk_sndbuf = sndbuf; | 1327 | tun->socket.sk->sk_sndbuf = sndbuf; |
| 1323 | break; | 1328 | break; |
| 1324 | 1329 | ||
| 1330 | case TUNGETVNETHDRSZ: | ||
| 1331 | vnet_hdr_sz = tun->vnet_hdr_sz; | ||
| 1332 | if (copy_to_user(argp, &vnet_hdr_sz, sizeof(vnet_hdr_sz))) | ||
| 1333 | ret = -EFAULT; | ||
| 1334 | break; | ||
| 1335 | |||
| 1336 | case TUNSETVNETHDRSZ: | ||
| 1337 | if (copy_from_user(&vnet_hdr_sz, argp, sizeof(vnet_hdr_sz))) { | ||
| 1338 | ret = -EFAULT; | ||
| 1339 | break; | ||
| 1340 | } | ||
| 1341 | if (vnet_hdr_sz < (int)sizeof(struct virtio_net_hdr)) { | ||
| 1342 | ret = -EINVAL; | ||
| 1343 | break; | ||
| 1344 | } | ||
| 1345 | |||
| 1346 | tun->vnet_hdr_sz = vnet_hdr_sz; | ||
| 1347 | break; | ||
| 1348 | |||
| 1325 | case TUNATTACHFILTER: | 1349 | case TUNATTACHFILTER: |
| 1326 | /* Can be set only for TAPs */ | 1350 | /* Can be set only for TAPs */ |
| 1327 | ret = -EINVAL; | 1351 | ret = -EINVAL; |
