From 223a0d0b8398a9da309e0b724569a0315166cbf7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 20 May 2003 05:19:45 -0300 Subject: o wan/cycx: remove unneeded ioctl stub and fix namespace --- include/linux/cyclomx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/cyclomx.h b/include/linux/cyclomx.h index c8f4173cc4d1..d84bc68e2af7 100644 --- a/include/linux/cyclomx.h +++ b/include/linux/cyclomx.h @@ -71,10 +71,10 @@ struct cycx_device { }; /* Public Functions */ -void cyclomx_set_state(struct cycx_device *card, int state); +void cycx_set_state(struct cycx_device *card, int state); #ifdef CONFIG_CYCLOMX_X25 -int cyx_init(struct cycx_device *card, wandev_conf_t *conf); +int cycx_x25_wan_init(struct cycx_device *card, wandev_conf_t *conf); #endif #endif /* __KERNEL__ */ #endif /* _CYCLOMX_H */ -- cgit v1.2.3 From a6a1faca24996aaab9527353e6112919cd99ca73 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 20 May 2003 04:56:40 -0700 Subject: [NET]: Clean up the divert ifdef mess. --- drivers/net/Space.c | 6 ------ include/linux/divert.h | 17 +++++++++++++++-- net/core/dev.c | 15 --------------- net/socket.c | 4 ---- 4 files changed, 15 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/drivers/net/Space.c b/drivers/net/Space.c index b09a14ceae14..16b90c0ee242 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -131,26 +131,20 @@ static int __init probe_list(struct net_device *dev, struct devprobe *plist) { struct devprobe *p = plist; unsigned long base_addr = dev->base_addr; -#ifdef CONFIG_NET_DIVERT int ret; -#endif /* CONFIG_NET_DIVERT */ while (p->probe != NULL) { if (base_addr && p->probe(dev) == 0) { /* probe given addr */ -#ifdef CONFIG_NET_DIVERT ret = alloc_divert_blk(dev); if (ret) return ret; -#endif /* CONFIG_NET_DIVERT */ return 0; } else if (p->status == 0) { /* has autoprobe failed yet? */ p->status = p->probe(dev); /* no, try autoprobe */ if (p->status == 0) { -#ifdef CONFIG_NET_DIVERT ret = alloc_divert_blk(dev); if (ret) return ret; -#endif /* CONFIG_NET_DIVERT */ return 0; } } diff --git a/include/linux/divert.h b/include/linux/divert.h index 66e56ec15b66..38497a643657 100644 --- a/include/linux/divert.h +++ b/include/linux/divert.h @@ -107,11 +107,24 @@ struct divert_cf /* diverter functions */ #include + +#ifdef CONFIG_NET_DIVERT int alloc_divert_blk(struct net_device *); void free_divert_blk(struct net_device *); int divert_ioctl(unsigned int cmd, struct divert_cf *arg); void divert_frame(struct sk_buff *skb); - +static inline void handle_diverter(struct sk_buff *skb) +{ + /* if diversion is supported on device, then divert */ + if (skb->dev->divert && skb->dev->divert->divert) + divert_frame(skb); +} + +#else +# define alloc_divert_blk(dev) (0) +# define free_divert_blk(dev) do {} while (0) +# define divert_ioctl(cmd, arg) (-ENOPKG) +# define handle_diverter(skb) do {} while (0) +#endif #endif - #endif /* _LINUX_DIVERT_H */ diff --git a/net/core/dev.c b/net/core/dev.c index db0273ba4a3a..ccbd5700dcb8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1465,15 +1465,6 @@ static __inline__ int handle_bridge(struct sk_buff *skb, #endif -static inline void handle_diverter(struct sk_buff *skb) -{ -#ifdef CONFIG_NET_DIVERT - /* if diversion is supported on device, then divert */ - if (skb->dev->divert && skb->dev->divert->divert) - divert_frame(skb); -#endif -} - static inline int __handle_bridge(struct sk_buff *skb, struct packet_type **pt_prev, int *ret) { @@ -2568,11 +2559,9 @@ int register_netdevice(struct net_device *dev) dev->fastpath_lock = RW_LOCK_UNLOCKED; #endif -#ifdef CONFIG_NET_DIVERT ret = alloc_divert_blk(dev); if (ret) goto out; -#endif /* CONFIG_NET_DIVERT */ dev->iflink = -1; @@ -2638,9 +2627,7 @@ int register_netdevice(struct net_device *dev) out: return ret; out_err: -#ifdef CONFIG_NET_DIVERT free_divert_blk(dev); -#endif goto out; } @@ -2845,9 +2832,7 @@ int unregister_netdevice(struct net_device *dev) /* Notifier chain MUST detach us from master device. */ BUG_TRAP(!dev->master); -#ifdef CONFIG_NET_DIVERT free_divert_blk(dev); -#endif kobject_unregister(&dev->kobj); diff --git a/net/socket.c b/net/socket.c index 2f65bf513848..ba8e4fb345ab 100644 --- a/net/socket.c +++ b/net/socket.c @@ -821,11 +821,7 @@ static int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case SIOCGIFDIVERT: case SIOCSIFDIVERT: /* Convert this to call through a hook */ -#ifdef CONFIG_NET_DIVERT err = divert_ioctl(cmd, (struct divert_cf *)arg); -#else - err = -ENOPKG; -#endif /* CONFIG_NET_DIVERT */ break; case SIOCADDDLCI: case SIOCDELDLCI: -- cgit v1.2.3 From 081f608e26f3d7e70cb52f0dacdeefe3dd905264 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 20 May 2003 05:59:44 -0700 Subject: [NET]: sysfs support of network devices. --- include/linux/netdevice.h | 25 +++- net/core/Makefile | 3 +- net/core/dev.c | 104 +++++++------- net/core/net-sysfs.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 421 insertions(+), 55 deletions(-) create mode 100644 net/core/net-sysfs.c (limited to 'include') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 94d077ef70be..7106c2eaf67e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include @@ -441,11 +441,22 @@ struct net_device struct divert_blk *divert; #endif /* CONFIG_NET_DIVERT */ - /* generic object representation */ - struct kobject kobj; + /* generic device structure used in constructing class */ + struct device *dev; + + /* class/net/name entry */ + struct class_device class_dev; + + /* statistics sub-directory */ + struct kobject stats_kobj; }; #define SET_MODULE_OWNER(dev) do { } while (0) +/* Set the sysfs physical device reference for the network logical device + * if set prior to registration will cause a symlink during initialization. + */ +#define SET_NETDEV_DEV(net, pdev) ((net)->dev = (pdev)) + struct packet_type { @@ -561,12 +572,12 @@ static inline void netif_stop_queue(struct net_device *dev) set_bit(__LINK_STATE_XOFF, &dev->state); } -static inline int netif_queue_stopped(struct net_device *dev) +static inline int netif_queue_stopped(const struct net_device *dev) { return test_bit(__LINK_STATE_XOFF, &dev->state); } -static inline int netif_running(struct net_device *dev) +static inline int netif_running(const struct net_device *dev) { return test_bit(__LINK_STATE_START, &dev->state); } @@ -606,7 +617,9 @@ extern int netif_rx(struct sk_buff *skb); #define HAVE_NETIF_RECEIVE_SKB 1 extern int netif_receive_skb(struct sk_buff *skb); extern int dev_ioctl(unsigned int cmd, void *); +extern unsigned dev_get_flags(const struct net_device *); extern int dev_change_flags(struct net_device *, unsigned); +extern int dev_set_mtu(struct net_device *, int); extern void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev); extern void dev_init(void); @@ -642,7 +655,7 @@ static inline void dev_put(struct net_device *dev) extern void linkwatch_fire_event(struct net_device *dev); -static inline int netif_carrier_ok(struct net_device *dev) +static inline int netif_carrier_ok(const struct net_device *dev) { return !test_bit(__LINK_STATE_NOCARRIER, &dev->state); } diff --git a/net/core/Makefile b/net/core/Makefile index c30bc3bc7abd..dc05b5f08a5a 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -10,7 +10,8 @@ obj-y += sysctl_net_core.o endif endif -obj-$(CONFIG_NET) += flow.o dev.o dev_mcast.o dst.o neighbour.o rtnetlink.o utils.o link_watch.o filter.o +obj-$(CONFIG_NET) += flow.o dev.o net-sysfs.o dev_mcast.o dst.o neighbour.o \ + rtnetlink.o utils.o link_watch.o filter.o obj-$(CONFIG_NETFILTER) += netfilter.o obj-$(CONFIG_NET_DIVERT) += dv.o diff --git a/net/core/dev.c b/net/core/dev.c index ccbd5700dcb8..d6d458ec7e4a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -131,16 +131,6 @@ extern int plip_init(void); NET_PROFILE_DEFINE(dev_queue_xmit) NET_PROFILE_DEFINE(softnet_process) -const char *if_port_text[] = { - "unknown", - "BNC", - "10baseT", - "AUI", - "100baseT", - "100baseTX", - "100baseFX" -}; - /* * The list of packet types we will receive (as opposed to discard) * and the routines to invoke. @@ -203,7 +193,9 @@ int netdev_fastroute; int netdev_fastroute_obstacles; #endif -static struct subsystem net_subsys; +extern int netdev_sysfs_init(void); +extern int netdev_register_sysfs(struct net_device *); +extern void netdev_unregister_sysfs(struct net_device *); /******************************************************************************* @@ -2075,6 +2067,22 @@ void dev_set_allmulti(struct net_device *dev, int inc) dev_mc_upload(dev); } +unsigned dev_get_flags(const struct net_device *dev) +{ + unsigned flags; + + flags = (dev->flags & ~(IFF_PROMISC | + IFF_ALLMULTI | + IFF_RUNNING)) | + (dev->gflags & (IFF_PROMISC | + IFF_ALLMULTI)); + + if (netif_running(dev) && netif_carrier_ok(dev)) + flags |= IFF_RUNNING; + + return flags; +} + int dev_change_flags(struct net_device *dev, unsigned flags) { int ret; @@ -2137,6 +2145,32 @@ int dev_change_flags(struct net_device *dev, unsigned flags) return ret; } +int dev_set_mtu(struct net_device *dev, int new_mtu) +{ + int err; + + if (new_mtu == dev->mtu) + return 0; + + /* MTU must be positive. */ + if (new_mtu < 0) + return -EINVAL; + + if (!netif_device_present(dev)) + return -ENODEV; + + err = 0; + if (dev->change_mtu) + err = dev->change_mtu(dev, new_mtu); + else + dev->mtu = new_mtu; + if (!err && dev->flags & IFF_UP) + notifier_call_chain(&netdev_chain, + NETDEV_CHANGEMTU, dev); + return err; +} + + /* * Perform the SIOCxIFxxx calls. */ @@ -2150,13 +2184,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) switch (cmd) { case SIOCGIFFLAGS: /* Get interface flags */ - ifr->ifr_flags = (dev->flags & ~(IFF_PROMISC | - IFF_ALLMULTI | - IFF_RUNNING)) | - (dev->gflags & (IFF_PROMISC | - IFF_ALLMULTI)); - if (netif_running(dev) && netif_carrier_ok(dev)) - ifr->ifr_flags |= IFF_RUNNING; + ifr->ifr_flags = dev_get_flags(dev); return 0; case SIOCSIFFLAGS: /* Set interface flags */ @@ -2176,27 +2204,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) return 0; case SIOCSIFMTU: /* Set the MTU of a device */ - if (ifr->ifr_mtu == dev->mtu) - return 0; - - /* - * MTU must be positive. - */ - if (ifr->ifr_mtu < 0) - return -EINVAL; - - if (!netif_device_present(dev)) - return -ENODEV; - - err = 0; - if (dev->change_mtu) - err = dev->change_mtu(dev, ifr->ifr_mtu); - else - dev->mtu = ifr->ifr_mtu; - if (!err && dev->flags & IFF_UP) - notifier_call_chain(&netdev_chain, - NETDEV_CHANGEMTU, dev); - return err; + return dev_set_mtu(dev, ifr->ifr_mtu); case SIOCGIFHWADDR: memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr, @@ -2284,6 +2292,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) return -EEXIST; memcpy(dev->name, ifr->ifr_newname, IFNAMSIZ); dev->name[IFNAMSIZ - 1] = 0; + snprintf(dev->class_dev.class_id, BUS_ID_SIZE, dev->name); notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); return 0; @@ -2580,11 +2589,10 @@ int register_netdevice(struct net_device *dev) if (d == dev || !strcmp(d->name, dev->name)) goto out_err; } - snprintf(dev->kobj.name,KOBJ_NAME_LEN,dev->name); - kobj_set_kset_s(dev,net_subsys); - if ((ret = kobject_register(&dev->kobj))) - goto out_err; + if ((ret = netdev_register_sysfs(dev))) + goto out_err; + /* Fix illegal SG+CSUM combinations. */ if ((dev->features & NETIF_F_SG) && !(dev->features & (NETIF_F_IP_CSUM | @@ -2834,7 +2842,7 @@ int unregister_netdevice(struct net_device *dev) free_divert_blk(dev); - kobject_unregister(&dev->kobj); + netdev_unregister_sysfs(dev); spin_lock(&unregister_todo_lock); dev->next = unregister_todo; @@ -2859,8 +2867,6 @@ extern void ip_auto_config(void); extern void dv_init(void); #endif /* CONFIG_NET_DIVERT */ -static decl_subsys(net,NULL,NULL); - /* * This is called single threaded during boot, so no need @@ -2876,7 +2882,8 @@ static int __init net_dev_init(void) if (dev_proc_init()) goto out; - subsystem_register(&net_subsys); + if (netdev_sysfs_init()) + goto out; INIT_LIST_HEAD(&ptype_all); for (i = 0; i < 16; i++) @@ -2950,7 +2957,8 @@ static int __init net_dev_init(void) */ netdev_boot_setup_check(dev); - if (dev->init && dev->init(dev)) { + if ( (dev->init && dev->init(dev)) || + netdev_register_sysfs(dev) ) { /* * It failed to come up. It will be unhooked later. * dev_alloc_name can now advance to next suitable diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c new file mode 100644 index 000000000000..e4f69ff53bf6 --- /dev/null +++ b/net/core/net-sysfs.c @@ -0,0 +1,344 @@ +/* + * net-sysfs.c - network device class and attributes + * + * Copyright (c) 2003 Stephen Hemminber + * + * + * TODO: + * last_tx + * last_rx + */ + +#include +#include +#include +#include +#include +#include + +const char *if_port_text[] = { + [IF_PORT_UNKNOWN] = "unknown", + [IF_PORT_10BASE2] = "BNC", + [IF_PORT_10BASET] = "10baseT", + [IF_PORT_AUI] = "AUI", + [IF_PORT_100BASET] = "100baseT", + [IF_PORT_100BASETX] = "100baseTX", + [IF_PORT_100BASEFX] = "100baseFX" +}; + +#define to_net_dev(class) container_of((class), struct net_device, class_dev) + +/* generate a show function for simple field */ +#define NETDEVICE_SHOW(field, format_string) \ +static ssize_t show_##field(struct class_device *dev, char *buf) \ +{ \ + return sprintf(buf, format_string, to_net_dev(dev)->field); \ +} + +/* generate a store function for a field with locking */ +#define NETDEVICE_STORE(field) \ +static ssize_t \ +store_##field(struct class_device *dev, const char *buf, size_t len) \ +{ \ + char *endp; \ + long new = simple_strtol(buf, &endp, 16); \ + \ + if (endp == buf || new < 0) \ + return -EINVAL; \ + \ + if (!capable(CAP_NET_ADMIN)) \ + return -EPERM; \ + \ + rtnl_lock(); \ + to_net_dev(dev)->field = new; \ + rtnl_unlock(); \ + return len; \ +} + +/* generate a read-only network device class attribute */ +#define NETDEVICE_ATTR(field, format_string) \ +NETDEVICE_SHOW(field, format_string) \ +static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL) \ + +NETDEVICE_ATTR(addr_len, "%d\n"); +NETDEVICE_ATTR(iflink, "%d\n"); +NETDEVICE_ATTR(ifindex, "%d\n"); +NETDEVICE_ATTR(features, "%#x\n"); +NETDEVICE_ATTR(type, "%d\n"); + +/* TODO: only a few devices set this now should fix others. */ +static ssize_t show_port(struct class_device *dev, char *buf) +{ + unsigned char port = to_net_dev(dev)->if_port; + char *cp = buf; + + cp += sprintf(cp, "%d", port); + if (port < ARRAY_SIZE(if_port_text)) + cp += sprintf(cp, " (%s)", if_port_text[port]); + *cp++ ='\n'; + return cp - buf; +} +static CLASS_DEVICE_ATTR(if_port, S_IRUGO, show_port, NULL); + +static ssize_t format_addr(char *buf, const unsigned char *addr, int len) +{ + int i; + char *cp = buf; + + read_lock(&dev_base_lock); + for (i = 0; i < len; i++) + cp += sprintf(cp, "%02x%c", addr[i], + i == (len - 1) ? '\n' : ':'); + read_unlock(&dev_base_lock); + return cp - buf; +} + +static ssize_t show_address(struct class_device *dev, char *buf) +{ + struct net_device *net = to_net_dev(dev); + return format_addr(buf, net->dev_addr, net->addr_len); +} + +static ssize_t show_broadcast(struct class_device *dev, char *buf) +{ + struct net_device *net = to_net_dev(dev); + return format_addr(buf, net->broadcast, net->addr_len); +} + +static CLASS_DEVICE_ATTR(address, S_IRUGO, show_address, NULL); +static CLASS_DEVICE_ATTR(broadcast, S_IRUGO, show_broadcast, NULL); + +/* read-write attributes */ +NETDEVICE_SHOW(mtu, "%d\n"); + +static ssize_t store_mtu(struct class_device *dev, const char *buf, size_t len) +{ + char *endp; + int new_mtu; + int err; + + new_mtu = simple_strtoul(buf, &endp, 10); + if (endp == buf) + return -EINVAL; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + rtnl_lock(); + err = dev_set_mtu(to_net_dev(dev), new_mtu); + rtnl_unlock(); + + return err == 0 ? len : err; +} + +static CLASS_DEVICE_ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu); + +NETDEVICE_SHOW(flags, "%#x\n"); + +static ssize_t store_flags(struct class_device *dev, const char *buf, size_t len) +{ + unsigned long new_flags; + char *endp; + int err = 0; + + new_flags = simple_strtoul(buf, &endp, 16); + if (endp == buf) + return -EINVAL; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + rtnl_lock(); + err = dev_change_flags(to_net_dev(dev), new_flags); + rtnl_unlock(); + + return err ? err : len; +} + +static CLASS_DEVICE_ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags); + +NETDEVICE_SHOW(tx_queue_len, "%lu\n"); +NETDEVICE_STORE(tx_queue_len); +static CLASS_DEVICE_ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len, + store_tx_queue_len); + +static struct class net_class = { + .name = "net", +}; + + +static struct class_device_attribute *net_class_attributes[] = { + &class_device_attr_ifindex, + &class_device_attr_iflink, + &class_device_attr_addr_len, + &class_device_attr_tx_queue_len, + &class_device_attr_features, + &class_device_attr_mtu, + &class_device_attr_flags, + &class_device_attr_if_port, + &class_device_attr_type, + &class_device_attr_address, + &class_device_attr_broadcast, + NULL +}; + +struct netstat_fs_entry { + struct attribute attr; + ssize_t (*show)(const struct net_device_stats *, char *); + ssize_t (*store)(struct net_device_stats *, const char *, size_t); +}; + +static ssize_t net_device_stat_show(unsigned long var, char *buf) +{ + return sprintf(buf, "%ld\n", var); +} + +/* generate a read-only statistics attribute */ +#define NETDEVICE_STAT(_NAME) \ +static ssize_t show_stat_##_NAME(const struct net_device_stats *stats, \ + char *buf) \ +{ \ + return net_device_stat_show(stats->_NAME, buf); \ +} \ +static struct netstat_fs_entry net_stat_##_NAME = { \ + .attr = {.name = __stringify(_NAME), .mode = S_IRUGO }, \ + .show = show_stat_##_NAME, \ +} + +NETDEVICE_STAT(rx_packets); +NETDEVICE_STAT(tx_packets); +NETDEVICE_STAT(rx_bytes); +NETDEVICE_STAT(tx_bytes); +NETDEVICE_STAT(rx_errors); +NETDEVICE_STAT(tx_errors); +NETDEVICE_STAT(rx_dropped); +NETDEVICE_STAT(tx_dropped); +NETDEVICE_STAT(multicast); +NETDEVICE_STAT(collisions); +NETDEVICE_STAT(rx_length_errors); +NETDEVICE_STAT(rx_over_errors); +NETDEVICE_STAT(rx_crc_errors); +NETDEVICE_STAT(rx_frame_errors); +NETDEVICE_STAT(rx_fifo_errors); +NETDEVICE_STAT(rx_missed_errors); +NETDEVICE_STAT(tx_aborted_errors); +NETDEVICE_STAT(tx_carrier_errors); +NETDEVICE_STAT(tx_fifo_errors); +NETDEVICE_STAT(tx_heartbeat_errors); +NETDEVICE_STAT(tx_window_errors); +NETDEVICE_STAT(rx_compressed); +NETDEVICE_STAT(tx_compressed); + +static struct attribute *default_attrs[] = { + &net_stat_rx_packets.attr, + &net_stat_tx_packets.attr, + &net_stat_rx_bytes.attr, + &net_stat_tx_bytes.attr, + &net_stat_rx_errors.attr, + &net_stat_tx_errors.attr, + &net_stat_rx_dropped.attr, + &net_stat_tx_dropped.attr, + &net_stat_multicast.attr, + &net_stat_collisions.attr, + &net_stat_rx_length_errors.attr, + &net_stat_rx_over_errors.attr, + &net_stat_rx_crc_errors.attr, + &net_stat_rx_frame_errors.attr, + &net_stat_rx_fifo_errors.attr, + &net_stat_rx_missed_errors.attr, + &net_stat_tx_aborted_errors.attr, + &net_stat_tx_carrier_errors.attr, + &net_stat_tx_fifo_errors.attr, + &net_stat_tx_heartbeat_errors.attr, + &net_stat_tx_window_errors.attr, + &net_stat_rx_compressed.attr, + &net_stat_tx_compressed.attr, + NULL +}; + + +static ssize_t +netstat_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) +{ + struct netstat_fs_entry *entry + = container_of(attr, struct netstat_fs_entry, attr); + struct class_device *class_dev + = container_of(kobj->parent, struct class_device, kobj); + struct net_device *dev + = to_net_dev(class_dev); + struct net_device_stats *stats + = dev->get_stats ? dev->get_stats(dev) : NULL; + + if (stats && entry->show) + return entry->show(stats, buf); + return -EINVAL; +} + +static struct sysfs_ops netstat_sysfs_ops = { + .show = netstat_attr_show, +}; + +static struct kobj_type netstat_ktype = { + .sysfs_ops = &netstat_sysfs_ops, + .default_attrs = default_attrs, +}; + +/* Create sysfs entries for network device. */ +int netdev_register_sysfs(struct net_device *net) +{ + struct class_device *class_dev = &(net->class_dev); + int i; + struct class_device_attribute *attr; + int ret; + + memset(class_dev, 0, sizeof(struct class_device)); + class_dev->class = &net_class; + class_dev->dev = net->dev; + class_dev->class_data = net; + + snprintf(class_dev->class_id, BUS_ID_SIZE, net->name); + if ((ret = class_device_register(class_dev))) + goto out; + + for (i = 0; (attr = net_class_attributes[i]); i++) { + if ((ret = class_device_create_file(class_dev, attr))) + goto out_unreg; + } + + if (net->get_stats) { + struct kobject *k = &net->stats_kobj; + + memset(k, 0, sizeof(*k)); + k->parent = kobject_get(&class_dev->kobj); + if (!k->parent) { + ret = -EBUSY; + goto out_unreg; + } + + snprintf(k->name, KOBJ_NAME_LEN, "%s", "statistics"); + k->ktype = &netstat_ktype; + + if((ret = kobject_register(k))) + goto out_unreg; + } + +out: + return ret; +out_unreg: + printk(KERN_WARNING "%s: sysfs attribute registration failed %d\n", + net->name, ret); + class_device_unregister(class_dev); + goto out; +} + +void netdev_unregister_sysfs(struct net_device *net) +{ + if (net->get_stats) + kobject_del(&net->stats_kobj); + class_device_unregister(&net->class_dev); +} + +int netdev_sysfs_init(void) +{ + return class_register(&net_class); +} -- cgit v1.2.3