forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
2.9 KiB
136 lines
2.9 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
#include <linux/ethtool.h> |
|
#include <linux/module.h> |
|
#include <linux/kernel.h> |
|
#include <linux/netdevice.h> |
|
#include <linux/netlink.h> |
|
#include <net/net_namespace.h> |
|
#include <linux/if_arp.h> |
|
#include <net/rtnetlink.h> |
|
|
|
static netdev_tx_t nlmon_xmit(struct sk_buff *skb, struct net_device *dev) |
|
{ |
|
dev_lstats_add(dev, skb->len); |
|
|
|
dev_kfree_skb(skb); |
|
|
|
return NETDEV_TX_OK; |
|
} |
|
|
|
static int nlmon_dev_init(struct net_device *dev) |
|
{ |
|
dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); |
|
return dev->lstats == NULL ? -ENOMEM : 0; |
|
} |
|
|
|
static void nlmon_dev_uninit(struct net_device *dev) |
|
{ |
|
free_percpu(dev->lstats); |
|
} |
|
|
|
struct nlmon { |
|
struct netlink_tap nt; |
|
}; |
|
|
|
static int nlmon_open(struct net_device *dev) |
|
{ |
|
struct nlmon *nlmon = netdev_priv(dev); |
|
|
|
nlmon->nt.dev = dev; |
|
nlmon->nt.module = THIS_MODULE; |
|
return netlink_add_tap(&nlmon->nt); |
|
} |
|
|
|
static int nlmon_close(struct net_device *dev) |
|
{ |
|
struct nlmon *nlmon = netdev_priv(dev); |
|
|
|
return netlink_remove_tap(&nlmon->nt); |
|
} |
|
|
|
static void |
|
nlmon_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) |
|
{ |
|
u64 packets, bytes; |
|
|
|
dev_lstats_read(dev, &packets, &bytes); |
|
|
|
stats->rx_packets = packets; |
|
stats->tx_packets = 0; |
|
|
|
stats->rx_bytes = bytes; |
|
stats->tx_bytes = 0; |
|
} |
|
|
|
static u32 always_on(struct net_device *dev) |
|
{ |
|
return 1; |
|
} |
|
|
|
static const struct ethtool_ops nlmon_ethtool_ops = { |
|
.get_link = always_on, |
|
}; |
|
|
|
static const struct net_device_ops nlmon_ops = { |
|
.ndo_init = nlmon_dev_init, |
|
.ndo_uninit = nlmon_dev_uninit, |
|
.ndo_open = nlmon_open, |
|
.ndo_stop = nlmon_close, |
|
.ndo_start_xmit = nlmon_xmit, |
|
.ndo_get_stats64 = nlmon_get_stats64, |
|
}; |
|
|
|
static void nlmon_setup(struct net_device *dev) |
|
{ |
|
dev->type = ARPHRD_NETLINK; |
|
dev->priv_flags |= IFF_NO_QUEUE; |
|
|
|
dev->netdev_ops = &nlmon_ops; |
|
dev->ethtool_ops = &nlmon_ethtool_ops; |
|
dev->needs_free_netdev = true; |
|
|
|
dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | |
|
NETIF_F_HIGHDMA | NETIF_F_LLTX; |
|
dev->flags = IFF_NOARP; |
|
|
|
/* That's rather a softlimit here, which, of course, |
|
* can be altered. Not a real MTU, but what is to be |
|
* expected in most cases. |
|
*/ |
|
dev->mtu = NLMSG_GOODSIZE; |
|
dev->min_mtu = sizeof(struct nlmsghdr); |
|
} |
|
|
|
static int nlmon_validate(struct nlattr *tb[], struct nlattr *data[], |
|
struct netlink_ext_ack *extack) |
|
{ |
|
if (tb[IFLA_ADDRESS]) |
|
return -EINVAL; |
|
return 0; |
|
} |
|
|
|
static struct rtnl_link_ops nlmon_link_ops __read_mostly = { |
|
.kind = "nlmon", |
|
.priv_size = sizeof(struct nlmon), |
|
.setup = nlmon_setup, |
|
.validate = nlmon_validate, |
|
}; |
|
|
|
static __init int nlmon_register(void) |
|
{ |
|
return rtnl_link_register(&nlmon_link_ops); |
|
} |
|
|
|
static __exit void nlmon_unregister(void) |
|
{ |
|
rtnl_link_unregister(&nlmon_link_ops); |
|
} |
|
|
|
module_init(nlmon_register); |
|
module_exit(nlmon_unregister); |
|
|
|
MODULE_LICENSE("GPL v2"); |
|
MODULE_AUTHOR("Daniel Borkmann <[email protected]>"); |
|
MODULE_AUTHOR("Mathieu Geli <[email protected]>"); |
|
MODULE_DESCRIPTION("Netlink monitoring device"); |
|
MODULE_ALIAS_RTNL_LINK("nlmon");
|
|
|