1  // SPDX-License-Identifier: GPL-2.0-or-later
2  /*
3   * Tap functions for AF_VSOCK sockets.
4   *
5   * Code based on net/netlink/af_netlink.c tap functions.
6   */
7  
8  #include <linux/module.h>
9  #include <net/sock.h>
10  #include <net/af_vsock.h>
11  #include <linux/if_arp.h>
12  
13  static DEFINE_SPINLOCK(vsock_tap_lock);
14  static struct list_head vsock_tap_all __read_mostly =
15  				LIST_HEAD_INIT(vsock_tap_all);
16  
vsock_add_tap(struct vsock_tap * vt)17  int vsock_add_tap(struct vsock_tap *vt)
18  {
19  	if (unlikely(vt->dev->type != ARPHRD_VSOCKMON))
20  		return -EINVAL;
21  
22  	__module_get(vt->module);
23  
24  	spin_lock(&vsock_tap_lock);
25  	list_add_rcu(&vt->list, &vsock_tap_all);
26  	spin_unlock(&vsock_tap_lock);
27  
28  	return 0;
29  }
30  EXPORT_SYMBOL_GPL(vsock_add_tap);
31  
vsock_remove_tap(struct vsock_tap * vt)32  int vsock_remove_tap(struct vsock_tap *vt)
33  {
34  	struct vsock_tap *tmp;
35  	bool found = false;
36  
37  	spin_lock(&vsock_tap_lock);
38  
39  	list_for_each_entry(tmp, &vsock_tap_all, list) {
40  		if (vt == tmp) {
41  			list_del_rcu(&vt->list);
42  			found = true;
43  			goto out;
44  		}
45  	}
46  
47  	pr_warn("vsock_remove_tap: %p not found\n", vt);
48  out:
49  	spin_unlock(&vsock_tap_lock);
50  
51  	synchronize_net();
52  
53  	if (found)
54  		module_put(vt->module);
55  
56  	return found ? 0 : -ENODEV;
57  }
58  EXPORT_SYMBOL_GPL(vsock_remove_tap);
59  
__vsock_deliver_tap_skb(struct sk_buff * skb,struct net_device * dev)60  static int __vsock_deliver_tap_skb(struct sk_buff *skb,
61  				   struct net_device *dev)
62  {
63  	int ret = 0;
64  	struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
65  
66  	if (nskb) {
67  		dev_hold(dev);
68  
69  		nskb->dev = dev;
70  		ret = dev_queue_xmit(nskb);
71  		if (unlikely(ret > 0))
72  			ret = net_xmit_errno(ret);
73  
74  		dev_put(dev);
75  	}
76  
77  	return ret;
78  }
79  
__vsock_deliver_tap(struct sk_buff * skb)80  static void __vsock_deliver_tap(struct sk_buff *skb)
81  {
82  	int ret;
83  	struct vsock_tap *tmp;
84  
85  	list_for_each_entry_rcu(tmp, &vsock_tap_all, list) {
86  		ret = __vsock_deliver_tap_skb(skb, tmp->dev);
87  		if (unlikely(ret))
88  			break;
89  	}
90  }
91  
vsock_deliver_tap(struct sk_buff * build_skb (void * opaque),void * opaque)92  void vsock_deliver_tap(struct sk_buff *build_skb(void *opaque), void *opaque)
93  {
94  	struct sk_buff *skb;
95  
96  	rcu_read_lock();
97  
98  	if (likely(list_empty(&vsock_tap_all)))
99  		goto out;
100  
101  	skb = build_skb(opaque);
102  	if (skb) {
103  		__vsock_deliver_tap(skb);
104  		consume_skb(skb);
105  	}
106  
107  out:
108  	rcu_read_unlock();
109  }
110  EXPORT_SYMBOL_GPL(vsock_deliver_tap);
111