diff options
Diffstat (limited to 'drivers/net/tun.c')
| -rw-r--r-- | drivers/net/tun.c | 64 | 
1 files changed, 57 insertions, 7 deletions
| diff --git a/drivers/net/tun.c b/drivers/net/tun.c index fc86da7f1628..84f832806313 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -69,6 +69,14 @@  #include <linux/bpf.h>  #include <linux/bpf_trace.h>  #include <linux/mutex.h> +#include <linux/ieee802154.h> +#include <linux/if_ltalk.h> +#include <uapi/linux/if_fddi.h> +#include <uapi/linux/if_hippi.h> +#include <uapi/linux/if_fc.h> +#include <net/ax25.h> +#include <net/rose.h> +#include <net/6lowpan.h>  #include <linux/uaccess.h>  #include <linux/proc_fs.h> @@ -1181,8 +1189,7 @@ static int tun_xdp_xmit(struct net_device *dev, int n,  	struct tun_struct *tun = netdev_priv(dev);  	struct tun_file *tfile;  	u32 numqueues; -	int drops = 0; -	int cnt = n; +	int nxmit = 0;  	int i;  	if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) @@ -1212,9 +1219,9 @@ resample:  		if (__ptr_ring_produce(&tfile->tx_ring, frame)) {  			atomic_long_inc(&dev->tx_dropped); -			xdp_return_frame_rx_napi(xdp); -			drops++; +			break;  		} +		nxmit++;  	}  	spin_unlock(&tfile->tx_ring.producer_lock); @@ -1222,17 +1229,21 @@ resample:  		__tun_xdp_flush_tfile(tfile);  	rcu_read_unlock(); -	return cnt - drops; +	return nxmit;  }  static int tun_xdp_tx(struct net_device *dev, struct xdp_buff *xdp)  {  	struct xdp_frame *frame = xdp_convert_buff_to_frame(xdp); +	int nxmit;  	if (unlikely(!frame))  		return -EOVERFLOW; -	return tun_xdp_xmit(dev, 1, &frame, XDP_XMIT_FLUSH); +	nxmit = tun_xdp_xmit(dev, 1, &frame, XDP_XMIT_FLUSH); +	if (!nxmit) +		xdp_return_frame_rx_napi(frame); +	return nxmit;  }  static const struct net_device_ops tap_netdev_ops = { @@ -2919,6 +2930,45 @@ static int tun_set_ebpf(struct tun_struct *tun, struct tun_prog __rcu **prog_p,  	return __tun_set_ebpf(tun, prog_p, prog);  } +/* Return correct value for tun->dev->addr_len based on tun->dev->type. */ +static unsigned char tun_get_addr_len(unsigned short type) +{ +	switch (type) { +	case ARPHRD_IP6GRE: +	case ARPHRD_TUNNEL6: +		return sizeof(struct in6_addr); +	case ARPHRD_IPGRE: +	case ARPHRD_TUNNEL: +	case ARPHRD_SIT: +		return 4; +	case ARPHRD_ETHER: +		return ETH_ALEN; +	case ARPHRD_IEEE802154: +	case ARPHRD_IEEE802154_MONITOR: +		return IEEE802154_EXTENDED_ADDR_LEN; +	case ARPHRD_PHONET_PIPE: +	case ARPHRD_PPP: +	case ARPHRD_NONE: +		return 0; +	case ARPHRD_6LOWPAN: +		return EUI64_ADDR_LEN; +	case ARPHRD_FDDI: +		return FDDI_K_ALEN; +	case ARPHRD_HIPPI: +		return HIPPI_ALEN; +	case ARPHRD_IEEE802: +		return FC_ALEN; +	case ARPHRD_ROSE: +		return ROSE_ADDR_LEN; +	case ARPHRD_NETROM: +		return AX25_ADDR_LEN; +	case ARPHRD_LOCALTLK: +		return LTALK_ALEN; +	default: +		return 0; +	} +} +  static long __tun_chr_ioctl(struct file *file, unsigned int cmd,  			    unsigned long arg, int ifreq_len)  { @@ -2958,7 +3008,6 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,  		return open_related_ns(&net->ns, get_net_ns);  	} -	ret = 0;  	rtnl_lock();  	tun = tun_get(tfile); @@ -3082,6 +3131,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,  				break;  			}  			tun->dev->type = (int) arg; +			tun->dev->addr_len = tun_get_addr_len(tun->dev->type);  			netif_info(tun, drv, tun->dev, "linktype set to %d\n",  				   tun->dev->type);  			call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, | 
