/* * TUN - Universal TUN/TAP device driver. * Copyright (C) 1999-2002 Maxim Krasnyansky <maxk@qualcomm.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * $Id: tun.c,v 1.15 2002/03/01 02:44:24 maxk Exp $ */ /* * Changes: * * Mike Kershaw <dragorn@kismetwireless.net> 2005/08/14 * Add TUNSETLINK ioctl to set the link encapsulation * * Mark Smith <markzzzsmith@yahoo.com.au> * Use random_ether_addr() for tap MAC address. * * Harald Roelle <harald.roelle@ifi.lmu.de> 2004/04/20 * Fixes in packet dropping, queue length setting and queue wakeup. * Increased default tx queue length. * Added ethtool API. * Minor cleanups * * Daniel Podlejski <underley@underley.eu.org> * Modifications for 2.3.99-pre5 kernel. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define DRV_NAME "tun"#define DRV_VERSION "1.6"#define DRV_DESCRIPTION "Universal TUN/TAP device driver"#define DRV_COPYRIGHT "(C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>" #include <linux/module.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/slab.h>#include <linux/poll.h>#include <linux/fcntl.h>#include <linux/init.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/miscdevice.h>#include <linux/ethtool.h>#include <linux/rtnetlink.h>#include <linux/compat.h>#include <linux/if.h>#include <linux/if_arp.h>#include <linux/if_ether.h>#include <linux/if_tun.h>#include <linux/crc32.h>#include <linux/nsproxy.h>#include <linux/virtio_net.h>#include <linux/rcupdate.h>#include <net/net_namespace.h>#include <net/netns/generic.h>#include <net/rtnetlink.h>#include <net/sock.h> #include <asm/uaccess.h> /* Uncomment to enable debugging *//* #define TUN_DEBUG 1 */ #ifdef TUN_DEBUGstatic int debug; #define tun_debug(level, tun, fmt, args...) \do { \ if (tun->debug) \ netdev_printk(level, tun->dev, fmt, ##args); \} while (0)#define DBG1(level, fmt, args...) \do { \ if (debug == 2) \ printk(level fmt, ##args); \} while (0)#else#define tun_debug(level, tun, fmt, args...) \do { \ if (0) \ netdev_printk(level, tun->dev, fmt, ##args); \} while (0)#define DBG1(level, fmt, args...) \do { \ if (0) \ printk(level fmt, ##args); \} while (0)#endif #define FLT_EXACT_COUNT 8struct tap_filter { unsigned int count; /* Number of addrs. Zero means disabled */ u32 mask[2]; /* Mask of the hashed addrs */ unsigned char addr[FLT_EXACT_COUNT][ETH_ALEN];}; struct tun_file { atomic_t count; struct tun_struct *tun; struct net *net;}; struct tun_sock; struct tun_struct { struct tun_file *tfile; unsigned int flags; uid_t owner; gid_t group; struct net_device *dev; netdev_features_t set_features;#define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \ NETIF_F_TSO6|NETIF_F_UFO) struct fasync_struct *fasync; struct tap_filter txflt; struct socket socket; struct socket_wq wq; int vnet_hdr_sz; #ifdef TUN_DEBUG int debug;#endif}; struct tun_sock { struct sock sk; struct tun_struct *tun;}; static inline struct tun_sock *tun_sk(struct sock *sk){ return container_of(sk, struct tun_sock, sk);} static int tun_attach(struct tun_struct *tun, struct file *file){ struct tun_file *tfile = file->private_data; int err; ASSERT_RTNL(); netif_tx_lock_bh(tun->dev); err = -EINVAL; if (tfile->tun) goto out; err = -EBUSY; if (tun->tfile) goto out; err = 0; tfile->tun = tun; tun->tfile = tfile; tun->socket.file = file; netif_carrier_on(tun->dev); dev_hold(tun->dev); sock_hold(tun->socket.sk); atomic_inc(&tfile->count); out: netif_tx_unlock_bh(tun->dev); return err;} static void __tun_detach(struct tun_struct *tun){ /* Detach from net device */ netif_tx_lock_bh(tun->dev); netif_carrier_off(tun->dev); tun->tfile = NULL; tun->socket.file = NULL; netif_tx_unlock_bh(tun->dev); /* Drop read queue */ skb_queue_purge(&tun->socket.sk->sk_receive_queue); /* Drop the extra count on the net device */ dev_put(tun->dev);} static void tun_detach(struct tun_struct *tun){ rtnl_lock(); __tun_detach(tun); rtnl_unlock();} static struct tun_struct *__tun_get(struct tun_file *tfile){ struct tun_struct *tun = NULL; if (atomic_inc_not_zero(&tfile->count)) tun = tfile->tun; return tun;} static struct tun_struct *tun_get(struct file *file){ return __tun_get(file->private_data);} static void tun_put(struct tun_struct *tun){ struct tun_file *tfile = tun->tfile; if (atomic_dec_and_test(&tfile->count)) tun_detach(tfile->tun);} /* TAP filtering */static void addr_hash_set(u32 *mask, const u8 *addr){ int n = ether_crc(ETH_ALEN, addr) >> 26; mask[n >> 5] |= (1 << (n & 31));} static unsigned int addr_hash_test(const u32 *mask, const u8 *addr){ int n = ether_crc(ETH_ALEN, addr) >> 26; return mask[n >> 5] & (1 << (n & 31));} static int update_filter(struct tap_filter *filter, void __user *arg){ struct { u8 u[ETH_ALEN]; } *addr; struct tun_filter uf; int err, alen, n, nexact; if (copy_from_user(&uf, arg, sizeof(uf))) return -EFAULT; if (!uf.count) { /* Disabled */ filter->count = 0; return 0; } alen = ETH_ALEN * uf.count; addr = kmalloc(alen, GFP_KERNEL); if (!addr) return -ENOMEM; if (copy_from_user(addr, arg + sizeof(uf), alen)) { err = -EFAULT; goto done; } /* The filter is updated without holding any locks. Which is * perfectly safe. We disable it first and in the worst * case we'll accept a few undesired packets. */ filter->count = 0; wmb(); /* Use first set of addresses as an exact filter */ for (n = 0; n < uf.count && n < FLT_EXACT_COUNT; n++) memcpy(filter->addr[n], addr[n].u, ETH_ALEN); nexact = n; /* Remaining multicast addresses are hashed, * unicast will leave the filter disabled. */ memset(filter->mask, 0, sizeof(filter->mask)); for (; n < uf.count; n++) { if (!is_multicast_ether_addr(addr[n].u)) { err = 0; /* no filter */ goto done; } addr_hash_set(filter->mask, addr[n].u); } /* For ALLMULTI just set the mask to all ones. * This overrides the mask populated above. */ if ((uf.flags & TUN_FLT_ALLMULTI)) memset(filter->mask, ~0, sizeof(filter->mask)); /* Now enable the filter */ wmb(); filter->count = nexact; /* Return the number of exact filters */ err = nexact; done: kfree(addr); return err;} /* Returns: 0 - drop, !=0 - accept */static int run_filter(struct tap_filter *filter, const struct sk_buff *skb){ /* Cannot use eth_hdr(skb) here because skb_mac_hdr() is incorrect * at this point. */ struct ethhdr *eh = (struct ethhdr *) skb->data; int i; /* Exact match */ for (i = 0; i < filter->count; i++) if (ether_addr_equal(eh->h_dest, filter->addr[i])) return 1; /* Inexact match (multicast only) */ if (is_multicast_ether_addr(eh->h_dest)) return addr_hash_test(filter->mask, eh->h_dest); return 0;} /* * Checks whether the packet is accepted or not. * Returns: 0 - drop, !=0 - accept */static int check_filter(struct tap_filter *filter, const struct sk_buff *skb){ if (!filter->count) return 1; return run_filter(filter, skb);} /* Network device part of the driver */ static const struct ethtool_ops tun_ethtool_ops; /* Net device detach from fd. */static void tun_net_uninit(struct net_device *dev){ struct tun_struct *tun = netdev_priv(dev); struct tun_file *tfile = tun->tfile; /* Inform the methods they need to stop using the dev. */ if (tfile) { wake_up_all(&tun->wq.wait); if (atomic_dec_and_test(&tfile->count)) __tun_detach(tun); }} static void tun_free_netdev(struct net_device *dev){ struct tun_struct *tun = netdev_priv(dev); sk_release_kernel(tun->socket.sk);} /* Net device open. */static int tun_net_open(struct net_device *dev){ netif_start_queue(dev); return 0;} /* Net device close. */static int tun_net_close(struct net_device *dev){ netif_stop_queue(dev); return 0;} /* Net device start xmit */static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev){ struct tun_struct *tun = netdev_priv(dev); tun_debug(KERN_INFO, tun, "tun_net_xmit %d\n", skb->len); /* Drop packet if interface is not attached */ if (!tun->tfile) goto drop; /* Drop if the filter does not like it. * This is a noop if the filter is disabled. * Filter can be enabled only for the TAP devices. */ if (!check_filter(&tun->txflt, skb)) goto drop; if (tun->socket.sk->sk_filter && sk_filter(tun->socket.sk, skb)) goto drop; if (skb_queue_len(&tun->socket.sk->sk_receive_queue) >= dev->tx_queue_len) { if (!(tun->flags & TUN_ONE_QUEUE)) { /* Normal queueing mode. */ /* Packet scheduler handles dropping of further packets. */ netif_stop_queue(dev); /* We won't see all dropped packets individually, so overrun * error is more appropriate. */ dev->stats.tx_fifo_errors++; } else { /* Single queue mode. * Driver handles dropping of all packets itself. */ goto drop; } } /* Orphan the skb - required as we might hang on to it * for indefinite time. */ skb_orphan(skb); /* Enqueue packet */ skb_queue_tail(&tun->socket.sk->sk_receive_queue, skb); /* Notify and wake up reader process */ if (tun->flags & TUN_FASYNC) kill_fasync(&tun->fasync, SIGIO, POLL_IN); wake_up_interruptible_poll(&tun->wq.wait, POLLIN | POLLRDNORM | POLLRDBAND); return NETDEV_TX_OK; drop: dev->stats.tx_dropped++; kfree_skb(skb); return NETDEV_TX_OK;} static void tun_net_mclist(struct net_device *dev){ /* * This callback is supposed to deal with mc filter in * _rx_ path and has nothing to do with the _tx_ path. * In rx path we always accept everything userspace gives us. */} #define MIN_MTU 68#define MAX_MTU 65535 static inttun_net_change_mtu(struct net_device *dev, int new_mtu){ if (new_mtu < MIN_MTU || new_mtu + dev->hard_header_len > MAX_MTU) return -EINVAL; dev->mtu = new_mtu; return 0;} static netdev_features_t tun_net_fix_features(struct net_device *dev, netdev_features_t features){ struct tun_struct *tun = netdev_priv(dev); return (features & tun->set_features) | (features & ~TUN_USER_FEATURES);}#ifdef CONFIG_NET_POLL_CONTROLLERstatic void tun_poll_controller(struct net_device *dev){ /* * Tun only receives frames when: * 1) the char device endpoint gets data from user space * 2) the tun socket gets a sendmsg call from user space * Since both of those are syncronous operations, we are guaranteed * never to have pending data when we poll for it * so theres nothing to do here but return. * We need this though so netpoll recognizes us as an interface that * supports polling, which enables bridge devices in virt setups to * still use netconsole */ return;}#endifstatic const struct net_device_ops tun_netdev_ops = { .ndo_uninit = tun_net_uninit, .ndo_open = tun_net_open, .ndo_stop = tun_net_close, .ndo_start_xmit = tun_net_xmit, .ndo_change_mtu = tun_net_change_mtu, .ndo_fix_features = tun_net_fix_features,#ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = tun_poll_controller,#endif}; static const struct net_device_ops tap_netdev_ops = { .ndo_uninit = tun_net_uninit, .ndo_open = tun_net_open, .ndo_stop = tun_net_close, .ndo_start_xmit = tun_net_xmit, .ndo_change_mtu = tun_net_change_mtu, .ndo_fix_features = tun_net_fix_features, .ndo_set_rx_mode = tun_net_mclist, .ndo_set_mac_address = eth_mac_addr,Lines 1–500 of 1695. Load more
/* * TUN - Universal TUN/TAP device driver. * Copyright (C) 1999-2002 Maxim Krasnyansky <maxk@qualcomm.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * $Id: tun.c,v 1.15 2002/03/01 02:44:24 maxk Exp $ */ /* * Changes: * * Mike Kershaw <dragorn@kismetwireless.net> 2005/08/14 * Add TUNSETLINK ioctl to set the link encapsulation * * Mark Smith <markzzzsmith@yahoo.com.au> * Use random_ether_addr() for tap MAC address. * * Harald Roelle <harald.roelle@ifi.lmu.de> 2004/04/20 * Fixes in packet dropping, queue length setting and queue wakeup. * Increased default tx queue length. * Added ethtool API. * Minor cleanups * * Daniel Podlejski <underley@underley.eu.org> * Modifications for 2.3.99-pre5 kernel. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define DRV_NAME "tun" #define DRV_VERSION "1.6" #define DRV_DESCRIPTION "Universal TUN/TAP device driver" #define DRV_COPYRIGHT "(C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>" #include <linux/module.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/slab.h> #include <linux/poll.h> #include <linux/fcntl.h> #include <linux/init.h> #include <linux/skbuff.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/miscdevice.h> #include <linux/ethtool.h> #include <linux/rtnetlink.h> #include <linux/compat.h> #include <linux/if.h> #include <linux/if_arp.h> #include <linux/if_ether.h> #include <linux/if_tun.h> #include <linux/crc32.h> #include <linux/nsproxy.h> #include <linux/virtio_net.h> #include <linux/rcupdate.h> #include <net/net_namespace.h> #include <net/netns/generic.h> #include <net/rtnetlink.h> #include <net/sock.h> #include <asm/uaccess.h> /* Uncomment to enable debugging */ /* #define TUN_DEBUG 1 */ #ifdef TUN_DEBUG static int debug; #define tun_debug(level, tun, fmt, args...) \ do { \ if (tun->debug) \ netdev_printk(level, tun->dev, fmt, ##args); \ } while (0) #define DBG1(level, fmt, args...) \ do { \ if (debug == 2) \ printk(level fmt, ##args); \ } while (0) #else #define tun_debug(level, tun, fmt, args...) \ do { \ if (0) \ netdev_printk(level, tun->dev, fmt, ##args); \ } while (0) #define DBG1(level, fmt, args...) \ do { \ if (0) \ printk(level fmt, ##args); \ } while (0) #endif #define FLT_EXACT_COUNT 8 struct tap_filter { unsigned int count; /* Number of addrs. Zero means disabled */ u32 mask[2]; /* Mask of the hashed addrs */ unsigned char addr[FLT_EXACT_COUNT][ETH_ALEN]; }; struct tun_file { atomic_t count; struct tun_struct *tun; struct net *net; }; struct tun_sock; struct tun_struct { struct tun_file *tfile; unsigned int flags; uid_t owner; gid_t group; struct net_device *dev; netdev_features_t set_features; #define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \ NETIF_F_TSO6|NETIF_F_UFO) struct fasync_struct *fasync; struct tap_filter txflt; struct socket socket; struct socket_wq wq; int vnet_hdr_sz; #ifdef TUN_DEBUG int debug; #endif }; struct tun_sock { struct sock sk; struct tun_struct *tun; }; static inline struct tun_sock *tun_sk(struct sock *sk) { return container_of(sk, struct tun_sock, sk); } static int tun_attach(struct tun_struct *tun, struct file *file) { struct tun_file *tfile = file->private_data; int err; ASSERT_RTNL(); netif_tx_lock_bh(tun->dev); err = -EINVAL; if (tfile->tun) goto out; err = -EBUSY; if (tun->tfile) goto out; err = 0; tfile->tun = tun; tun->tfile = tfile; tun->socket.file = file; netif_carrier_on(tun->dev); dev_hold(tun->dev); sock_hold(tun->socket.sk); atomic_inc(&tfile->count); out: netif_tx_unlock_bh(tun->dev); return err; } static void __tun_detach(struct tun_struct *tun) { /* Detach from net device */ netif_tx_lock_bh(tun->dev); netif_carrier_off(tun->dev); tun->tfile = NULL; tun->socket.file = NULL; netif_tx_unlock_bh(tun->dev); /* Drop read queue */ skb_queue_purge(&tun->socket.sk->sk_receive_queue); /* Drop the extra count on the net device */ dev_put(tun->dev); } static void tun_detach(struct tun_struct *tun) { rtnl_lock(); __tun_detach(tun); rtnl_unlock(); } static struct tun_struct *__tun_get(struct tun_file *tfile) { struct tun_struct *tun = NULL; if (atomic_inc_not_zero(&tfile->count)) tun = tfile->tun; return tun; } static struct tun_struct *tun_get(struct file *file) { return __tun_get(file->private_data); } static void tun_put(struct tun_struct *tun) { struct tun_file *tfile = tun->tfile; if (atomic_dec_and_test(&tfile->count)) tun_detach(tfile->tun); } /* TAP filtering */ static void addr_hash_set(u32 *mask, const u8 *addr) { int n = ether_crc(ETH_ALEN, addr) >> 26; mask[n >> 5] |= (1 << (n & 31)); } static unsigned int addr_hash_test(const u32 *mask, const u8 *addr) { int n = ether_crc(ETH_ALEN, addr) >> 26; return mask[n >> 5] & (1 << (n & 31)); } static int update_filter(struct tap_filter *filter, void __user *arg) { struct { u8 u[ETH_ALEN]; } *addr; struct tun_filter uf; int err, alen, n, nexact; if (copy_from_user(&uf, arg, sizeof(uf))) return -EFAULT; if (!uf.count) { /* Disabled */ filter->count = 0; return 0; } alen = ETH_ALEN * uf.count; addr = kmalloc(alen, GFP_KERNEL); if (!addr) return -ENOMEM; if (copy_from_user(addr, arg + sizeof(uf), alen)) { err = -EFAULT; goto done; } /* The filter is updated without holding any locks. Which is * perfectly safe. We disable it first and in the worst * case we'll accept a few undesired packets. */ filter->count = 0; wmb(); /* Use first set of addresses as an exact filter */ for (n = 0; n < uf.count && n < FLT_EXACT_COUNT; n++) memcpy(filter->addr[n], addr[n].u, ETH_ALEN); nexact = n; /* Remaining multicast addresses are hashed, * unicast will leave the filter disabled. */ memset(filter->mask, 0, sizeof(filter->mask)); for (; n < uf.count; n++) { if (!is_multicast_ether_addr(addr[n].u)) { err = 0; /* no filter */ goto done; } addr_hash_set(filter->mask, addr[n].u); } /* For ALLMULTI just set the mask to all ones. * This overrides the mask populated above. */ if ((uf.flags & TUN_FLT_ALLMULTI)) memset(filter->mask, ~0, sizeof(filter->mask)); /* Now enable the filter */ wmb(); filter->count = nexact; /* Return the number of exact filters */ err = nexact; done: kfree(addr); return err; } /* Returns: 0 - drop, !=0 - accept */ static int run_filter(struct tap_filter *filter, const struct sk_buff *skb) { /* Cannot use eth_hdr(skb) here because skb_mac_hdr() is incorrect * at this point. */ struct ethhdr *eh = (struct ethhdr *) skb->data; int i; /* Exact match */ for (i = 0; i < filter->count; i++) if (ether_addr_equal(eh->h_dest, filter->addr[i])) return 1; /* Inexact match (multicast only) */ if (is_multicast_ether_addr(eh->h_dest)) return addr_hash_test(filter->mask, eh->h_dest); return 0; } /* * Checks whether the packet is accepted or not. * Returns: 0 - drop, !=0 - accept */ static int check_filter(struct tap_filter *filter, const struct sk_buff *skb) { if (!filter->count) return 1; return run_filter(filter, skb); } /* Network device part of the driver */ static const struct ethtool_ops tun_ethtool_ops; /* Net device detach from fd. */ static void tun_net_uninit(struct net_device *dev) { struct tun_struct *tun = netdev_priv(dev); struct tun_file *tfile = tun->tfile; /* Inform the methods they need to stop using the dev. */ if (tfile) { wake_up_all(&tun->wq.wait); if (atomic_dec_and_test(&tfile->count)) __tun_detach(tun); } } static void tun_free_netdev(struct net_device *dev) { struct tun_struct *tun = netdev_priv(dev); sk_release_kernel(tun->socket.sk); } /* Net device open. */ static int tun_net_open(struct net_device *dev) { netif_start_queue(dev); return 0; } /* Net device close. */ static int tun_net_close(struct net_device *dev) { netif_stop_queue(dev); return 0; } /* Net device start xmit */ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) { struct tun_struct *tun = netdev_priv(dev); tun_debug(KERN_INFO, tun, "tun_net_xmit %d\n", skb->len); /* Drop packet if interface is not attached */ if (!tun->tfile) goto drop; /* Drop if the filter does not like it. * This is a noop if the filter is disabled. * Filter can be enabled only for the TAP devices. */ if (!check_filter(&tun->txflt, skb)) goto drop; if (tun->socket.sk->sk_filter && sk_filter(tun->socket.sk, skb)) goto drop; if (skb_queue_len(&tun->socket.sk->sk_receive_queue) >= dev->tx_queue_len) { if (!(tun->flags & TUN_ONE_QUEUE)) { /* Normal queueing mode. */ /* Packet scheduler handles dropping of further packets. */ netif_stop_queue(dev); /* We won't see all dropped packets individually, so overrun * error is more appropriate. */ dev->stats.tx_fifo_errors++; } else { /* Single queue mode. * Driver handles dropping of all packets itself. */ goto drop; } } /* Orphan the skb - required as we might hang on to it * for indefinite time. */ skb_orphan(skb); /* Enqueue packet */ skb_queue_tail(&tun->socket.sk->sk_receive_queue, skb); /* Notify and wake up reader process */ if (tun->flags & TUN_FASYNC) kill_fasync(&tun->fasync, SIGIO, POLL_IN); wake_up_interruptible_poll(&tun->wq.wait, POLLIN | POLLRDNORM | POLLRDBAND); return NETDEV_TX_OK; drop: dev->stats.tx_dropped++; kfree_skb(skb); return NETDEV_TX_OK; } static void tun_net_mclist(struct net_device *dev) { /* * This callback is supposed to deal with mc filter in * _rx_ path and has nothing to do with the _tx_ path. * In rx path we always accept everything userspace gives us. */ } #define MIN_MTU 68 #define MAX_MTU 65535 static int tun_net_change_mtu(struct net_device *dev, int new_mtu) { if (new_mtu < MIN_MTU || new_mtu + dev->hard_header_len > MAX_MTU) return -EINVAL; dev->mtu = new_mtu; return 0; } static netdev_features_t tun_net_fix_features(struct net_device *dev, netdev_features_t features) { struct tun_struct *tun = netdev_priv(dev); return (features & tun->set_features) | (features & ~TUN_USER_FEATURES); } #ifdef CONFIG_NET_POLL_CONTROLLER static void tun_poll_controller(struct net_device *dev) { /* * Tun only receives frames when: * 1) the char device endpoint gets data from user space * 2) the tun socket gets a sendmsg call from user space * Since both of those are syncronous operations, we are guaranteed * never to have pending data when we poll for it * so theres nothing to do here but return. * We need this though so netpoll recognizes us as an interface that * supports polling, which enables bridge devices in virt setups to * still use netconsole */ return; } #endif static const struct net_device_ops tun_netdev_ops = { .ndo_uninit = tun_net_uninit, .ndo_open = tun_net_open, .ndo_stop = tun_net_close, .ndo_start_xmit = tun_net_xmit, .ndo_change_mtu = tun_net_change_mtu, .ndo_fix_features = tun_net_fix_features, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = tun_poll_controller, #endif }; static const struct net_device_ops tap_netdev_ops = { .ndo_uninit = tun_net_uninit, .ndo_open = tun_net_open, .ndo_stop = tun_net_close, .ndo_start_xmit = tun_net_xmit, .ndo_change_mtu = tun_net_change_mtu, .ndo_fix_features = tun_net_fix_features, .ndo_set_rx_mode = tun_net_mclist, .ndo_set_mac_address = eth_mac_addr,