diff options
Diffstat (limited to 'drivers/net/tun.c')
| -rw-r--r-- | drivers/net/tun.c | 140 |
1 files changed, 132 insertions, 8 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 4884802e0af1..5eadb7a1ad7b 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
| @@ -71,6 +71,7 @@ | |||
| 71 | #include <net/sock.h> | 71 | #include <net/sock.h> |
| 72 | #include <linux/seq_file.h> | 72 | #include <linux/seq_file.h> |
| 73 | #include <linux/uio.h> | 73 | #include <linux/uio.h> |
| 74 | #include <linux/skb_array.h> | ||
| 74 | 75 | ||
| 75 | #include <asm/uaccess.h> | 76 | #include <asm/uaccess.h> |
| 76 | 77 | ||
| @@ -167,6 +168,7 @@ struct tun_file { | |||
| 167 | }; | 168 | }; |
| 168 | struct list_head next; | 169 | struct list_head next; |
| 169 | struct tun_struct *detached; | 170 | struct tun_struct *detached; |
| 171 | struct skb_array tx_array; | ||
| 170 | }; | 172 | }; |
| 171 | 173 | ||
| 172 | struct tun_flow_entry { | 174 | struct tun_flow_entry { |
| @@ -515,7 +517,11 @@ static struct tun_struct *tun_enable_queue(struct tun_file *tfile) | |||
| 515 | 517 | ||
| 516 | static void tun_queue_purge(struct tun_file *tfile) | 518 | static void tun_queue_purge(struct tun_file *tfile) |
| 517 | { | 519 | { |
| 518 | skb_queue_purge(&tfile->sk.sk_receive_queue); | 520 | struct sk_buff *skb; |
| 521 | |||
| 522 | while ((skb = skb_array_consume(&tfile->tx_array)) != NULL) | ||
| 523 | kfree_skb(skb); | ||
| 524 | |||
| 519 | skb_queue_purge(&tfile->sk.sk_error_queue); | 525 | skb_queue_purge(&tfile->sk.sk_error_queue); |
| 520 | } | 526 | } |
| 521 | 527 | ||
| @@ -560,6 +566,8 @@ static void __tun_detach(struct tun_file *tfile, bool clean) | |||
| 560 | tun->dev->reg_state == NETREG_REGISTERED) | 566 | tun->dev->reg_state == NETREG_REGISTERED) |
| 561 | unregister_netdevice(tun->dev); | 567 | unregister_netdevice(tun->dev); |
| 562 | } | 568 | } |
| 569 | if (tun) | ||
| 570 | skb_array_cleanup(&tfile->tx_array); | ||
| 563 | sock_put(&tfile->sk); | 571 | sock_put(&tfile->sk); |
| 564 | } | 572 | } |
| 565 | } | 573 | } |
| @@ -613,6 +621,7 @@ static void tun_detach_all(struct net_device *dev) | |||
| 613 | static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filter) | 621 | static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filter) |
| 614 | { | 622 | { |
| 615 | struct tun_file *tfile = file->private_data; | 623 | struct tun_file *tfile = file->private_data; |
| 624 | struct net_device *dev = tun->dev; | ||
| 616 | int err; | 625 | int err; |
| 617 | 626 | ||
| 618 | err = security_tun_dev_attach(tfile->socket.sk, tun->security); | 627 | err = security_tun_dev_attach(tfile->socket.sk, tun->security); |
| @@ -642,6 +651,13 @@ static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filte | |||
| 642 | if (!err) | 651 | if (!err) |
| 643 | goto out; | 652 | goto out; |
| 644 | } | 653 | } |
| 654 | |||
| 655 | if (!tfile->detached && | ||
| 656 | skb_array_init(&tfile->tx_array, dev->tx_queue_len, GFP_KERNEL)) { | ||
| 657 | err = -ENOMEM; | ||
| 658 | goto out; | ||
| 659 | } | ||
| 660 | |||
| 645 | tfile->queue_index = tun->numqueues; | 661 | tfile->queue_index = tun->numqueues; |
| 646 | tfile->socket.sk->sk_shutdown &= ~RCV_SHUTDOWN; | 662 | tfile->socket.sk->sk_shutdown &= ~RCV_SHUTDOWN; |
| 647 | rcu_assign_pointer(tfile->tun, tun); | 663 | rcu_assign_pointer(tfile->tun, tun); |
| @@ -891,8 +907,8 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 891 | 907 | ||
| 892 | nf_reset(skb); | 908 | nf_reset(skb); |
| 893 | 909 | ||
| 894 | /* Enqueue packet */ | 910 | if (skb_array_produce(&tfile->tx_array, skb)) |
| 895 | skb_queue_tail(&tfile->socket.sk->sk_receive_queue, skb); | 911 | goto drop; |
| 896 | 912 | ||
| 897 | /* Notify and wake up reader process */ | 913 | /* Notify and wake up reader process */ |
| 898 | if (tfile->flags & TUN_FASYNC) | 914 | if (tfile->flags & TUN_FASYNC) |
| @@ -1107,7 +1123,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table *wait) | |||
| 1107 | 1123 | ||
| 1108 | poll_wait(file, sk_sleep(sk), wait); | 1124 | poll_wait(file, sk_sleep(sk), wait); |
| 1109 | 1125 | ||
| 1110 | if (!skb_queue_empty(&sk->sk_receive_queue)) | 1126 | if (!skb_array_empty(&tfile->tx_array)) |
| 1111 | mask |= POLLIN | POLLRDNORM; | 1127 | mask |= POLLIN | POLLRDNORM; |
| 1112 | 1128 | ||
| 1113 | if (sock_writeable(sk) || | 1129 | if (sock_writeable(sk) || |
| @@ -1426,22 +1442,63 @@ done: | |||
| 1426 | return total; | 1442 | return total; |
| 1427 | } | 1443 | } |
| 1428 | 1444 | ||
| 1445 | static struct sk_buff *tun_ring_recv(struct tun_file *tfile, int noblock, | ||
| 1446 | int *err) | ||
| 1447 | { | ||
| 1448 | DECLARE_WAITQUEUE(wait, current); | ||
| 1449 | struct sk_buff *skb = NULL; | ||
| 1450 | int error = 0; | ||
| 1451 | |||
| 1452 | skb = skb_array_consume(&tfile->tx_array); | ||
| 1453 | if (skb) | ||
| 1454 | goto out; | ||
| 1455 | if (noblock) { | ||
| 1456 | error = -EAGAIN; | ||
| 1457 | goto out; | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | add_wait_queue(&tfile->wq.wait, &wait); | ||
| 1461 | current->state = TASK_INTERRUPTIBLE; | ||
| 1462 | |||
| 1463 | while (1) { | ||
| 1464 | skb = skb_array_consume(&tfile->tx_array); | ||
| 1465 | if (skb) | ||
| 1466 | break; | ||
| 1467 | if (signal_pending(current)) { | ||
| 1468 | error = -ERESTARTSYS; | ||
| 1469 | break; | ||
| 1470 | } | ||
| 1471 | if (tfile->socket.sk->sk_shutdown & RCV_SHUTDOWN) { | ||
| 1472 | error = -EFAULT; | ||
| 1473 | break; | ||
| 1474 | } | ||
| 1475 | |||
| 1476 | schedule(); | ||
| 1477 | } | ||
| 1478 | |||
| 1479 | current->state = TASK_RUNNING; | ||
| 1480 | remove_wait_queue(&tfile->wq.wait, &wait); | ||
| 1481 | |||
| 1482 | out: | ||
| 1483 | *err = error; | ||
| 1484 | return skb; | ||
| 1485 | } | ||
| 1486 | |||
| 1429 | static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, | 1487 | static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, |
| 1430 | struct iov_iter *to, | 1488 | struct iov_iter *to, |
| 1431 | int noblock) | 1489 | int noblock) |
| 1432 | { | 1490 | { |
| 1433 | struct sk_buff *skb; | 1491 | struct sk_buff *skb; |
| 1434 | ssize_t ret; | 1492 | ssize_t ret; |
| 1435 | int peeked, err, off = 0; | 1493 | int err; |
| 1436 | 1494 | ||
| 1437 | tun_debug(KERN_INFO, tun, "tun_do_read\n"); | 1495 | tun_debug(KERN_INFO, tun, "tun_do_read\n"); |
| 1438 | 1496 | ||
| 1439 | if (!iov_iter_count(to)) | 1497 | if (!iov_iter_count(to)) |
| 1440 | return 0; | 1498 | return 0; |
| 1441 | 1499 | ||
| 1442 | /* Read frames from queue */ | 1500 | /* Read frames from ring */ |
| 1443 | skb = __skb_recv_datagram(tfile->socket.sk, noblock ? MSG_DONTWAIT : 0, | 1501 | skb = tun_ring_recv(tfile, noblock, &err); |
| 1444 | &peeked, &off, &err); | ||
| 1445 | if (!skb) | 1502 | if (!skb) |
| 1446 | return err; | 1503 | return err; |
| 1447 | 1504 | ||
| @@ -1574,8 +1631,25 @@ out: | |||
| 1574 | return ret; | 1631 | return ret; |
| 1575 | } | 1632 | } |
| 1576 | 1633 | ||
| 1634 | static int tun_peek_len(struct socket *sock) | ||
| 1635 | { | ||
| 1636 | struct tun_file *tfile = container_of(sock, struct tun_file, socket); | ||
| 1637 | struct tun_struct *tun; | ||
| 1638 | int ret = 0; | ||
| 1639 | |||
| 1640 | tun = __tun_get(tfile); | ||
| 1641 | if (!tun) | ||
| 1642 | return 0; | ||
| 1643 | |||
| 1644 | ret = skb_array_peek_len(&tfile->tx_array); | ||
| 1645 | tun_put(tun); | ||
| 1646 | |||
| 1647 | return ret; | ||
| 1648 | } | ||
| 1649 | |||
| 1577 | /* Ops structure to mimic raw sockets with tun */ | 1650 | /* Ops structure to mimic raw sockets with tun */ |
| 1578 | static const struct proto_ops tun_socket_ops = { | 1651 | static const struct proto_ops tun_socket_ops = { |
| 1652 | .peek_len = tun_peek_len, | ||
| 1579 | .sendmsg = tun_sendmsg, | 1653 | .sendmsg = tun_sendmsg, |
| 1580 | .recvmsg = tun_recvmsg, | 1654 | .recvmsg = tun_recvmsg, |
| 1581 | }; | 1655 | }; |
| @@ -2397,6 +2471,53 @@ static const struct ethtool_ops tun_ethtool_ops = { | |||
| 2397 | .get_ts_info = ethtool_op_get_ts_info, | 2471 | .get_ts_info = ethtool_op_get_ts_info, |
| 2398 | }; | 2472 | }; |
| 2399 | 2473 | ||
| 2474 | static int tun_queue_resize(struct tun_struct *tun) | ||
| 2475 | { | ||
| 2476 | struct net_device *dev = tun->dev; | ||
| 2477 | struct tun_file *tfile; | ||
| 2478 | struct skb_array **arrays; | ||
| 2479 | int n = tun->numqueues + tun->numdisabled; | ||
| 2480 | int ret, i; | ||
| 2481 | |||
| 2482 | arrays = kmalloc(sizeof *arrays * n, GFP_KERNEL); | ||
| 2483 | if (!arrays) | ||
| 2484 | return -ENOMEM; | ||
| 2485 | |||
| 2486 | for (i = 0; i < tun->numqueues; i++) { | ||
| 2487 | tfile = rtnl_dereference(tun->tfiles[i]); | ||
| 2488 | arrays[i] = &tfile->tx_array; | ||
| 2489 | } | ||
| 2490 | list_for_each_entry(tfile, &tun->disabled, next) | ||
| 2491 | arrays[i++] = &tfile->tx_array; | ||
| 2492 | |||
| 2493 | ret = skb_array_resize_multiple(arrays, n, | ||
| 2494 | dev->tx_queue_len, GFP_KERNEL); | ||
| 2495 | |||
| 2496 | kfree(arrays); | ||
| 2497 | return ret; | ||
| 2498 | } | ||
| 2499 | |||
| 2500 | static int tun_device_event(struct notifier_block *unused, | ||
| 2501 | unsigned long event, void *ptr) | ||
| 2502 | { | ||
| 2503 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | ||
| 2504 | struct tun_struct *tun = netdev_priv(dev); | ||
| 2505 | |||
| 2506 | switch (event) { | ||
| 2507 | case NETDEV_CHANGE_TX_QUEUE_LEN: | ||
| 2508 | if (tun_queue_resize(tun)) | ||
| 2509 | return NOTIFY_BAD; | ||
| 2510 | break; | ||
| 2511 | default: | ||
| 2512 | break; | ||
| 2513 | } | ||
| 2514 | |||
| 2515 | return NOTIFY_DONE; | ||
| 2516 | } | ||
| 2517 | |||
| 2518 | static struct notifier_block tun_notifier_block __read_mostly = { | ||
| 2519 | .notifier_call = tun_device_event, | ||
| 2520 | }; | ||
| 2400 | 2521 | ||
| 2401 | static int __init tun_init(void) | 2522 | static int __init tun_init(void) |
| 2402 | { | 2523 | { |
| @@ -2416,6 +2537,8 @@ static int __init tun_init(void) | |||
| 2416 | pr_err("Can't register misc device %d\n", TUN_MINOR); | 2537 | pr_err("Can't register misc device %d\n", TUN_MINOR); |
| 2417 | goto err_misc; | 2538 | goto err_misc; |
| 2418 | } | 2539 | } |
| 2540 | |||
| 2541 | register_netdevice_notifier(&tun_notifier_block); | ||
| 2419 | return 0; | 2542 | return 0; |
| 2420 | err_misc: | 2543 | err_misc: |
| 2421 | rtnl_link_unregister(&tun_link_ops); | 2544 | rtnl_link_unregister(&tun_link_ops); |
| @@ -2427,6 +2550,7 @@ static void tun_cleanup(void) | |||
| 2427 | { | 2550 | { |
| 2428 | misc_deregister(&tun_miscdev); | 2551 | misc_deregister(&tun_miscdev); |
| 2429 | rtnl_link_unregister(&tun_link_ops); | 2552 | rtnl_link_unregister(&tun_link_ops); |
| 2553 | unregister_netdevice_notifier(&tun_notifier_block); | ||
| 2430 | } | 2554 | } |
| 2431 | 2555 | ||
| 2432 | /* Get an underlying socket object from tun file. Returns error unless file is | 2556 | /* Get an underlying socket object from tun file. Returns error unless file is |
