lib/genalloc: fix the overflow when size is too big
[linux-2.6-microblaze.git] / net / vmw_vsock / af_vsock_tap.c
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
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
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
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
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
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);