cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

af_vsock_tap.c (2032B)


      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
     13static DEFINE_SPINLOCK(vsock_tap_lock);
     14static struct list_head vsock_tap_all __read_mostly =
     15				LIST_HEAD_INIT(vsock_tap_all);
     16
     17int 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}
     30EXPORT_SYMBOL_GPL(vsock_add_tap);
     31
     32int 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);
     48out:
     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}
     58EXPORT_SYMBOL_GPL(vsock_remove_tap);
     59
     60static 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
     80static 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
     92void 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
    107out:
    108	rcu_read_unlock();
    109}
    110EXPORT_SYMBOL_GPL(vsock_deliver_tap);