diff options
Diffstat (limited to 'drivers/vlan_mon')
-rw-r--r-- | drivers/vlan_mon/CMakeLists.txt | 17 | ||||
-rw-r--r-- | drivers/vlan_mon/Makefile | 4 | ||||
-rw-r--r-- | drivers/vlan_mon/vlan_mon.c | 664 | ||||
-rw-r--r-- | drivers/vlan_mon/vlan_mon.h | 36 |
4 files changed, 721 insertions, 0 deletions
diff --git a/drivers/vlan_mon/CMakeLists.txt b/drivers/vlan_mon/CMakeLists.txt new file mode 100644 index 0000000..892fed1 --- /dev/null +++ b/drivers/vlan_mon/CMakeLists.txt @@ -0,0 +1,17 @@ +if (NOT DEFINED KDIR) + set(KDIR "/usr/src/linux") +endif (NOT DEFINED KDIR) + +ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/driver/vlan_mon.ko + COMMAND rm -rf ${CMAKE_CURRENT_BINARY_DIR}/driver + COMMAND mkdir ${CMAKE_CURRENT_BINARY_DIR}/driver + COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/* ${CMAKE_CURRENT_BINARY_DIR}/driver + COMMAND make -C ${KDIR} M=${CMAKE_CURRENT_BINARY_DIR}/driver modules + DEPENDS vlan_mon.c vlan_mon.h +) + +ADD_CUSTOM_TARGET(vlan_mon_drv ALL + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/driver/vlan_mon.ko +) + +INSTALL(CODE "EXECUTE_PROCESS(COMMAND make -C ${KDIR} M=${CMAKE_CURRENT_BINARY_DIR}/drivers/vlan_mon modules_install)") diff --git a/drivers/vlan_mon/Makefile b/drivers/vlan_mon/Makefile new file mode 100644 index 0000000..c70e47a --- /dev/null +++ b/drivers/vlan_mon/Makefile @@ -0,0 +1,4 @@ +obj-m += vlan_mon.o + +default: + make -C $(KDIR) M=$(PWD) modules diff --git a/drivers/vlan_mon/vlan_mon.c b/drivers/vlan_mon/vlan_mon.c new file mode 100644 index 0000000..f61d932 --- /dev/null +++ b/drivers/vlan_mon/vlan_mon.c @@ -0,0 +1,664 @@ +#include <linux/capability.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/in.h> +#include <linux/init.h> +#include <linux/if_ether.h> +#include <linux/if_vlan.h> +#include <linux/semaphore.h> +#include <linux/version.h> + +#include <net/genetlink.h> +#include <net/sock.h> +#include <net/net_namespace.h> +#include <net/netns/generic.h> + +#include "vlan_mon.h" + +#define VLAN_MON_MAGIC 0x639fa78c + +#define VLAN_MON_PROTO_IP 0 +#define VLAN_MON_PROTO_PPPOE 1 +//#define VLAN_MON_PROTO_IP6 2 + +#define VLAN_MON_NLMSG_SIZE (NLMSG_DEFAULT_SIZE - GENL_HDRLEN - 128) + +#ifndef DEFINE_SEMAPHORE +#define DEFINE_SEMAPHORE(name) struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1) +#endif + +#ifndef NETIF_F_HW_VLAN_FILTER +#define NETIF_F_HW_VLAN_FILTER NETIF_F_HW_VLAN_CTAG_FILTER +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0) +#define vlan_tx_tag_present(skb) skb_vlan_tag_present(skb) +#endif + +struct vlan_dev { + unsigned int magic; + int ifindex; + struct rcu_head rcu_head; + struct list_head entry; + + spinlock_t lock; + unsigned long vid[2][4096/8/sizeof(long)]; + int proto; +}; + +struct vlan_notify { + struct list_head entry; + int ifindex; + int vid; + int proto; +}; + +static LIST_HEAD(vlan_devices); +static LIST_HEAD(vlan_notifies); +static DEFINE_SPINLOCK(vlan_lock); +static struct work_struct vlan_notify_work; + +static struct genl_family vlan_mon_nl_family; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) +static struct genl_multicast_group vlan_mon_nl_mcg; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) +static void vlan_mon_kfree_rcu(struct rcu_head *head) +{ + kfree(head); +} +#endif + +static DEFINE_SEMAPHORE(vlan_mon_lock); + +static inline int vlan_mon_proto(int proto) +{ + if (proto == ETH_P_PPP_DISC) + return VLAN_MON_PROTO_PPPOE; + + if (proto == ETH_P_IP) + return VLAN_MON_PROTO_IP; + + return -ENOSYS; +} + +static int vlan_pt_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *prev, struct net_device *orig_dev) +{ + struct vlan_dev *d; + struct vlan_notify *n; + int vid; + int proto; + + if (!dev->ml_priv) + goto out; + + if (!vlan_tx_tag_present(skb)) + goto out; + + if (skb->protocol == htons(ETH_P_IP) || skb->protocol == htons(ETH_P_ARP)) + proto = VLAN_MON_PROTO_IP; + //else if (skb->protocol == htons(ETH_P_IPV6)) + // proto = VLAN_MON_PROTO_IP6; + else if (skb->protocol == htons(ETH_P_PPP_DISC)) + proto = VLAN_MON_PROTO_PPPOE; + else + goto out; + + rcu_read_lock(); + + d = rcu_dereference(dev->ml_priv); + if (!d || d->magic != VLAN_MON_MAGIC || d->ifindex != dev->ifindex || (d->proto & (1 << proto)) == 0) { + rcu_read_unlock(); + goto out; + } + + vid = skb->vlan_tci & VLAN_VID_MASK; + //pr_info("vid %i\n", vid); + + if (d->vid[proto][vid / (8*sizeof(long))] & (1lu << (vid % (8*sizeof(long))))) + vid = -1; + else { + spin_lock(&d->lock); + d->vid[proto][vid / (8*sizeof(long))] |= 1lu << (vid % (8*sizeof(long))); + spin_unlock(&d->lock); + } + rcu_read_unlock(); + + if (vid == -1) + goto out; + + //pr_info("queue %i %i %04x\n", dev->ifindex, vid, skb->protocol); + + n = kmalloc(sizeof(*n), GFP_ATOMIC); + if (!n) + goto out; + + n->ifindex = dev->ifindex; + n->vid = vid; + n->proto = ntohs(skb->protocol); + + spin_lock(&vlan_lock); + list_add_tail(&n->entry, &vlan_notifies); + spin_unlock(&vlan_lock); + + schedule_work(&vlan_notify_work); + +out: + kfree_skb(skb); + return 0; +} + +static void vlan_do_notify(struct work_struct *w) +{ + struct vlan_notify *n; + struct sk_buff *report_skb = NULL; + void *header = NULL; + struct nlattr *ns; + int id = 1; + unsigned long flags; + + //pr_info("vlan_do_notify\n"); + + while (1) { + spin_lock_irqsave(&vlan_lock, flags); + if (list_empty(&vlan_notifies)) + n = NULL; + else { + n = list_first_entry(&vlan_notifies, typeof(*n), entry); + list_del(&n->entry); + } + spin_unlock_irqrestore(&vlan_lock, flags); + + if (!n) + break; + + if (!report_skb) { + report_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) + header = genlmsg_put(report_skb, 0, vlan_mon_nl_mcg.id, &vlan_mon_nl_family, 0, VLAN_MON_NOTIFY); +#else + header = genlmsg_put(report_skb, 0, vlan_mon_nl_family.mcgrp_offset, &vlan_mon_nl_family, 0, VLAN_MON_NOTIFY); +#endif + } + + //pr_info("notify %i vlan %i\n", id, n->vid); + + ns = nla_nest_start(report_skb, id++); + if (!ns) + goto nl_err; + + if (nla_put_u32(report_skb, VLAN_MON_ATTR_IFINDEX, n->ifindex)) + goto nl_err; + + if (nla_put_u16(report_skb, VLAN_MON_ATTR_VID, n->vid)) + goto nl_err; + + if (nla_put_u16(report_skb, VLAN_MON_ATTR_PROTO, n->proto)) + goto nl_err; + + if (nla_nest_end(report_skb, ns) >= VLAN_MON_NLMSG_SIZE || id == 255) { + genlmsg_end(report_skb, header); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) + genlmsg_multicast(report_skb, 0, vlan_mon_nl_mcg.id, GFP_KERNEL); +#else + genlmsg_multicast(&vlan_mon_nl_family, report_skb, 0, 0, GFP_KERNEL); +#endif + report_skb = NULL; + id = 1; + } + + kfree(n); + continue; + +nl_err: + nlmsg_free(report_skb); + report_skb = NULL; + } + + if (report_skb) { + genlmsg_end(report_skb, header); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) + genlmsg_multicast(report_skb, 0, vlan_mon_nl_mcg.id, GFP_KERNEL); +#else + genlmsg_multicast(&vlan_mon_nl_family, report_skb, 0, 0, GFP_KERNEL); +#endif + } +} + +static int vlan_mon_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + void *hdr; + int ret = -ENOBUFS; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) { + ret = -ENOMEM; + goto out; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &vlan_mon_nl_family, 0, VLAN_MON_CMD_NOOP); +#else + hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &vlan_mon_nl_family, 0, VLAN_MON_CMD_NOOP); +#endif + + if (IS_ERR(hdr)) { + ret = PTR_ERR(hdr); + goto err_out; + } + + genlmsg_end(msg, hdr); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + return genlmsg_unicast(msg, info->snd_pid); +#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid); +#else + return genlmsg_unicast(genl_info_net(info), msg, info->snd_portid); +#endif + +err_out: + nlmsg_free(msg); + +out: + return ret; +} + +static int vlan_mon_nl_cmd_add_vlan_mon(struct sk_buff *skb, struct genl_info *info) +{ + struct vlan_dev *d; + struct net_device *dev; + int ifindex, i, proto; + + if (!info->attrs[VLAN_MON_ATTR_IFINDEX]) + return -EINVAL; + + if (!info->attrs[VLAN_MON_ATTR_PROTO]) + return -EINVAL; + + proto = nla_get_u16(info->attrs[VLAN_MON_ATTR_PROTO]); + + proto = vlan_mon_proto(proto); + if (proto < 0) + return proto; + + ifindex = nla_get_u32(info->attrs[VLAN_MON_ATTR_IFINDEX]); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) + rtnl_lock(); + dev = __dev_get_by_index(&init_net, ifindex); + rtnl_unlock(); +#else + dev = dev_get_by_index(&init_net, ifindex); +#endif + + if (!dev) + return -ENODEV; + + down(&vlan_mon_lock); + if (dev->ml_priv) { + d = (struct vlan_dev *)dev->ml_priv; + if (d->magic != VLAN_MON_MAGIC || (d->proto & (1 << proto))) { + up(&vlan_mon_lock); + dev_put(dev); + return -EBUSY; + } + } else { + d = kzalloc(sizeof(*d), GFP_KERNEL); + if (!d) { + up(&vlan_mon_lock); + dev_put(dev); + return -ENOMEM; + } + + spin_lock_init(&d->lock); + d->magic = VLAN_MON_MAGIC; + d->ifindex = ifindex; + d->proto = 0; + + rcu_assign_pointer(dev->ml_priv, d); + } + + d->proto |= 1 << proto; + + if (info->attrs[VLAN_MON_ATTR_VLAN_MASK]) { + memcpy(d->vid[proto], nla_data(info->attrs[VLAN_MON_ATTR_VLAN_MASK]), min((int)nla_len(info->attrs[VLAN_MON_ATTR_VLAN_MASK]), (int)sizeof(d->vid))); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + if (dev->features & NETIF_F_HW_VLAN_FILTER) { + rtnl_lock(); + for (i = 1; i < 4096; i++) { + if (!(d->vid[proto][i / (8*sizeof(long))] & (1lu << (i % (8*sizeof(long)))))) + dev->netdev_ops->ndo_vlan_rx_add_vid(dev, i); + } + rtnl_unlock(); + } +#else + if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) { + rtnl_lock(); + for (i = 1; i < 4096; i++) { + if (!(d->vid[proto][i / (8*sizeof(long))] & (1lu << (i % (8*sizeof(long)))))) + dev->netdev_ops->ndo_vlan_rx_add_vid(dev, htons(ETH_P_8021Q), i); + } + rtnl_unlock(); + } +#endif + } + + list_add_tail_rcu(&d->entry, &vlan_devices); + up(&vlan_mon_lock); + + dev_put(dev); + + return 0; +} + +static int vlan_mon_nl_cmd_add_vlan_mon_vid(struct sk_buff *skb, struct genl_info *info) +{ + struct vlan_dev *d; + int ifindex, vid, proto; + struct net_device *dev; + unsigned long flags; + + if (!info->attrs[VLAN_MON_ATTR_IFINDEX] || !info->attrs[VLAN_MON_ATTR_VID] || !info->attrs[VLAN_MON_ATTR_PROTO]) + return -EINVAL; + + ifindex = nla_get_u32(info->attrs[VLAN_MON_ATTR_IFINDEX]); + vid = nla_get_u16(info->attrs[VLAN_MON_ATTR_VID]); + proto = nla_get_u16(info->attrs[VLAN_MON_ATTR_PROTO]); + + proto = nla_get_u16(info->attrs[VLAN_MON_ATTR_PROTO]); + + proto = vlan_mon_proto(proto); + if (proto < 0) + return proto; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) + rtnl_lock(); + dev = __dev_get_by_index(&init_net, ifindex); + rtnl_unlock(); +#else + dev = dev_get_by_index(&init_net, ifindex); +#endif + + if (!dev) + return -ENODEV; + + down(&vlan_mon_lock); + + if (!dev->ml_priv) { + up(&vlan_mon_lock); + dev_put(dev); + return -EINVAL; + } + + d = dev->ml_priv; + + spin_lock_irqsave(&d->lock, flags); + d->vid[proto][vid / (8*sizeof(long))] &= ~(1lu << (vid % (8*sizeof(long)))); + spin_unlock_irqrestore(&d->lock, flags); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + if (dev->features & NETIF_F_HW_VLAN_FILTER) { + rtnl_lock(); + dev->netdev_ops->ndo_vlan_rx_add_vid(dev, vid); + rtnl_unlock(); + } +#else + if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) { + rtnl_lock(); + dev->netdev_ops->ndo_vlan_rx_add_vid(dev, htons(ETH_P_8021Q), vid); + rtnl_unlock(); + } +#endif + + up(&vlan_mon_lock); + + dev_put(dev); + + return 0; +} + +static int vlan_mon_nl_cmd_del_vlan_mon(struct sk_buff *skb, struct genl_info *info) +{ + struct vlan_dev *d; + struct vlan_notify *vn; + int ifindex, proto = 0xffff; + unsigned long flags; + struct list_head *pos, *n; + struct net_device *dev; + + if (info->attrs[VLAN_MON_ATTR_PROTO]) { + proto = nla_get_u16(info->attrs[VLAN_MON_ATTR_PROTO]); + + proto = vlan_mon_proto(proto); + if (proto < 0) + return proto; + + proto = 1 << proto; + } + + if (info->attrs[VLAN_MON_ATTR_IFINDEX]) + ifindex = nla_get_u32(info->attrs[VLAN_MON_ATTR_IFINDEX]); + else + ifindex = -1; + + down(&vlan_mon_lock); + list_for_each_entry(d, &vlan_devices, entry) { + if ((ifindex == -1 || d->ifindex == ifindex) && (d->proto & proto)) { + //pr_info("del net %08x/%08x\n", n->addr, n->mask); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) + rtnl_lock(); + dev = __dev_get_by_index(&init_net, d->ifindex); + rtnl_unlock(); +#else + dev = dev_get_by_index(&init_net, d->ifindex); +#endif + + if (dev) { + if (dev->ml_priv == d) { + d->proto &= ~proto; + if (!d->proto) + rcu_assign_pointer(dev->ml_priv, NULL); + } + dev_put(dev); + } + + if (!d->proto) { + //pr_info("vlan_mon del %i\n", ifindex); + list_del_rcu(&d->entry); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) + kfree_rcu(d, rcu_head); +#else + call_rcu(&d->rcu_head, vlan_mon_kfree_rcu); +#endif + } + } + } + up(&vlan_mon_lock); + + spin_lock_irqsave(&vlan_lock, flags); + list_for_each_safe(pos, n, &vlan_notifies) { + vn = list_entry(pos, typeof(*vn), entry); + if ((ifindex == -1 || vn->ifindex == ifindex) && (proto & (1 << vlan_mon_proto(vn->proto)))) { + list_del(&vn->entry); + kfree(vn); + } + } + spin_unlock_irqrestore(&vlan_lock, flags); + + return 0; +} + +static struct nla_policy vlan_mon_nl_policy[VLAN_MON_ATTR_MAX + 1] = { + [VLAN_MON_ATTR_NONE] = { .type = NLA_UNSPEC, }, + [VLAN_MON_ATTR_VLAN_MASK] = { .type = NLA_BINARY, .len = 4096/8 }, + [VLAN_MON_ATTR_PROTO] = { .type = NLA_U16, }, + [VLAN_MON_ATTR_IFINDEX] = { .type = NLA_U32, }, + [VLAN_MON_ATTR_VID] = { .type = NLA_U16, }, +}; + +static struct genl_ops vlan_mon_nl_ops[] = { + { + .cmd = VLAN_MON_CMD_NOOP, + .doit = vlan_mon_nl_cmd_noop, + .policy = vlan_mon_nl_policy, + /* can be retrieved by unprivileged users */ + }, + { + .cmd = VLAN_MON_CMD_ADD, + .doit = vlan_mon_nl_cmd_add_vlan_mon, + .policy = vlan_mon_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = VLAN_MON_CMD_ADD_VID, + .doit = vlan_mon_nl_cmd_add_vlan_mon_vid, + .policy = vlan_mon_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = VLAN_MON_CMD_DEL, + .doit = vlan_mon_nl_cmd_del_vlan_mon, + .policy = vlan_mon_nl_policy, + .flags = GENL_ADMIN_PERM, + }, +}; + +static struct genl_family vlan_mon_nl_family = { + .id = GENL_ID_GENERATE, + .name = VLAN_MON_GENL_NAME, + .version = VLAN_MON_GENL_VERSION, + .hdrsize = 0, + .maxattr = VLAN_MON_ATTR_MAX, +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) +static struct genl_multicast_group vlan_mon_nl_mcg = { + .name = VLAN_MON_GENL_MCG, +}; +#else +static struct genl_multicast_group vlan_mon_nl_mcgs[] = { + { .name = VLAN_MON_GENL_MCG, } +}; +#endif + +static struct packet_type vlan_pt __read_mostly = { + .type = __constant_htons(ETH_P_ALL), + .func = vlan_pt_recv, +}; + +static int __init vlan_mon_init(void) +{ + int err; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + int i; +#endif + + + printk("vlan-mon driver v1.10-rc1\n"); + + INIT_WORK(&vlan_notify_work, vlan_do_notify); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + err = genl_register_family(&vlan_mon_nl_family); + if (err < 0) { + printk(KERN_INFO "vlan_mon: can't register netlink interface\n"); + goto out; + } + + for (i = 0; i < ARRAY_SIZE(vlan_mon_nl_ops); i++) { + err = genl_register_ops(&vlan_mon_nl_family, &vlan_mon_nl_ops[i]); + if (err) + break; + } + + if (err < 0) { + printk(KERN_INFO "vlan_mon: can't register netlink interface\n"); + goto out_unreg; + } +#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) + err = genl_register_family_with_ops(&vlan_mon_nl_family, vlan_mon_nl_ops, ARRAY_SIZE(vlan_mon_nl_ops)); +#else + err = genl_register_family_with_ops_groups(&vlan_mon_nl_family, vlan_mon_nl_ops, vlan_mon_nl_mcgs); +#endif + if (err < 0) { + printk(KERN_INFO "vlan_mon: can't register netlink interface\n"); + goto out; + } +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) + err = genl_register_mc_group(&vlan_mon_nl_family, &vlan_mon_nl_mcg); + if (err < 0) { + printk(KERN_INFO "vlan_mon: can't register netlink multicast group\n"); + goto out_unreg; + } +#endif + + dev_add_pack(&vlan_pt); + + return 0; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) +out_unreg: +#endif + genl_unregister_family(&vlan_mon_nl_family); +out: + return err; +} + +static void __exit vlan_mon_fini(void) +{ + struct vlan_dev *d; + struct vlan_notify *vn; + struct net_device *dev; + + dev_remove_pack(&vlan_pt); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) + genl_unregister_mc_group(&vlan_mon_nl_family, &vlan_mon_nl_mcg); +#endif + genl_unregister_family(&vlan_mon_nl_family); + + down(&vlan_mon_lock); + up(&vlan_mon_lock); + + while (!list_empty(&vlan_devices)) { + d = list_first_entry(&vlan_devices, typeof(*d), entry); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) + rtnl_lock(); + dev = __dev_get_by_index(&init_net, d->ifindex); + rtnl_unlock(); +#else + dev = dev_get_by_index(&init_net, d->ifindex); +#endif + if (dev) + rcu_assign_pointer(dev->ml_priv, NULL); + list_del(&d->entry); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) + kfree_rcu(d, rcu_head); +#else + call_rcu(&d->rcu_head, vlan_mon_kfree_rcu); +#endif + } + + while (!list_empty(&vlan_notifies)) { + vn = list_first_entry(&vlan_notifies, typeof(*vn), entry); + list_del(&vn->entry); + kfree(vn); + } + + synchronize_rcu(); +} + +module_init(vlan_mon_init); +module_exit(vlan_mon_fini); +MODULE_LICENSE("GPL"); + diff --git a/drivers/vlan_mon/vlan_mon.h b/drivers/vlan_mon/vlan_mon.h new file mode 100644 index 0000000..e65f65e --- /dev/null +++ b/drivers/vlan_mon/vlan_mon.h @@ -0,0 +1,36 @@ +#ifndef __LINUX_VLAN_MON_H +#define __LINUX_VLAN_MON_H + +#include <linux/types.h> + +enum { + VLAN_MON_CMD_NOOP, + VLAN_MON_CMD_ADD, + VLAN_MON_CMD_ADD_VID, + VLAN_MON_CMD_DEL, + VLAN_MON_NOTIFY, + __VLAN_MON_CMD_MAX, +}; + +#define VLAN_MON_CMD_MAX (__VLAN_MON_CMD_MAX - 1) + +enum { + VLAN_MON_ATTR_NONE, /* u32 */ + VLAN_MON_ATTR_VLAN_MASK, /* u32 */ + VLAN_MON_ATTR_PROTO, /* u32 */ + VLAN_MON_ATTR_IFINDEX, /* u32 */ + VLAN_MON_ATTR_VID, /* u32 */ + __VLAN_MON_ATTR_MAX, +}; + +#define VLAN_MON_ATTR_MAX (__VLAN_MON_ATTR_MAX - 1) + +/* + * NETLINK_GENERIC related info + */ +#define VLAN_MON_GENL_NAME "vlan-mon" +#define VLAN_MON_GENL_MCG "notify" +#define VLAN_MON_GENL_VERSION 0x01 + +#endif + |