@@ -44,6 +44,7 @@
#include <linux/workqueue.h>
#include <linux/ethtool.h>
+#include <linux/cdev.h>
#include <net/net_namespace.h>
#include <net/dsa.h>
#ifdef CONFIG_DCB
@@ -916,6 +917,9 @@ struct net_device
/* max exchange id for FCoE LRO by ddp */
unsigned int fcoe_ddp_xid;
#endif
+#ifdef CONFIG_NET_CDEV
+ struct cdev cdev;
+#endif
};
#define to_net_dev(d) container_of(d, struct net_device, dev)
@@ -43,6 +43,16 @@ config COMPAT_NETLINK_MESSAGES
Newly written code should NEVER need this option but do
compat-independent messages instead!
+config NET_CDEV
+ bool "/dev files for network devices"
+ default y
+ help
+ This option causes /dev entries to be created for each
+ network device. This allows the use of udev to create
+ alternate device naming policies.
+
+ If unsure, say Y.
+
menu "Networking options"
source "net/packet/Kconfig"
@@ -19,4 +19,5 @@ obj-$(CONFIG_NET_DMA) += user_dma.o
obj-$(CONFIG_FIB_RULES) += fib_rules.o
obj-$(CONFIG_TRACEPOINTS) += net-traces.o
obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o
+obj-$(CONFIG_NET_CDEV) += cdev.o
new file mode 100644
@@ -0,0 +1,42 @@
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/netdevice.h>
+#include <linux/device.h>
+
+/* Used for network dynamic major number */
+static dev_t netdev_devt;
+
+static int netdev_cdev_open(struct inode *inode, struct file *filep)
+{
+ /* no operations on this device are implemented */
+ return -ENOSYS;
+}
+
+static const struct file_operations netdev_cdev_fops = {
+ .owner = THIS_MODULE,
+ .open = netdev_cdev_open,
+};
+
+void netdev_cdev_alloc(void)
+{
+ alloc_chrdev_region(&netdev_devt, 0, 1<<20, "net");
+}
+
+void netdev_cdev_init(struct net_device *dev)
+{
+ cdev_init(&dev->cdev, &netdev_cdev_fops);
+ cdev_add(&dev->cdev, MKDEV(MAJOR(netdev_devt), dev->ifindex), 1);
+
+}
+
+void netdev_cdev_del(struct net_device *dev)
+{
+ if (dev->cdev.dev)
+ cdev_del(&dev->cdev);
+}
+
+void netdev_cdev_kobj_init(struct device *dev, struct net_device *net)
+{
+ if (net->cdev.dev)
+ dev->devt = net->cdev.dev;
+}
new file mode 100644
@@ -0,0 +1,13 @@
+#include <linux/netdevice.h>
+
+#ifdef CONFIG_NET_CDEV
+void netdev_cdev_alloc(void);
+void netdev_cdev_init(struct net_device *dev);
+void netdev_cdev_del(struct net_device *dev);
+void netdev_cdev_kobj_init(struct device *dev, struct net_device *net);
+#else
+static inline void netdev_cdev_alloc(void) {}
+static inline void netdev_cdev_init(struct net_device *dev) {}
+static inline void netdev_cdev_del(struct net_device *dev) {}
+static inline void netdev_cdev_kobj_init(struct device *dev, struct net_device *net) {}
+#endif
@@ -129,6 +129,7 @@
#include <trace/events/napi.h>
#include "net-sysfs.h"
+#include "cdev.h"
/* Instead of increasing this, you should create a hash table. */
#define MAX_GRO_SKBS 8
@@ -4684,6 +4685,7 @@ static void rollback_registered(struct net_device *dev)
/* Remove entries from kobject tree */
netdev_unregister_kobject(dev);
+ netdev_cdev_del(dev);
synchronize_net();
@@ -4835,6 +4837,8 @@ int register_netdevice(struct net_device *dev)
if (dev->features & NETIF_F_SG)
dev->features |= NETIF_F_GSO;
+ netdev_cdev_init(dev);
+
netdev_initialize_kobject(dev);
ret = netdev_register_kobject(dev);
if (ret)
@@ -4864,6 +4868,7 @@ out:
return ret;
err_uninit:
+ netdev_cdev_del(dev);
if (dev->netdev_ops->ndo_uninit)
dev->netdev_ops->ndo_uninit(dev);
goto out;
@@ -5371,6 +5376,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
dev_addr_discard(dev);
netdev_unregister_kobject(dev);
+ netdev_cdev_del(dev);
/* Actually switch the network namespace */
dev_net_set(dev, net);
@@ -5387,6 +5393,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
dev->iflink = dev->ifindex;
}
+ netdev_cdev_init(dev);
+
/* Fixup kobjects */
err = netdev_register_kobject(dev);
WARN_ON(err);
@@ -5620,6 +5628,8 @@ static int __init net_dev_init(void)
BUG_ON(!dev_boot_phase);
+ netdev_cdev_alloc();
+
if (dev_proc_init())
goto out;
@@ -19,6 +19,7 @@
#include <net/wext.h>
#include "net-sysfs.h"
+#include "cdev.h"
#ifdef CONFIG_SYSFS
static const char fmt_hex[] = "%#x\n";
@@ -461,6 +462,14 @@ static void netdev_release(struct device *d)
kfree((char *)dev - dev->padded);
}
+#ifdef CONFIG_NET_CDEV
+static char *netdev_devnode(struct device *d, mode_t *mode)
+{
+ struct net_device *dev = to_net_dev(d);
+ return kasprintf(GFP_KERNEL, "netdev/%s", dev->name);
+}
+#endif
+
static struct class net_class = {
.name = "net",
.dev_release = netdev_release,
@@ -470,6 +479,9 @@ static struct class net_class = {
#ifdef CONFIG_HOTPLUG
.dev_uevent = netdev_uevent,
#endif
+#ifdef CONFIG_NET_CDEV
+ .devnode = netdev_devnode,
+#endif
};
/* Delete sysfs entries but hold kobject reference until after all
@@ -496,6 +508,7 @@ int netdev_register_kobject(struct net_device *net)
dev->class = &net_class;
dev->platform_data = net;
dev->groups = groups;
+ netdev_cdev_kobj_init(dev, net);
dev_set_name(dev, "%s", net->name);