18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * TUN - Universal TUN/TAP device driver. 48c2ecf20Sopenharmony_ci * Copyright (C) 1999-2002 Maxim Krasnyansky <maxk@qualcomm.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * $Id: tun.c,v 1.15 2002/03/01 02:44:24 maxk Exp $ 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci/* 108c2ecf20Sopenharmony_ci * Changes: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Mike Kershaw <dragorn@kismetwireless.net> 2005/08/14 138c2ecf20Sopenharmony_ci * Add TUNSETLINK ioctl to set the link encapsulation 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Mark Smith <markzzzsmith@yahoo.com.au> 168c2ecf20Sopenharmony_ci * Use eth_random_addr() for tap MAC address. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Harald Roelle <harald.roelle@ifi.lmu.de> 2004/04/20 198c2ecf20Sopenharmony_ci * Fixes in packet dropping, queue length setting and queue wakeup. 208c2ecf20Sopenharmony_ci * Increased default tx queue length. 218c2ecf20Sopenharmony_ci * Added ethtool API. 228c2ecf20Sopenharmony_ci * Minor cleanups 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Daniel Podlejski <underley@underley.eu.org> 258c2ecf20Sopenharmony_ci * Modifications for 2.3.99-pre5 kernel. 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define DRV_NAME "tun" 318c2ecf20Sopenharmony_ci#define DRV_VERSION "1.6" 328c2ecf20Sopenharmony_ci#define DRV_DESCRIPTION "Universal TUN/TAP device driver" 338c2ecf20Sopenharmony_ci#define DRV_COPYRIGHT "(C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <linux/module.h> 368c2ecf20Sopenharmony_ci#include <linux/errno.h> 378c2ecf20Sopenharmony_ci#include <linux/kernel.h> 388c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 398c2ecf20Sopenharmony_ci#include <linux/major.h> 408c2ecf20Sopenharmony_ci#include <linux/slab.h> 418c2ecf20Sopenharmony_ci#include <linux/poll.h> 428c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 438c2ecf20Sopenharmony_ci#include <linux/init.h> 448c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 458c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 468c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 478c2ecf20Sopenharmony_ci#include <linux/miscdevice.h> 488c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 498c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 508c2ecf20Sopenharmony_ci#include <linux/compat.h> 518c2ecf20Sopenharmony_ci#include <linux/if.h> 528c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 538c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 548c2ecf20Sopenharmony_ci#include <linux/if_tun.h> 558c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 568c2ecf20Sopenharmony_ci#include <linux/crc32.h> 578c2ecf20Sopenharmony_ci#include <linux/nsproxy.h> 588c2ecf20Sopenharmony_ci#include <linux/virtio_net.h> 598c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 608c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 618c2ecf20Sopenharmony_ci#include <net/netns/generic.h> 628c2ecf20Sopenharmony_ci#include <net/rtnetlink.h> 638c2ecf20Sopenharmony_ci#include <net/sock.h> 648c2ecf20Sopenharmony_ci#include <net/xdp.h> 658c2ecf20Sopenharmony_ci#include <net/ip_tunnels.h> 668c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 678c2ecf20Sopenharmony_ci#include <linux/uio.h> 688c2ecf20Sopenharmony_ci#include <linux/skb_array.h> 698c2ecf20Sopenharmony_ci#include <linux/bpf.h> 708c2ecf20Sopenharmony_ci#include <linux/bpf_trace.h> 718c2ecf20Sopenharmony_ci#include <linux/mutex.h> 728c2ecf20Sopenharmony_ci#include <linux/ieee802154.h> 738c2ecf20Sopenharmony_ci#include <linux/if_ltalk.h> 748c2ecf20Sopenharmony_ci#include <uapi/linux/if_fddi.h> 758c2ecf20Sopenharmony_ci#include <uapi/linux/if_hippi.h> 768c2ecf20Sopenharmony_ci#include <uapi/linux/if_fc.h> 778c2ecf20Sopenharmony_ci#include <net/ax25.h> 788c2ecf20Sopenharmony_ci#include <net/rose.h> 798c2ecf20Sopenharmony_ci#include <net/6lowpan.h> 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 828c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic void tun_default_link_ksettings(struct net_device *dev, 858c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci#define TUN_RX_PAD (NET_IP_ALIGN + NET_SKB_PAD) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* TUN device flags */ 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci/* IFF_ATTACH_QUEUE is never stored in device flags, 928c2ecf20Sopenharmony_ci * overload it to mean fasync when stored there. 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci#define TUN_FASYNC IFF_ATTACH_QUEUE 958c2ecf20Sopenharmony_ci/* High bits in flags field are unused. */ 968c2ecf20Sopenharmony_ci#define TUN_VNET_LE 0x80000000 978c2ecf20Sopenharmony_ci#define TUN_VNET_BE 0x40000000 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci#define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \ 1008c2ecf20Sopenharmony_ci IFF_MULTI_QUEUE | IFF_NAPI | IFF_NAPI_FRAGS) 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#define GOODCOPY_LEN 128 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci#define FLT_EXACT_COUNT 8 1058c2ecf20Sopenharmony_cistruct tap_filter { 1068c2ecf20Sopenharmony_ci unsigned int count; /* Number of addrs. Zero means disabled */ 1078c2ecf20Sopenharmony_ci u32 mask[2]; /* Mask of the hashed addrs */ 1088c2ecf20Sopenharmony_ci unsigned char addr[FLT_EXACT_COUNT][ETH_ALEN]; 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* MAX_TAP_QUEUES 256 is chosen to allow rx/tx queues to be equal 1128c2ecf20Sopenharmony_ci * to max number of VCPUs in guest. */ 1138c2ecf20Sopenharmony_ci#define MAX_TAP_QUEUES 256 1148c2ecf20Sopenharmony_ci#define MAX_TAP_FLOWS 4096 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#define TUN_FLOW_EXPIRE (3 * HZ) 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistruct tun_pcpu_stats { 1198c2ecf20Sopenharmony_ci u64_stats_t rx_packets; 1208c2ecf20Sopenharmony_ci u64_stats_t rx_bytes; 1218c2ecf20Sopenharmony_ci u64_stats_t tx_packets; 1228c2ecf20Sopenharmony_ci u64_stats_t tx_bytes; 1238c2ecf20Sopenharmony_ci struct u64_stats_sync syncp; 1248c2ecf20Sopenharmony_ci u32 rx_dropped; 1258c2ecf20Sopenharmony_ci u32 tx_dropped; 1268c2ecf20Sopenharmony_ci u32 rx_frame_errors; 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* A tun_file connects an open character device to a tuntap netdevice. It 1308c2ecf20Sopenharmony_ci * also contains all socket related structures (except sock_fprog and tap_filter) 1318c2ecf20Sopenharmony_ci * to serve as one transmit queue for tuntap device. The sock_fprog and 1328c2ecf20Sopenharmony_ci * tap_filter were kept in tun_struct since they were used for filtering for the 1338c2ecf20Sopenharmony_ci * netdevice not for a specific queue (at least I didn't see the requirement for 1348c2ecf20Sopenharmony_ci * this). 1358c2ecf20Sopenharmony_ci * 1368c2ecf20Sopenharmony_ci * RCU usage: 1378c2ecf20Sopenharmony_ci * The tun_file and tun_struct are loosely coupled, the pointer from one to the 1388c2ecf20Sopenharmony_ci * other can only be read while rcu_read_lock or rtnl_lock is held. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_cistruct tun_file { 1418c2ecf20Sopenharmony_ci struct sock sk; 1428c2ecf20Sopenharmony_ci struct socket socket; 1438c2ecf20Sopenharmony_ci struct tun_struct __rcu *tun; 1448c2ecf20Sopenharmony_ci struct fasync_struct *fasync; 1458c2ecf20Sopenharmony_ci /* only used for fasnyc */ 1468c2ecf20Sopenharmony_ci unsigned int flags; 1478c2ecf20Sopenharmony_ci union { 1488c2ecf20Sopenharmony_ci u16 queue_index; 1498c2ecf20Sopenharmony_ci unsigned int ifindex; 1508c2ecf20Sopenharmony_ci }; 1518c2ecf20Sopenharmony_ci struct napi_struct napi; 1528c2ecf20Sopenharmony_ci bool napi_enabled; 1538c2ecf20Sopenharmony_ci bool napi_frags_enabled; 1548c2ecf20Sopenharmony_ci struct mutex napi_mutex; /* Protects access to the above napi */ 1558c2ecf20Sopenharmony_ci struct list_head next; 1568c2ecf20Sopenharmony_ci struct tun_struct *detached; 1578c2ecf20Sopenharmony_ci struct ptr_ring tx_ring; 1588c2ecf20Sopenharmony_ci struct xdp_rxq_info xdp_rxq; 1598c2ecf20Sopenharmony_ci}; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistruct tun_page { 1628c2ecf20Sopenharmony_ci struct page *page; 1638c2ecf20Sopenharmony_ci int count; 1648c2ecf20Sopenharmony_ci}; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistruct tun_flow_entry { 1678c2ecf20Sopenharmony_ci struct hlist_node hash_link; 1688c2ecf20Sopenharmony_ci struct rcu_head rcu; 1698c2ecf20Sopenharmony_ci struct tun_struct *tun; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci u32 rxhash; 1728c2ecf20Sopenharmony_ci u32 rps_rxhash; 1738c2ecf20Sopenharmony_ci int queue_index; 1748c2ecf20Sopenharmony_ci unsigned long updated ____cacheline_aligned_in_smp; 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci#define TUN_NUM_FLOW_ENTRIES 1024 1788c2ecf20Sopenharmony_ci#define TUN_MASK_FLOW_ENTRIES (TUN_NUM_FLOW_ENTRIES - 1) 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistruct tun_prog { 1818c2ecf20Sopenharmony_ci struct rcu_head rcu; 1828c2ecf20Sopenharmony_ci struct bpf_prog *prog; 1838c2ecf20Sopenharmony_ci}; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci/* Since the socket were moved to tun_file, to preserve the behavior of persist 1868c2ecf20Sopenharmony_ci * device, socket filter, sndbuf and vnet header size were restore when the 1878c2ecf20Sopenharmony_ci * file were attached to a persist device. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_cistruct tun_struct { 1908c2ecf20Sopenharmony_ci struct tun_file __rcu *tfiles[MAX_TAP_QUEUES]; 1918c2ecf20Sopenharmony_ci unsigned int numqueues; 1928c2ecf20Sopenharmony_ci unsigned int flags; 1938c2ecf20Sopenharmony_ci kuid_t owner; 1948c2ecf20Sopenharmony_ci kgid_t group; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci struct net_device *dev; 1978c2ecf20Sopenharmony_ci netdev_features_t set_features; 1988c2ecf20Sopenharmony_ci#define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \ 1998c2ecf20Sopenharmony_ci NETIF_F_TSO6) 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci int align; 2028c2ecf20Sopenharmony_ci int vnet_hdr_sz; 2038c2ecf20Sopenharmony_ci int sndbuf; 2048c2ecf20Sopenharmony_ci struct tap_filter txflt; 2058c2ecf20Sopenharmony_ci struct sock_fprog fprog; 2068c2ecf20Sopenharmony_ci /* protected by rtnl lock */ 2078c2ecf20Sopenharmony_ci bool filter_attached; 2088c2ecf20Sopenharmony_ci u32 msg_enable; 2098c2ecf20Sopenharmony_ci spinlock_t lock; 2108c2ecf20Sopenharmony_ci struct hlist_head flows[TUN_NUM_FLOW_ENTRIES]; 2118c2ecf20Sopenharmony_ci struct timer_list flow_gc_timer; 2128c2ecf20Sopenharmony_ci unsigned long ageing_time; 2138c2ecf20Sopenharmony_ci unsigned int numdisabled; 2148c2ecf20Sopenharmony_ci struct list_head disabled; 2158c2ecf20Sopenharmony_ci void *security; 2168c2ecf20Sopenharmony_ci u32 flow_count; 2178c2ecf20Sopenharmony_ci u32 rx_batched; 2188c2ecf20Sopenharmony_ci struct tun_pcpu_stats __percpu *pcpu_stats; 2198c2ecf20Sopenharmony_ci struct bpf_prog __rcu *xdp_prog; 2208c2ecf20Sopenharmony_ci struct tun_prog __rcu *steering_prog; 2218c2ecf20Sopenharmony_ci struct tun_prog __rcu *filter_prog; 2228c2ecf20Sopenharmony_ci struct ethtool_link_ksettings link_ksettings; 2238c2ecf20Sopenharmony_ci /* init args */ 2248c2ecf20Sopenharmony_ci struct file *file; 2258c2ecf20Sopenharmony_ci struct ifreq *ifr; 2268c2ecf20Sopenharmony_ci}; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistruct veth { 2298c2ecf20Sopenharmony_ci __be16 h_vlan_proto; 2308c2ecf20Sopenharmony_ci __be16 h_vlan_TCI; 2318c2ecf20Sopenharmony_ci}; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic void tun_flow_init(struct tun_struct *tun); 2348c2ecf20Sopenharmony_cistatic void tun_flow_uninit(struct tun_struct *tun); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int tun_napi_receive(struct napi_struct *napi, int budget) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct tun_file *tfile = container_of(napi, struct tun_file, napi); 2398c2ecf20Sopenharmony_ci struct sk_buff_head *queue = &tfile->sk.sk_write_queue; 2408c2ecf20Sopenharmony_ci struct sk_buff_head process_queue; 2418c2ecf20Sopenharmony_ci struct sk_buff *skb; 2428c2ecf20Sopenharmony_ci int received = 0; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci __skb_queue_head_init(&process_queue); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci spin_lock(&queue->lock); 2478c2ecf20Sopenharmony_ci skb_queue_splice_tail_init(queue, &process_queue); 2488c2ecf20Sopenharmony_ci spin_unlock(&queue->lock); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci while (received < budget && (skb = __skb_dequeue(&process_queue))) { 2518c2ecf20Sopenharmony_ci napi_gro_receive(napi, skb); 2528c2ecf20Sopenharmony_ci ++received; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (!skb_queue_empty(&process_queue)) { 2568c2ecf20Sopenharmony_ci spin_lock(&queue->lock); 2578c2ecf20Sopenharmony_ci skb_queue_splice(&process_queue, queue); 2588c2ecf20Sopenharmony_ci spin_unlock(&queue->lock); 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return received; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic int tun_napi_poll(struct napi_struct *napi, int budget) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci unsigned int received; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci received = tun_napi_receive(napi, budget); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (received < budget) 2718c2ecf20Sopenharmony_ci napi_complete_done(napi, received); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return received; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic void tun_napi_init(struct tun_struct *tun, struct tun_file *tfile, 2778c2ecf20Sopenharmony_ci bool napi_en, bool napi_frags) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci tfile->napi_enabled = napi_en; 2808c2ecf20Sopenharmony_ci tfile->napi_frags_enabled = napi_en && napi_frags; 2818c2ecf20Sopenharmony_ci if (napi_en) { 2828c2ecf20Sopenharmony_ci netif_tx_napi_add(tun->dev, &tfile->napi, tun_napi_poll, 2838c2ecf20Sopenharmony_ci NAPI_POLL_WEIGHT); 2848c2ecf20Sopenharmony_ci napi_enable(&tfile->napi); 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic void tun_napi_enable(struct tun_file *tfile) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci if (tfile->napi_enabled) 2918c2ecf20Sopenharmony_ci napi_enable(&tfile->napi); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic void tun_napi_disable(struct tun_file *tfile) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci if (tfile->napi_enabled) 2978c2ecf20Sopenharmony_ci napi_disable(&tfile->napi); 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic void tun_napi_del(struct tun_file *tfile) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci if (tfile->napi_enabled) 3038c2ecf20Sopenharmony_ci netif_napi_del(&tfile->napi); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic bool tun_napi_frags_enabled(const struct tun_file *tfile) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci return tfile->napi_frags_enabled; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci#ifdef CONFIG_TUN_VNET_CROSS_LE 3128c2ecf20Sopenharmony_cistatic inline bool tun_legacy_is_little_endian(struct tun_struct *tun) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci return tun->flags & TUN_VNET_BE ? false : 3158c2ecf20Sopenharmony_ci virtio_legacy_is_little_endian(); 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic long tun_get_vnet_be(struct tun_struct *tun, int __user *argp) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci int be = !!(tun->flags & TUN_VNET_BE); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (put_user(be, argp)) 3238c2ecf20Sopenharmony_ci return -EFAULT; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci return 0; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic long tun_set_vnet_be(struct tun_struct *tun, int __user *argp) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci int be; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (get_user(be, argp)) 3338c2ecf20Sopenharmony_ci return -EFAULT; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (be) 3368c2ecf20Sopenharmony_ci tun->flags |= TUN_VNET_BE; 3378c2ecf20Sopenharmony_ci else 3388c2ecf20Sopenharmony_ci tun->flags &= ~TUN_VNET_BE; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return 0; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci#else 3438c2ecf20Sopenharmony_cistatic inline bool tun_legacy_is_little_endian(struct tun_struct *tun) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci return virtio_legacy_is_little_endian(); 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic long tun_get_vnet_be(struct tun_struct *tun, int __user *argp) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci return -EINVAL; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic long tun_set_vnet_be(struct tun_struct *tun, int __user *argp) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci return -EINVAL; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci#endif /* CONFIG_TUN_VNET_CROSS_LE */ 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic inline bool tun_is_little_endian(struct tun_struct *tun) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci return tun->flags & TUN_VNET_LE || 3628c2ecf20Sopenharmony_ci tun_legacy_is_little_endian(tun); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci return __virtio16_to_cpu(tun_is_little_endian(tun), val); 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic inline __virtio16 cpu_to_tun16(struct tun_struct *tun, u16 val) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci return __cpu_to_virtio16(tun_is_little_endian(tun), val); 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic inline u32 tun_hashfn(u32 rxhash) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci return rxhash & TUN_MASK_FLOW_ENTRIES; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic struct tun_flow_entry *tun_flow_find(struct hlist_head *head, u32 rxhash) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci struct tun_flow_entry *e; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(e, head, hash_link) { 3858c2ecf20Sopenharmony_ci if (e->rxhash == rxhash) 3868c2ecf20Sopenharmony_ci return e; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci return NULL; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic struct tun_flow_entry *tun_flow_create(struct tun_struct *tun, 3928c2ecf20Sopenharmony_ci struct hlist_head *head, 3938c2ecf20Sopenharmony_ci u32 rxhash, u16 queue_index) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci struct tun_flow_entry *e = kmalloc(sizeof(*e), GFP_ATOMIC); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (e) { 3988c2ecf20Sopenharmony_ci netif_info(tun, tx_queued, tun->dev, 3998c2ecf20Sopenharmony_ci "create flow: hash %u index %u\n", 4008c2ecf20Sopenharmony_ci rxhash, queue_index); 4018c2ecf20Sopenharmony_ci e->updated = jiffies; 4028c2ecf20Sopenharmony_ci e->rxhash = rxhash; 4038c2ecf20Sopenharmony_ci e->rps_rxhash = 0; 4048c2ecf20Sopenharmony_ci e->queue_index = queue_index; 4058c2ecf20Sopenharmony_ci e->tun = tun; 4068c2ecf20Sopenharmony_ci hlist_add_head_rcu(&e->hash_link, head); 4078c2ecf20Sopenharmony_ci ++tun->flow_count; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci return e; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic void tun_flow_delete(struct tun_struct *tun, struct tun_flow_entry *e) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci netif_info(tun, tx_queued, tun->dev, "delete flow: hash %u index %u\n", 4158c2ecf20Sopenharmony_ci e->rxhash, e->queue_index); 4168c2ecf20Sopenharmony_ci hlist_del_rcu(&e->hash_link); 4178c2ecf20Sopenharmony_ci kfree_rcu(e, rcu); 4188c2ecf20Sopenharmony_ci --tun->flow_count; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic void tun_flow_flush(struct tun_struct *tun) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci int i; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci spin_lock_bh(&tun->lock); 4268c2ecf20Sopenharmony_ci for (i = 0; i < TUN_NUM_FLOW_ENTRIES; i++) { 4278c2ecf20Sopenharmony_ci struct tun_flow_entry *e; 4288c2ecf20Sopenharmony_ci struct hlist_node *n; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(e, n, &tun->flows[i], hash_link) 4318c2ecf20Sopenharmony_ci tun_flow_delete(tun, e); 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci spin_unlock_bh(&tun->lock); 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic void tun_flow_delete_by_queue(struct tun_struct *tun, u16 queue_index) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci int i; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci spin_lock_bh(&tun->lock); 4418c2ecf20Sopenharmony_ci for (i = 0; i < TUN_NUM_FLOW_ENTRIES; i++) { 4428c2ecf20Sopenharmony_ci struct tun_flow_entry *e; 4438c2ecf20Sopenharmony_ci struct hlist_node *n; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(e, n, &tun->flows[i], hash_link) { 4468c2ecf20Sopenharmony_ci if (e->queue_index == queue_index) 4478c2ecf20Sopenharmony_ci tun_flow_delete(tun, e); 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci spin_unlock_bh(&tun->lock); 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic void tun_flow_cleanup(struct timer_list *t) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci struct tun_struct *tun = from_timer(tun, t, flow_gc_timer); 4568c2ecf20Sopenharmony_ci unsigned long delay = tun->ageing_time; 4578c2ecf20Sopenharmony_ci unsigned long next_timer = jiffies + delay; 4588c2ecf20Sopenharmony_ci unsigned long count = 0; 4598c2ecf20Sopenharmony_ci int i; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci spin_lock(&tun->lock); 4628c2ecf20Sopenharmony_ci for (i = 0; i < TUN_NUM_FLOW_ENTRIES; i++) { 4638c2ecf20Sopenharmony_ci struct tun_flow_entry *e; 4648c2ecf20Sopenharmony_ci struct hlist_node *n; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(e, n, &tun->flows[i], hash_link) { 4678c2ecf20Sopenharmony_ci unsigned long this_timer; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci this_timer = e->updated + delay; 4708c2ecf20Sopenharmony_ci if (time_before_eq(this_timer, jiffies)) { 4718c2ecf20Sopenharmony_ci tun_flow_delete(tun, e); 4728c2ecf20Sopenharmony_ci continue; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci count++; 4758c2ecf20Sopenharmony_ci if (time_before(this_timer, next_timer)) 4768c2ecf20Sopenharmony_ci next_timer = this_timer; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (count) 4818c2ecf20Sopenharmony_ci mod_timer(&tun->flow_gc_timer, round_jiffies_up(next_timer)); 4828c2ecf20Sopenharmony_ci spin_unlock(&tun->lock); 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic void tun_flow_update(struct tun_struct *tun, u32 rxhash, 4868c2ecf20Sopenharmony_ci struct tun_file *tfile) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci struct hlist_head *head; 4898c2ecf20Sopenharmony_ci struct tun_flow_entry *e; 4908c2ecf20Sopenharmony_ci unsigned long delay = tun->ageing_time; 4918c2ecf20Sopenharmony_ci u16 queue_index = tfile->queue_index; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci head = &tun->flows[tun_hashfn(rxhash)]; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci rcu_read_lock(); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci e = tun_flow_find(head, rxhash); 4988c2ecf20Sopenharmony_ci if (likely(e)) { 4998c2ecf20Sopenharmony_ci /* TODO: keep queueing to old queue until it's empty? */ 5008c2ecf20Sopenharmony_ci if (READ_ONCE(e->queue_index) != queue_index) 5018c2ecf20Sopenharmony_ci WRITE_ONCE(e->queue_index, queue_index); 5028c2ecf20Sopenharmony_ci if (e->updated != jiffies) 5038c2ecf20Sopenharmony_ci e->updated = jiffies; 5048c2ecf20Sopenharmony_ci sock_rps_record_flow_hash(e->rps_rxhash); 5058c2ecf20Sopenharmony_ci } else { 5068c2ecf20Sopenharmony_ci spin_lock_bh(&tun->lock); 5078c2ecf20Sopenharmony_ci if (!tun_flow_find(head, rxhash) && 5088c2ecf20Sopenharmony_ci tun->flow_count < MAX_TAP_FLOWS) 5098c2ecf20Sopenharmony_ci tun_flow_create(tun, head, rxhash, queue_index); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (!timer_pending(&tun->flow_gc_timer)) 5128c2ecf20Sopenharmony_ci mod_timer(&tun->flow_gc_timer, 5138c2ecf20Sopenharmony_ci round_jiffies_up(jiffies + delay)); 5148c2ecf20Sopenharmony_ci spin_unlock_bh(&tun->lock); 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci rcu_read_unlock(); 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci/* Save the hash received in the stack receive path and update the 5218c2ecf20Sopenharmony_ci * flow_hash table accordingly. 5228c2ecf20Sopenharmony_ci */ 5238c2ecf20Sopenharmony_cistatic inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci if (unlikely(e->rps_rxhash != hash)) 5268c2ecf20Sopenharmony_ci e->rps_rxhash = hash; 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci/* We try to identify a flow through its rxhash. The reason that 5308c2ecf20Sopenharmony_ci * we do not check rxq no. is because some cards(e.g 82599), chooses 5318c2ecf20Sopenharmony_ci * the rxq based on the txq where the last packet of the flow comes. As 5328c2ecf20Sopenharmony_ci * the userspace application move between processors, we may get a 5338c2ecf20Sopenharmony_ci * different rxq no. here. 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_cistatic u16 tun_automq_select_queue(struct tun_struct *tun, struct sk_buff *skb) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci struct tun_flow_entry *e; 5388c2ecf20Sopenharmony_ci u32 txq = 0; 5398c2ecf20Sopenharmony_ci u32 numqueues = 0; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci numqueues = READ_ONCE(tun->numqueues); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci txq = __skb_get_hash_symmetric(skb); 5448c2ecf20Sopenharmony_ci e = tun_flow_find(&tun->flows[tun_hashfn(txq)], txq); 5458c2ecf20Sopenharmony_ci if (e) { 5468c2ecf20Sopenharmony_ci tun_flow_save_rps_rxhash(e, txq); 5478c2ecf20Sopenharmony_ci txq = e->queue_index; 5488c2ecf20Sopenharmony_ci } else { 5498c2ecf20Sopenharmony_ci /* use multiply and shift instead of expensive divide */ 5508c2ecf20Sopenharmony_ci txq = ((u64)txq * numqueues) >> 32; 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci return txq; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic u16 tun_ebpf_select_queue(struct tun_struct *tun, struct sk_buff *skb) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci struct tun_prog *prog; 5598c2ecf20Sopenharmony_ci u32 numqueues; 5608c2ecf20Sopenharmony_ci u16 ret = 0; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci numqueues = READ_ONCE(tun->numqueues); 5638c2ecf20Sopenharmony_ci if (!numqueues) 5648c2ecf20Sopenharmony_ci return 0; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci prog = rcu_dereference(tun->steering_prog); 5678c2ecf20Sopenharmony_ci if (prog) 5688c2ecf20Sopenharmony_ci ret = bpf_prog_run_clear_cb(prog->prog, skb); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci return ret % numqueues; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb, 5748c2ecf20Sopenharmony_ci struct net_device *sb_dev) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 5778c2ecf20Sopenharmony_ci u16 ret; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci rcu_read_lock(); 5808c2ecf20Sopenharmony_ci if (rcu_dereference(tun->steering_prog)) 5818c2ecf20Sopenharmony_ci ret = tun_ebpf_select_queue(tun, skb); 5828c2ecf20Sopenharmony_ci else 5838c2ecf20Sopenharmony_ci ret = tun_automq_select_queue(tun, skb); 5848c2ecf20Sopenharmony_ci rcu_read_unlock(); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci return ret; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic inline bool tun_not_capable(struct tun_struct *tun) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 5928c2ecf20Sopenharmony_ci struct net *net = dev_net(tun->dev); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci return ((uid_valid(tun->owner) && !uid_eq(cred->euid, tun->owner)) || 5958c2ecf20Sopenharmony_ci (gid_valid(tun->group) && !in_egroup_p(tun->group))) && 5968c2ecf20Sopenharmony_ci !ns_capable(net->user_ns, CAP_NET_ADMIN); 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic void tun_set_real_num_queues(struct tun_struct *tun) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci netif_set_real_num_tx_queues(tun->dev, tun->numqueues); 6028c2ecf20Sopenharmony_ci netif_set_real_num_rx_queues(tun->dev, tun->numqueues); 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic void tun_disable_queue(struct tun_struct *tun, struct tun_file *tfile) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci tfile->detached = tun; 6088c2ecf20Sopenharmony_ci list_add_tail(&tfile->next, &tun->disabled); 6098c2ecf20Sopenharmony_ci ++tun->numdisabled; 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic struct tun_struct *tun_enable_queue(struct tun_file *tfile) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci struct tun_struct *tun = tfile->detached; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci tfile->detached = NULL; 6178c2ecf20Sopenharmony_ci list_del_init(&tfile->next); 6188c2ecf20Sopenharmony_ci --tun->numdisabled; 6198c2ecf20Sopenharmony_ci return tun; 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_civoid tun_ptr_free(void *ptr) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci if (!ptr) 6258c2ecf20Sopenharmony_ci return; 6268c2ecf20Sopenharmony_ci if (tun_is_xdp_frame(ptr)) { 6278c2ecf20Sopenharmony_ci struct xdp_frame *xdpf = tun_ptr_to_xdp(ptr); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci xdp_return_frame(xdpf); 6308c2ecf20Sopenharmony_ci } else { 6318c2ecf20Sopenharmony_ci __skb_array_destroy_skb(ptr); 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tun_ptr_free); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic void tun_queue_purge(struct tun_file *tfile) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci void *ptr; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci while ((ptr = ptr_ring_consume(&tfile->tx_ring)) != NULL) 6418c2ecf20Sopenharmony_ci tun_ptr_free(ptr); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci skb_queue_purge(&tfile->sk.sk_write_queue); 6448c2ecf20Sopenharmony_ci skb_queue_purge(&tfile->sk.sk_error_queue); 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic void __tun_detach(struct tun_file *tfile, bool clean) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci struct tun_file *ntfile; 6508c2ecf20Sopenharmony_ci struct tun_struct *tun; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci tun = rtnl_dereference(tfile->tun); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (tun && clean) { 6558c2ecf20Sopenharmony_ci if (!tfile->detached) 6568c2ecf20Sopenharmony_ci tun_napi_disable(tfile); 6578c2ecf20Sopenharmony_ci tun_napi_del(tfile); 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci if (tun && !tfile->detached) { 6618c2ecf20Sopenharmony_ci u16 index = tfile->queue_index; 6628c2ecf20Sopenharmony_ci BUG_ON(index >= tun->numqueues); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci rcu_assign_pointer(tun->tfiles[index], 6658c2ecf20Sopenharmony_ci tun->tfiles[tun->numqueues - 1]); 6668c2ecf20Sopenharmony_ci ntfile = rtnl_dereference(tun->tfiles[index]); 6678c2ecf20Sopenharmony_ci ntfile->queue_index = index; 6688c2ecf20Sopenharmony_ci rcu_assign_pointer(tun->tfiles[tun->numqueues - 1], 6698c2ecf20Sopenharmony_ci NULL); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci --tun->numqueues; 6728c2ecf20Sopenharmony_ci if (clean) { 6738c2ecf20Sopenharmony_ci RCU_INIT_POINTER(tfile->tun, NULL); 6748c2ecf20Sopenharmony_ci sock_put(&tfile->sk); 6758c2ecf20Sopenharmony_ci } else { 6768c2ecf20Sopenharmony_ci tun_disable_queue(tun, tfile); 6778c2ecf20Sopenharmony_ci tun_napi_disable(tfile); 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci synchronize_net(); 6818c2ecf20Sopenharmony_ci tun_flow_delete_by_queue(tun, tun->numqueues + 1); 6828c2ecf20Sopenharmony_ci /* Drop read queue */ 6838c2ecf20Sopenharmony_ci tun_queue_purge(tfile); 6848c2ecf20Sopenharmony_ci tun_set_real_num_queues(tun); 6858c2ecf20Sopenharmony_ci } else if (tfile->detached && clean) { 6868c2ecf20Sopenharmony_ci tun = tun_enable_queue(tfile); 6878c2ecf20Sopenharmony_ci sock_put(&tfile->sk); 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (clean) { 6918c2ecf20Sopenharmony_ci if (tun && tun->numqueues == 0 && tun->numdisabled == 0) { 6928c2ecf20Sopenharmony_ci netif_carrier_off(tun->dev); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if (!(tun->flags & IFF_PERSIST) && 6958c2ecf20Sopenharmony_ci tun->dev->reg_state == NETREG_REGISTERED) 6968c2ecf20Sopenharmony_ci unregister_netdevice(tun->dev); 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci if (tun) 6998c2ecf20Sopenharmony_ci xdp_rxq_info_unreg(&tfile->xdp_rxq); 7008c2ecf20Sopenharmony_ci ptr_ring_cleanup(&tfile->tx_ring, tun_ptr_free); 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic void tun_detach(struct tun_file *tfile, bool clean) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci struct tun_struct *tun; 7078c2ecf20Sopenharmony_ci struct net_device *dev; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci rtnl_lock(); 7108c2ecf20Sopenharmony_ci tun = rtnl_dereference(tfile->tun); 7118c2ecf20Sopenharmony_ci dev = tun ? tun->dev : NULL; 7128c2ecf20Sopenharmony_ci __tun_detach(tfile, clean); 7138c2ecf20Sopenharmony_ci if (dev) 7148c2ecf20Sopenharmony_ci netdev_state_change(dev); 7158c2ecf20Sopenharmony_ci rtnl_unlock(); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if (clean) 7188c2ecf20Sopenharmony_ci sock_put(&tfile->sk); 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_cistatic void tun_detach_all(struct net_device *dev) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 7248c2ecf20Sopenharmony_ci struct tun_file *tfile, *tmp; 7258c2ecf20Sopenharmony_ci int i, n = tun->numqueues; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 7288c2ecf20Sopenharmony_ci tfile = rtnl_dereference(tun->tfiles[i]); 7298c2ecf20Sopenharmony_ci BUG_ON(!tfile); 7308c2ecf20Sopenharmony_ci tun_napi_disable(tfile); 7318c2ecf20Sopenharmony_ci tfile->socket.sk->sk_shutdown = RCV_SHUTDOWN; 7328c2ecf20Sopenharmony_ci tfile->socket.sk->sk_data_ready(tfile->socket.sk); 7338c2ecf20Sopenharmony_ci RCU_INIT_POINTER(tfile->tun, NULL); 7348c2ecf20Sopenharmony_ci --tun->numqueues; 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci list_for_each_entry(tfile, &tun->disabled, next) { 7378c2ecf20Sopenharmony_ci tfile->socket.sk->sk_shutdown = RCV_SHUTDOWN; 7388c2ecf20Sopenharmony_ci tfile->socket.sk->sk_data_ready(tfile->socket.sk); 7398c2ecf20Sopenharmony_ci RCU_INIT_POINTER(tfile->tun, NULL); 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci BUG_ON(tun->numqueues != 0); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci synchronize_net(); 7448c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 7458c2ecf20Sopenharmony_ci tfile = rtnl_dereference(tun->tfiles[i]); 7468c2ecf20Sopenharmony_ci tun_napi_del(tfile); 7478c2ecf20Sopenharmony_ci /* Drop read queue */ 7488c2ecf20Sopenharmony_ci tun_queue_purge(tfile); 7498c2ecf20Sopenharmony_ci xdp_rxq_info_unreg(&tfile->xdp_rxq); 7508c2ecf20Sopenharmony_ci sock_put(&tfile->sk); 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) { 7538c2ecf20Sopenharmony_ci tun_napi_del(tfile); 7548c2ecf20Sopenharmony_ci tun_enable_queue(tfile); 7558c2ecf20Sopenharmony_ci tun_queue_purge(tfile); 7568c2ecf20Sopenharmony_ci xdp_rxq_info_unreg(&tfile->xdp_rxq); 7578c2ecf20Sopenharmony_ci sock_put(&tfile->sk); 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci BUG_ON(tun->numdisabled != 0); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (tun->flags & IFF_PERSIST) 7628c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_cistatic int tun_attach(struct tun_struct *tun, struct file *file, 7668c2ecf20Sopenharmony_ci bool skip_filter, bool napi, bool napi_frags, 7678c2ecf20Sopenharmony_ci bool publish_tun) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci struct tun_file *tfile = file->private_data; 7708c2ecf20Sopenharmony_ci struct net_device *dev = tun->dev; 7718c2ecf20Sopenharmony_ci int err; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci err = security_tun_dev_attach(tfile->socket.sk, tun->security); 7748c2ecf20Sopenharmony_ci if (err < 0) 7758c2ecf20Sopenharmony_ci goto out; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci err = -EINVAL; 7788c2ecf20Sopenharmony_ci if (rtnl_dereference(tfile->tun) && !tfile->detached) 7798c2ecf20Sopenharmony_ci goto out; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci err = -EBUSY; 7828c2ecf20Sopenharmony_ci if (!(tun->flags & IFF_MULTI_QUEUE) && tun->numqueues == 1) 7838c2ecf20Sopenharmony_ci goto out; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci err = -E2BIG; 7868c2ecf20Sopenharmony_ci if (!tfile->detached && 7878c2ecf20Sopenharmony_ci tun->numqueues + tun->numdisabled == MAX_TAP_QUEUES) 7888c2ecf20Sopenharmony_ci goto out; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci err = 0; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci /* Re-attach the filter to persist device */ 7938c2ecf20Sopenharmony_ci if (!skip_filter && (tun->filter_attached == true)) { 7948c2ecf20Sopenharmony_ci lock_sock(tfile->socket.sk); 7958c2ecf20Sopenharmony_ci err = sk_attach_filter(&tun->fprog, tfile->socket.sk); 7968c2ecf20Sopenharmony_ci release_sock(tfile->socket.sk); 7978c2ecf20Sopenharmony_ci if (!err) 7988c2ecf20Sopenharmony_ci goto out; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (!tfile->detached && 8028c2ecf20Sopenharmony_ci ptr_ring_resize(&tfile->tx_ring, dev->tx_queue_len, 8038c2ecf20Sopenharmony_ci GFP_KERNEL, tun_ptr_free)) { 8048c2ecf20Sopenharmony_ci err = -ENOMEM; 8058c2ecf20Sopenharmony_ci goto out; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci tfile->queue_index = tun->numqueues; 8098c2ecf20Sopenharmony_ci tfile->socket.sk->sk_shutdown &= ~RCV_SHUTDOWN; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci if (tfile->detached) { 8128c2ecf20Sopenharmony_ci /* Re-attach detached tfile, updating XDP queue_index */ 8138c2ecf20Sopenharmony_ci WARN_ON(!xdp_rxq_info_is_reg(&tfile->xdp_rxq)); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci if (tfile->xdp_rxq.queue_index != tfile->queue_index) 8168c2ecf20Sopenharmony_ci tfile->xdp_rxq.queue_index = tfile->queue_index; 8178c2ecf20Sopenharmony_ci } else { 8188c2ecf20Sopenharmony_ci /* Setup XDP RX-queue info, for new tfile getting attached */ 8198c2ecf20Sopenharmony_ci err = xdp_rxq_info_reg(&tfile->xdp_rxq, 8208c2ecf20Sopenharmony_ci tun->dev, tfile->queue_index); 8218c2ecf20Sopenharmony_ci if (err < 0) 8228c2ecf20Sopenharmony_ci goto out; 8238c2ecf20Sopenharmony_ci err = xdp_rxq_info_reg_mem_model(&tfile->xdp_rxq, 8248c2ecf20Sopenharmony_ci MEM_TYPE_PAGE_SHARED, NULL); 8258c2ecf20Sopenharmony_ci if (err < 0) { 8268c2ecf20Sopenharmony_ci xdp_rxq_info_unreg(&tfile->xdp_rxq); 8278c2ecf20Sopenharmony_ci goto out; 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci err = 0; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (tfile->detached) { 8338c2ecf20Sopenharmony_ci tun_enable_queue(tfile); 8348c2ecf20Sopenharmony_ci tun_napi_enable(tfile); 8358c2ecf20Sopenharmony_ci } else { 8368c2ecf20Sopenharmony_ci sock_hold(&tfile->sk); 8378c2ecf20Sopenharmony_ci tun_napi_init(tun, tfile, napi, napi_frags); 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci if (rtnl_dereference(tun->xdp_prog)) 8418c2ecf20Sopenharmony_ci sock_set_flag(&tfile->sk, SOCK_XDP); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci /* device is allowed to go away first, so no need to hold extra 8448c2ecf20Sopenharmony_ci * refcnt. 8458c2ecf20Sopenharmony_ci */ 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci /* Publish tfile->tun and tun->tfiles only after we've fully 8488c2ecf20Sopenharmony_ci * initialized tfile; otherwise we risk using half-initialized 8498c2ecf20Sopenharmony_ci * object. 8508c2ecf20Sopenharmony_ci */ 8518c2ecf20Sopenharmony_ci if (publish_tun) 8528c2ecf20Sopenharmony_ci rcu_assign_pointer(tfile->tun, tun); 8538c2ecf20Sopenharmony_ci rcu_assign_pointer(tun->tfiles[tun->numqueues], tfile); 8548c2ecf20Sopenharmony_ci tun->numqueues++; 8558c2ecf20Sopenharmony_ci tun_set_real_num_queues(tun); 8568c2ecf20Sopenharmony_ciout: 8578c2ecf20Sopenharmony_ci return err; 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic struct tun_struct *tun_get(struct tun_file *tfile) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci struct tun_struct *tun; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci rcu_read_lock(); 8658c2ecf20Sopenharmony_ci tun = rcu_dereference(tfile->tun); 8668c2ecf20Sopenharmony_ci if (tun) 8678c2ecf20Sopenharmony_ci dev_hold(tun->dev); 8688c2ecf20Sopenharmony_ci rcu_read_unlock(); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci return tun; 8718c2ecf20Sopenharmony_ci} 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_cistatic void tun_put(struct tun_struct *tun) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci dev_put(tun->dev); 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci/* TAP filtering */ 8798c2ecf20Sopenharmony_cistatic void addr_hash_set(u32 *mask, const u8 *addr) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci int n = ether_crc(ETH_ALEN, addr) >> 26; 8828c2ecf20Sopenharmony_ci mask[n >> 5] |= (1 << (n & 31)); 8838c2ecf20Sopenharmony_ci} 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_cistatic unsigned int addr_hash_test(const u32 *mask, const u8 *addr) 8868c2ecf20Sopenharmony_ci{ 8878c2ecf20Sopenharmony_ci int n = ether_crc(ETH_ALEN, addr) >> 26; 8888c2ecf20Sopenharmony_ci return mask[n >> 5] & (1 << (n & 31)); 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cistatic int update_filter(struct tap_filter *filter, void __user *arg) 8928c2ecf20Sopenharmony_ci{ 8938c2ecf20Sopenharmony_ci struct { u8 u[ETH_ALEN]; } *addr; 8948c2ecf20Sopenharmony_ci struct tun_filter uf; 8958c2ecf20Sopenharmony_ci int err, alen, n, nexact; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci if (copy_from_user(&uf, arg, sizeof(uf))) 8988c2ecf20Sopenharmony_ci return -EFAULT; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if (!uf.count) { 9018c2ecf20Sopenharmony_ci /* Disabled */ 9028c2ecf20Sopenharmony_ci filter->count = 0; 9038c2ecf20Sopenharmony_ci return 0; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci alen = ETH_ALEN * uf.count; 9078c2ecf20Sopenharmony_ci addr = memdup_user(arg + sizeof(uf), alen); 9088c2ecf20Sopenharmony_ci if (IS_ERR(addr)) 9098c2ecf20Sopenharmony_ci return PTR_ERR(addr); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci /* The filter is updated without holding any locks. Which is 9128c2ecf20Sopenharmony_ci * perfectly safe. We disable it first and in the worst 9138c2ecf20Sopenharmony_ci * case we'll accept a few undesired packets. */ 9148c2ecf20Sopenharmony_ci filter->count = 0; 9158c2ecf20Sopenharmony_ci wmb(); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci /* Use first set of addresses as an exact filter */ 9188c2ecf20Sopenharmony_ci for (n = 0; n < uf.count && n < FLT_EXACT_COUNT; n++) 9198c2ecf20Sopenharmony_ci memcpy(filter->addr[n], addr[n].u, ETH_ALEN); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci nexact = n; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci /* Remaining multicast addresses are hashed, 9248c2ecf20Sopenharmony_ci * unicast will leave the filter disabled. */ 9258c2ecf20Sopenharmony_ci memset(filter->mask, 0, sizeof(filter->mask)); 9268c2ecf20Sopenharmony_ci for (; n < uf.count; n++) { 9278c2ecf20Sopenharmony_ci if (!is_multicast_ether_addr(addr[n].u)) { 9288c2ecf20Sopenharmony_ci err = 0; /* no filter */ 9298c2ecf20Sopenharmony_ci goto free_addr; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci addr_hash_set(filter->mask, addr[n].u); 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci /* For ALLMULTI just set the mask to all ones. 9358c2ecf20Sopenharmony_ci * This overrides the mask populated above. */ 9368c2ecf20Sopenharmony_ci if ((uf.flags & TUN_FLT_ALLMULTI)) 9378c2ecf20Sopenharmony_ci memset(filter->mask, ~0, sizeof(filter->mask)); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci /* Now enable the filter */ 9408c2ecf20Sopenharmony_ci wmb(); 9418c2ecf20Sopenharmony_ci filter->count = nexact; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci /* Return the number of exact filters */ 9448c2ecf20Sopenharmony_ci err = nexact; 9458c2ecf20Sopenharmony_cifree_addr: 9468c2ecf20Sopenharmony_ci kfree(addr); 9478c2ecf20Sopenharmony_ci return err; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci/* Returns: 0 - drop, !=0 - accept */ 9518c2ecf20Sopenharmony_cistatic int run_filter(struct tap_filter *filter, const struct sk_buff *skb) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci /* Cannot use eth_hdr(skb) here because skb_mac_hdr() is incorrect 9548c2ecf20Sopenharmony_ci * at this point. */ 9558c2ecf20Sopenharmony_ci struct ethhdr *eh = (struct ethhdr *) skb->data; 9568c2ecf20Sopenharmony_ci int i; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci /* Exact match */ 9598c2ecf20Sopenharmony_ci for (i = 0; i < filter->count; i++) 9608c2ecf20Sopenharmony_ci if (ether_addr_equal(eh->h_dest, filter->addr[i])) 9618c2ecf20Sopenharmony_ci return 1; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci /* Inexact match (multicast only) */ 9648c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(eh->h_dest)) 9658c2ecf20Sopenharmony_ci return addr_hash_test(filter->mask, eh->h_dest); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci return 0; 9688c2ecf20Sopenharmony_ci} 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci/* 9718c2ecf20Sopenharmony_ci * Checks whether the packet is accepted or not. 9728c2ecf20Sopenharmony_ci * Returns: 0 - drop, !=0 - accept 9738c2ecf20Sopenharmony_ci */ 9748c2ecf20Sopenharmony_cistatic int check_filter(struct tap_filter *filter, const struct sk_buff *skb) 9758c2ecf20Sopenharmony_ci{ 9768c2ecf20Sopenharmony_ci if (!filter->count) 9778c2ecf20Sopenharmony_ci return 1; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci return run_filter(filter, skb); 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci/* Network device part of the driver */ 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic const struct ethtool_ops tun_ethtool_ops; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cistatic int tun_net_init(struct net_device *dev) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 9898c2ecf20Sopenharmony_ci struct ifreq *ifr = tun->ifr; 9908c2ecf20Sopenharmony_ci int err; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci tun->pcpu_stats = netdev_alloc_pcpu_stats(struct tun_pcpu_stats); 9938c2ecf20Sopenharmony_ci if (!tun->pcpu_stats) 9948c2ecf20Sopenharmony_ci return -ENOMEM; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci spin_lock_init(&tun->lock); 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci err = security_tun_dev_alloc_security(&tun->security); 9998c2ecf20Sopenharmony_ci if (err < 0) { 10008c2ecf20Sopenharmony_ci free_percpu(tun->pcpu_stats); 10018c2ecf20Sopenharmony_ci return err; 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci tun_flow_init(tun); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | 10078c2ecf20Sopenharmony_ci TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX | 10088c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_STAG_TX; 10098c2ecf20Sopenharmony_ci dev->features = dev->hw_features | NETIF_F_LLTX; 10108c2ecf20Sopenharmony_ci dev->vlan_features = dev->features & 10118c2ecf20Sopenharmony_ci ~(NETIF_F_HW_VLAN_CTAG_TX | 10128c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_STAG_TX); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci tun->flags = (tun->flags & ~TUN_FEATURES) | 10158c2ecf20Sopenharmony_ci (ifr->ifr_flags & TUN_FEATURES); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tun->disabled); 10188c2ecf20Sopenharmony_ci err = tun_attach(tun, tun->file, false, ifr->ifr_flags & IFF_NAPI, 10198c2ecf20Sopenharmony_ci ifr->ifr_flags & IFF_NAPI_FRAGS, false); 10208c2ecf20Sopenharmony_ci if (err < 0) { 10218c2ecf20Sopenharmony_ci tun_flow_uninit(tun); 10228c2ecf20Sopenharmony_ci security_tun_dev_free_security(tun->security); 10238c2ecf20Sopenharmony_ci free_percpu(tun->pcpu_stats); 10248c2ecf20Sopenharmony_ci return err; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci return 0; 10278c2ecf20Sopenharmony_ci} 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci/* Net device detach from fd. */ 10308c2ecf20Sopenharmony_cistatic void tun_net_uninit(struct net_device *dev) 10318c2ecf20Sopenharmony_ci{ 10328c2ecf20Sopenharmony_ci tun_detach_all(dev); 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci/* Net device open. */ 10368c2ecf20Sopenharmony_cistatic int tun_net_open(struct net_device *dev) 10378c2ecf20Sopenharmony_ci{ 10388c2ecf20Sopenharmony_ci netif_tx_start_all_queues(dev); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci return 0; 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci/* Net device close. */ 10448c2ecf20Sopenharmony_cistatic int tun_net_close(struct net_device *dev) 10458c2ecf20Sopenharmony_ci{ 10468c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(dev); 10478c2ecf20Sopenharmony_ci return 0; 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci/* Net device start xmit */ 10518c2ecf20Sopenharmony_cistatic void tun_automq_xmit(struct tun_struct *tun, struct sk_buff *skb) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci#ifdef CONFIG_RPS 10548c2ecf20Sopenharmony_ci if (tun->numqueues == 1 && static_branch_unlikely(&rps_needed)) { 10558c2ecf20Sopenharmony_ci /* Select queue was not called for the skbuff, so we extract the 10568c2ecf20Sopenharmony_ci * RPS hash and save it into the flow_table here. 10578c2ecf20Sopenharmony_ci */ 10588c2ecf20Sopenharmony_ci struct tun_flow_entry *e; 10598c2ecf20Sopenharmony_ci __u32 rxhash; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci rxhash = __skb_get_hash_symmetric(skb); 10628c2ecf20Sopenharmony_ci e = tun_flow_find(&tun->flows[tun_hashfn(rxhash)], rxhash); 10638c2ecf20Sopenharmony_ci if (e) 10648c2ecf20Sopenharmony_ci tun_flow_save_rps_rxhash(e, rxhash); 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci#endif 10678c2ecf20Sopenharmony_ci} 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_cistatic unsigned int run_ebpf_filter(struct tun_struct *tun, 10708c2ecf20Sopenharmony_ci struct sk_buff *skb, 10718c2ecf20Sopenharmony_ci int len) 10728c2ecf20Sopenharmony_ci{ 10738c2ecf20Sopenharmony_ci struct tun_prog *prog = rcu_dereference(tun->filter_prog); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci if (prog) 10768c2ecf20Sopenharmony_ci len = bpf_prog_run_clear_cb(prog->prog, skb); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci return len; 10798c2ecf20Sopenharmony_ci} 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci/* Net device start xmit */ 10828c2ecf20Sopenharmony_cistatic netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) 10838c2ecf20Sopenharmony_ci{ 10848c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 10858c2ecf20Sopenharmony_ci int txq = skb->queue_mapping; 10868c2ecf20Sopenharmony_ci struct netdev_queue *queue; 10878c2ecf20Sopenharmony_ci struct tun_file *tfile; 10888c2ecf20Sopenharmony_ci int len = skb->len; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci rcu_read_lock(); 10918c2ecf20Sopenharmony_ci tfile = rcu_dereference(tun->tfiles[txq]); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci /* Drop packet if interface is not attached */ 10948c2ecf20Sopenharmony_ci if (!tfile) 10958c2ecf20Sopenharmony_ci goto drop; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (!rcu_dereference(tun->steering_prog)) 10988c2ecf20Sopenharmony_ci tun_automq_xmit(tun, skb); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci netif_info(tun, tx_queued, tun->dev, "%s %d\n", __func__, skb->len); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci /* Drop if the filter does not like it. 11038c2ecf20Sopenharmony_ci * This is a noop if the filter is disabled. 11048c2ecf20Sopenharmony_ci * Filter can be enabled only for the TAP devices. */ 11058c2ecf20Sopenharmony_ci if (!check_filter(&tun->txflt, skb)) 11068c2ecf20Sopenharmony_ci goto drop; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (tfile->socket.sk->sk_filter && 11098c2ecf20Sopenharmony_ci sk_filter(tfile->socket.sk, skb)) 11108c2ecf20Sopenharmony_ci goto drop; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci len = run_ebpf_filter(tun, skb, len); 11138c2ecf20Sopenharmony_ci if (len == 0 || pskb_trim(skb, len)) 11148c2ecf20Sopenharmony_ci goto drop; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (unlikely(skb_orphan_frags_rx(skb, GFP_ATOMIC))) 11178c2ecf20Sopenharmony_ci goto drop; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci skb_tx_timestamp(skb); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci /* Orphan the skb - required as we might hang on to it 11228c2ecf20Sopenharmony_ci * for indefinite time. 11238c2ecf20Sopenharmony_ci */ 11248c2ecf20Sopenharmony_ci skb_orphan(skb); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci nf_reset_ct(skb); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci if (ptr_ring_produce(&tfile->tx_ring, skb)) 11298c2ecf20Sopenharmony_ci goto drop; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci /* NETIF_F_LLTX requires to do our own update of trans_start */ 11328c2ecf20Sopenharmony_ci queue = netdev_get_tx_queue(dev, txq); 11338c2ecf20Sopenharmony_ci queue->trans_start = jiffies; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci /* Notify and wake up reader process */ 11368c2ecf20Sopenharmony_ci if (tfile->flags & TUN_FASYNC) 11378c2ecf20Sopenharmony_ci kill_fasync(&tfile->fasync, SIGIO, POLL_IN); 11388c2ecf20Sopenharmony_ci tfile->socket.sk->sk_data_ready(tfile->socket.sk); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci rcu_read_unlock(); 11418c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cidrop: 11448c2ecf20Sopenharmony_ci this_cpu_inc(tun->pcpu_stats->tx_dropped); 11458c2ecf20Sopenharmony_ci skb_tx_error(skb); 11468c2ecf20Sopenharmony_ci kfree_skb(skb); 11478c2ecf20Sopenharmony_ci rcu_read_unlock(); 11488c2ecf20Sopenharmony_ci return NET_XMIT_DROP; 11498c2ecf20Sopenharmony_ci} 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_cistatic void tun_net_mclist(struct net_device *dev) 11528c2ecf20Sopenharmony_ci{ 11538c2ecf20Sopenharmony_ci /* 11548c2ecf20Sopenharmony_ci * This callback is supposed to deal with mc filter in 11558c2ecf20Sopenharmony_ci * _rx_ path and has nothing to do with the _tx_ path. 11568c2ecf20Sopenharmony_ci * In rx path we always accept everything userspace gives us. 11578c2ecf20Sopenharmony_ci */ 11588c2ecf20Sopenharmony_ci} 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_cistatic netdev_features_t tun_net_fix_features(struct net_device *dev, 11618c2ecf20Sopenharmony_ci netdev_features_t features) 11628c2ecf20Sopenharmony_ci{ 11638c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci return (features & tun->set_features) | (features & ~TUN_USER_FEATURES); 11668c2ecf20Sopenharmony_ci} 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_cistatic void tun_set_headroom(struct net_device *dev, int new_hr) 11698c2ecf20Sopenharmony_ci{ 11708c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci if (new_hr < NET_SKB_PAD) 11738c2ecf20Sopenharmony_ci new_hr = NET_SKB_PAD; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci tun->align = new_hr; 11768c2ecf20Sopenharmony_ci} 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_cistatic void 11798c2ecf20Sopenharmony_citun_net_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) 11808c2ecf20Sopenharmony_ci{ 11818c2ecf20Sopenharmony_ci u32 rx_dropped = 0, tx_dropped = 0, rx_frame_errors = 0; 11828c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 11838c2ecf20Sopenharmony_ci struct tun_pcpu_stats *p; 11848c2ecf20Sopenharmony_ci int i; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci for_each_possible_cpu(i) { 11878c2ecf20Sopenharmony_ci u64 rxpackets, rxbytes, txpackets, txbytes; 11888c2ecf20Sopenharmony_ci unsigned int start; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci p = per_cpu_ptr(tun->pcpu_stats, i); 11918c2ecf20Sopenharmony_ci do { 11928c2ecf20Sopenharmony_ci start = u64_stats_fetch_begin(&p->syncp); 11938c2ecf20Sopenharmony_ci rxpackets = u64_stats_read(&p->rx_packets); 11948c2ecf20Sopenharmony_ci rxbytes = u64_stats_read(&p->rx_bytes); 11958c2ecf20Sopenharmony_ci txpackets = u64_stats_read(&p->tx_packets); 11968c2ecf20Sopenharmony_ci txbytes = u64_stats_read(&p->tx_bytes); 11978c2ecf20Sopenharmony_ci } while (u64_stats_fetch_retry(&p->syncp, start)); 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci stats->rx_packets += rxpackets; 12008c2ecf20Sopenharmony_ci stats->rx_bytes += rxbytes; 12018c2ecf20Sopenharmony_ci stats->tx_packets += txpackets; 12028c2ecf20Sopenharmony_ci stats->tx_bytes += txbytes; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci /* u32 counters */ 12058c2ecf20Sopenharmony_ci rx_dropped += p->rx_dropped; 12068c2ecf20Sopenharmony_ci rx_frame_errors += p->rx_frame_errors; 12078c2ecf20Sopenharmony_ci tx_dropped += p->tx_dropped; 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci stats->rx_dropped = rx_dropped; 12108c2ecf20Sopenharmony_ci stats->rx_frame_errors = rx_frame_errors; 12118c2ecf20Sopenharmony_ci stats->tx_dropped = tx_dropped; 12128c2ecf20Sopenharmony_ci} 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_cistatic int tun_xdp_set(struct net_device *dev, struct bpf_prog *prog, 12158c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 12168c2ecf20Sopenharmony_ci{ 12178c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 12188c2ecf20Sopenharmony_ci struct tun_file *tfile; 12198c2ecf20Sopenharmony_ci struct bpf_prog *old_prog; 12208c2ecf20Sopenharmony_ci int i; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci old_prog = rtnl_dereference(tun->xdp_prog); 12238c2ecf20Sopenharmony_ci rcu_assign_pointer(tun->xdp_prog, prog); 12248c2ecf20Sopenharmony_ci if (old_prog) 12258c2ecf20Sopenharmony_ci bpf_prog_put(old_prog); 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci for (i = 0; i < tun->numqueues; i++) { 12288c2ecf20Sopenharmony_ci tfile = rtnl_dereference(tun->tfiles[i]); 12298c2ecf20Sopenharmony_ci if (prog) 12308c2ecf20Sopenharmony_ci sock_set_flag(&tfile->sk, SOCK_XDP); 12318c2ecf20Sopenharmony_ci else 12328c2ecf20Sopenharmony_ci sock_reset_flag(&tfile->sk, SOCK_XDP); 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci list_for_each_entry(tfile, &tun->disabled, next) { 12358c2ecf20Sopenharmony_ci if (prog) 12368c2ecf20Sopenharmony_ci sock_set_flag(&tfile->sk, SOCK_XDP); 12378c2ecf20Sopenharmony_ci else 12388c2ecf20Sopenharmony_ci sock_reset_flag(&tfile->sk, SOCK_XDP); 12398c2ecf20Sopenharmony_ci } 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci return 0; 12428c2ecf20Sopenharmony_ci} 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_cistatic int tun_xdp(struct net_device *dev, struct netdev_bpf *xdp) 12458c2ecf20Sopenharmony_ci{ 12468c2ecf20Sopenharmony_ci switch (xdp->command) { 12478c2ecf20Sopenharmony_ci case XDP_SETUP_PROG: 12488c2ecf20Sopenharmony_ci return tun_xdp_set(dev, xdp->prog, xdp->extack); 12498c2ecf20Sopenharmony_ci default: 12508c2ecf20Sopenharmony_ci return -EINVAL; 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci} 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_cistatic int tun_net_change_carrier(struct net_device *dev, bool new_carrier) 12558c2ecf20Sopenharmony_ci{ 12568c2ecf20Sopenharmony_ci if (new_carrier) { 12578c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci if (!tun->numqueues) 12608c2ecf20Sopenharmony_ci return -EPERM; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci netif_carrier_on(dev); 12638c2ecf20Sopenharmony_ci } else { 12648c2ecf20Sopenharmony_ci netif_carrier_off(dev); 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci return 0; 12678c2ecf20Sopenharmony_ci} 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_cistatic const struct net_device_ops tun_netdev_ops = { 12708c2ecf20Sopenharmony_ci .ndo_init = tun_net_init, 12718c2ecf20Sopenharmony_ci .ndo_uninit = tun_net_uninit, 12728c2ecf20Sopenharmony_ci .ndo_open = tun_net_open, 12738c2ecf20Sopenharmony_ci .ndo_stop = tun_net_close, 12748c2ecf20Sopenharmony_ci .ndo_start_xmit = tun_net_xmit, 12758c2ecf20Sopenharmony_ci .ndo_fix_features = tun_net_fix_features, 12768c2ecf20Sopenharmony_ci .ndo_select_queue = tun_select_queue, 12778c2ecf20Sopenharmony_ci .ndo_set_rx_headroom = tun_set_headroom, 12788c2ecf20Sopenharmony_ci .ndo_get_stats64 = tun_net_get_stats64, 12798c2ecf20Sopenharmony_ci .ndo_change_carrier = tun_net_change_carrier, 12808c2ecf20Sopenharmony_ci}; 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_cistatic void __tun_xdp_flush_tfile(struct tun_file *tfile) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci /* Notify and wake up reader process */ 12858c2ecf20Sopenharmony_ci if (tfile->flags & TUN_FASYNC) 12868c2ecf20Sopenharmony_ci kill_fasync(&tfile->fasync, SIGIO, POLL_IN); 12878c2ecf20Sopenharmony_ci tfile->socket.sk->sk_data_ready(tfile->socket.sk); 12888c2ecf20Sopenharmony_ci} 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_cistatic int tun_xdp_xmit(struct net_device *dev, int n, 12918c2ecf20Sopenharmony_ci struct xdp_frame **frames, u32 flags) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 12948c2ecf20Sopenharmony_ci struct tun_file *tfile; 12958c2ecf20Sopenharmony_ci u32 numqueues; 12968c2ecf20Sopenharmony_ci int drops = 0; 12978c2ecf20Sopenharmony_ci int cnt = n; 12988c2ecf20Sopenharmony_ci int i; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) 13018c2ecf20Sopenharmony_ci return -EINVAL; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci rcu_read_lock(); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ciresample: 13068c2ecf20Sopenharmony_ci numqueues = READ_ONCE(tun->numqueues); 13078c2ecf20Sopenharmony_ci if (!numqueues) { 13088c2ecf20Sopenharmony_ci rcu_read_unlock(); 13098c2ecf20Sopenharmony_ci return -ENXIO; /* Caller will free/return all frames */ 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci tfile = rcu_dereference(tun->tfiles[smp_processor_id() % 13138c2ecf20Sopenharmony_ci numqueues]); 13148c2ecf20Sopenharmony_ci if (unlikely(!tfile)) 13158c2ecf20Sopenharmony_ci goto resample; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci spin_lock(&tfile->tx_ring.producer_lock); 13188c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 13198c2ecf20Sopenharmony_ci struct xdp_frame *xdp = frames[i]; 13208c2ecf20Sopenharmony_ci /* Encode the XDP flag into lowest bit for consumer to differ 13218c2ecf20Sopenharmony_ci * XDP buffer from sk_buff. 13228c2ecf20Sopenharmony_ci */ 13238c2ecf20Sopenharmony_ci void *frame = tun_xdp_to_ptr(xdp); 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci if (__ptr_ring_produce(&tfile->tx_ring, frame)) { 13268c2ecf20Sopenharmony_ci this_cpu_inc(tun->pcpu_stats->tx_dropped); 13278c2ecf20Sopenharmony_ci xdp_return_frame_rx_napi(xdp); 13288c2ecf20Sopenharmony_ci drops++; 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci spin_unlock(&tfile->tx_ring.producer_lock); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci if (flags & XDP_XMIT_FLUSH) 13348c2ecf20Sopenharmony_ci __tun_xdp_flush_tfile(tfile); 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci rcu_read_unlock(); 13378c2ecf20Sopenharmony_ci return cnt - drops; 13388c2ecf20Sopenharmony_ci} 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_cistatic int tun_xdp_tx(struct net_device *dev, struct xdp_buff *xdp) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci struct xdp_frame *frame = xdp_convert_buff_to_frame(xdp); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci if (unlikely(!frame)) 13458c2ecf20Sopenharmony_ci return -EOVERFLOW; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci return tun_xdp_xmit(dev, 1, &frame, XDP_XMIT_FLUSH); 13488c2ecf20Sopenharmony_ci} 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_cistatic const struct net_device_ops tap_netdev_ops = { 13518c2ecf20Sopenharmony_ci .ndo_init = tun_net_init, 13528c2ecf20Sopenharmony_ci .ndo_uninit = tun_net_uninit, 13538c2ecf20Sopenharmony_ci .ndo_open = tun_net_open, 13548c2ecf20Sopenharmony_ci .ndo_stop = tun_net_close, 13558c2ecf20Sopenharmony_ci .ndo_start_xmit = tun_net_xmit, 13568c2ecf20Sopenharmony_ci .ndo_fix_features = tun_net_fix_features, 13578c2ecf20Sopenharmony_ci .ndo_set_rx_mode = tun_net_mclist, 13588c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 13598c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 13608c2ecf20Sopenharmony_ci .ndo_select_queue = tun_select_queue, 13618c2ecf20Sopenharmony_ci .ndo_features_check = passthru_features_check, 13628c2ecf20Sopenharmony_ci .ndo_set_rx_headroom = tun_set_headroom, 13638c2ecf20Sopenharmony_ci .ndo_get_stats64 = tun_net_get_stats64, 13648c2ecf20Sopenharmony_ci .ndo_bpf = tun_xdp, 13658c2ecf20Sopenharmony_ci .ndo_xdp_xmit = tun_xdp_xmit, 13668c2ecf20Sopenharmony_ci .ndo_change_carrier = tun_net_change_carrier, 13678c2ecf20Sopenharmony_ci}; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_cistatic void tun_flow_init(struct tun_struct *tun) 13708c2ecf20Sopenharmony_ci{ 13718c2ecf20Sopenharmony_ci int i; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci for (i = 0; i < TUN_NUM_FLOW_ENTRIES; i++) 13748c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(&tun->flows[i]); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci tun->ageing_time = TUN_FLOW_EXPIRE; 13778c2ecf20Sopenharmony_ci timer_setup(&tun->flow_gc_timer, tun_flow_cleanup, 0); 13788c2ecf20Sopenharmony_ci mod_timer(&tun->flow_gc_timer, 13798c2ecf20Sopenharmony_ci round_jiffies_up(jiffies + tun->ageing_time)); 13808c2ecf20Sopenharmony_ci} 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_cistatic void tun_flow_uninit(struct tun_struct *tun) 13838c2ecf20Sopenharmony_ci{ 13848c2ecf20Sopenharmony_ci del_timer_sync(&tun->flow_gc_timer); 13858c2ecf20Sopenharmony_ci tun_flow_flush(tun); 13868c2ecf20Sopenharmony_ci} 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci#define MIN_MTU 68 13898c2ecf20Sopenharmony_ci#define MAX_MTU 65535 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci/* Initialize net device. */ 13928c2ecf20Sopenharmony_cistatic void tun_net_initialize(struct net_device *dev) 13938c2ecf20Sopenharmony_ci{ 13948c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci switch (tun->flags & TUN_TYPE_MASK) { 13978c2ecf20Sopenharmony_ci case IFF_TUN: 13988c2ecf20Sopenharmony_ci dev->netdev_ops = &tun_netdev_ops; 13998c2ecf20Sopenharmony_ci dev->header_ops = &ip_tunnel_header_ops; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci /* Point-to-Point TUN Device */ 14028c2ecf20Sopenharmony_ci dev->hard_header_len = 0; 14038c2ecf20Sopenharmony_ci dev->addr_len = 0; 14048c2ecf20Sopenharmony_ci dev->mtu = 1500; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci /* Zero header length */ 14078c2ecf20Sopenharmony_ci dev->type = ARPHRD_NONE; 14088c2ecf20Sopenharmony_ci dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; 14098c2ecf20Sopenharmony_ci break; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci case IFF_TAP: 14128c2ecf20Sopenharmony_ci dev->netdev_ops = &tap_netdev_ops; 14138c2ecf20Sopenharmony_ci /* Ethernet TAP Device */ 14148c2ecf20Sopenharmony_ci ether_setup(dev); 14158c2ecf20Sopenharmony_ci dev->priv_flags &= ~IFF_TX_SKB_SHARING; 14168c2ecf20Sopenharmony_ci dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci eth_hw_addr_random(dev); 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci break; 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci dev->min_mtu = MIN_MTU; 14248c2ecf20Sopenharmony_ci dev->max_mtu = MAX_MTU - dev->hard_header_len; 14258c2ecf20Sopenharmony_ci} 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_cistatic bool tun_sock_writeable(struct tun_struct *tun, struct tun_file *tfile) 14288c2ecf20Sopenharmony_ci{ 14298c2ecf20Sopenharmony_ci struct sock *sk = tfile->socket.sk; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci return (tun->dev->flags & IFF_UP) && sock_writeable(sk); 14328c2ecf20Sopenharmony_ci} 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci/* Character device part */ 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci/* Poll */ 14378c2ecf20Sopenharmony_cistatic __poll_t tun_chr_poll(struct file *file, poll_table *wait) 14388c2ecf20Sopenharmony_ci{ 14398c2ecf20Sopenharmony_ci struct tun_file *tfile = file->private_data; 14408c2ecf20Sopenharmony_ci struct tun_struct *tun = tun_get(tfile); 14418c2ecf20Sopenharmony_ci struct sock *sk; 14428c2ecf20Sopenharmony_ci __poll_t mask = 0; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci if (!tun) 14458c2ecf20Sopenharmony_ci return EPOLLERR; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci sk = tfile->socket.sk; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci poll_wait(file, sk_sleep(sk), wait); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci if (!ptr_ring_empty(&tfile->tx_ring)) 14528c2ecf20Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci /* Make sure SOCKWQ_ASYNC_NOSPACE is set if not writable to 14558c2ecf20Sopenharmony_ci * guarantee EPOLLOUT to be raised by either here or 14568c2ecf20Sopenharmony_ci * tun_sock_write_space(). Then process could get notification 14578c2ecf20Sopenharmony_ci * after it writes to a down device and meets -EIO. 14588c2ecf20Sopenharmony_ci */ 14598c2ecf20Sopenharmony_ci if (tun_sock_writeable(tun, tfile) || 14608c2ecf20Sopenharmony_ci (!test_and_set_bit(SOCKWQ_ASYNC_NOSPACE, &sk->sk_socket->flags) && 14618c2ecf20Sopenharmony_ci tun_sock_writeable(tun, tfile))) 14628c2ecf20Sopenharmony_ci mask |= EPOLLOUT | EPOLLWRNORM; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci if (tun->dev->reg_state != NETREG_REGISTERED) 14658c2ecf20Sopenharmony_ci mask = EPOLLERR; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci tun_put(tun); 14688c2ecf20Sopenharmony_ci return mask; 14698c2ecf20Sopenharmony_ci} 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_cistatic struct sk_buff *tun_napi_alloc_frags(struct tun_file *tfile, 14728c2ecf20Sopenharmony_ci size_t len, 14738c2ecf20Sopenharmony_ci const struct iov_iter *it) 14748c2ecf20Sopenharmony_ci{ 14758c2ecf20Sopenharmony_ci struct sk_buff *skb; 14768c2ecf20Sopenharmony_ci size_t linear; 14778c2ecf20Sopenharmony_ci int err; 14788c2ecf20Sopenharmony_ci int i; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci if (it->nr_segs > MAX_SKB_FRAGS + 1 || 14818c2ecf20Sopenharmony_ci len > (ETH_MAX_MTU - NET_SKB_PAD - NET_IP_ALIGN)) 14828c2ecf20Sopenharmony_ci return ERR_PTR(-EMSGSIZE); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci local_bh_disable(); 14858c2ecf20Sopenharmony_ci skb = napi_get_frags(&tfile->napi); 14868c2ecf20Sopenharmony_ci local_bh_enable(); 14878c2ecf20Sopenharmony_ci if (!skb) 14888c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci linear = iov_iter_single_seg_count(it); 14918c2ecf20Sopenharmony_ci err = __skb_grow(skb, linear); 14928c2ecf20Sopenharmony_ci if (err) 14938c2ecf20Sopenharmony_ci goto free; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci skb->len = len; 14968c2ecf20Sopenharmony_ci skb->data_len = len - linear; 14978c2ecf20Sopenharmony_ci skb->truesize += skb->data_len; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci for (i = 1; i < it->nr_segs; i++) { 15008c2ecf20Sopenharmony_ci size_t fragsz = it->iov[i].iov_len; 15018c2ecf20Sopenharmony_ci struct page *page; 15028c2ecf20Sopenharmony_ci void *frag; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci if (fragsz == 0 || fragsz > PAGE_SIZE) { 15058c2ecf20Sopenharmony_ci err = -EINVAL; 15068c2ecf20Sopenharmony_ci goto free; 15078c2ecf20Sopenharmony_ci } 15088c2ecf20Sopenharmony_ci frag = netdev_alloc_frag(fragsz); 15098c2ecf20Sopenharmony_ci if (!frag) { 15108c2ecf20Sopenharmony_ci err = -ENOMEM; 15118c2ecf20Sopenharmony_ci goto free; 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci page = virt_to_head_page(frag); 15148c2ecf20Sopenharmony_ci skb_fill_page_desc(skb, i - 1, page, 15158c2ecf20Sopenharmony_ci frag - page_address(page), fragsz); 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci return skb; 15198c2ecf20Sopenharmony_cifree: 15208c2ecf20Sopenharmony_ci /* frees skb and all frags allocated with napi_alloc_frag() */ 15218c2ecf20Sopenharmony_ci napi_free_frags(&tfile->napi); 15228c2ecf20Sopenharmony_ci return ERR_PTR(err); 15238c2ecf20Sopenharmony_ci} 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci/* prepad is the amount to reserve at front. len is length after that. 15268c2ecf20Sopenharmony_ci * linear is a hint as to how much to copy (usually headers). */ 15278c2ecf20Sopenharmony_cistatic struct sk_buff *tun_alloc_skb(struct tun_file *tfile, 15288c2ecf20Sopenharmony_ci size_t prepad, size_t len, 15298c2ecf20Sopenharmony_ci size_t linear, int noblock) 15308c2ecf20Sopenharmony_ci{ 15318c2ecf20Sopenharmony_ci struct sock *sk = tfile->socket.sk; 15328c2ecf20Sopenharmony_ci struct sk_buff *skb; 15338c2ecf20Sopenharmony_ci int err; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci /* Under a page? Don't bother with paged skb. */ 15368c2ecf20Sopenharmony_ci if (prepad + len < PAGE_SIZE || !linear) 15378c2ecf20Sopenharmony_ci linear = len; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci skb = sock_alloc_send_pskb(sk, prepad + linear, len - linear, noblock, 15408c2ecf20Sopenharmony_ci &err, 0); 15418c2ecf20Sopenharmony_ci if (!skb) 15428c2ecf20Sopenharmony_ci return ERR_PTR(err); 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci skb_reserve(skb, prepad); 15458c2ecf20Sopenharmony_ci skb_put(skb, linear); 15468c2ecf20Sopenharmony_ci skb->data_len = len - linear; 15478c2ecf20Sopenharmony_ci skb->len += len - linear; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci return skb; 15508c2ecf20Sopenharmony_ci} 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_cistatic void tun_rx_batched(struct tun_struct *tun, struct tun_file *tfile, 15538c2ecf20Sopenharmony_ci struct sk_buff *skb, int more) 15548c2ecf20Sopenharmony_ci{ 15558c2ecf20Sopenharmony_ci struct sk_buff_head *queue = &tfile->sk.sk_write_queue; 15568c2ecf20Sopenharmony_ci struct sk_buff_head process_queue; 15578c2ecf20Sopenharmony_ci u32 rx_batched = tun->rx_batched; 15588c2ecf20Sopenharmony_ci bool rcv = false; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci if (!rx_batched || (!more && skb_queue_empty(queue))) { 15618c2ecf20Sopenharmony_ci local_bh_disable(); 15628c2ecf20Sopenharmony_ci skb_record_rx_queue(skb, tfile->queue_index); 15638c2ecf20Sopenharmony_ci netif_receive_skb(skb); 15648c2ecf20Sopenharmony_ci local_bh_enable(); 15658c2ecf20Sopenharmony_ci return; 15668c2ecf20Sopenharmony_ci } 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci spin_lock(&queue->lock); 15698c2ecf20Sopenharmony_ci if (!more || skb_queue_len(queue) == rx_batched) { 15708c2ecf20Sopenharmony_ci __skb_queue_head_init(&process_queue); 15718c2ecf20Sopenharmony_ci skb_queue_splice_tail_init(queue, &process_queue); 15728c2ecf20Sopenharmony_ci rcv = true; 15738c2ecf20Sopenharmony_ci } else { 15748c2ecf20Sopenharmony_ci __skb_queue_tail(queue, skb); 15758c2ecf20Sopenharmony_ci } 15768c2ecf20Sopenharmony_ci spin_unlock(&queue->lock); 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci if (rcv) { 15798c2ecf20Sopenharmony_ci struct sk_buff *nskb; 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci local_bh_disable(); 15828c2ecf20Sopenharmony_ci while ((nskb = __skb_dequeue(&process_queue))) { 15838c2ecf20Sopenharmony_ci skb_record_rx_queue(nskb, tfile->queue_index); 15848c2ecf20Sopenharmony_ci netif_receive_skb(nskb); 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci skb_record_rx_queue(skb, tfile->queue_index); 15878c2ecf20Sopenharmony_ci netif_receive_skb(skb); 15888c2ecf20Sopenharmony_ci local_bh_enable(); 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci} 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_cistatic bool tun_can_build_skb(struct tun_struct *tun, struct tun_file *tfile, 15938c2ecf20Sopenharmony_ci int len, int noblock, bool zerocopy) 15948c2ecf20Sopenharmony_ci{ 15958c2ecf20Sopenharmony_ci if ((tun->flags & TUN_TYPE_MASK) != IFF_TAP) 15968c2ecf20Sopenharmony_ci return false; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci if (tfile->socket.sk->sk_sndbuf != INT_MAX) 15998c2ecf20Sopenharmony_ci return false; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci if (!noblock) 16028c2ecf20Sopenharmony_ci return false; 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci if (zerocopy) 16058c2ecf20Sopenharmony_ci return false; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci if (SKB_DATA_ALIGN(len + TUN_RX_PAD + XDP_PACKET_HEADROOM) + 16088c2ecf20Sopenharmony_ci SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) > PAGE_SIZE) 16098c2ecf20Sopenharmony_ci return false; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci return true; 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_cistatic struct sk_buff *__tun_build_skb(struct tun_file *tfile, 16158c2ecf20Sopenharmony_ci struct page_frag *alloc_frag, char *buf, 16168c2ecf20Sopenharmony_ci int buflen, int len, int pad) 16178c2ecf20Sopenharmony_ci{ 16188c2ecf20Sopenharmony_ci struct sk_buff *skb = build_skb(buf, buflen); 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci if (!skb) 16218c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci skb_reserve(skb, pad); 16248c2ecf20Sopenharmony_ci skb_put(skb, len); 16258c2ecf20Sopenharmony_ci skb_set_owner_w(skb, tfile->socket.sk); 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci get_page(alloc_frag->page); 16288c2ecf20Sopenharmony_ci alloc_frag->offset += buflen; 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci return skb; 16318c2ecf20Sopenharmony_ci} 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_cistatic int tun_xdp_act(struct tun_struct *tun, struct bpf_prog *xdp_prog, 16348c2ecf20Sopenharmony_ci struct xdp_buff *xdp, u32 act) 16358c2ecf20Sopenharmony_ci{ 16368c2ecf20Sopenharmony_ci int err; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci switch (act) { 16398c2ecf20Sopenharmony_ci case XDP_REDIRECT: 16408c2ecf20Sopenharmony_ci err = xdp_do_redirect(tun->dev, xdp, xdp_prog); 16418c2ecf20Sopenharmony_ci if (err) 16428c2ecf20Sopenharmony_ci return err; 16438c2ecf20Sopenharmony_ci break; 16448c2ecf20Sopenharmony_ci case XDP_TX: 16458c2ecf20Sopenharmony_ci err = tun_xdp_tx(tun->dev, xdp); 16468c2ecf20Sopenharmony_ci if (err < 0) 16478c2ecf20Sopenharmony_ci return err; 16488c2ecf20Sopenharmony_ci break; 16498c2ecf20Sopenharmony_ci case XDP_PASS: 16508c2ecf20Sopenharmony_ci break; 16518c2ecf20Sopenharmony_ci default: 16528c2ecf20Sopenharmony_ci bpf_warn_invalid_xdp_action(act); 16538c2ecf20Sopenharmony_ci fallthrough; 16548c2ecf20Sopenharmony_ci case XDP_ABORTED: 16558c2ecf20Sopenharmony_ci trace_xdp_exception(tun->dev, xdp_prog, act); 16568c2ecf20Sopenharmony_ci fallthrough; 16578c2ecf20Sopenharmony_ci case XDP_DROP: 16588c2ecf20Sopenharmony_ci this_cpu_inc(tun->pcpu_stats->rx_dropped); 16598c2ecf20Sopenharmony_ci break; 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci return act; 16638c2ecf20Sopenharmony_ci} 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_cistatic struct sk_buff *tun_build_skb(struct tun_struct *tun, 16668c2ecf20Sopenharmony_ci struct tun_file *tfile, 16678c2ecf20Sopenharmony_ci struct iov_iter *from, 16688c2ecf20Sopenharmony_ci struct virtio_net_hdr *hdr, 16698c2ecf20Sopenharmony_ci int len, int *skb_xdp) 16708c2ecf20Sopenharmony_ci{ 16718c2ecf20Sopenharmony_ci struct page_frag *alloc_frag = ¤t->task_frag; 16728c2ecf20Sopenharmony_ci struct bpf_prog *xdp_prog; 16738c2ecf20Sopenharmony_ci int buflen = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 16748c2ecf20Sopenharmony_ci char *buf; 16758c2ecf20Sopenharmony_ci size_t copied; 16768c2ecf20Sopenharmony_ci int pad = TUN_RX_PAD; 16778c2ecf20Sopenharmony_ci int err = 0; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci rcu_read_lock(); 16808c2ecf20Sopenharmony_ci xdp_prog = rcu_dereference(tun->xdp_prog); 16818c2ecf20Sopenharmony_ci if (xdp_prog) 16828c2ecf20Sopenharmony_ci pad += XDP_PACKET_HEADROOM; 16838c2ecf20Sopenharmony_ci buflen += SKB_DATA_ALIGN(len + pad); 16848c2ecf20Sopenharmony_ci rcu_read_unlock(); 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci alloc_frag->offset = ALIGN((u64)alloc_frag->offset, SMP_CACHE_BYTES); 16878c2ecf20Sopenharmony_ci if (unlikely(!skb_page_frag_refill(buflen, alloc_frag, GFP_KERNEL))) 16888c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci buf = (char *)page_address(alloc_frag->page) + alloc_frag->offset; 16918c2ecf20Sopenharmony_ci copied = copy_page_from_iter(alloc_frag->page, 16928c2ecf20Sopenharmony_ci alloc_frag->offset + pad, 16938c2ecf20Sopenharmony_ci len, from); 16948c2ecf20Sopenharmony_ci if (copied != len) 16958c2ecf20Sopenharmony_ci return ERR_PTR(-EFAULT); 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci /* There's a small window that XDP may be set after the check 16988c2ecf20Sopenharmony_ci * of xdp_prog above, this should be rare and for simplicity 16998c2ecf20Sopenharmony_ci * we do XDP on skb in case the headroom is not enough. 17008c2ecf20Sopenharmony_ci */ 17018c2ecf20Sopenharmony_ci if (hdr->gso_type || !xdp_prog) { 17028c2ecf20Sopenharmony_ci *skb_xdp = 1; 17038c2ecf20Sopenharmony_ci return __tun_build_skb(tfile, alloc_frag, buf, buflen, len, 17048c2ecf20Sopenharmony_ci pad); 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci *skb_xdp = 0; 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci local_bh_disable(); 17108c2ecf20Sopenharmony_ci rcu_read_lock(); 17118c2ecf20Sopenharmony_ci xdp_prog = rcu_dereference(tun->xdp_prog); 17128c2ecf20Sopenharmony_ci if (xdp_prog) { 17138c2ecf20Sopenharmony_ci struct xdp_buff xdp; 17148c2ecf20Sopenharmony_ci u32 act; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci xdp.data_hard_start = buf; 17178c2ecf20Sopenharmony_ci xdp.data = buf + pad; 17188c2ecf20Sopenharmony_ci xdp_set_data_meta_invalid(&xdp); 17198c2ecf20Sopenharmony_ci xdp.data_end = xdp.data + len; 17208c2ecf20Sopenharmony_ci xdp.rxq = &tfile->xdp_rxq; 17218c2ecf20Sopenharmony_ci xdp.frame_sz = buflen; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci act = bpf_prog_run_xdp(xdp_prog, &xdp); 17248c2ecf20Sopenharmony_ci if (act == XDP_REDIRECT || act == XDP_TX) { 17258c2ecf20Sopenharmony_ci get_page(alloc_frag->page); 17268c2ecf20Sopenharmony_ci alloc_frag->offset += buflen; 17278c2ecf20Sopenharmony_ci } 17288c2ecf20Sopenharmony_ci err = tun_xdp_act(tun, xdp_prog, &xdp, act); 17298c2ecf20Sopenharmony_ci if (err < 0) { 17308c2ecf20Sopenharmony_ci if (act == XDP_REDIRECT || act == XDP_TX) 17318c2ecf20Sopenharmony_ci put_page(alloc_frag->page); 17328c2ecf20Sopenharmony_ci goto out; 17338c2ecf20Sopenharmony_ci } 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci if (err == XDP_REDIRECT) 17368c2ecf20Sopenharmony_ci xdp_do_flush(); 17378c2ecf20Sopenharmony_ci if (err != XDP_PASS) 17388c2ecf20Sopenharmony_ci goto out; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci pad = xdp.data - xdp.data_hard_start; 17418c2ecf20Sopenharmony_ci len = xdp.data_end - xdp.data; 17428c2ecf20Sopenharmony_ci } 17438c2ecf20Sopenharmony_ci rcu_read_unlock(); 17448c2ecf20Sopenharmony_ci local_bh_enable(); 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci return __tun_build_skb(tfile, alloc_frag, buf, buflen, len, pad); 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ciout: 17498c2ecf20Sopenharmony_ci rcu_read_unlock(); 17508c2ecf20Sopenharmony_ci local_bh_enable(); 17518c2ecf20Sopenharmony_ci return NULL; 17528c2ecf20Sopenharmony_ci} 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci/* Get packet from user space buffer */ 17558c2ecf20Sopenharmony_cistatic ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, 17568c2ecf20Sopenharmony_ci void *msg_control, struct iov_iter *from, 17578c2ecf20Sopenharmony_ci int noblock, bool more) 17588c2ecf20Sopenharmony_ci{ 17598c2ecf20Sopenharmony_ci struct tun_pi pi = { 0, cpu_to_be16(ETH_P_IP) }; 17608c2ecf20Sopenharmony_ci struct sk_buff *skb; 17618c2ecf20Sopenharmony_ci size_t total_len = iov_iter_count(from); 17628c2ecf20Sopenharmony_ci size_t len = total_len, align = tun->align, linear; 17638c2ecf20Sopenharmony_ci struct virtio_net_hdr gso = { 0 }; 17648c2ecf20Sopenharmony_ci struct tun_pcpu_stats *stats; 17658c2ecf20Sopenharmony_ci int good_linear; 17668c2ecf20Sopenharmony_ci int copylen; 17678c2ecf20Sopenharmony_ci bool zerocopy = false; 17688c2ecf20Sopenharmony_ci int err; 17698c2ecf20Sopenharmony_ci u32 rxhash = 0; 17708c2ecf20Sopenharmony_ci int skb_xdp = 1; 17718c2ecf20Sopenharmony_ci bool frags = tun_napi_frags_enabled(tfile); 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci if (!(tun->flags & IFF_NO_PI)) { 17748c2ecf20Sopenharmony_ci if (len < sizeof(pi)) 17758c2ecf20Sopenharmony_ci return -EINVAL; 17768c2ecf20Sopenharmony_ci len -= sizeof(pi); 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci if (!copy_from_iter_full(&pi, sizeof(pi), from)) 17798c2ecf20Sopenharmony_ci return -EFAULT; 17808c2ecf20Sopenharmony_ci } 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci if (tun->flags & IFF_VNET_HDR) { 17838c2ecf20Sopenharmony_ci int vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz); 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci if (len < vnet_hdr_sz) 17868c2ecf20Sopenharmony_ci return -EINVAL; 17878c2ecf20Sopenharmony_ci len -= vnet_hdr_sz; 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci if (!copy_from_iter_full(&gso, sizeof(gso), from)) 17908c2ecf20Sopenharmony_ci return -EFAULT; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && 17938c2ecf20Sopenharmony_ci tun16_to_cpu(tun, gso.csum_start) + tun16_to_cpu(tun, gso.csum_offset) + 2 > tun16_to_cpu(tun, gso.hdr_len)) 17948c2ecf20Sopenharmony_ci gso.hdr_len = cpu_to_tun16(tun, tun16_to_cpu(tun, gso.csum_start) + tun16_to_cpu(tun, gso.csum_offset) + 2); 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci if (tun16_to_cpu(tun, gso.hdr_len) > len) 17978c2ecf20Sopenharmony_ci return -EINVAL; 17988c2ecf20Sopenharmony_ci iov_iter_advance(from, vnet_hdr_sz - sizeof(gso)); 17998c2ecf20Sopenharmony_ci } 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP) { 18028c2ecf20Sopenharmony_ci align += NET_IP_ALIGN; 18038c2ecf20Sopenharmony_ci if (unlikely(len < ETH_HLEN || 18048c2ecf20Sopenharmony_ci (gso.hdr_len && tun16_to_cpu(tun, gso.hdr_len) < ETH_HLEN))) 18058c2ecf20Sopenharmony_ci return -EINVAL; 18068c2ecf20Sopenharmony_ci } 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci good_linear = SKB_MAX_HEAD(align); 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci if (msg_control) { 18118c2ecf20Sopenharmony_ci struct iov_iter i = *from; 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci /* There are 256 bytes to be copied in skb, so there is 18148c2ecf20Sopenharmony_ci * enough room for skb expand head in case it is used. 18158c2ecf20Sopenharmony_ci * The rest of the buffer is mapped from userspace. 18168c2ecf20Sopenharmony_ci */ 18178c2ecf20Sopenharmony_ci copylen = gso.hdr_len ? tun16_to_cpu(tun, gso.hdr_len) : GOODCOPY_LEN; 18188c2ecf20Sopenharmony_ci if (copylen > good_linear) 18198c2ecf20Sopenharmony_ci copylen = good_linear; 18208c2ecf20Sopenharmony_ci linear = copylen; 18218c2ecf20Sopenharmony_ci iov_iter_advance(&i, copylen); 18228c2ecf20Sopenharmony_ci if (iov_iter_npages(&i, INT_MAX) <= MAX_SKB_FRAGS) 18238c2ecf20Sopenharmony_ci zerocopy = true; 18248c2ecf20Sopenharmony_ci } 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci if (!frags && tun_can_build_skb(tun, tfile, len, noblock, zerocopy)) { 18278c2ecf20Sopenharmony_ci /* For the packet that is not easy to be processed 18288c2ecf20Sopenharmony_ci * (e.g gso or jumbo packet), we will do it at after 18298c2ecf20Sopenharmony_ci * skb was created with generic XDP routine. 18308c2ecf20Sopenharmony_ci */ 18318c2ecf20Sopenharmony_ci skb = tun_build_skb(tun, tfile, from, &gso, len, &skb_xdp); 18328c2ecf20Sopenharmony_ci if (IS_ERR(skb)) { 18338c2ecf20Sopenharmony_ci this_cpu_inc(tun->pcpu_stats->rx_dropped); 18348c2ecf20Sopenharmony_ci return PTR_ERR(skb); 18358c2ecf20Sopenharmony_ci } 18368c2ecf20Sopenharmony_ci if (!skb) 18378c2ecf20Sopenharmony_ci return total_len; 18388c2ecf20Sopenharmony_ci } else { 18398c2ecf20Sopenharmony_ci if (!zerocopy) { 18408c2ecf20Sopenharmony_ci copylen = len; 18418c2ecf20Sopenharmony_ci if (tun16_to_cpu(tun, gso.hdr_len) > good_linear) 18428c2ecf20Sopenharmony_ci linear = good_linear; 18438c2ecf20Sopenharmony_ci else 18448c2ecf20Sopenharmony_ci linear = tun16_to_cpu(tun, gso.hdr_len); 18458c2ecf20Sopenharmony_ci } 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci if (frags) { 18488c2ecf20Sopenharmony_ci mutex_lock(&tfile->napi_mutex); 18498c2ecf20Sopenharmony_ci skb = tun_napi_alloc_frags(tfile, copylen, from); 18508c2ecf20Sopenharmony_ci /* tun_napi_alloc_frags() enforces a layout for the skb. 18518c2ecf20Sopenharmony_ci * If zerocopy is enabled, then this layout will be 18528c2ecf20Sopenharmony_ci * overwritten by zerocopy_sg_from_iter(). 18538c2ecf20Sopenharmony_ci */ 18548c2ecf20Sopenharmony_ci zerocopy = false; 18558c2ecf20Sopenharmony_ci } else { 18568c2ecf20Sopenharmony_ci skb = tun_alloc_skb(tfile, align, copylen, linear, 18578c2ecf20Sopenharmony_ci noblock); 18588c2ecf20Sopenharmony_ci } 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci if (IS_ERR(skb)) { 18618c2ecf20Sopenharmony_ci if (PTR_ERR(skb) != -EAGAIN) 18628c2ecf20Sopenharmony_ci this_cpu_inc(tun->pcpu_stats->rx_dropped); 18638c2ecf20Sopenharmony_ci if (frags) 18648c2ecf20Sopenharmony_ci mutex_unlock(&tfile->napi_mutex); 18658c2ecf20Sopenharmony_ci return PTR_ERR(skb); 18668c2ecf20Sopenharmony_ci } 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci if (zerocopy) 18698c2ecf20Sopenharmony_ci err = zerocopy_sg_from_iter(skb, from); 18708c2ecf20Sopenharmony_ci else 18718c2ecf20Sopenharmony_ci err = skb_copy_datagram_from_iter(skb, 0, from, len); 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci if (err) { 18748c2ecf20Sopenharmony_ci err = -EFAULT; 18758c2ecf20Sopenharmony_cidrop: 18768c2ecf20Sopenharmony_ci this_cpu_inc(tun->pcpu_stats->rx_dropped); 18778c2ecf20Sopenharmony_ci kfree_skb(skb); 18788c2ecf20Sopenharmony_ci if (frags) { 18798c2ecf20Sopenharmony_ci tfile->napi.skb = NULL; 18808c2ecf20Sopenharmony_ci mutex_unlock(&tfile->napi_mutex); 18818c2ecf20Sopenharmony_ci } 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci return err; 18848c2ecf20Sopenharmony_ci } 18858c2ecf20Sopenharmony_ci } 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci if (virtio_net_hdr_to_skb(skb, &gso, tun_is_little_endian(tun))) { 18888c2ecf20Sopenharmony_ci this_cpu_inc(tun->pcpu_stats->rx_frame_errors); 18898c2ecf20Sopenharmony_ci kfree_skb(skb); 18908c2ecf20Sopenharmony_ci if (frags) { 18918c2ecf20Sopenharmony_ci tfile->napi.skb = NULL; 18928c2ecf20Sopenharmony_ci mutex_unlock(&tfile->napi_mutex); 18938c2ecf20Sopenharmony_ci } 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci return -EINVAL; 18968c2ecf20Sopenharmony_ci } 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci switch (tun->flags & TUN_TYPE_MASK) { 18998c2ecf20Sopenharmony_ci case IFF_TUN: 19008c2ecf20Sopenharmony_ci if (tun->flags & IFF_NO_PI) { 19018c2ecf20Sopenharmony_ci u8 ip_version = skb->len ? (skb->data[0] >> 4) : 0; 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci switch (ip_version) { 19048c2ecf20Sopenharmony_ci case 4: 19058c2ecf20Sopenharmony_ci pi.proto = htons(ETH_P_IP); 19068c2ecf20Sopenharmony_ci break; 19078c2ecf20Sopenharmony_ci case 6: 19088c2ecf20Sopenharmony_ci pi.proto = htons(ETH_P_IPV6); 19098c2ecf20Sopenharmony_ci break; 19108c2ecf20Sopenharmony_ci default: 19118c2ecf20Sopenharmony_ci this_cpu_inc(tun->pcpu_stats->rx_dropped); 19128c2ecf20Sopenharmony_ci kfree_skb(skb); 19138c2ecf20Sopenharmony_ci return -EINVAL; 19148c2ecf20Sopenharmony_ci } 19158c2ecf20Sopenharmony_ci } 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 19188c2ecf20Sopenharmony_ci skb->protocol = pi.proto; 19198c2ecf20Sopenharmony_ci skb->dev = tun->dev; 19208c2ecf20Sopenharmony_ci break; 19218c2ecf20Sopenharmony_ci case IFF_TAP: 19228c2ecf20Sopenharmony_ci if (frags && !pskb_may_pull(skb, ETH_HLEN)) { 19238c2ecf20Sopenharmony_ci err = -ENOMEM; 19248c2ecf20Sopenharmony_ci goto drop; 19258c2ecf20Sopenharmony_ci } 19268c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, tun->dev); 19278c2ecf20Sopenharmony_ci break; 19288c2ecf20Sopenharmony_ci } 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci /* copy skb_ubuf_info for callback when skb has no error */ 19318c2ecf20Sopenharmony_ci if (zerocopy) { 19328c2ecf20Sopenharmony_ci skb_shinfo(skb)->destructor_arg = msg_control; 19338c2ecf20Sopenharmony_ci skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; 19348c2ecf20Sopenharmony_ci skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; 19358c2ecf20Sopenharmony_ci } else if (msg_control) { 19368c2ecf20Sopenharmony_ci struct ubuf_info *uarg = msg_control; 19378c2ecf20Sopenharmony_ci uarg->callback(uarg, false); 19388c2ecf20Sopenharmony_ci } 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 19418c2ecf20Sopenharmony_ci skb_probe_transport_header(skb); 19428c2ecf20Sopenharmony_ci skb_record_rx_queue(skb, tfile->queue_index); 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci if (skb_xdp) { 19458c2ecf20Sopenharmony_ci struct bpf_prog *xdp_prog; 19468c2ecf20Sopenharmony_ci int ret; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci local_bh_disable(); 19498c2ecf20Sopenharmony_ci rcu_read_lock(); 19508c2ecf20Sopenharmony_ci xdp_prog = rcu_dereference(tun->xdp_prog); 19518c2ecf20Sopenharmony_ci if (xdp_prog) { 19528c2ecf20Sopenharmony_ci ret = do_xdp_generic(xdp_prog, skb); 19538c2ecf20Sopenharmony_ci if (ret != XDP_PASS) { 19548c2ecf20Sopenharmony_ci rcu_read_unlock(); 19558c2ecf20Sopenharmony_ci local_bh_enable(); 19568c2ecf20Sopenharmony_ci if (frags) { 19578c2ecf20Sopenharmony_ci tfile->napi.skb = NULL; 19588c2ecf20Sopenharmony_ci mutex_unlock(&tfile->napi_mutex); 19598c2ecf20Sopenharmony_ci } 19608c2ecf20Sopenharmony_ci return total_len; 19618c2ecf20Sopenharmony_ci } 19628c2ecf20Sopenharmony_ci } 19638c2ecf20Sopenharmony_ci rcu_read_unlock(); 19648c2ecf20Sopenharmony_ci local_bh_enable(); 19658c2ecf20Sopenharmony_ci } 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci /* Compute the costly rx hash only if needed for flow updates. 19688c2ecf20Sopenharmony_ci * We may get a very small possibility of OOO during switching, not 19698c2ecf20Sopenharmony_ci * worth to optimize. 19708c2ecf20Sopenharmony_ci */ 19718c2ecf20Sopenharmony_ci if (!rcu_access_pointer(tun->steering_prog) && tun->numqueues > 1 && 19728c2ecf20Sopenharmony_ci !tfile->detached) 19738c2ecf20Sopenharmony_ci rxhash = __skb_get_hash_symmetric(skb); 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci rcu_read_lock(); 19768c2ecf20Sopenharmony_ci if (unlikely(!(tun->dev->flags & IFF_UP))) { 19778c2ecf20Sopenharmony_ci err = -EIO; 19788c2ecf20Sopenharmony_ci rcu_read_unlock(); 19798c2ecf20Sopenharmony_ci goto drop; 19808c2ecf20Sopenharmony_ci } 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci if (frags) { 19838c2ecf20Sopenharmony_ci u32 headlen; 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci /* Exercise flow dissector code path. */ 19868c2ecf20Sopenharmony_ci skb_push(skb, ETH_HLEN); 19878c2ecf20Sopenharmony_ci headlen = eth_get_headlen(tun->dev, skb->data, 19888c2ecf20Sopenharmony_ci skb_headlen(skb)); 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci if (unlikely(headlen > skb_headlen(skb))) { 19918c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 19928c2ecf20Sopenharmony_ci err = -ENOMEM; 19938c2ecf20Sopenharmony_ci this_cpu_inc(tun->pcpu_stats->rx_dropped); 19948c2ecf20Sopenharmony_cinapi_busy: 19958c2ecf20Sopenharmony_ci napi_free_frags(&tfile->napi); 19968c2ecf20Sopenharmony_ci rcu_read_unlock(); 19978c2ecf20Sopenharmony_ci mutex_unlock(&tfile->napi_mutex); 19988c2ecf20Sopenharmony_ci return err; 19998c2ecf20Sopenharmony_ci } 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci if (likely(napi_schedule_prep(&tfile->napi))) { 20028c2ecf20Sopenharmony_ci local_bh_disable(); 20038c2ecf20Sopenharmony_ci napi_gro_frags(&tfile->napi); 20048c2ecf20Sopenharmony_ci napi_complete(&tfile->napi); 20058c2ecf20Sopenharmony_ci local_bh_enable(); 20068c2ecf20Sopenharmony_ci } else { 20078c2ecf20Sopenharmony_ci err = -EBUSY; 20088c2ecf20Sopenharmony_ci goto napi_busy; 20098c2ecf20Sopenharmony_ci } 20108c2ecf20Sopenharmony_ci mutex_unlock(&tfile->napi_mutex); 20118c2ecf20Sopenharmony_ci } else if (tfile->napi_enabled) { 20128c2ecf20Sopenharmony_ci struct sk_buff_head *queue = &tfile->sk.sk_write_queue; 20138c2ecf20Sopenharmony_ci int queue_len; 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci spin_lock_bh(&queue->lock); 20168c2ecf20Sopenharmony_ci __skb_queue_tail(queue, skb); 20178c2ecf20Sopenharmony_ci queue_len = skb_queue_len(queue); 20188c2ecf20Sopenharmony_ci spin_unlock(&queue->lock); 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci if (!more || queue_len > NAPI_POLL_WEIGHT) 20218c2ecf20Sopenharmony_ci napi_schedule(&tfile->napi); 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci local_bh_enable(); 20248c2ecf20Sopenharmony_ci } else if (!IS_ENABLED(CONFIG_4KSTACKS)) { 20258c2ecf20Sopenharmony_ci tun_rx_batched(tun, tfile, skb, more); 20268c2ecf20Sopenharmony_ci } else { 20278c2ecf20Sopenharmony_ci netif_rx_ni(skb); 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci rcu_read_unlock(); 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci stats = get_cpu_ptr(tun->pcpu_stats); 20328c2ecf20Sopenharmony_ci u64_stats_update_begin(&stats->syncp); 20338c2ecf20Sopenharmony_ci u64_stats_inc(&stats->rx_packets); 20348c2ecf20Sopenharmony_ci u64_stats_add(&stats->rx_bytes, len); 20358c2ecf20Sopenharmony_ci u64_stats_update_end(&stats->syncp); 20368c2ecf20Sopenharmony_ci put_cpu_ptr(stats); 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci if (rxhash) 20398c2ecf20Sopenharmony_ci tun_flow_update(tun, rxhash, tfile); 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci return total_len; 20428c2ecf20Sopenharmony_ci} 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_cistatic ssize_t tun_chr_write_iter(struct kiocb *iocb, struct iov_iter *from) 20458c2ecf20Sopenharmony_ci{ 20468c2ecf20Sopenharmony_ci struct file *file = iocb->ki_filp; 20478c2ecf20Sopenharmony_ci struct tun_file *tfile = file->private_data; 20488c2ecf20Sopenharmony_ci struct tun_struct *tun = tun_get(tfile); 20498c2ecf20Sopenharmony_ci ssize_t result; 20508c2ecf20Sopenharmony_ci int noblock = 0; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci if (!tun) 20538c2ecf20Sopenharmony_ci return -EBADFD; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci if ((file->f_flags & O_NONBLOCK) || (iocb->ki_flags & IOCB_NOWAIT)) 20568c2ecf20Sopenharmony_ci noblock = 1; 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci result = tun_get_user(tun, tfile, NULL, from, noblock, false); 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci tun_put(tun); 20618c2ecf20Sopenharmony_ci return result; 20628c2ecf20Sopenharmony_ci} 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_cistatic ssize_t tun_put_user_xdp(struct tun_struct *tun, 20658c2ecf20Sopenharmony_ci struct tun_file *tfile, 20668c2ecf20Sopenharmony_ci struct xdp_frame *xdp_frame, 20678c2ecf20Sopenharmony_ci struct iov_iter *iter) 20688c2ecf20Sopenharmony_ci{ 20698c2ecf20Sopenharmony_ci int vnet_hdr_sz = 0; 20708c2ecf20Sopenharmony_ci size_t size = xdp_frame->len; 20718c2ecf20Sopenharmony_ci struct tun_pcpu_stats *stats; 20728c2ecf20Sopenharmony_ci size_t ret; 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci if (tun->flags & IFF_VNET_HDR) { 20758c2ecf20Sopenharmony_ci struct virtio_net_hdr gso = { 0 }; 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz); 20788c2ecf20Sopenharmony_ci if (unlikely(iov_iter_count(iter) < vnet_hdr_sz)) 20798c2ecf20Sopenharmony_ci return -EINVAL; 20808c2ecf20Sopenharmony_ci if (unlikely(copy_to_iter(&gso, sizeof(gso), iter) != 20818c2ecf20Sopenharmony_ci sizeof(gso))) 20828c2ecf20Sopenharmony_ci return -EFAULT; 20838c2ecf20Sopenharmony_ci iov_iter_advance(iter, vnet_hdr_sz - sizeof(gso)); 20848c2ecf20Sopenharmony_ci } 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci ret = copy_to_iter(xdp_frame->data, size, iter) + vnet_hdr_sz; 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci stats = get_cpu_ptr(tun->pcpu_stats); 20898c2ecf20Sopenharmony_ci u64_stats_update_begin(&stats->syncp); 20908c2ecf20Sopenharmony_ci u64_stats_inc(&stats->tx_packets); 20918c2ecf20Sopenharmony_ci u64_stats_add(&stats->tx_bytes, ret); 20928c2ecf20Sopenharmony_ci u64_stats_update_end(&stats->syncp); 20938c2ecf20Sopenharmony_ci put_cpu_ptr(tun->pcpu_stats); 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci return ret; 20968c2ecf20Sopenharmony_ci} 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci/* Put packet to the user space buffer */ 20998c2ecf20Sopenharmony_cistatic ssize_t tun_put_user(struct tun_struct *tun, 21008c2ecf20Sopenharmony_ci struct tun_file *tfile, 21018c2ecf20Sopenharmony_ci struct sk_buff *skb, 21028c2ecf20Sopenharmony_ci struct iov_iter *iter) 21038c2ecf20Sopenharmony_ci{ 21048c2ecf20Sopenharmony_ci struct tun_pi pi = { 0, skb->protocol }; 21058c2ecf20Sopenharmony_ci struct tun_pcpu_stats *stats; 21068c2ecf20Sopenharmony_ci ssize_t total; 21078c2ecf20Sopenharmony_ci int vlan_offset = 0; 21088c2ecf20Sopenharmony_ci int vlan_hlen = 0; 21098c2ecf20Sopenharmony_ci int vnet_hdr_sz = 0; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci if (skb_vlan_tag_present(skb)) 21128c2ecf20Sopenharmony_ci vlan_hlen = VLAN_HLEN; 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci if (tun->flags & IFF_VNET_HDR) 21158c2ecf20Sopenharmony_ci vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz); 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci total = skb->len + vlan_hlen + vnet_hdr_sz; 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci if (!(tun->flags & IFF_NO_PI)) { 21208c2ecf20Sopenharmony_ci if (iov_iter_count(iter) < sizeof(pi)) 21218c2ecf20Sopenharmony_ci return -EINVAL; 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci total += sizeof(pi); 21248c2ecf20Sopenharmony_ci if (iov_iter_count(iter) < total) { 21258c2ecf20Sopenharmony_ci /* Packet will be striped */ 21268c2ecf20Sopenharmony_ci pi.flags |= TUN_PKT_STRIP; 21278c2ecf20Sopenharmony_ci } 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci if (copy_to_iter(&pi, sizeof(pi), iter) != sizeof(pi)) 21308c2ecf20Sopenharmony_ci return -EFAULT; 21318c2ecf20Sopenharmony_ci } 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci if (vnet_hdr_sz) { 21348c2ecf20Sopenharmony_ci struct virtio_net_hdr gso; 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci if (iov_iter_count(iter) < vnet_hdr_sz) 21378c2ecf20Sopenharmony_ci return -EINVAL; 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci if (virtio_net_hdr_from_skb(skb, &gso, 21408c2ecf20Sopenharmony_ci tun_is_little_endian(tun), true, 21418c2ecf20Sopenharmony_ci vlan_hlen)) { 21428c2ecf20Sopenharmony_ci struct skb_shared_info *sinfo = skb_shinfo(skb); 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci if (net_ratelimit()) { 21458c2ecf20Sopenharmony_ci netdev_err(tun->dev, "unexpected GSO type: 0x%x, gso_size %d, hdr_len %d\n", 21468c2ecf20Sopenharmony_ci sinfo->gso_type, tun16_to_cpu(tun, gso.gso_size), 21478c2ecf20Sopenharmony_ci tun16_to_cpu(tun, gso.hdr_len)); 21488c2ecf20Sopenharmony_ci print_hex_dump(KERN_ERR, "tun: ", 21498c2ecf20Sopenharmony_ci DUMP_PREFIX_NONE, 21508c2ecf20Sopenharmony_ci 16, 1, skb->head, 21518c2ecf20Sopenharmony_ci min((int)tun16_to_cpu(tun, gso.hdr_len), 64), true); 21528c2ecf20Sopenharmony_ci } 21538c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 21548c2ecf20Sopenharmony_ci return -EINVAL; 21558c2ecf20Sopenharmony_ci } 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci if (copy_to_iter(&gso, sizeof(gso), iter) != sizeof(gso)) 21588c2ecf20Sopenharmony_ci return -EFAULT; 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci iov_iter_advance(iter, vnet_hdr_sz - sizeof(gso)); 21618c2ecf20Sopenharmony_ci } 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci if (vlan_hlen) { 21648c2ecf20Sopenharmony_ci int ret; 21658c2ecf20Sopenharmony_ci struct veth veth; 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci veth.h_vlan_proto = skb->vlan_proto; 21688c2ecf20Sopenharmony_ci veth.h_vlan_TCI = htons(skb_vlan_tag_get(skb)); 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto); 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci ret = skb_copy_datagram_iter(skb, 0, iter, vlan_offset); 21738c2ecf20Sopenharmony_ci if (ret || !iov_iter_count(iter)) 21748c2ecf20Sopenharmony_ci goto done; 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci ret = copy_to_iter(&veth, sizeof(veth), iter); 21778c2ecf20Sopenharmony_ci if (ret != sizeof(veth) || !iov_iter_count(iter)) 21788c2ecf20Sopenharmony_ci goto done; 21798c2ecf20Sopenharmony_ci } 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci skb_copy_datagram_iter(skb, vlan_offset, iter, skb->len - vlan_offset); 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_cidone: 21848c2ecf20Sopenharmony_ci /* caller is in process context, */ 21858c2ecf20Sopenharmony_ci stats = get_cpu_ptr(tun->pcpu_stats); 21868c2ecf20Sopenharmony_ci u64_stats_update_begin(&stats->syncp); 21878c2ecf20Sopenharmony_ci u64_stats_inc(&stats->tx_packets); 21888c2ecf20Sopenharmony_ci u64_stats_add(&stats->tx_bytes, skb->len + vlan_hlen); 21898c2ecf20Sopenharmony_ci u64_stats_update_end(&stats->syncp); 21908c2ecf20Sopenharmony_ci put_cpu_ptr(tun->pcpu_stats); 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci return total; 21938c2ecf20Sopenharmony_ci} 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_cistatic void *tun_ring_recv(struct tun_file *tfile, int noblock, int *err) 21968c2ecf20Sopenharmony_ci{ 21978c2ecf20Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 21988c2ecf20Sopenharmony_ci void *ptr = NULL; 21998c2ecf20Sopenharmony_ci int error = 0; 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci ptr = ptr_ring_consume(&tfile->tx_ring); 22028c2ecf20Sopenharmony_ci if (ptr) 22038c2ecf20Sopenharmony_ci goto out; 22048c2ecf20Sopenharmony_ci if (noblock) { 22058c2ecf20Sopenharmony_ci error = -EAGAIN; 22068c2ecf20Sopenharmony_ci goto out; 22078c2ecf20Sopenharmony_ci } 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci add_wait_queue(&tfile->socket.wq.wait, &wait); 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci while (1) { 22128c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 22138c2ecf20Sopenharmony_ci ptr = ptr_ring_consume(&tfile->tx_ring); 22148c2ecf20Sopenharmony_ci if (ptr) 22158c2ecf20Sopenharmony_ci break; 22168c2ecf20Sopenharmony_ci if (signal_pending(current)) { 22178c2ecf20Sopenharmony_ci error = -ERESTARTSYS; 22188c2ecf20Sopenharmony_ci break; 22198c2ecf20Sopenharmony_ci } 22208c2ecf20Sopenharmony_ci if (tfile->socket.sk->sk_shutdown & RCV_SHUTDOWN) { 22218c2ecf20Sopenharmony_ci error = -EFAULT; 22228c2ecf20Sopenharmony_ci break; 22238c2ecf20Sopenharmony_ci } 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci schedule(); 22268c2ecf20Sopenharmony_ci } 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci __set_current_state(TASK_RUNNING); 22298c2ecf20Sopenharmony_ci remove_wait_queue(&tfile->socket.wq.wait, &wait); 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ciout: 22328c2ecf20Sopenharmony_ci *err = error; 22338c2ecf20Sopenharmony_ci return ptr; 22348c2ecf20Sopenharmony_ci} 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_cistatic ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, 22378c2ecf20Sopenharmony_ci struct iov_iter *to, 22388c2ecf20Sopenharmony_ci int noblock, void *ptr) 22398c2ecf20Sopenharmony_ci{ 22408c2ecf20Sopenharmony_ci ssize_t ret; 22418c2ecf20Sopenharmony_ci int err; 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci if (!iov_iter_count(to)) { 22448c2ecf20Sopenharmony_ci tun_ptr_free(ptr); 22458c2ecf20Sopenharmony_ci return 0; 22468c2ecf20Sopenharmony_ci } 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci if (!ptr) { 22498c2ecf20Sopenharmony_ci /* Read frames from ring */ 22508c2ecf20Sopenharmony_ci ptr = tun_ring_recv(tfile, noblock, &err); 22518c2ecf20Sopenharmony_ci if (!ptr) 22528c2ecf20Sopenharmony_ci return err; 22538c2ecf20Sopenharmony_ci } 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci if (tun_is_xdp_frame(ptr)) { 22568c2ecf20Sopenharmony_ci struct xdp_frame *xdpf = tun_ptr_to_xdp(ptr); 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci ret = tun_put_user_xdp(tun, tfile, xdpf, to); 22598c2ecf20Sopenharmony_ci xdp_return_frame(xdpf); 22608c2ecf20Sopenharmony_ci } else { 22618c2ecf20Sopenharmony_ci struct sk_buff *skb = ptr; 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci ret = tun_put_user(tun, tfile, skb, to); 22648c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) 22658c2ecf20Sopenharmony_ci kfree_skb(skb); 22668c2ecf20Sopenharmony_ci else 22678c2ecf20Sopenharmony_ci consume_skb(skb); 22688c2ecf20Sopenharmony_ci } 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci return ret; 22718c2ecf20Sopenharmony_ci} 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_cistatic ssize_t tun_chr_read_iter(struct kiocb *iocb, struct iov_iter *to) 22748c2ecf20Sopenharmony_ci{ 22758c2ecf20Sopenharmony_ci struct file *file = iocb->ki_filp; 22768c2ecf20Sopenharmony_ci struct tun_file *tfile = file->private_data; 22778c2ecf20Sopenharmony_ci struct tun_struct *tun = tun_get(tfile); 22788c2ecf20Sopenharmony_ci ssize_t len = iov_iter_count(to), ret; 22798c2ecf20Sopenharmony_ci int noblock = 0; 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci if (!tun) 22828c2ecf20Sopenharmony_ci return -EBADFD; 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci if ((file->f_flags & O_NONBLOCK) || (iocb->ki_flags & IOCB_NOWAIT)) 22858c2ecf20Sopenharmony_ci noblock = 1; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci ret = tun_do_read(tun, tfile, to, noblock, NULL); 22888c2ecf20Sopenharmony_ci ret = min_t(ssize_t, ret, len); 22898c2ecf20Sopenharmony_ci if (ret > 0) 22908c2ecf20Sopenharmony_ci iocb->ki_pos = ret; 22918c2ecf20Sopenharmony_ci tun_put(tun); 22928c2ecf20Sopenharmony_ci return ret; 22938c2ecf20Sopenharmony_ci} 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_cistatic void tun_prog_free(struct rcu_head *rcu) 22968c2ecf20Sopenharmony_ci{ 22978c2ecf20Sopenharmony_ci struct tun_prog *prog = container_of(rcu, struct tun_prog, rcu); 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci bpf_prog_destroy(prog->prog); 23008c2ecf20Sopenharmony_ci kfree(prog); 23018c2ecf20Sopenharmony_ci} 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_cistatic int __tun_set_ebpf(struct tun_struct *tun, 23048c2ecf20Sopenharmony_ci struct tun_prog __rcu **prog_p, 23058c2ecf20Sopenharmony_ci struct bpf_prog *prog) 23068c2ecf20Sopenharmony_ci{ 23078c2ecf20Sopenharmony_ci struct tun_prog *old, *new = NULL; 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci if (prog) { 23108c2ecf20Sopenharmony_ci new = kmalloc(sizeof(*new), GFP_KERNEL); 23118c2ecf20Sopenharmony_ci if (!new) 23128c2ecf20Sopenharmony_ci return -ENOMEM; 23138c2ecf20Sopenharmony_ci new->prog = prog; 23148c2ecf20Sopenharmony_ci } 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci spin_lock_bh(&tun->lock); 23178c2ecf20Sopenharmony_ci old = rcu_dereference_protected(*prog_p, 23188c2ecf20Sopenharmony_ci lockdep_is_held(&tun->lock)); 23198c2ecf20Sopenharmony_ci rcu_assign_pointer(*prog_p, new); 23208c2ecf20Sopenharmony_ci spin_unlock_bh(&tun->lock); 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci if (old) 23238c2ecf20Sopenharmony_ci call_rcu(&old->rcu, tun_prog_free); 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ci return 0; 23268c2ecf20Sopenharmony_ci} 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_cistatic void tun_free_netdev(struct net_device *dev) 23298c2ecf20Sopenharmony_ci{ 23308c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci BUG_ON(!(list_empty(&tun->disabled))); 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci free_percpu(tun->pcpu_stats); 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci tun_flow_uninit(tun); 23378c2ecf20Sopenharmony_ci security_tun_dev_free_security(tun->security); 23388c2ecf20Sopenharmony_ci __tun_set_ebpf(tun, &tun->steering_prog, NULL); 23398c2ecf20Sopenharmony_ci __tun_set_ebpf(tun, &tun->filter_prog, NULL); 23408c2ecf20Sopenharmony_ci} 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_cistatic void tun_setup(struct net_device *dev) 23438c2ecf20Sopenharmony_ci{ 23448c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci tun->owner = INVALID_UID; 23478c2ecf20Sopenharmony_ci tun->group = INVALID_GID; 23488c2ecf20Sopenharmony_ci tun_default_link_ksettings(dev, &tun->link_ksettings); 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci dev->ethtool_ops = &tun_ethtool_ops; 23518c2ecf20Sopenharmony_ci dev->needs_free_netdev = true; 23528c2ecf20Sopenharmony_ci dev->priv_destructor = tun_free_netdev; 23538c2ecf20Sopenharmony_ci /* We prefer our own queue length */ 23548c2ecf20Sopenharmony_ci dev->tx_queue_len = TUN_READQ_SIZE; 23558c2ecf20Sopenharmony_ci} 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci/* Trivial set of netlink ops to allow deleting tun or tap 23588c2ecf20Sopenharmony_ci * device with netlink. 23598c2ecf20Sopenharmony_ci */ 23608c2ecf20Sopenharmony_cistatic int tun_validate(struct nlattr *tb[], struct nlattr *data[], 23618c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 23628c2ecf20Sopenharmony_ci{ 23638c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, 23648c2ecf20Sopenharmony_ci "tun/tap creation via rtnetlink is not supported."); 23658c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 23668c2ecf20Sopenharmony_ci} 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_cistatic size_t tun_get_size(const struct net_device *dev) 23698c2ecf20Sopenharmony_ci{ 23708c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(u32) != sizeof(uid_t)); 23718c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(u32) != sizeof(gid_t)); 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci return nla_total_size(sizeof(uid_t)) + /* OWNER */ 23748c2ecf20Sopenharmony_ci nla_total_size(sizeof(gid_t)) + /* GROUP */ 23758c2ecf20Sopenharmony_ci nla_total_size(sizeof(u8)) + /* TYPE */ 23768c2ecf20Sopenharmony_ci nla_total_size(sizeof(u8)) + /* PI */ 23778c2ecf20Sopenharmony_ci nla_total_size(sizeof(u8)) + /* VNET_HDR */ 23788c2ecf20Sopenharmony_ci nla_total_size(sizeof(u8)) + /* PERSIST */ 23798c2ecf20Sopenharmony_ci nla_total_size(sizeof(u8)) + /* MULTI_QUEUE */ 23808c2ecf20Sopenharmony_ci nla_total_size(sizeof(u32)) + /* NUM_QUEUES */ 23818c2ecf20Sopenharmony_ci nla_total_size(sizeof(u32)) + /* NUM_DISABLED_QUEUES */ 23828c2ecf20Sopenharmony_ci 0; 23838c2ecf20Sopenharmony_ci} 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_cistatic int tun_fill_info(struct sk_buff *skb, const struct net_device *dev) 23868c2ecf20Sopenharmony_ci{ 23878c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci if (nla_put_u8(skb, IFLA_TUN_TYPE, tun->flags & TUN_TYPE_MASK)) 23908c2ecf20Sopenharmony_ci goto nla_put_failure; 23918c2ecf20Sopenharmony_ci if (uid_valid(tun->owner) && 23928c2ecf20Sopenharmony_ci nla_put_u32(skb, IFLA_TUN_OWNER, 23938c2ecf20Sopenharmony_ci from_kuid_munged(current_user_ns(), tun->owner))) 23948c2ecf20Sopenharmony_ci goto nla_put_failure; 23958c2ecf20Sopenharmony_ci if (gid_valid(tun->group) && 23968c2ecf20Sopenharmony_ci nla_put_u32(skb, IFLA_TUN_GROUP, 23978c2ecf20Sopenharmony_ci from_kgid_munged(current_user_ns(), tun->group))) 23988c2ecf20Sopenharmony_ci goto nla_put_failure; 23998c2ecf20Sopenharmony_ci if (nla_put_u8(skb, IFLA_TUN_PI, !(tun->flags & IFF_NO_PI))) 24008c2ecf20Sopenharmony_ci goto nla_put_failure; 24018c2ecf20Sopenharmony_ci if (nla_put_u8(skb, IFLA_TUN_VNET_HDR, !!(tun->flags & IFF_VNET_HDR))) 24028c2ecf20Sopenharmony_ci goto nla_put_failure; 24038c2ecf20Sopenharmony_ci if (nla_put_u8(skb, IFLA_TUN_PERSIST, !!(tun->flags & IFF_PERSIST))) 24048c2ecf20Sopenharmony_ci goto nla_put_failure; 24058c2ecf20Sopenharmony_ci if (nla_put_u8(skb, IFLA_TUN_MULTI_QUEUE, 24068c2ecf20Sopenharmony_ci !!(tun->flags & IFF_MULTI_QUEUE))) 24078c2ecf20Sopenharmony_ci goto nla_put_failure; 24088c2ecf20Sopenharmony_ci if (tun->flags & IFF_MULTI_QUEUE) { 24098c2ecf20Sopenharmony_ci if (nla_put_u32(skb, IFLA_TUN_NUM_QUEUES, tun->numqueues)) 24108c2ecf20Sopenharmony_ci goto nla_put_failure; 24118c2ecf20Sopenharmony_ci if (nla_put_u32(skb, IFLA_TUN_NUM_DISABLED_QUEUES, 24128c2ecf20Sopenharmony_ci tun->numdisabled)) 24138c2ecf20Sopenharmony_ci goto nla_put_failure; 24148c2ecf20Sopenharmony_ci } 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci return 0; 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_cinla_put_failure: 24198c2ecf20Sopenharmony_ci return -EMSGSIZE; 24208c2ecf20Sopenharmony_ci} 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_cistatic struct rtnl_link_ops tun_link_ops __read_mostly = { 24238c2ecf20Sopenharmony_ci .kind = DRV_NAME, 24248c2ecf20Sopenharmony_ci .priv_size = sizeof(struct tun_struct), 24258c2ecf20Sopenharmony_ci .setup = tun_setup, 24268c2ecf20Sopenharmony_ci .validate = tun_validate, 24278c2ecf20Sopenharmony_ci .get_size = tun_get_size, 24288c2ecf20Sopenharmony_ci .fill_info = tun_fill_info, 24298c2ecf20Sopenharmony_ci}; 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_cistatic void tun_sock_write_space(struct sock *sk) 24328c2ecf20Sopenharmony_ci{ 24338c2ecf20Sopenharmony_ci struct tun_file *tfile; 24348c2ecf20Sopenharmony_ci wait_queue_head_t *wqueue; 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci if (!sock_writeable(sk)) 24378c2ecf20Sopenharmony_ci return; 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci if (!test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &sk->sk_socket->flags)) 24408c2ecf20Sopenharmony_ci return; 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci wqueue = sk_sleep(sk); 24438c2ecf20Sopenharmony_ci if (wqueue && waitqueue_active(wqueue)) 24448c2ecf20Sopenharmony_ci wake_up_interruptible_sync_poll(wqueue, EPOLLOUT | 24458c2ecf20Sopenharmony_ci EPOLLWRNORM | EPOLLWRBAND); 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci tfile = container_of(sk, struct tun_file, sk); 24488c2ecf20Sopenharmony_ci kill_fasync(&tfile->fasync, SIGIO, POLL_OUT); 24498c2ecf20Sopenharmony_ci} 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_cistatic void tun_put_page(struct tun_page *tpage) 24528c2ecf20Sopenharmony_ci{ 24538c2ecf20Sopenharmony_ci if (tpage->page) 24548c2ecf20Sopenharmony_ci __page_frag_cache_drain(tpage->page, tpage->count); 24558c2ecf20Sopenharmony_ci} 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_cistatic int tun_xdp_one(struct tun_struct *tun, 24588c2ecf20Sopenharmony_ci struct tun_file *tfile, 24598c2ecf20Sopenharmony_ci struct xdp_buff *xdp, int *flush, 24608c2ecf20Sopenharmony_ci struct tun_page *tpage) 24618c2ecf20Sopenharmony_ci{ 24628c2ecf20Sopenharmony_ci unsigned int datasize = xdp->data_end - xdp->data; 24638c2ecf20Sopenharmony_ci struct tun_xdp_hdr *hdr = xdp->data_hard_start; 24648c2ecf20Sopenharmony_ci struct virtio_net_hdr *gso = &hdr->gso; 24658c2ecf20Sopenharmony_ci struct tun_pcpu_stats *stats; 24668c2ecf20Sopenharmony_ci struct bpf_prog *xdp_prog; 24678c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 24688c2ecf20Sopenharmony_ci u32 rxhash = 0, act; 24698c2ecf20Sopenharmony_ci int buflen = hdr->buflen; 24708c2ecf20Sopenharmony_ci int err = 0; 24718c2ecf20Sopenharmony_ci bool skb_xdp = false; 24728c2ecf20Sopenharmony_ci struct page *page; 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci if (unlikely(datasize < ETH_HLEN)) 24758c2ecf20Sopenharmony_ci return -EINVAL; 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci xdp_prog = rcu_dereference(tun->xdp_prog); 24788c2ecf20Sopenharmony_ci if (xdp_prog) { 24798c2ecf20Sopenharmony_ci if (gso->gso_type) { 24808c2ecf20Sopenharmony_ci skb_xdp = true; 24818c2ecf20Sopenharmony_ci goto build; 24828c2ecf20Sopenharmony_ci } 24838c2ecf20Sopenharmony_ci xdp_set_data_meta_invalid(xdp); 24848c2ecf20Sopenharmony_ci xdp->rxq = &tfile->xdp_rxq; 24858c2ecf20Sopenharmony_ci xdp->frame_sz = buflen; 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci act = bpf_prog_run_xdp(xdp_prog, xdp); 24888c2ecf20Sopenharmony_ci err = tun_xdp_act(tun, xdp_prog, xdp, act); 24898c2ecf20Sopenharmony_ci if (err < 0) { 24908c2ecf20Sopenharmony_ci put_page(virt_to_head_page(xdp->data)); 24918c2ecf20Sopenharmony_ci return err; 24928c2ecf20Sopenharmony_ci } 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci switch (err) { 24958c2ecf20Sopenharmony_ci case XDP_REDIRECT: 24968c2ecf20Sopenharmony_ci *flush = true; 24978c2ecf20Sopenharmony_ci fallthrough; 24988c2ecf20Sopenharmony_ci case XDP_TX: 24998c2ecf20Sopenharmony_ci return 0; 25008c2ecf20Sopenharmony_ci case XDP_PASS: 25018c2ecf20Sopenharmony_ci break; 25028c2ecf20Sopenharmony_ci default: 25038c2ecf20Sopenharmony_ci page = virt_to_head_page(xdp->data); 25048c2ecf20Sopenharmony_ci if (tpage->page == page) { 25058c2ecf20Sopenharmony_ci ++tpage->count; 25068c2ecf20Sopenharmony_ci } else { 25078c2ecf20Sopenharmony_ci tun_put_page(tpage); 25088c2ecf20Sopenharmony_ci tpage->page = page; 25098c2ecf20Sopenharmony_ci tpage->count = 1; 25108c2ecf20Sopenharmony_ci } 25118c2ecf20Sopenharmony_ci return 0; 25128c2ecf20Sopenharmony_ci } 25138c2ecf20Sopenharmony_ci } 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_cibuild: 25168c2ecf20Sopenharmony_ci skb = build_skb(xdp->data_hard_start, buflen); 25178c2ecf20Sopenharmony_ci if (!skb) { 25188c2ecf20Sopenharmony_ci err = -ENOMEM; 25198c2ecf20Sopenharmony_ci goto out; 25208c2ecf20Sopenharmony_ci } 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_ci skb_reserve(skb, xdp->data - xdp->data_hard_start); 25238c2ecf20Sopenharmony_ci skb_put(skb, xdp->data_end - xdp->data); 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci if (virtio_net_hdr_to_skb(skb, gso, tun_is_little_endian(tun))) { 25268c2ecf20Sopenharmony_ci this_cpu_inc(tun->pcpu_stats->rx_frame_errors); 25278c2ecf20Sopenharmony_ci kfree_skb(skb); 25288c2ecf20Sopenharmony_ci err = -EINVAL; 25298c2ecf20Sopenharmony_ci goto out; 25308c2ecf20Sopenharmony_ci } 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, tun->dev); 25338c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 25348c2ecf20Sopenharmony_ci skb_probe_transport_header(skb); 25358c2ecf20Sopenharmony_ci skb_record_rx_queue(skb, tfile->queue_index); 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci if (skb_xdp) { 25388c2ecf20Sopenharmony_ci err = do_xdp_generic(xdp_prog, skb); 25398c2ecf20Sopenharmony_ci if (err != XDP_PASS) 25408c2ecf20Sopenharmony_ci goto out; 25418c2ecf20Sopenharmony_ci } 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci if (!rcu_dereference(tun->steering_prog) && tun->numqueues > 1 && 25448c2ecf20Sopenharmony_ci !tfile->detached) 25458c2ecf20Sopenharmony_ci rxhash = __skb_get_hash_symmetric(skb); 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_ci netif_receive_skb(skb); 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci /* No need for get_cpu_ptr() here since this function is 25508c2ecf20Sopenharmony_ci * always called with bh disabled 25518c2ecf20Sopenharmony_ci */ 25528c2ecf20Sopenharmony_ci stats = this_cpu_ptr(tun->pcpu_stats); 25538c2ecf20Sopenharmony_ci u64_stats_update_begin(&stats->syncp); 25548c2ecf20Sopenharmony_ci u64_stats_inc(&stats->rx_packets); 25558c2ecf20Sopenharmony_ci u64_stats_add(&stats->rx_bytes, datasize); 25568c2ecf20Sopenharmony_ci u64_stats_update_end(&stats->syncp); 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci if (rxhash) 25598c2ecf20Sopenharmony_ci tun_flow_update(tun, rxhash, tfile); 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ciout: 25628c2ecf20Sopenharmony_ci return err; 25638c2ecf20Sopenharmony_ci} 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_cistatic int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len) 25668c2ecf20Sopenharmony_ci{ 25678c2ecf20Sopenharmony_ci int ret, i; 25688c2ecf20Sopenharmony_ci struct tun_file *tfile = container_of(sock, struct tun_file, socket); 25698c2ecf20Sopenharmony_ci struct tun_struct *tun = tun_get(tfile); 25708c2ecf20Sopenharmony_ci struct tun_msg_ctl *ctl = m->msg_control; 25718c2ecf20Sopenharmony_ci struct xdp_buff *xdp; 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci if (!tun) 25748c2ecf20Sopenharmony_ci return -EBADFD; 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_ci if (m->msg_controllen == sizeof(struct tun_msg_ctl) && 25778c2ecf20Sopenharmony_ci ctl && ctl->type == TUN_MSG_PTR) { 25788c2ecf20Sopenharmony_ci struct tun_page tpage; 25798c2ecf20Sopenharmony_ci int n = ctl->num; 25808c2ecf20Sopenharmony_ci int flush = 0; 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_ci memset(&tpage, 0, sizeof(tpage)); 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci local_bh_disable(); 25858c2ecf20Sopenharmony_ci rcu_read_lock(); 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 25888c2ecf20Sopenharmony_ci xdp = &((struct xdp_buff *)ctl->ptr)[i]; 25898c2ecf20Sopenharmony_ci tun_xdp_one(tun, tfile, xdp, &flush, &tpage); 25908c2ecf20Sopenharmony_ci } 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci if (flush) 25938c2ecf20Sopenharmony_ci xdp_do_flush(); 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci rcu_read_unlock(); 25968c2ecf20Sopenharmony_ci local_bh_enable(); 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci tun_put_page(&tpage); 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_ci ret = total_len; 26018c2ecf20Sopenharmony_ci goto out; 26028c2ecf20Sopenharmony_ci } 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci ret = tun_get_user(tun, tfile, ctl ? ctl->ptr : NULL, &m->msg_iter, 26058c2ecf20Sopenharmony_ci m->msg_flags & MSG_DONTWAIT, 26068c2ecf20Sopenharmony_ci m->msg_flags & MSG_MORE); 26078c2ecf20Sopenharmony_ciout: 26088c2ecf20Sopenharmony_ci tun_put(tun); 26098c2ecf20Sopenharmony_ci return ret; 26108c2ecf20Sopenharmony_ci} 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_cistatic int tun_recvmsg(struct socket *sock, struct msghdr *m, size_t total_len, 26138c2ecf20Sopenharmony_ci int flags) 26148c2ecf20Sopenharmony_ci{ 26158c2ecf20Sopenharmony_ci struct tun_file *tfile = container_of(sock, struct tun_file, socket); 26168c2ecf20Sopenharmony_ci struct tun_struct *tun = tun_get(tfile); 26178c2ecf20Sopenharmony_ci void *ptr = m->msg_control; 26188c2ecf20Sopenharmony_ci int ret; 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci if (!tun) { 26218c2ecf20Sopenharmony_ci ret = -EBADFD; 26228c2ecf20Sopenharmony_ci goto out_free; 26238c2ecf20Sopenharmony_ci } 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci if (flags & ~(MSG_DONTWAIT|MSG_TRUNC|MSG_ERRQUEUE)) { 26268c2ecf20Sopenharmony_ci ret = -EINVAL; 26278c2ecf20Sopenharmony_ci goto out_put_tun; 26288c2ecf20Sopenharmony_ci } 26298c2ecf20Sopenharmony_ci if (flags & MSG_ERRQUEUE) { 26308c2ecf20Sopenharmony_ci ret = sock_recv_errqueue(sock->sk, m, total_len, 26318c2ecf20Sopenharmony_ci SOL_PACKET, TUN_TX_TIMESTAMP); 26328c2ecf20Sopenharmony_ci goto out; 26338c2ecf20Sopenharmony_ci } 26348c2ecf20Sopenharmony_ci ret = tun_do_read(tun, tfile, &m->msg_iter, flags & MSG_DONTWAIT, ptr); 26358c2ecf20Sopenharmony_ci if (ret > (ssize_t)total_len) { 26368c2ecf20Sopenharmony_ci m->msg_flags |= MSG_TRUNC; 26378c2ecf20Sopenharmony_ci ret = flags & MSG_TRUNC ? ret : total_len; 26388c2ecf20Sopenharmony_ci } 26398c2ecf20Sopenharmony_ciout: 26408c2ecf20Sopenharmony_ci tun_put(tun); 26418c2ecf20Sopenharmony_ci return ret; 26428c2ecf20Sopenharmony_ci 26438c2ecf20Sopenharmony_ciout_put_tun: 26448c2ecf20Sopenharmony_ci tun_put(tun); 26458c2ecf20Sopenharmony_ciout_free: 26468c2ecf20Sopenharmony_ci tun_ptr_free(ptr); 26478c2ecf20Sopenharmony_ci return ret; 26488c2ecf20Sopenharmony_ci} 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_cistatic int tun_ptr_peek_len(void *ptr) 26518c2ecf20Sopenharmony_ci{ 26528c2ecf20Sopenharmony_ci if (likely(ptr)) { 26538c2ecf20Sopenharmony_ci if (tun_is_xdp_frame(ptr)) { 26548c2ecf20Sopenharmony_ci struct xdp_frame *xdpf = tun_ptr_to_xdp(ptr); 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_ci return xdpf->len; 26578c2ecf20Sopenharmony_ci } 26588c2ecf20Sopenharmony_ci return __skb_array_len_with_tag(ptr); 26598c2ecf20Sopenharmony_ci } else { 26608c2ecf20Sopenharmony_ci return 0; 26618c2ecf20Sopenharmony_ci } 26628c2ecf20Sopenharmony_ci} 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_cistatic int tun_peek_len(struct socket *sock) 26658c2ecf20Sopenharmony_ci{ 26668c2ecf20Sopenharmony_ci struct tun_file *tfile = container_of(sock, struct tun_file, socket); 26678c2ecf20Sopenharmony_ci struct tun_struct *tun; 26688c2ecf20Sopenharmony_ci int ret = 0; 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci tun = tun_get(tfile); 26718c2ecf20Sopenharmony_ci if (!tun) 26728c2ecf20Sopenharmony_ci return 0; 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_ci ret = PTR_RING_PEEK_CALL(&tfile->tx_ring, tun_ptr_peek_len); 26758c2ecf20Sopenharmony_ci tun_put(tun); 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_ci return ret; 26788c2ecf20Sopenharmony_ci} 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci/* Ops structure to mimic raw sockets with tun */ 26818c2ecf20Sopenharmony_cistatic const struct proto_ops tun_socket_ops = { 26828c2ecf20Sopenharmony_ci .peek_len = tun_peek_len, 26838c2ecf20Sopenharmony_ci .sendmsg = tun_sendmsg, 26848c2ecf20Sopenharmony_ci .recvmsg = tun_recvmsg, 26858c2ecf20Sopenharmony_ci}; 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_cistatic struct proto tun_proto = { 26888c2ecf20Sopenharmony_ci .name = "tun", 26898c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 26908c2ecf20Sopenharmony_ci .obj_size = sizeof(struct tun_file), 26918c2ecf20Sopenharmony_ci}; 26928c2ecf20Sopenharmony_ci 26938c2ecf20Sopenharmony_cistatic int tun_flags(struct tun_struct *tun) 26948c2ecf20Sopenharmony_ci{ 26958c2ecf20Sopenharmony_ci return tun->flags & (TUN_FEATURES | IFF_PERSIST | IFF_TUN | IFF_TAP); 26968c2ecf20Sopenharmony_ci} 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_cistatic ssize_t tun_show_flags(struct device *dev, struct device_attribute *attr, 26998c2ecf20Sopenharmony_ci char *buf) 27008c2ecf20Sopenharmony_ci{ 27018c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(to_net_dev(dev)); 27028c2ecf20Sopenharmony_ci return sprintf(buf, "0x%x\n", tun_flags(tun)); 27038c2ecf20Sopenharmony_ci} 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_cistatic ssize_t tun_show_owner(struct device *dev, struct device_attribute *attr, 27068c2ecf20Sopenharmony_ci char *buf) 27078c2ecf20Sopenharmony_ci{ 27088c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(to_net_dev(dev)); 27098c2ecf20Sopenharmony_ci return uid_valid(tun->owner)? 27108c2ecf20Sopenharmony_ci sprintf(buf, "%u\n", 27118c2ecf20Sopenharmony_ci from_kuid_munged(current_user_ns(), tun->owner)): 27128c2ecf20Sopenharmony_ci sprintf(buf, "-1\n"); 27138c2ecf20Sopenharmony_ci} 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_cistatic ssize_t tun_show_group(struct device *dev, struct device_attribute *attr, 27168c2ecf20Sopenharmony_ci char *buf) 27178c2ecf20Sopenharmony_ci{ 27188c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(to_net_dev(dev)); 27198c2ecf20Sopenharmony_ci return gid_valid(tun->group) ? 27208c2ecf20Sopenharmony_ci sprintf(buf, "%u\n", 27218c2ecf20Sopenharmony_ci from_kgid_munged(current_user_ns(), tun->group)): 27228c2ecf20Sopenharmony_ci sprintf(buf, "-1\n"); 27238c2ecf20Sopenharmony_ci} 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_cistatic DEVICE_ATTR(tun_flags, 0444, tun_show_flags, NULL); 27268c2ecf20Sopenharmony_cistatic DEVICE_ATTR(owner, 0444, tun_show_owner, NULL); 27278c2ecf20Sopenharmony_cistatic DEVICE_ATTR(group, 0444, tun_show_group, NULL); 27288c2ecf20Sopenharmony_ci 27298c2ecf20Sopenharmony_cistatic struct attribute *tun_dev_attrs[] = { 27308c2ecf20Sopenharmony_ci &dev_attr_tun_flags.attr, 27318c2ecf20Sopenharmony_ci &dev_attr_owner.attr, 27328c2ecf20Sopenharmony_ci &dev_attr_group.attr, 27338c2ecf20Sopenharmony_ci NULL 27348c2ecf20Sopenharmony_ci}; 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_cistatic const struct attribute_group tun_attr_group = { 27378c2ecf20Sopenharmony_ci .attrs = tun_dev_attrs 27388c2ecf20Sopenharmony_ci}; 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_cistatic int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) 27418c2ecf20Sopenharmony_ci{ 27428c2ecf20Sopenharmony_ci struct tun_struct *tun; 27438c2ecf20Sopenharmony_ci struct tun_file *tfile = file->private_data; 27448c2ecf20Sopenharmony_ci struct net_device *dev; 27458c2ecf20Sopenharmony_ci int err; 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci if (tfile->detached) 27488c2ecf20Sopenharmony_ci return -EINVAL; 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci if ((ifr->ifr_flags & IFF_NAPI_FRAGS)) { 27518c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 27528c2ecf20Sopenharmony_ci return -EPERM; 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci if (!(ifr->ifr_flags & IFF_NAPI) || 27558c2ecf20Sopenharmony_ci (ifr->ifr_flags & TUN_TYPE_MASK) != IFF_TAP) 27568c2ecf20Sopenharmony_ci return -EINVAL; 27578c2ecf20Sopenharmony_ci } 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci dev = __dev_get_by_name(net, ifr->ifr_name); 27608c2ecf20Sopenharmony_ci if (dev) { 27618c2ecf20Sopenharmony_ci if (ifr->ifr_flags & IFF_TUN_EXCL) 27628c2ecf20Sopenharmony_ci return -EBUSY; 27638c2ecf20Sopenharmony_ci if ((ifr->ifr_flags & IFF_TUN) && dev->netdev_ops == &tun_netdev_ops) 27648c2ecf20Sopenharmony_ci tun = netdev_priv(dev); 27658c2ecf20Sopenharmony_ci else if ((ifr->ifr_flags & IFF_TAP) && dev->netdev_ops == &tap_netdev_ops) 27668c2ecf20Sopenharmony_ci tun = netdev_priv(dev); 27678c2ecf20Sopenharmony_ci else 27688c2ecf20Sopenharmony_ci return -EINVAL; 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci if (!!(ifr->ifr_flags & IFF_MULTI_QUEUE) != 27718c2ecf20Sopenharmony_ci !!(tun->flags & IFF_MULTI_QUEUE)) 27728c2ecf20Sopenharmony_ci return -EINVAL; 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci if (tun_not_capable(tun)) 27758c2ecf20Sopenharmony_ci return -EPERM; 27768c2ecf20Sopenharmony_ci err = security_tun_dev_open(tun->security); 27778c2ecf20Sopenharmony_ci if (err < 0) 27788c2ecf20Sopenharmony_ci return err; 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_ci err = tun_attach(tun, file, ifr->ifr_flags & IFF_NOFILTER, 27818c2ecf20Sopenharmony_ci ifr->ifr_flags & IFF_NAPI, 27828c2ecf20Sopenharmony_ci ifr->ifr_flags & IFF_NAPI_FRAGS, true); 27838c2ecf20Sopenharmony_ci if (err < 0) 27848c2ecf20Sopenharmony_ci return err; 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci if (tun->flags & IFF_MULTI_QUEUE && 27878c2ecf20Sopenharmony_ci (tun->numqueues + tun->numdisabled > 1)) { 27888c2ecf20Sopenharmony_ci /* One or more queue has already been attached, no need 27898c2ecf20Sopenharmony_ci * to initialize the device again. 27908c2ecf20Sopenharmony_ci */ 27918c2ecf20Sopenharmony_ci netdev_state_change(dev); 27928c2ecf20Sopenharmony_ci return 0; 27938c2ecf20Sopenharmony_ci } 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci tun->flags = (tun->flags & ~TUN_FEATURES) | 27968c2ecf20Sopenharmony_ci (ifr->ifr_flags & TUN_FEATURES); 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_ci netdev_state_change(dev); 27998c2ecf20Sopenharmony_ci } else { 28008c2ecf20Sopenharmony_ci char *name; 28018c2ecf20Sopenharmony_ci unsigned long flags = 0; 28028c2ecf20Sopenharmony_ci int queues = ifr->ifr_flags & IFF_MULTI_QUEUE ? 28038c2ecf20Sopenharmony_ci MAX_TAP_QUEUES : 1; 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 28068c2ecf20Sopenharmony_ci return -EPERM; 28078c2ecf20Sopenharmony_ci err = security_tun_dev_create(); 28088c2ecf20Sopenharmony_ci if (err < 0) 28098c2ecf20Sopenharmony_ci return err; 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci /* Set dev type */ 28128c2ecf20Sopenharmony_ci if (ifr->ifr_flags & IFF_TUN) { 28138c2ecf20Sopenharmony_ci /* TUN device */ 28148c2ecf20Sopenharmony_ci flags |= IFF_TUN; 28158c2ecf20Sopenharmony_ci name = "tun%d"; 28168c2ecf20Sopenharmony_ci } else if (ifr->ifr_flags & IFF_TAP) { 28178c2ecf20Sopenharmony_ci /* TAP device */ 28188c2ecf20Sopenharmony_ci flags |= IFF_TAP; 28198c2ecf20Sopenharmony_ci name = "tap%d"; 28208c2ecf20Sopenharmony_ci } else 28218c2ecf20Sopenharmony_ci return -EINVAL; 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_ci if (*ifr->ifr_name) 28248c2ecf20Sopenharmony_ci name = ifr->ifr_name; 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ci dev = alloc_netdev_mqs(sizeof(struct tun_struct), name, 28278c2ecf20Sopenharmony_ci NET_NAME_UNKNOWN, tun_setup, queues, 28288c2ecf20Sopenharmony_ci queues); 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_ci if (!dev) 28318c2ecf20Sopenharmony_ci return -ENOMEM; 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_ci dev_net_set(dev, net); 28348c2ecf20Sopenharmony_ci dev->rtnl_link_ops = &tun_link_ops; 28358c2ecf20Sopenharmony_ci dev->ifindex = tfile->ifindex; 28368c2ecf20Sopenharmony_ci dev->sysfs_groups[0] = &tun_attr_group; 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ci tun = netdev_priv(dev); 28398c2ecf20Sopenharmony_ci tun->dev = dev; 28408c2ecf20Sopenharmony_ci tun->flags = flags; 28418c2ecf20Sopenharmony_ci tun->txflt.count = 0; 28428c2ecf20Sopenharmony_ci tun->vnet_hdr_sz = sizeof(struct virtio_net_hdr); 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci tun->align = NET_SKB_PAD; 28458c2ecf20Sopenharmony_ci tun->filter_attached = false; 28468c2ecf20Sopenharmony_ci tun->sndbuf = tfile->socket.sk->sk_sndbuf; 28478c2ecf20Sopenharmony_ci tun->rx_batched = 0; 28488c2ecf20Sopenharmony_ci RCU_INIT_POINTER(tun->steering_prog, NULL); 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci tun->ifr = ifr; 28518c2ecf20Sopenharmony_ci tun->file = file; 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci tun_net_initialize(dev); 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci err = register_netdevice(tun->dev); 28568c2ecf20Sopenharmony_ci if (err < 0) { 28578c2ecf20Sopenharmony_ci free_netdev(dev); 28588c2ecf20Sopenharmony_ci return err; 28598c2ecf20Sopenharmony_ci } 28608c2ecf20Sopenharmony_ci /* free_netdev() won't check refcnt, to aovid race 28618c2ecf20Sopenharmony_ci * with dev_put() we need publish tun after registration. 28628c2ecf20Sopenharmony_ci */ 28638c2ecf20Sopenharmony_ci rcu_assign_pointer(tfile->tun, tun); 28648c2ecf20Sopenharmony_ci } 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci netif_carrier_on(tun->dev); 28678c2ecf20Sopenharmony_ci 28688c2ecf20Sopenharmony_ci /* Make sure persistent devices do not get stuck in 28698c2ecf20Sopenharmony_ci * xoff state. 28708c2ecf20Sopenharmony_ci */ 28718c2ecf20Sopenharmony_ci if (netif_running(tun->dev)) 28728c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(tun->dev); 28738c2ecf20Sopenharmony_ci 28748c2ecf20Sopenharmony_ci strcpy(ifr->ifr_name, tun->dev->name); 28758c2ecf20Sopenharmony_ci return 0; 28768c2ecf20Sopenharmony_ci} 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_cistatic void tun_get_iff(struct tun_struct *tun, struct ifreq *ifr) 28798c2ecf20Sopenharmony_ci{ 28808c2ecf20Sopenharmony_ci strcpy(ifr->ifr_name, tun->dev->name); 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci ifr->ifr_flags = tun_flags(tun); 28838c2ecf20Sopenharmony_ci 28848c2ecf20Sopenharmony_ci} 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci/* This is like a cut-down ethtool ops, except done via tun fd so no 28878c2ecf20Sopenharmony_ci * privs required. */ 28888c2ecf20Sopenharmony_cistatic int set_offload(struct tun_struct *tun, unsigned long arg) 28898c2ecf20Sopenharmony_ci{ 28908c2ecf20Sopenharmony_ci netdev_features_t features = 0; 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci if (arg & TUN_F_CSUM) { 28938c2ecf20Sopenharmony_ci features |= NETIF_F_HW_CSUM; 28948c2ecf20Sopenharmony_ci arg &= ~TUN_F_CSUM; 28958c2ecf20Sopenharmony_ci 28968c2ecf20Sopenharmony_ci if (arg & (TUN_F_TSO4|TUN_F_TSO6)) { 28978c2ecf20Sopenharmony_ci if (arg & TUN_F_TSO_ECN) { 28988c2ecf20Sopenharmony_ci features |= NETIF_F_TSO_ECN; 28998c2ecf20Sopenharmony_ci arg &= ~TUN_F_TSO_ECN; 29008c2ecf20Sopenharmony_ci } 29018c2ecf20Sopenharmony_ci if (arg & TUN_F_TSO4) 29028c2ecf20Sopenharmony_ci features |= NETIF_F_TSO; 29038c2ecf20Sopenharmony_ci if (arg & TUN_F_TSO6) 29048c2ecf20Sopenharmony_ci features |= NETIF_F_TSO6; 29058c2ecf20Sopenharmony_ci arg &= ~(TUN_F_TSO4|TUN_F_TSO6); 29068c2ecf20Sopenharmony_ci } 29078c2ecf20Sopenharmony_ci 29088c2ecf20Sopenharmony_ci arg &= ~TUN_F_UFO; 29098c2ecf20Sopenharmony_ci } 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci /* This gives the user a way to test for new features in future by 29128c2ecf20Sopenharmony_ci * trying to set them. */ 29138c2ecf20Sopenharmony_ci if (arg) 29148c2ecf20Sopenharmony_ci return -EINVAL; 29158c2ecf20Sopenharmony_ci 29168c2ecf20Sopenharmony_ci tun->set_features = features; 29178c2ecf20Sopenharmony_ci tun->dev->wanted_features &= ~TUN_USER_FEATURES; 29188c2ecf20Sopenharmony_ci tun->dev->wanted_features |= features; 29198c2ecf20Sopenharmony_ci netdev_update_features(tun->dev); 29208c2ecf20Sopenharmony_ci 29218c2ecf20Sopenharmony_ci return 0; 29228c2ecf20Sopenharmony_ci} 29238c2ecf20Sopenharmony_ci 29248c2ecf20Sopenharmony_cistatic void tun_detach_filter(struct tun_struct *tun, int n) 29258c2ecf20Sopenharmony_ci{ 29268c2ecf20Sopenharmony_ci int i; 29278c2ecf20Sopenharmony_ci struct tun_file *tfile; 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 29308c2ecf20Sopenharmony_ci tfile = rtnl_dereference(tun->tfiles[i]); 29318c2ecf20Sopenharmony_ci lock_sock(tfile->socket.sk); 29328c2ecf20Sopenharmony_ci sk_detach_filter(tfile->socket.sk); 29338c2ecf20Sopenharmony_ci release_sock(tfile->socket.sk); 29348c2ecf20Sopenharmony_ci } 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci tun->filter_attached = false; 29378c2ecf20Sopenharmony_ci} 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_cistatic int tun_attach_filter(struct tun_struct *tun) 29408c2ecf20Sopenharmony_ci{ 29418c2ecf20Sopenharmony_ci int i, ret = 0; 29428c2ecf20Sopenharmony_ci struct tun_file *tfile; 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_ci for (i = 0; i < tun->numqueues; i++) { 29458c2ecf20Sopenharmony_ci tfile = rtnl_dereference(tun->tfiles[i]); 29468c2ecf20Sopenharmony_ci lock_sock(tfile->socket.sk); 29478c2ecf20Sopenharmony_ci ret = sk_attach_filter(&tun->fprog, tfile->socket.sk); 29488c2ecf20Sopenharmony_ci release_sock(tfile->socket.sk); 29498c2ecf20Sopenharmony_ci if (ret) { 29508c2ecf20Sopenharmony_ci tun_detach_filter(tun, i); 29518c2ecf20Sopenharmony_ci return ret; 29528c2ecf20Sopenharmony_ci } 29538c2ecf20Sopenharmony_ci } 29548c2ecf20Sopenharmony_ci 29558c2ecf20Sopenharmony_ci tun->filter_attached = true; 29568c2ecf20Sopenharmony_ci return ret; 29578c2ecf20Sopenharmony_ci} 29588c2ecf20Sopenharmony_ci 29598c2ecf20Sopenharmony_cistatic void tun_set_sndbuf(struct tun_struct *tun) 29608c2ecf20Sopenharmony_ci{ 29618c2ecf20Sopenharmony_ci struct tun_file *tfile; 29628c2ecf20Sopenharmony_ci int i; 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci for (i = 0; i < tun->numqueues; i++) { 29658c2ecf20Sopenharmony_ci tfile = rtnl_dereference(tun->tfiles[i]); 29668c2ecf20Sopenharmony_ci tfile->socket.sk->sk_sndbuf = tun->sndbuf; 29678c2ecf20Sopenharmony_ci } 29688c2ecf20Sopenharmony_ci} 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_cistatic int tun_set_queue(struct file *file, struct ifreq *ifr) 29718c2ecf20Sopenharmony_ci{ 29728c2ecf20Sopenharmony_ci struct tun_file *tfile = file->private_data; 29738c2ecf20Sopenharmony_ci struct tun_struct *tun; 29748c2ecf20Sopenharmony_ci int ret = 0; 29758c2ecf20Sopenharmony_ci 29768c2ecf20Sopenharmony_ci rtnl_lock(); 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_ci if (ifr->ifr_flags & IFF_ATTACH_QUEUE) { 29798c2ecf20Sopenharmony_ci tun = tfile->detached; 29808c2ecf20Sopenharmony_ci if (!tun) { 29818c2ecf20Sopenharmony_ci ret = -EINVAL; 29828c2ecf20Sopenharmony_ci goto unlock; 29838c2ecf20Sopenharmony_ci } 29848c2ecf20Sopenharmony_ci ret = security_tun_dev_attach_queue(tun->security); 29858c2ecf20Sopenharmony_ci if (ret < 0) 29868c2ecf20Sopenharmony_ci goto unlock; 29878c2ecf20Sopenharmony_ci ret = tun_attach(tun, file, false, tun->flags & IFF_NAPI, 29888c2ecf20Sopenharmony_ci tun->flags & IFF_NAPI_FRAGS, true); 29898c2ecf20Sopenharmony_ci } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) { 29908c2ecf20Sopenharmony_ci tun = rtnl_dereference(tfile->tun); 29918c2ecf20Sopenharmony_ci if (!tun || !(tun->flags & IFF_MULTI_QUEUE) || tfile->detached) 29928c2ecf20Sopenharmony_ci ret = -EINVAL; 29938c2ecf20Sopenharmony_ci else 29948c2ecf20Sopenharmony_ci __tun_detach(tfile, false); 29958c2ecf20Sopenharmony_ci } else 29968c2ecf20Sopenharmony_ci ret = -EINVAL; 29978c2ecf20Sopenharmony_ci 29988c2ecf20Sopenharmony_ci if (ret >= 0) 29998c2ecf20Sopenharmony_ci netdev_state_change(tun->dev); 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_ciunlock: 30028c2ecf20Sopenharmony_ci rtnl_unlock(); 30038c2ecf20Sopenharmony_ci return ret; 30048c2ecf20Sopenharmony_ci} 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_cistatic int tun_set_ebpf(struct tun_struct *tun, struct tun_prog __rcu **prog_p, 30078c2ecf20Sopenharmony_ci void __user *data) 30088c2ecf20Sopenharmony_ci{ 30098c2ecf20Sopenharmony_ci struct bpf_prog *prog; 30108c2ecf20Sopenharmony_ci int fd; 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci if (copy_from_user(&fd, data, sizeof(fd))) 30138c2ecf20Sopenharmony_ci return -EFAULT; 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ci if (fd == -1) { 30168c2ecf20Sopenharmony_ci prog = NULL; 30178c2ecf20Sopenharmony_ci } else { 30188c2ecf20Sopenharmony_ci prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_SOCKET_FILTER); 30198c2ecf20Sopenharmony_ci if (IS_ERR(prog)) 30208c2ecf20Sopenharmony_ci return PTR_ERR(prog); 30218c2ecf20Sopenharmony_ci } 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_ci return __tun_set_ebpf(tun, prog_p, prog); 30248c2ecf20Sopenharmony_ci} 30258c2ecf20Sopenharmony_ci 30268c2ecf20Sopenharmony_ci/* Return correct value for tun->dev->addr_len based on tun->dev->type. */ 30278c2ecf20Sopenharmony_cistatic unsigned char tun_get_addr_len(unsigned short type) 30288c2ecf20Sopenharmony_ci{ 30298c2ecf20Sopenharmony_ci switch (type) { 30308c2ecf20Sopenharmony_ci case ARPHRD_IP6GRE: 30318c2ecf20Sopenharmony_ci case ARPHRD_TUNNEL6: 30328c2ecf20Sopenharmony_ci return sizeof(struct in6_addr); 30338c2ecf20Sopenharmony_ci case ARPHRD_IPGRE: 30348c2ecf20Sopenharmony_ci case ARPHRD_TUNNEL: 30358c2ecf20Sopenharmony_ci case ARPHRD_SIT: 30368c2ecf20Sopenharmony_ci return 4; 30378c2ecf20Sopenharmony_ci case ARPHRD_ETHER: 30388c2ecf20Sopenharmony_ci return ETH_ALEN; 30398c2ecf20Sopenharmony_ci case ARPHRD_IEEE802154: 30408c2ecf20Sopenharmony_ci case ARPHRD_IEEE802154_MONITOR: 30418c2ecf20Sopenharmony_ci return IEEE802154_EXTENDED_ADDR_LEN; 30428c2ecf20Sopenharmony_ci case ARPHRD_PHONET_PIPE: 30438c2ecf20Sopenharmony_ci case ARPHRD_PPP: 30448c2ecf20Sopenharmony_ci case ARPHRD_NONE: 30458c2ecf20Sopenharmony_ci return 0; 30468c2ecf20Sopenharmony_ci case ARPHRD_6LOWPAN: 30478c2ecf20Sopenharmony_ci return EUI64_ADDR_LEN; 30488c2ecf20Sopenharmony_ci case ARPHRD_FDDI: 30498c2ecf20Sopenharmony_ci return FDDI_K_ALEN; 30508c2ecf20Sopenharmony_ci case ARPHRD_HIPPI: 30518c2ecf20Sopenharmony_ci return HIPPI_ALEN; 30528c2ecf20Sopenharmony_ci case ARPHRD_IEEE802: 30538c2ecf20Sopenharmony_ci return FC_ALEN; 30548c2ecf20Sopenharmony_ci case ARPHRD_ROSE: 30558c2ecf20Sopenharmony_ci return ROSE_ADDR_LEN; 30568c2ecf20Sopenharmony_ci case ARPHRD_NETROM: 30578c2ecf20Sopenharmony_ci return AX25_ADDR_LEN; 30588c2ecf20Sopenharmony_ci case ARPHRD_LOCALTLK: 30598c2ecf20Sopenharmony_ci return LTALK_ALEN; 30608c2ecf20Sopenharmony_ci default: 30618c2ecf20Sopenharmony_ci return 0; 30628c2ecf20Sopenharmony_ci } 30638c2ecf20Sopenharmony_ci} 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_cistatic long __tun_chr_ioctl(struct file *file, unsigned int cmd, 30668c2ecf20Sopenharmony_ci unsigned long arg, int ifreq_len) 30678c2ecf20Sopenharmony_ci{ 30688c2ecf20Sopenharmony_ci struct tun_file *tfile = file->private_data; 30698c2ecf20Sopenharmony_ci struct net *net = sock_net(&tfile->sk); 30708c2ecf20Sopenharmony_ci struct tun_struct *tun; 30718c2ecf20Sopenharmony_ci void __user* argp = (void __user*)arg; 30728c2ecf20Sopenharmony_ci unsigned int carrier; 30738c2ecf20Sopenharmony_ci struct ifreq ifr; 30748c2ecf20Sopenharmony_ci kuid_t owner; 30758c2ecf20Sopenharmony_ci kgid_t group; 30768c2ecf20Sopenharmony_ci int ifindex; 30778c2ecf20Sopenharmony_ci int sndbuf; 30788c2ecf20Sopenharmony_ci int vnet_hdr_sz; 30798c2ecf20Sopenharmony_ci int le; 30808c2ecf20Sopenharmony_ci int ret; 30818c2ecf20Sopenharmony_ci bool do_notify = false; 30828c2ecf20Sopenharmony_ci 30838c2ecf20Sopenharmony_ci if (cmd == TUNSETIFF || cmd == TUNSETQUEUE || 30848c2ecf20Sopenharmony_ci (_IOC_TYPE(cmd) == SOCK_IOC_TYPE && cmd != SIOCGSKNS)) { 30858c2ecf20Sopenharmony_ci if (copy_from_user(&ifr, argp, ifreq_len)) 30868c2ecf20Sopenharmony_ci return -EFAULT; 30878c2ecf20Sopenharmony_ci } else { 30888c2ecf20Sopenharmony_ci memset(&ifr, 0, sizeof(ifr)); 30898c2ecf20Sopenharmony_ci } 30908c2ecf20Sopenharmony_ci if (cmd == TUNGETFEATURES) { 30918c2ecf20Sopenharmony_ci /* Currently this just means: "what IFF flags are valid?". 30928c2ecf20Sopenharmony_ci * This is needed because we never checked for invalid flags on 30938c2ecf20Sopenharmony_ci * TUNSETIFF. 30948c2ecf20Sopenharmony_ci */ 30958c2ecf20Sopenharmony_ci return put_user(IFF_TUN | IFF_TAP | TUN_FEATURES, 30968c2ecf20Sopenharmony_ci (unsigned int __user*)argp); 30978c2ecf20Sopenharmony_ci } else if (cmd == TUNSETQUEUE) { 30988c2ecf20Sopenharmony_ci return tun_set_queue(file, &ifr); 30998c2ecf20Sopenharmony_ci } else if (cmd == SIOCGSKNS) { 31008c2ecf20Sopenharmony_ci if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 31018c2ecf20Sopenharmony_ci return -EPERM; 31028c2ecf20Sopenharmony_ci return open_related_ns(&net->ns, get_net_ns); 31038c2ecf20Sopenharmony_ci } 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_ci ret = 0; 31068c2ecf20Sopenharmony_ci rtnl_lock(); 31078c2ecf20Sopenharmony_ci 31088c2ecf20Sopenharmony_ci tun = tun_get(tfile); 31098c2ecf20Sopenharmony_ci if (cmd == TUNSETIFF) { 31108c2ecf20Sopenharmony_ci ret = -EEXIST; 31118c2ecf20Sopenharmony_ci if (tun) 31128c2ecf20Sopenharmony_ci goto unlock; 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_ci ifr.ifr_name[IFNAMSIZ-1] = '\0'; 31158c2ecf20Sopenharmony_ci 31168c2ecf20Sopenharmony_ci ret = tun_set_iff(net, file, &ifr); 31178c2ecf20Sopenharmony_ci 31188c2ecf20Sopenharmony_ci if (ret) 31198c2ecf20Sopenharmony_ci goto unlock; 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci if (copy_to_user(argp, &ifr, ifreq_len)) 31228c2ecf20Sopenharmony_ci ret = -EFAULT; 31238c2ecf20Sopenharmony_ci goto unlock; 31248c2ecf20Sopenharmony_ci } 31258c2ecf20Sopenharmony_ci if (cmd == TUNSETIFINDEX) { 31268c2ecf20Sopenharmony_ci ret = -EPERM; 31278c2ecf20Sopenharmony_ci if (tun) 31288c2ecf20Sopenharmony_ci goto unlock; 31298c2ecf20Sopenharmony_ci 31308c2ecf20Sopenharmony_ci ret = -EFAULT; 31318c2ecf20Sopenharmony_ci if (copy_from_user(&ifindex, argp, sizeof(ifindex))) 31328c2ecf20Sopenharmony_ci goto unlock; 31338c2ecf20Sopenharmony_ci ret = -EINVAL; 31348c2ecf20Sopenharmony_ci if (ifindex < 0) 31358c2ecf20Sopenharmony_ci goto unlock; 31368c2ecf20Sopenharmony_ci ret = 0; 31378c2ecf20Sopenharmony_ci tfile->ifindex = ifindex; 31388c2ecf20Sopenharmony_ci goto unlock; 31398c2ecf20Sopenharmony_ci } 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ci ret = -EBADFD; 31428c2ecf20Sopenharmony_ci if (!tun) 31438c2ecf20Sopenharmony_ci goto unlock; 31448c2ecf20Sopenharmony_ci 31458c2ecf20Sopenharmony_ci netif_info(tun, drv, tun->dev, "tun_chr_ioctl cmd %u\n", cmd); 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_ci net = dev_net(tun->dev); 31488c2ecf20Sopenharmony_ci ret = 0; 31498c2ecf20Sopenharmony_ci switch (cmd) { 31508c2ecf20Sopenharmony_ci case TUNGETIFF: 31518c2ecf20Sopenharmony_ci tun_get_iff(tun, &ifr); 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci if (tfile->detached) 31548c2ecf20Sopenharmony_ci ifr.ifr_flags |= IFF_DETACH_QUEUE; 31558c2ecf20Sopenharmony_ci if (!tfile->socket.sk->sk_filter) 31568c2ecf20Sopenharmony_ci ifr.ifr_flags |= IFF_NOFILTER; 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_ci if (copy_to_user(argp, &ifr, ifreq_len)) 31598c2ecf20Sopenharmony_ci ret = -EFAULT; 31608c2ecf20Sopenharmony_ci break; 31618c2ecf20Sopenharmony_ci 31628c2ecf20Sopenharmony_ci case TUNSETNOCSUM: 31638c2ecf20Sopenharmony_ci /* Disable/Enable checksum */ 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci /* [unimplemented] */ 31668c2ecf20Sopenharmony_ci netif_info(tun, drv, tun->dev, "ignored: set checksum %s\n", 31678c2ecf20Sopenharmony_ci arg ? "disabled" : "enabled"); 31688c2ecf20Sopenharmony_ci break; 31698c2ecf20Sopenharmony_ci 31708c2ecf20Sopenharmony_ci case TUNSETPERSIST: 31718c2ecf20Sopenharmony_ci /* Disable/Enable persist mode. Keep an extra reference to the 31728c2ecf20Sopenharmony_ci * module to prevent the module being unprobed. 31738c2ecf20Sopenharmony_ci */ 31748c2ecf20Sopenharmony_ci if (arg && !(tun->flags & IFF_PERSIST)) { 31758c2ecf20Sopenharmony_ci tun->flags |= IFF_PERSIST; 31768c2ecf20Sopenharmony_ci __module_get(THIS_MODULE); 31778c2ecf20Sopenharmony_ci do_notify = true; 31788c2ecf20Sopenharmony_ci } 31798c2ecf20Sopenharmony_ci if (!arg && (tun->flags & IFF_PERSIST)) { 31808c2ecf20Sopenharmony_ci tun->flags &= ~IFF_PERSIST; 31818c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 31828c2ecf20Sopenharmony_ci do_notify = true; 31838c2ecf20Sopenharmony_ci } 31848c2ecf20Sopenharmony_ci 31858c2ecf20Sopenharmony_ci netif_info(tun, drv, tun->dev, "persist %s\n", 31868c2ecf20Sopenharmony_ci arg ? "enabled" : "disabled"); 31878c2ecf20Sopenharmony_ci break; 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_ci case TUNSETOWNER: 31908c2ecf20Sopenharmony_ci /* Set owner of the device */ 31918c2ecf20Sopenharmony_ci owner = make_kuid(current_user_ns(), arg); 31928c2ecf20Sopenharmony_ci if (!uid_valid(owner)) { 31938c2ecf20Sopenharmony_ci ret = -EINVAL; 31948c2ecf20Sopenharmony_ci break; 31958c2ecf20Sopenharmony_ci } 31968c2ecf20Sopenharmony_ci tun->owner = owner; 31978c2ecf20Sopenharmony_ci do_notify = true; 31988c2ecf20Sopenharmony_ci netif_info(tun, drv, tun->dev, "owner set to %u\n", 31998c2ecf20Sopenharmony_ci from_kuid(&init_user_ns, tun->owner)); 32008c2ecf20Sopenharmony_ci break; 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_ci case TUNSETGROUP: 32038c2ecf20Sopenharmony_ci /* Set group of the device */ 32048c2ecf20Sopenharmony_ci group = make_kgid(current_user_ns(), arg); 32058c2ecf20Sopenharmony_ci if (!gid_valid(group)) { 32068c2ecf20Sopenharmony_ci ret = -EINVAL; 32078c2ecf20Sopenharmony_ci break; 32088c2ecf20Sopenharmony_ci } 32098c2ecf20Sopenharmony_ci tun->group = group; 32108c2ecf20Sopenharmony_ci do_notify = true; 32118c2ecf20Sopenharmony_ci netif_info(tun, drv, tun->dev, "group set to %u\n", 32128c2ecf20Sopenharmony_ci from_kgid(&init_user_ns, tun->group)); 32138c2ecf20Sopenharmony_ci break; 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci case TUNSETLINK: 32168c2ecf20Sopenharmony_ci /* Only allow setting the type when the interface is down */ 32178c2ecf20Sopenharmony_ci if (tun->dev->flags & IFF_UP) { 32188c2ecf20Sopenharmony_ci netif_info(tun, drv, tun->dev, 32198c2ecf20Sopenharmony_ci "Linktype set failed because interface is up\n"); 32208c2ecf20Sopenharmony_ci ret = -EBUSY; 32218c2ecf20Sopenharmony_ci } else { 32228c2ecf20Sopenharmony_ci tun->dev->type = (int) arg; 32238c2ecf20Sopenharmony_ci tun->dev->addr_len = tun_get_addr_len(tun->dev->type); 32248c2ecf20Sopenharmony_ci netif_info(tun, drv, tun->dev, "linktype set to %d\n", 32258c2ecf20Sopenharmony_ci tun->dev->type); 32268c2ecf20Sopenharmony_ci ret = 0; 32278c2ecf20Sopenharmony_ci } 32288c2ecf20Sopenharmony_ci break; 32298c2ecf20Sopenharmony_ci 32308c2ecf20Sopenharmony_ci case TUNSETDEBUG: 32318c2ecf20Sopenharmony_ci tun->msg_enable = (u32)arg; 32328c2ecf20Sopenharmony_ci break; 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci case TUNSETOFFLOAD: 32358c2ecf20Sopenharmony_ci ret = set_offload(tun, arg); 32368c2ecf20Sopenharmony_ci break; 32378c2ecf20Sopenharmony_ci 32388c2ecf20Sopenharmony_ci case TUNSETTXFILTER: 32398c2ecf20Sopenharmony_ci /* Can be set only for TAPs */ 32408c2ecf20Sopenharmony_ci ret = -EINVAL; 32418c2ecf20Sopenharmony_ci if ((tun->flags & TUN_TYPE_MASK) != IFF_TAP) 32428c2ecf20Sopenharmony_ci break; 32438c2ecf20Sopenharmony_ci ret = update_filter(&tun->txflt, (void __user *)arg); 32448c2ecf20Sopenharmony_ci break; 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_ci case SIOCGIFHWADDR: 32478c2ecf20Sopenharmony_ci /* Get hw address */ 32488c2ecf20Sopenharmony_ci dev_get_mac_address(&ifr.ifr_hwaddr, net, tun->dev->name); 32498c2ecf20Sopenharmony_ci if (copy_to_user(argp, &ifr, ifreq_len)) 32508c2ecf20Sopenharmony_ci ret = -EFAULT; 32518c2ecf20Sopenharmony_ci break; 32528c2ecf20Sopenharmony_ci 32538c2ecf20Sopenharmony_ci case SIOCSIFHWADDR: 32548c2ecf20Sopenharmony_ci /* Set hw address */ 32558c2ecf20Sopenharmony_ci ret = dev_set_mac_address_user(tun->dev, &ifr.ifr_hwaddr, NULL); 32568c2ecf20Sopenharmony_ci break; 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_ci case TUNGETSNDBUF: 32598c2ecf20Sopenharmony_ci sndbuf = tfile->socket.sk->sk_sndbuf; 32608c2ecf20Sopenharmony_ci if (copy_to_user(argp, &sndbuf, sizeof(sndbuf))) 32618c2ecf20Sopenharmony_ci ret = -EFAULT; 32628c2ecf20Sopenharmony_ci break; 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci case TUNSETSNDBUF: 32658c2ecf20Sopenharmony_ci if (copy_from_user(&sndbuf, argp, sizeof(sndbuf))) { 32668c2ecf20Sopenharmony_ci ret = -EFAULT; 32678c2ecf20Sopenharmony_ci break; 32688c2ecf20Sopenharmony_ci } 32698c2ecf20Sopenharmony_ci if (sndbuf <= 0) { 32708c2ecf20Sopenharmony_ci ret = -EINVAL; 32718c2ecf20Sopenharmony_ci break; 32728c2ecf20Sopenharmony_ci } 32738c2ecf20Sopenharmony_ci 32748c2ecf20Sopenharmony_ci tun->sndbuf = sndbuf; 32758c2ecf20Sopenharmony_ci tun_set_sndbuf(tun); 32768c2ecf20Sopenharmony_ci break; 32778c2ecf20Sopenharmony_ci 32788c2ecf20Sopenharmony_ci case TUNGETVNETHDRSZ: 32798c2ecf20Sopenharmony_ci vnet_hdr_sz = tun->vnet_hdr_sz; 32808c2ecf20Sopenharmony_ci if (copy_to_user(argp, &vnet_hdr_sz, sizeof(vnet_hdr_sz))) 32818c2ecf20Sopenharmony_ci ret = -EFAULT; 32828c2ecf20Sopenharmony_ci break; 32838c2ecf20Sopenharmony_ci 32848c2ecf20Sopenharmony_ci case TUNSETVNETHDRSZ: 32858c2ecf20Sopenharmony_ci if (copy_from_user(&vnet_hdr_sz, argp, sizeof(vnet_hdr_sz))) { 32868c2ecf20Sopenharmony_ci ret = -EFAULT; 32878c2ecf20Sopenharmony_ci break; 32888c2ecf20Sopenharmony_ci } 32898c2ecf20Sopenharmony_ci if (vnet_hdr_sz < (int)sizeof(struct virtio_net_hdr)) { 32908c2ecf20Sopenharmony_ci ret = -EINVAL; 32918c2ecf20Sopenharmony_ci break; 32928c2ecf20Sopenharmony_ci } 32938c2ecf20Sopenharmony_ci 32948c2ecf20Sopenharmony_ci tun->vnet_hdr_sz = vnet_hdr_sz; 32958c2ecf20Sopenharmony_ci break; 32968c2ecf20Sopenharmony_ci 32978c2ecf20Sopenharmony_ci case TUNGETVNETLE: 32988c2ecf20Sopenharmony_ci le = !!(tun->flags & TUN_VNET_LE); 32998c2ecf20Sopenharmony_ci if (put_user(le, (int __user *)argp)) 33008c2ecf20Sopenharmony_ci ret = -EFAULT; 33018c2ecf20Sopenharmony_ci break; 33028c2ecf20Sopenharmony_ci 33038c2ecf20Sopenharmony_ci case TUNSETVNETLE: 33048c2ecf20Sopenharmony_ci if (get_user(le, (int __user *)argp)) { 33058c2ecf20Sopenharmony_ci ret = -EFAULT; 33068c2ecf20Sopenharmony_ci break; 33078c2ecf20Sopenharmony_ci } 33088c2ecf20Sopenharmony_ci if (le) 33098c2ecf20Sopenharmony_ci tun->flags |= TUN_VNET_LE; 33108c2ecf20Sopenharmony_ci else 33118c2ecf20Sopenharmony_ci tun->flags &= ~TUN_VNET_LE; 33128c2ecf20Sopenharmony_ci break; 33138c2ecf20Sopenharmony_ci 33148c2ecf20Sopenharmony_ci case TUNGETVNETBE: 33158c2ecf20Sopenharmony_ci ret = tun_get_vnet_be(tun, argp); 33168c2ecf20Sopenharmony_ci break; 33178c2ecf20Sopenharmony_ci 33188c2ecf20Sopenharmony_ci case TUNSETVNETBE: 33198c2ecf20Sopenharmony_ci ret = tun_set_vnet_be(tun, argp); 33208c2ecf20Sopenharmony_ci break; 33218c2ecf20Sopenharmony_ci 33228c2ecf20Sopenharmony_ci case TUNATTACHFILTER: 33238c2ecf20Sopenharmony_ci /* Can be set only for TAPs */ 33248c2ecf20Sopenharmony_ci ret = -EINVAL; 33258c2ecf20Sopenharmony_ci if ((tun->flags & TUN_TYPE_MASK) != IFF_TAP) 33268c2ecf20Sopenharmony_ci break; 33278c2ecf20Sopenharmony_ci ret = -EFAULT; 33288c2ecf20Sopenharmony_ci if (copy_from_user(&tun->fprog, argp, sizeof(tun->fprog))) 33298c2ecf20Sopenharmony_ci break; 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_ci ret = tun_attach_filter(tun); 33328c2ecf20Sopenharmony_ci break; 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci case TUNDETACHFILTER: 33358c2ecf20Sopenharmony_ci /* Can be set only for TAPs */ 33368c2ecf20Sopenharmony_ci ret = -EINVAL; 33378c2ecf20Sopenharmony_ci if ((tun->flags & TUN_TYPE_MASK) != IFF_TAP) 33388c2ecf20Sopenharmony_ci break; 33398c2ecf20Sopenharmony_ci ret = 0; 33408c2ecf20Sopenharmony_ci tun_detach_filter(tun, tun->numqueues); 33418c2ecf20Sopenharmony_ci break; 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_ci case TUNGETFILTER: 33448c2ecf20Sopenharmony_ci ret = -EINVAL; 33458c2ecf20Sopenharmony_ci if ((tun->flags & TUN_TYPE_MASK) != IFF_TAP) 33468c2ecf20Sopenharmony_ci break; 33478c2ecf20Sopenharmony_ci ret = -EFAULT; 33488c2ecf20Sopenharmony_ci if (copy_to_user(argp, &tun->fprog, sizeof(tun->fprog))) 33498c2ecf20Sopenharmony_ci break; 33508c2ecf20Sopenharmony_ci ret = 0; 33518c2ecf20Sopenharmony_ci break; 33528c2ecf20Sopenharmony_ci 33538c2ecf20Sopenharmony_ci case TUNSETSTEERINGEBPF: 33548c2ecf20Sopenharmony_ci ret = tun_set_ebpf(tun, &tun->steering_prog, argp); 33558c2ecf20Sopenharmony_ci break; 33568c2ecf20Sopenharmony_ci 33578c2ecf20Sopenharmony_ci case TUNSETFILTEREBPF: 33588c2ecf20Sopenharmony_ci ret = tun_set_ebpf(tun, &tun->filter_prog, argp); 33598c2ecf20Sopenharmony_ci break; 33608c2ecf20Sopenharmony_ci 33618c2ecf20Sopenharmony_ci case TUNSETCARRIER: 33628c2ecf20Sopenharmony_ci ret = -EFAULT; 33638c2ecf20Sopenharmony_ci if (copy_from_user(&carrier, argp, sizeof(carrier))) 33648c2ecf20Sopenharmony_ci goto unlock; 33658c2ecf20Sopenharmony_ci 33668c2ecf20Sopenharmony_ci ret = tun_net_change_carrier(tun->dev, (bool)carrier); 33678c2ecf20Sopenharmony_ci break; 33688c2ecf20Sopenharmony_ci 33698c2ecf20Sopenharmony_ci case TUNGETDEVNETNS: 33708c2ecf20Sopenharmony_ci ret = -EPERM; 33718c2ecf20Sopenharmony_ci if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 33728c2ecf20Sopenharmony_ci goto unlock; 33738c2ecf20Sopenharmony_ci ret = open_related_ns(&net->ns, get_net_ns); 33748c2ecf20Sopenharmony_ci break; 33758c2ecf20Sopenharmony_ci 33768c2ecf20Sopenharmony_ci default: 33778c2ecf20Sopenharmony_ci ret = -EINVAL; 33788c2ecf20Sopenharmony_ci break; 33798c2ecf20Sopenharmony_ci } 33808c2ecf20Sopenharmony_ci 33818c2ecf20Sopenharmony_ci if (do_notify) 33828c2ecf20Sopenharmony_ci netdev_state_change(tun->dev); 33838c2ecf20Sopenharmony_ci 33848c2ecf20Sopenharmony_ciunlock: 33858c2ecf20Sopenharmony_ci rtnl_unlock(); 33868c2ecf20Sopenharmony_ci if (tun) 33878c2ecf20Sopenharmony_ci tun_put(tun); 33888c2ecf20Sopenharmony_ci return ret; 33898c2ecf20Sopenharmony_ci} 33908c2ecf20Sopenharmony_ci 33918c2ecf20Sopenharmony_cistatic long tun_chr_ioctl(struct file *file, 33928c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 33938c2ecf20Sopenharmony_ci{ 33948c2ecf20Sopenharmony_ci return __tun_chr_ioctl(file, cmd, arg, sizeof (struct ifreq)); 33958c2ecf20Sopenharmony_ci} 33968c2ecf20Sopenharmony_ci 33978c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 33988c2ecf20Sopenharmony_cistatic long tun_chr_compat_ioctl(struct file *file, 33998c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 34008c2ecf20Sopenharmony_ci{ 34018c2ecf20Sopenharmony_ci switch (cmd) { 34028c2ecf20Sopenharmony_ci case TUNSETIFF: 34038c2ecf20Sopenharmony_ci case TUNGETIFF: 34048c2ecf20Sopenharmony_ci case TUNSETTXFILTER: 34058c2ecf20Sopenharmony_ci case TUNGETSNDBUF: 34068c2ecf20Sopenharmony_ci case TUNSETSNDBUF: 34078c2ecf20Sopenharmony_ci case SIOCGIFHWADDR: 34088c2ecf20Sopenharmony_ci case SIOCSIFHWADDR: 34098c2ecf20Sopenharmony_ci arg = (unsigned long)compat_ptr(arg); 34108c2ecf20Sopenharmony_ci break; 34118c2ecf20Sopenharmony_ci default: 34128c2ecf20Sopenharmony_ci arg = (compat_ulong_t)arg; 34138c2ecf20Sopenharmony_ci break; 34148c2ecf20Sopenharmony_ci } 34158c2ecf20Sopenharmony_ci 34168c2ecf20Sopenharmony_ci /* 34178c2ecf20Sopenharmony_ci * compat_ifreq is shorter than ifreq, so we must not access beyond 34188c2ecf20Sopenharmony_ci * the end of that structure. All fields that are used in this 34198c2ecf20Sopenharmony_ci * driver are compatible though, we don't need to convert the 34208c2ecf20Sopenharmony_ci * contents. 34218c2ecf20Sopenharmony_ci */ 34228c2ecf20Sopenharmony_ci return __tun_chr_ioctl(file, cmd, arg, sizeof(struct compat_ifreq)); 34238c2ecf20Sopenharmony_ci} 34248c2ecf20Sopenharmony_ci#endif /* CONFIG_COMPAT */ 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_cistatic int tun_chr_fasync(int fd, struct file *file, int on) 34278c2ecf20Sopenharmony_ci{ 34288c2ecf20Sopenharmony_ci struct tun_file *tfile = file->private_data; 34298c2ecf20Sopenharmony_ci int ret; 34308c2ecf20Sopenharmony_ci 34318c2ecf20Sopenharmony_ci if ((ret = fasync_helper(fd, file, on, &tfile->fasync)) < 0) 34328c2ecf20Sopenharmony_ci goto out; 34338c2ecf20Sopenharmony_ci 34348c2ecf20Sopenharmony_ci if (on) { 34358c2ecf20Sopenharmony_ci __f_setown(file, task_pid(current), PIDTYPE_TGID, 0); 34368c2ecf20Sopenharmony_ci tfile->flags |= TUN_FASYNC; 34378c2ecf20Sopenharmony_ci } else 34388c2ecf20Sopenharmony_ci tfile->flags &= ~TUN_FASYNC; 34398c2ecf20Sopenharmony_ci ret = 0; 34408c2ecf20Sopenharmony_ciout: 34418c2ecf20Sopenharmony_ci return ret; 34428c2ecf20Sopenharmony_ci} 34438c2ecf20Sopenharmony_ci 34448c2ecf20Sopenharmony_cistatic int tun_chr_open(struct inode *inode, struct file * file) 34458c2ecf20Sopenharmony_ci{ 34468c2ecf20Sopenharmony_ci struct net *net = current->nsproxy->net_ns; 34478c2ecf20Sopenharmony_ci struct tun_file *tfile; 34488c2ecf20Sopenharmony_ci 34498c2ecf20Sopenharmony_ci tfile = (struct tun_file *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL, 34508c2ecf20Sopenharmony_ci &tun_proto, 0); 34518c2ecf20Sopenharmony_ci if (!tfile) 34528c2ecf20Sopenharmony_ci return -ENOMEM; 34538c2ecf20Sopenharmony_ci if (ptr_ring_init(&tfile->tx_ring, 0, GFP_KERNEL)) { 34548c2ecf20Sopenharmony_ci sk_free(&tfile->sk); 34558c2ecf20Sopenharmony_ci return -ENOMEM; 34568c2ecf20Sopenharmony_ci } 34578c2ecf20Sopenharmony_ci 34588c2ecf20Sopenharmony_ci mutex_init(&tfile->napi_mutex); 34598c2ecf20Sopenharmony_ci RCU_INIT_POINTER(tfile->tun, NULL); 34608c2ecf20Sopenharmony_ci tfile->flags = 0; 34618c2ecf20Sopenharmony_ci tfile->ifindex = 0; 34628c2ecf20Sopenharmony_ci 34638c2ecf20Sopenharmony_ci init_waitqueue_head(&tfile->socket.wq.wait); 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_ci tfile->socket.file = file; 34668c2ecf20Sopenharmony_ci tfile->socket.ops = &tun_socket_ops; 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_ci sock_init_data_uid(&tfile->socket, &tfile->sk, current_fsuid()); 34698c2ecf20Sopenharmony_ci 34708c2ecf20Sopenharmony_ci tfile->sk.sk_write_space = tun_sock_write_space; 34718c2ecf20Sopenharmony_ci tfile->sk.sk_sndbuf = INT_MAX; 34728c2ecf20Sopenharmony_ci 34738c2ecf20Sopenharmony_ci file->private_data = tfile; 34748c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tfile->next); 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ci sock_set_flag(&tfile->sk, SOCK_ZEROCOPY); 34778c2ecf20Sopenharmony_ci 34788c2ecf20Sopenharmony_ci return 0; 34798c2ecf20Sopenharmony_ci} 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_cistatic int tun_chr_close(struct inode *inode, struct file *file) 34828c2ecf20Sopenharmony_ci{ 34838c2ecf20Sopenharmony_ci struct tun_file *tfile = file->private_data; 34848c2ecf20Sopenharmony_ci 34858c2ecf20Sopenharmony_ci tun_detach(tfile, true); 34868c2ecf20Sopenharmony_ci 34878c2ecf20Sopenharmony_ci return 0; 34888c2ecf20Sopenharmony_ci} 34898c2ecf20Sopenharmony_ci 34908c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 34918c2ecf20Sopenharmony_cistatic void tun_chr_show_fdinfo(struct seq_file *m, struct file *file) 34928c2ecf20Sopenharmony_ci{ 34938c2ecf20Sopenharmony_ci struct tun_file *tfile = file->private_data; 34948c2ecf20Sopenharmony_ci struct tun_struct *tun; 34958c2ecf20Sopenharmony_ci struct ifreq ifr; 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_ci memset(&ifr, 0, sizeof(ifr)); 34988c2ecf20Sopenharmony_ci 34998c2ecf20Sopenharmony_ci rtnl_lock(); 35008c2ecf20Sopenharmony_ci tun = tun_get(tfile); 35018c2ecf20Sopenharmony_ci if (tun) 35028c2ecf20Sopenharmony_ci tun_get_iff(tun, &ifr); 35038c2ecf20Sopenharmony_ci rtnl_unlock(); 35048c2ecf20Sopenharmony_ci 35058c2ecf20Sopenharmony_ci if (tun) 35068c2ecf20Sopenharmony_ci tun_put(tun); 35078c2ecf20Sopenharmony_ci 35088c2ecf20Sopenharmony_ci seq_printf(m, "iff:\t%s\n", ifr.ifr_name); 35098c2ecf20Sopenharmony_ci} 35108c2ecf20Sopenharmony_ci#endif 35118c2ecf20Sopenharmony_ci 35128c2ecf20Sopenharmony_cistatic const struct file_operations tun_fops = { 35138c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 35148c2ecf20Sopenharmony_ci .llseek = no_llseek, 35158c2ecf20Sopenharmony_ci .read_iter = tun_chr_read_iter, 35168c2ecf20Sopenharmony_ci .write_iter = tun_chr_write_iter, 35178c2ecf20Sopenharmony_ci .poll = tun_chr_poll, 35188c2ecf20Sopenharmony_ci .unlocked_ioctl = tun_chr_ioctl, 35198c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 35208c2ecf20Sopenharmony_ci .compat_ioctl = tun_chr_compat_ioctl, 35218c2ecf20Sopenharmony_ci#endif 35228c2ecf20Sopenharmony_ci .open = tun_chr_open, 35238c2ecf20Sopenharmony_ci .release = tun_chr_close, 35248c2ecf20Sopenharmony_ci .fasync = tun_chr_fasync, 35258c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 35268c2ecf20Sopenharmony_ci .show_fdinfo = tun_chr_show_fdinfo, 35278c2ecf20Sopenharmony_ci#endif 35288c2ecf20Sopenharmony_ci}; 35298c2ecf20Sopenharmony_ci 35308c2ecf20Sopenharmony_cistatic struct miscdevice tun_miscdev = { 35318c2ecf20Sopenharmony_ci .minor = TUN_MINOR, 35328c2ecf20Sopenharmony_ci .name = "tun", 35338c2ecf20Sopenharmony_ci .nodename = "net/tun", 35348c2ecf20Sopenharmony_ci .fops = &tun_fops, 35358c2ecf20Sopenharmony_ci}; 35368c2ecf20Sopenharmony_ci 35378c2ecf20Sopenharmony_ci/* ethtool interface */ 35388c2ecf20Sopenharmony_ci 35398c2ecf20Sopenharmony_cistatic void tun_default_link_ksettings(struct net_device *dev, 35408c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 35418c2ecf20Sopenharmony_ci{ 35428c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(cmd, supported); 35438c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(cmd, advertising); 35448c2ecf20Sopenharmony_ci cmd->base.speed = SPEED_10; 35458c2ecf20Sopenharmony_ci cmd->base.duplex = DUPLEX_FULL; 35468c2ecf20Sopenharmony_ci cmd->base.port = PORT_TP; 35478c2ecf20Sopenharmony_ci cmd->base.phy_address = 0; 35488c2ecf20Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 35498c2ecf20Sopenharmony_ci} 35508c2ecf20Sopenharmony_ci 35518c2ecf20Sopenharmony_cistatic int tun_get_link_ksettings(struct net_device *dev, 35528c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 35538c2ecf20Sopenharmony_ci{ 35548c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 35558c2ecf20Sopenharmony_ci 35568c2ecf20Sopenharmony_ci memcpy(cmd, &tun->link_ksettings, sizeof(*cmd)); 35578c2ecf20Sopenharmony_ci return 0; 35588c2ecf20Sopenharmony_ci} 35598c2ecf20Sopenharmony_ci 35608c2ecf20Sopenharmony_cistatic int tun_set_link_ksettings(struct net_device *dev, 35618c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 35628c2ecf20Sopenharmony_ci{ 35638c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 35648c2ecf20Sopenharmony_ci 35658c2ecf20Sopenharmony_ci memcpy(&tun->link_ksettings, cmd, sizeof(*cmd)); 35668c2ecf20Sopenharmony_ci return 0; 35678c2ecf20Sopenharmony_ci} 35688c2ecf20Sopenharmony_ci 35698c2ecf20Sopenharmony_cistatic void tun_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 35708c2ecf20Sopenharmony_ci{ 35718c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 35728c2ecf20Sopenharmony_ci 35738c2ecf20Sopenharmony_ci strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); 35748c2ecf20Sopenharmony_ci strlcpy(info->version, DRV_VERSION, sizeof(info->version)); 35758c2ecf20Sopenharmony_ci 35768c2ecf20Sopenharmony_ci switch (tun->flags & TUN_TYPE_MASK) { 35778c2ecf20Sopenharmony_ci case IFF_TUN: 35788c2ecf20Sopenharmony_ci strlcpy(info->bus_info, "tun", sizeof(info->bus_info)); 35798c2ecf20Sopenharmony_ci break; 35808c2ecf20Sopenharmony_ci case IFF_TAP: 35818c2ecf20Sopenharmony_ci strlcpy(info->bus_info, "tap", sizeof(info->bus_info)); 35828c2ecf20Sopenharmony_ci break; 35838c2ecf20Sopenharmony_ci } 35848c2ecf20Sopenharmony_ci} 35858c2ecf20Sopenharmony_ci 35868c2ecf20Sopenharmony_cistatic u32 tun_get_msglevel(struct net_device *dev) 35878c2ecf20Sopenharmony_ci{ 35888c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 35898c2ecf20Sopenharmony_ci 35908c2ecf20Sopenharmony_ci return tun->msg_enable; 35918c2ecf20Sopenharmony_ci} 35928c2ecf20Sopenharmony_ci 35938c2ecf20Sopenharmony_cistatic void tun_set_msglevel(struct net_device *dev, u32 value) 35948c2ecf20Sopenharmony_ci{ 35958c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 35968c2ecf20Sopenharmony_ci 35978c2ecf20Sopenharmony_ci tun->msg_enable = value; 35988c2ecf20Sopenharmony_ci} 35998c2ecf20Sopenharmony_ci 36008c2ecf20Sopenharmony_cistatic int tun_get_coalesce(struct net_device *dev, 36018c2ecf20Sopenharmony_ci struct ethtool_coalesce *ec) 36028c2ecf20Sopenharmony_ci{ 36038c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 36048c2ecf20Sopenharmony_ci 36058c2ecf20Sopenharmony_ci ec->rx_max_coalesced_frames = tun->rx_batched; 36068c2ecf20Sopenharmony_ci 36078c2ecf20Sopenharmony_ci return 0; 36088c2ecf20Sopenharmony_ci} 36098c2ecf20Sopenharmony_ci 36108c2ecf20Sopenharmony_cistatic int tun_set_coalesce(struct net_device *dev, 36118c2ecf20Sopenharmony_ci struct ethtool_coalesce *ec) 36128c2ecf20Sopenharmony_ci{ 36138c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 36148c2ecf20Sopenharmony_ci 36158c2ecf20Sopenharmony_ci if (ec->rx_max_coalesced_frames > NAPI_POLL_WEIGHT) 36168c2ecf20Sopenharmony_ci tun->rx_batched = NAPI_POLL_WEIGHT; 36178c2ecf20Sopenharmony_ci else 36188c2ecf20Sopenharmony_ci tun->rx_batched = ec->rx_max_coalesced_frames; 36198c2ecf20Sopenharmony_ci 36208c2ecf20Sopenharmony_ci return 0; 36218c2ecf20Sopenharmony_ci} 36228c2ecf20Sopenharmony_ci 36238c2ecf20Sopenharmony_cistatic const struct ethtool_ops tun_ethtool_ops = { 36248c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_RX_MAX_FRAMES, 36258c2ecf20Sopenharmony_ci .get_drvinfo = tun_get_drvinfo, 36268c2ecf20Sopenharmony_ci .get_msglevel = tun_get_msglevel, 36278c2ecf20Sopenharmony_ci .set_msglevel = tun_set_msglevel, 36288c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 36298c2ecf20Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 36308c2ecf20Sopenharmony_ci .get_coalesce = tun_get_coalesce, 36318c2ecf20Sopenharmony_ci .set_coalesce = tun_set_coalesce, 36328c2ecf20Sopenharmony_ci .get_link_ksettings = tun_get_link_ksettings, 36338c2ecf20Sopenharmony_ci .set_link_ksettings = tun_set_link_ksettings, 36348c2ecf20Sopenharmony_ci}; 36358c2ecf20Sopenharmony_ci 36368c2ecf20Sopenharmony_cistatic int tun_queue_resize(struct tun_struct *tun) 36378c2ecf20Sopenharmony_ci{ 36388c2ecf20Sopenharmony_ci struct net_device *dev = tun->dev; 36398c2ecf20Sopenharmony_ci struct tun_file *tfile; 36408c2ecf20Sopenharmony_ci struct ptr_ring **rings; 36418c2ecf20Sopenharmony_ci int n = tun->numqueues + tun->numdisabled; 36428c2ecf20Sopenharmony_ci int ret, i; 36438c2ecf20Sopenharmony_ci 36448c2ecf20Sopenharmony_ci rings = kmalloc_array(n, sizeof(*rings), GFP_KERNEL); 36458c2ecf20Sopenharmony_ci if (!rings) 36468c2ecf20Sopenharmony_ci return -ENOMEM; 36478c2ecf20Sopenharmony_ci 36488c2ecf20Sopenharmony_ci for (i = 0; i < tun->numqueues; i++) { 36498c2ecf20Sopenharmony_ci tfile = rtnl_dereference(tun->tfiles[i]); 36508c2ecf20Sopenharmony_ci rings[i] = &tfile->tx_ring; 36518c2ecf20Sopenharmony_ci } 36528c2ecf20Sopenharmony_ci list_for_each_entry(tfile, &tun->disabled, next) 36538c2ecf20Sopenharmony_ci rings[i++] = &tfile->tx_ring; 36548c2ecf20Sopenharmony_ci 36558c2ecf20Sopenharmony_ci ret = ptr_ring_resize_multiple(rings, n, 36568c2ecf20Sopenharmony_ci dev->tx_queue_len, GFP_KERNEL, 36578c2ecf20Sopenharmony_ci tun_ptr_free); 36588c2ecf20Sopenharmony_ci 36598c2ecf20Sopenharmony_ci kfree(rings); 36608c2ecf20Sopenharmony_ci return ret; 36618c2ecf20Sopenharmony_ci} 36628c2ecf20Sopenharmony_ci 36638c2ecf20Sopenharmony_cistatic int tun_device_event(struct notifier_block *unused, 36648c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 36658c2ecf20Sopenharmony_ci{ 36668c2ecf20Sopenharmony_ci struct net_device *dev = netdev_notifier_info_to_dev(ptr); 36678c2ecf20Sopenharmony_ci struct tun_struct *tun = netdev_priv(dev); 36688c2ecf20Sopenharmony_ci int i; 36698c2ecf20Sopenharmony_ci 36708c2ecf20Sopenharmony_ci if (dev->rtnl_link_ops != &tun_link_ops) 36718c2ecf20Sopenharmony_ci return NOTIFY_DONE; 36728c2ecf20Sopenharmony_ci 36738c2ecf20Sopenharmony_ci switch (event) { 36748c2ecf20Sopenharmony_ci case NETDEV_CHANGE_TX_QUEUE_LEN: 36758c2ecf20Sopenharmony_ci if (tun_queue_resize(tun)) 36768c2ecf20Sopenharmony_ci return NOTIFY_BAD; 36778c2ecf20Sopenharmony_ci break; 36788c2ecf20Sopenharmony_ci case NETDEV_UP: 36798c2ecf20Sopenharmony_ci for (i = 0; i < tun->numqueues; i++) { 36808c2ecf20Sopenharmony_ci struct tun_file *tfile; 36818c2ecf20Sopenharmony_ci 36828c2ecf20Sopenharmony_ci tfile = rtnl_dereference(tun->tfiles[i]); 36838c2ecf20Sopenharmony_ci tfile->socket.sk->sk_write_space(tfile->socket.sk); 36848c2ecf20Sopenharmony_ci } 36858c2ecf20Sopenharmony_ci break; 36868c2ecf20Sopenharmony_ci default: 36878c2ecf20Sopenharmony_ci break; 36888c2ecf20Sopenharmony_ci } 36898c2ecf20Sopenharmony_ci 36908c2ecf20Sopenharmony_ci return NOTIFY_DONE; 36918c2ecf20Sopenharmony_ci} 36928c2ecf20Sopenharmony_ci 36938c2ecf20Sopenharmony_cistatic struct notifier_block tun_notifier_block __read_mostly = { 36948c2ecf20Sopenharmony_ci .notifier_call = tun_device_event, 36958c2ecf20Sopenharmony_ci}; 36968c2ecf20Sopenharmony_ci 36978c2ecf20Sopenharmony_cistatic int __init tun_init(void) 36988c2ecf20Sopenharmony_ci{ 36998c2ecf20Sopenharmony_ci int ret = 0; 37008c2ecf20Sopenharmony_ci 37018c2ecf20Sopenharmony_ci pr_info("%s, %s\n", DRV_DESCRIPTION, DRV_VERSION); 37028c2ecf20Sopenharmony_ci 37038c2ecf20Sopenharmony_ci ret = rtnl_link_register(&tun_link_ops); 37048c2ecf20Sopenharmony_ci if (ret) { 37058c2ecf20Sopenharmony_ci pr_err("Can't register link_ops\n"); 37068c2ecf20Sopenharmony_ci goto err_linkops; 37078c2ecf20Sopenharmony_ci } 37088c2ecf20Sopenharmony_ci 37098c2ecf20Sopenharmony_ci ret = misc_register(&tun_miscdev); 37108c2ecf20Sopenharmony_ci if (ret) { 37118c2ecf20Sopenharmony_ci pr_err("Can't register misc device %d\n", TUN_MINOR); 37128c2ecf20Sopenharmony_ci goto err_misc; 37138c2ecf20Sopenharmony_ci } 37148c2ecf20Sopenharmony_ci 37158c2ecf20Sopenharmony_ci ret = register_netdevice_notifier(&tun_notifier_block); 37168c2ecf20Sopenharmony_ci if (ret) { 37178c2ecf20Sopenharmony_ci pr_err("Can't register netdevice notifier\n"); 37188c2ecf20Sopenharmony_ci goto err_notifier; 37198c2ecf20Sopenharmony_ci } 37208c2ecf20Sopenharmony_ci 37218c2ecf20Sopenharmony_ci return 0; 37228c2ecf20Sopenharmony_ci 37238c2ecf20Sopenharmony_cierr_notifier: 37248c2ecf20Sopenharmony_ci misc_deregister(&tun_miscdev); 37258c2ecf20Sopenharmony_cierr_misc: 37268c2ecf20Sopenharmony_ci rtnl_link_unregister(&tun_link_ops); 37278c2ecf20Sopenharmony_cierr_linkops: 37288c2ecf20Sopenharmony_ci return ret; 37298c2ecf20Sopenharmony_ci} 37308c2ecf20Sopenharmony_ci 37318c2ecf20Sopenharmony_cistatic void tun_cleanup(void) 37328c2ecf20Sopenharmony_ci{ 37338c2ecf20Sopenharmony_ci misc_deregister(&tun_miscdev); 37348c2ecf20Sopenharmony_ci rtnl_link_unregister(&tun_link_ops); 37358c2ecf20Sopenharmony_ci unregister_netdevice_notifier(&tun_notifier_block); 37368c2ecf20Sopenharmony_ci} 37378c2ecf20Sopenharmony_ci 37388c2ecf20Sopenharmony_ci/* Get an underlying socket object from tun file. Returns error unless file is 37398c2ecf20Sopenharmony_ci * attached to a device. The returned object works like a packet socket, it 37408c2ecf20Sopenharmony_ci * can be used for sock_sendmsg/sock_recvmsg. The caller is responsible for 37418c2ecf20Sopenharmony_ci * holding a reference to the file for as long as the socket is in use. */ 37428c2ecf20Sopenharmony_cistruct socket *tun_get_socket(struct file *file) 37438c2ecf20Sopenharmony_ci{ 37448c2ecf20Sopenharmony_ci struct tun_file *tfile; 37458c2ecf20Sopenharmony_ci if (file->f_op != &tun_fops) 37468c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 37478c2ecf20Sopenharmony_ci tfile = file->private_data; 37488c2ecf20Sopenharmony_ci if (!tfile) 37498c2ecf20Sopenharmony_ci return ERR_PTR(-EBADFD); 37508c2ecf20Sopenharmony_ci return &tfile->socket; 37518c2ecf20Sopenharmony_ci} 37528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tun_get_socket); 37538c2ecf20Sopenharmony_ci 37548c2ecf20Sopenharmony_cistruct ptr_ring *tun_get_tx_ring(struct file *file) 37558c2ecf20Sopenharmony_ci{ 37568c2ecf20Sopenharmony_ci struct tun_file *tfile; 37578c2ecf20Sopenharmony_ci 37588c2ecf20Sopenharmony_ci if (file->f_op != &tun_fops) 37598c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 37608c2ecf20Sopenharmony_ci tfile = file->private_data; 37618c2ecf20Sopenharmony_ci if (!tfile) 37628c2ecf20Sopenharmony_ci return ERR_PTR(-EBADFD); 37638c2ecf20Sopenharmony_ci return &tfile->tx_ring; 37648c2ecf20Sopenharmony_ci} 37658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tun_get_tx_ring); 37668c2ecf20Sopenharmony_ci 37678c2ecf20Sopenharmony_cimodule_init(tun_init); 37688c2ecf20Sopenharmony_cimodule_exit(tun_cleanup); 37698c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRV_DESCRIPTION); 37708c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRV_COPYRIGHT); 37718c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 37728c2ecf20Sopenharmony_ciMODULE_ALIAS_MISCDEV(TUN_MINOR); 37738c2ecf20Sopenharmony_ciMODULE_ALIAS("devname:net/tun"); 3774