#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) #define __INIT_NET(x) x #else #include #define __INIT_NET(x) &init_net,x #endif #ifndef CONFIG_IXIA_CONSOLE static inline void netdev_set_header_ops(struct net_device *dev, const struct header_ops *hops) { dev->header_ops = hops; } static inline void netdev_set_ops(struct net_device *dev, const struct net_device_ops *ops) { dev->netdev_ops = ops; } #endif static struct net_device_ops ndst_ops = { }; int ndst_add(int n) { int err, i; struct net_device * dev = NULL; char name[IFNAMSIZ]; for(i = 0; i < n; i++) { /* temporary hack until we fix __dev_alloc_name - it is O(n) ! */ rtnl_lock(); do { static unsigned counter = 1; snprintf(name, IFNAMSIZ, "ixtest%d", counter++); } while(__dev_get_by_name(__INIT_NET(name))); rtnl_unlock(); dev = alloc_netdev(0, name, ether_setup); if (dev == NULL) { err = -ENOMEM; goto err; } netdev_set_ops(dev, &ndst_ops); netdev_set_header_ops(dev, NULL); err = register_netdev(dev); if (err) goto err; } return 0; // Error handling. err: if (dev) free_netdev(dev); module_put(THIS_MODULE); printk(KERN_ERR "%s: failed to register netdev: %d\n", __func__, err); return err; } int ndst_del(int start, int stop) { struct net_device *dev; int i; for(i = start; i <= stop; i++) { rtnl_lock(); dev = __dev_get_by_index(__INIT_NET(i)); if (!dev) { rtnl_unlock(); return -EINVAL; } unregister_netdevice(dev); rtnl_unlock(); free_netdev(dev); } return 0; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) static int proc_do_add(struct ctl_table *ctl, int write, struct file * filp, void __user *buffer, size_t *lenp) #else static int proc_do_add(struct ctl_table *ctl, int write, struct file * filp, void __user *buffer, size_t *lenp, loff_t *ppos) #endif { int ret = 0; uint32_t data; ctl->data = &data; if (write) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) ret = proc_dointvec(ctl, write, filp, buffer, lenp); #else ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); #endif ndst_add(data); } return ret; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) static int proc_do_del(struct ctl_table *ctl, int write, struct file * filp, void __user *buffer, size_t *lenp) #else static int proc_do_del(struct ctl_table *ctl, int write, struct file * filp, void __user *buffer, size_t *lenp, loff_t *ppos) #endif { int ret = 0; uint32_t data[2]; ctl->data = data; if (write) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) ret = proc_dointvec(ctl, write, filp, buffer, lenp); #else ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); #endif ndst_del(data[0], data[1]); } return ret; } static ctl_table ndst_sysctl_table[] = { { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) .ctl_name = 1, #endif .procname = "add", .maxlen = sizeof(uint32_t), .mode = 0200, .proc_handler = &proc_do_add, }, { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) .ctl_name = 2, #endif .procname = "del", .maxlen = 2*sizeof(uint32_t), .mode = 0200, .proc_handler = &proc_do_del, }, {} }; static ctl_table ndst_sysctl_net_table[] = { { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) .ctl_name = 1024, #endif .procname = "ndst", .data = NULL, .maxlen = 0, .mode = 0555, .child = ndst_sysctl_table }, {} }; static ctl_table ndst_sysctl_root[] = { { .ctl_name = CTL_NET, .procname = "net", .data = NULL, .maxlen = 0, .mode = 0555, .child = ndst_sysctl_net_table }, {} }; static struct ctl_table_header *ndst_sysctl_hdr; int ndst_init(void) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) ndst_sysctl_hdr = register_sysctl_table(ndst_sysctl_root, 0); #else ndst_sysctl_hdr = register_sysctl_table(ndst_sysctl_root); #endif if (ndst_sysctl_hdr == NULL) return -EINVAL; return 0; } void ndst_cleanup(void) { unregister_sysctl_table(ndst_sysctl_hdr); } module_init(ndst_init); module_exit(ndst_cleanup);