11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * net-sysfs.c - network device class and attributes 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 2003 Stephen Hemminger <shemminger@osdl.org> 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 91da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 124fc268d2SRandy Dunlap #include <linux/capability.h> 131da177e4SLinus Torvalds #include <linux/kernel.h> 141da177e4SLinus Torvalds #include <linux/netdevice.h> 151da177e4SLinus Torvalds #include <linux/if_arp.h> 161da177e4SLinus Torvalds #include <net/sock.h> 171da177e4SLinus Torvalds #include <linux/rtnetlink.h> 181da177e4SLinus Torvalds #include <linux/wireless.h> 198f1546caSJohannes Berg #include <net/wext.h> 201da177e4SLinus Torvalds 21342709efSPavel Emelyanov #include "net-sysfs.h" 22342709efSPavel Emelyanov 238b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 241da177e4SLinus Torvalds static const char fmt_hex[] = "%#x\n"; 25d1102b59SDavid S. Miller static const char fmt_long_hex[] = "%#lx\n"; 261da177e4SLinus Torvalds static const char fmt_dec[] = "%d\n"; 271da177e4SLinus Torvalds static const char fmt_ulong[] = "%lu\n"; 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds static inline int dev_isalive(const struct net_device *dev) 301da177e4SLinus Torvalds { 31fe9925b5SStephen Hemminger return dev->reg_state <= NETREG_REGISTERED; 321da177e4SLinus Torvalds } 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds /* use same locking rules as GIF* ioctl's */ 3543cb76d9SGreg Kroah-Hartman static ssize_t netdev_show(const struct device *dev, 3643cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 371da177e4SLinus Torvalds ssize_t (*format)(const struct net_device *, char *)) 381da177e4SLinus Torvalds { 3943cb76d9SGreg Kroah-Hartman struct net_device *net = to_net_dev(dev); 401da177e4SLinus Torvalds ssize_t ret = -EINVAL; 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds read_lock(&dev_base_lock); 431da177e4SLinus Torvalds if (dev_isalive(net)) 441da177e4SLinus Torvalds ret = (*format)(net, buf); 451da177e4SLinus Torvalds read_unlock(&dev_base_lock); 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds return ret; 481da177e4SLinus Torvalds } 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds /* generate a show function for simple field */ 511da177e4SLinus Torvalds #define NETDEVICE_SHOW(field, format_string) \ 521da177e4SLinus Torvalds static ssize_t format_##field(const struct net_device *net, char *buf) \ 531da177e4SLinus Torvalds { \ 541da177e4SLinus Torvalds return sprintf(buf, format_string, net->field); \ 551da177e4SLinus Torvalds } \ 5643cb76d9SGreg Kroah-Hartman static ssize_t show_##field(struct device *dev, \ 5743cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 581da177e4SLinus Torvalds { \ 5943cb76d9SGreg Kroah-Hartman return netdev_show(dev, attr, buf, format_##field); \ 601da177e4SLinus Torvalds } 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds /* use same locking and permission rules as SIF* ioctl's */ 6443cb76d9SGreg Kroah-Hartman static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, 651da177e4SLinus Torvalds const char *buf, size_t len, 661da177e4SLinus Torvalds int (*set)(struct net_device *, unsigned long)) 671da177e4SLinus Torvalds { 681da177e4SLinus Torvalds struct net_device *net = to_net_dev(dev); 691da177e4SLinus Torvalds char *endp; 701da177e4SLinus Torvalds unsigned long new; 711da177e4SLinus Torvalds int ret = -EINVAL; 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) 741da177e4SLinus Torvalds return -EPERM; 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds new = simple_strtoul(buf, &endp, 0); 771da177e4SLinus Torvalds if (endp == buf) 781da177e4SLinus Torvalds goto err; 791da177e4SLinus Torvalds 805a5990d3SStephen Hemminger if (!rtnl_trylock()) 81336ca57cSEric W. Biederman return restart_syscall(); 825a5990d3SStephen Hemminger 831da177e4SLinus Torvalds if (dev_isalive(net)) { 841da177e4SLinus Torvalds if ((ret = (*set)(net, new)) == 0) 851da177e4SLinus Torvalds ret = len; 861da177e4SLinus Torvalds } 871da177e4SLinus Torvalds rtnl_unlock(); 881da177e4SLinus Torvalds err: 891da177e4SLinus Torvalds return ret; 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 929d29672cSDavid Woodhouse NETDEVICE_SHOW(dev_id, fmt_hex); 93fd586bacSKay Sievers NETDEVICE_SHOW(addr_len, fmt_dec); 94fd586bacSKay Sievers NETDEVICE_SHOW(iflink, fmt_dec); 95fd586bacSKay Sievers NETDEVICE_SHOW(ifindex, fmt_dec); 96fd586bacSKay Sievers NETDEVICE_SHOW(features, fmt_long_hex); 97fd586bacSKay Sievers NETDEVICE_SHOW(type, fmt_dec); 98b00055aaSStefan Rompf NETDEVICE_SHOW(link_mode, fmt_dec); 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds /* use same locking rules as GIFHWADDR ioctl's */ 10143cb76d9SGreg Kroah-Hartman static ssize_t show_address(struct device *dev, struct device_attribute *attr, 10243cb76d9SGreg Kroah-Hartman char *buf) 1031da177e4SLinus Torvalds { 1041da177e4SLinus Torvalds struct net_device *net = to_net_dev(dev); 1051da177e4SLinus Torvalds ssize_t ret = -EINVAL; 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds read_lock(&dev_base_lock); 1081da177e4SLinus Torvalds if (dev_isalive(net)) 1097ffc49a6SMichael Chan ret = sysfs_format_mac(buf, net->dev_addr, net->addr_len); 1101da177e4SLinus Torvalds read_unlock(&dev_base_lock); 1111da177e4SLinus Torvalds return ret; 1121da177e4SLinus Torvalds } 1131da177e4SLinus Torvalds 11443cb76d9SGreg Kroah-Hartman static ssize_t show_broadcast(struct device *dev, 11543cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1161da177e4SLinus Torvalds { 1171da177e4SLinus Torvalds struct net_device *net = to_net_dev(dev); 1181da177e4SLinus Torvalds if (dev_isalive(net)) 1197ffc49a6SMichael Chan return sysfs_format_mac(buf, net->broadcast, net->addr_len); 1201da177e4SLinus Torvalds return -EINVAL; 1211da177e4SLinus Torvalds } 1221da177e4SLinus Torvalds 12343cb76d9SGreg Kroah-Hartman static ssize_t show_carrier(struct device *dev, 12443cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1251da177e4SLinus Torvalds { 1261da177e4SLinus Torvalds struct net_device *netdev = to_net_dev(dev); 1271da177e4SLinus Torvalds if (netif_running(netdev)) { 1281da177e4SLinus Torvalds return sprintf(buf, fmt_dec, !!netif_carrier_ok(netdev)); 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds return -EINVAL; 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 133d519e17eSAndy Gospodarek static ssize_t show_speed(struct device *dev, 134d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 135d519e17eSAndy Gospodarek { 136d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 137d519e17eSAndy Gospodarek int ret = -EINVAL; 138d519e17eSAndy Gospodarek 139d519e17eSAndy Gospodarek if (!rtnl_trylock()) 140d519e17eSAndy Gospodarek return restart_syscall(); 141d519e17eSAndy Gospodarek 142ac5e3af9SEric Dumazet if (netif_running(netdev) && 143ac5e3af9SEric Dumazet netdev->ethtool_ops && 144ac5e3af9SEric Dumazet netdev->ethtool_ops->get_settings) { 145d519e17eSAndy Gospodarek struct ethtool_cmd cmd = { ETHTOOL_GSET }; 146d519e17eSAndy Gospodarek 147d519e17eSAndy Gospodarek if (!netdev->ethtool_ops->get_settings(netdev, &cmd)) 148d519e17eSAndy Gospodarek ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd)); 149d519e17eSAndy Gospodarek } 150d519e17eSAndy Gospodarek rtnl_unlock(); 151d519e17eSAndy Gospodarek return ret; 152d519e17eSAndy Gospodarek } 153d519e17eSAndy Gospodarek 154d519e17eSAndy Gospodarek static ssize_t show_duplex(struct device *dev, 155d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 156d519e17eSAndy Gospodarek { 157d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 158d519e17eSAndy Gospodarek int ret = -EINVAL; 159d519e17eSAndy Gospodarek 160d519e17eSAndy Gospodarek if (!rtnl_trylock()) 161d519e17eSAndy Gospodarek return restart_syscall(); 162d519e17eSAndy Gospodarek 163ac5e3af9SEric Dumazet if (netif_running(netdev) && 164ac5e3af9SEric Dumazet netdev->ethtool_ops && 165ac5e3af9SEric Dumazet netdev->ethtool_ops->get_settings) { 166d519e17eSAndy Gospodarek struct ethtool_cmd cmd = { ETHTOOL_GSET }; 167d519e17eSAndy Gospodarek 168d519e17eSAndy Gospodarek if (!netdev->ethtool_ops->get_settings(netdev, &cmd)) 169d519e17eSAndy Gospodarek ret = sprintf(buf, "%s\n", cmd.duplex ? "full" : "half"); 170d519e17eSAndy Gospodarek } 171d519e17eSAndy Gospodarek rtnl_unlock(); 172d519e17eSAndy Gospodarek return ret; 173d519e17eSAndy Gospodarek } 174d519e17eSAndy Gospodarek 17543cb76d9SGreg Kroah-Hartman static ssize_t show_dormant(struct device *dev, 17643cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 177b00055aaSStefan Rompf { 178b00055aaSStefan Rompf struct net_device *netdev = to_net_dev(dev); 179b00055aaSStefan Rompf 180b00055aaSStefan Rompf if (netif_running(netdev)) 181b00055aaSStefan Rompf return sprintf(buf, fmt_dec, !!netif_dormant(netdev)); 182b00055aaSStefan Rompf 183b00055aaSStefan Rompf return -EINVAL; 184b00055aaSStefan Rompf } 185b00055aaSStefan Rompf 18636cbd3dcSJan Engelhardt static const char *const operstates[] = { 187b00055aaSStefan Rompf "unknown", 188b00055aaSStefan Rompf "notpresent", /* currently unused */ 189b00055aaSStefan Rompf "down", 190b00055aaSStefan Rompf "lowerlayerdown", 191b00055aaSStefan Rompf "testing", /* currently unused */ 192b00055aaSStefan Rompf "dormant", 193b00055aaSStefan Rompf "up" 194b00055aaSStefan Rompf }; 195b00055aaSStefan Rompf 19643cb76d9SGreg Kroah-Hartman static ssize_t show_operstate(struct device *dev, 19743cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 198b00055aaSStefan Rompf { 199b00055aaSStefan Rompf const struct net_device *netdev = to_net_dev(dev); 200b00055aaSStefan Rompf unsigned char operstate; 201b00055aaSStefan Rompf 202b00055aaSStefan Rompf read_lock(&dev_base_lock); 203b00055aaSStefan Rompf operstate = netdev->operstate; 204b00055aaSStefan Rompf if (!netif_running(netdev)) 205b00055aaSStefan Rompf operstate = IF_OPER_DOWN; 206b00055aaSStefan Rompf read_unlock(&dev_base_lock); 207b00055aaSStefan Rompf 208e3a5cd9eSAdrian Bunk if (operstate >= ARRAY_SIZE(operstates)) 209b00055aaSStefan Rompf return -EINVAL; /* should not happen */ 210b00055aaSStefan Rompf 211b00055aaSStefan Rompf return sprintf(buf, "%s\n", operstates[operstate]); 212b00055aaSStefan Rompf } 213b00055aaSStefan Rompf 2141da177e4SLinus Torvalds /* read-write attributes */ 2151da177e4SLinus Torvalds NETDEVICE_SHOW(mtu, fmt_dec); 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds static int change_mtu(struct net_device *net, unsigned long new_mtu) 2181da177e4SLinus Torvalds { 2191da177e4SLinus Torvalds return dev_set_mtu(net, (int) new_mtu); 2201da177e4SLinus Torvalds } 2211da177e4SLinus Torvalds 22243cb76d9SGreg Kroah-Hartman static ssize_t store_mtu(struct device *dev, struct device_attribute *attr, 22343cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 2241da177e4SLinus Torvalds { 22543cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_mtu); 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds NETDEVICE_SHOW(flags, fmt_hex); 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds static int change_flags(struct net_device *net, unsigned long new_flags) 2311da177e4SLinus Torvalds { 2321da177e4SLinus Torvalds return dev_change_flags(net, (unsigned) new_flags); 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds 23543cb76d9SGreg Kroah-Hartman static ssize_t store_flags(struct device *dev, struct device_attribute *attr, 23643cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 2371da177e4SLinus Torvalds { 23843cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_flags); 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds NETDEVICE_SHOW(tx_queue_len, fmt_ulong); 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds static int change_tx_queue_len(struct net_device *net, unsigned long new_len) 2441da177e4SLinus Torvalds { 2451da177e4SLinus Torvalds net->tx_queue_len = new_len; 2461da177e4SLinus Torvalds return 0; 2471da177e4SLinus Torvalds } 2481da177e4SLinus Torvalds 24943cb76d9SGreg Kroah-Hartman static ssize_t store_tx_queue_len(struct device *dev, 25043cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 25143cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 2521da177e4SLinus Torvalds { 25343cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_tx_queue_len); 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds 2560b815a1aSStephen Hemminger static ssize_t store_ifalias(struct device *dev, struct device_attribute *attr, 2570b815a1aSStephen Hemminger const char *buf, size_t len) 2580b815a1aSStephen Hemminger { 2590b815a1aSStephen Hemminger struct net_device *netdev = to_net_dev(dev); 2600b815a1aSStephen Hemminger size_t count = len; 2610b815a1aSStephen Hemminger ssize_t ret; 2620b815a1aSStephen Hemminger 2630b815a1aSStephen Hemminger if (!capable(CAP_NET_ADMIN)) 2640b815a1aSStephen Hemminger return -EPERM; 2650b815a1aSStephen Hemminger 2660b815a1aSStephen Hemminger /* ignore trailing newline */ 2670b815a1aSStephen Hemminger if (len > 0 && buf[len - 1] == '\n') 2680b815a1aSStephen Hemminger --count; 2690b815a1aSStephen Hemminger 270336ca57cSEric W. Biederman if (!rtnl_trylock()) 271336ca57cSEric W. Biederman return restart_syscall(); 2720b815a1aSStephen Hemminger ret = dev_set_alias(netdev, buf, count); 2730b815a1aSStephen Hemminger rtnl_unlock(); 2740b815a1aSStephen Hemminger 2750b815a1aSStephen Hemminger return ret < 0 ? ret : len; 2760b815a1aSStephen Hemminger } 2770b815a1aSStephen Hemminger 2780b815a1aSStephen Hemminger static ssize_t show_ifalias(struct device *dev, 2790b815a1aSStephen Hemminger struct device_attribute *attr, char *buf) 2800b815a1aSStephen Hemminger { 2810b815a1aSStephen Hemminger const struct net_device *netdev = to_net_dev(dev); 2820b815a1aSStephen Hemminger ssize_t ret = 0; 2830b815a1aSStephen Hemminger 284336ca57cSEric W. Biederman if (!rtnl_trylock()) 285336ca57cSEric W. Biederman return restart_syscall(); 2860b815a1aSStephen Hemminger if (netdev->ifalias) 2870b815a1aSStephen Hemminger ret = sprintf(buf, "%s\n", netdev->ifalias); 2880b815a1aSStephen Hemminger rtnl_unlock(); 2890b815a1aSStephen Hemminger return ret; 2900b815a1aSStephen Hemminger } 2910b815a1aSStephen Hemminger 29243cb76d9SGreg Kroah-Hartman static struct device_attribute net_class_attributes[] = { 293fd586bacSKay Sievers __ATTR(addr_len, S_IRUGO, show_addr_len, NULL), 2949d29672cSDavid Woodhouse __ATTR(dev_id, S_IRUGO, show_dev_id, NULL), 2950b815a1aSStephen Hemminger __ATTR(ifalias, S_IRUGO | S_IWUSR, show_ifalias, store_ifalias), 296fd586bacSKay Sievers __ATTR(iflink, S_IRUGO, show_iflink, NULL), 297fd586bacSKay Sievers __ATTR(ifindex, S_IRUGO, show_ifindex, NULL), 298fd586bacSKay Sievers __ATTR(features, S_IRUGO, show_features, NULL), 299fd586bacSKay Sievers __ATTR(type, S_IRUGO, show_type, NULL), 300b00055aaSStefan Rompf __ATTR(link_mode, S_IRUGO, show_link_mode, NULL), 301fd586bacSKay Sievers __ATTR(address, S_IRUGO, show_address, NULL), 302fd586bacSKay Sievers __ATTR(broadcast, S_IRUGO, show_broadcast, NULL), 303fd586bacSKay Sievers __ATTR(carrier, S_IRUGO, show_carrier, NULL), 304d519e17eSAndy Gospodarek __ATTR(speed, S_IRUGO, show_speed, NULL), 305d519e17eSAndy Gospodarek __ATTR(duplex, S_IRUGO, show_duplex, NULL), 306b00055aaSStefan Rompf __ATTR(dormant, S_IRUGO, show_dormant, NULL), 307b00055aaSStefan Rompf __ATTR(operstate, S_IRUGO, show_operstate, NULL), 308fd586bacSKay Sievers __ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu), 309fd586bacSKay Sievers __ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags), 310fd586bacSKay Sievers __ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len, 311fd586bacSKay Sievers store_tx_queue_len), 312fd586bacSKay Sievers {} 3131da177e4SLinus Torvalds }; 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds /* Show a given an attribute in the statistics group */ 31643cb76d9SGreg Kroah-Hartman static ssize_t netstat_show(const struct device *d, 31743cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 3181da177e4SLinus Torvalds unsigned long offset) 3191da177e4SLinus Torvalds { 32043cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 3211da177e4SLinus Torvalds ssize_t ret = -EINVAL; 3221da177e4SLinus Torvalds 323df1b86c5SPavel Emelyanov WARN_ON(offset > sizeof(struct net_device_stats) || 324df1b86c5SPavel Emelyanov offset % sizeof(unsigned long) != 0); 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds read_lock(&dev_base_lock); 32796e74088SPavel Emelyanov if (dev_isalive(dev)) { 328eeda3fd6SStephen Hemminger const struct net_device_stats *stats = dev_get_stats(dev); 3291da177e4SLinus Torvalds ret = sprintf(buf, fmt_ulong, 3301da177e4SLinus Torvalds *(unsigned long *)(((u8 *) stats) + offset)); 33196e74088SPavel Emelyanov } 3321da177e4SLinus Torvalds read_unlock(&dev_base_lock); 3331da177e4SLinus Torvalds return ret; 3341da177e4SLinus Torvalds } 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds /* generate a read-only statistics attribute */ 3371da177e4SLinus Torvalds #define NETSTAT_ENTRY(name) \ 33843cb76d9SGreg Kroah-Hartman static ssize_t show_##name(struct device *d, \ 33943cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 3401da177e4SLinus Torvalds { \ 34143cb76d9SGreg Kroah-Hartman return netstat_show(d, attr, buf, \ 3421da177e4SLinus Torvalds offsetof(struct net_device_stats, name)); \ 3431da177e4SLinus Torvalds } \ 34443cb76d9SGreg Kroah-Hartman static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds NETSTAT_ENTRY(rx_packets); 3471da177e4SLinus Torvalds NETSTAT_ENTRY(tx_packets); 3481da177e4SLinus Torvalds NETSTAT_ENTRY(rx_bytes); 3491da177e4SLinus Torvalds NETSTAT_ENTRY(tx_bytes); 3501da177e4SLinus Torvalds NETSTAT_ENTRY(rx_errors); 3511da177e4SLinus Torvalds NETSTAT_ENTRY(tx_errors); 3521da177e4SLinus Torvalds NETSTAT_ENTRY(rx_dropped); 3531da177e4SLinus Torvalds NETSTAT_ENTRY(tx_dropped); 3541da177e4SLinus Torvalds NETSTAT_ENTRY(multicast); 3551da177e4SLinus Torvalds NETSTAT_ENTRY(collisions); 3561da177e4SLinus Torvalds NETSTAT_ENTRY(rx_length_errors); 3571da177e4SLinus Torvalds NETSTAT_ENTRY(rx_over_errors); 3581da177e4SLinus Torvalds NETSTAT_ENTRY(rx_crc_errors); 3591da177e4SLinus Torvalds NETSTAT_ENTRY(rx_frame_errors); 3601da177e4SLinus Torvalds NETSTAT_ENTRY(rx_fifo_errors); 3611da177e4SLinus Torvalds NETSTAT_ENTRY(rx_missed_errors); 3621da177e4SLinus Torvalds NETSTAT_ENTRY(tx_aborted_errors); 3631da177e4SLinus Torvalds NETSTAT_ENTRY(tx_carrier_errors); 3641da177e4SLinus Torvalds NETSTAT_ENTRY(tx_fifo_errors); 3651da177e4SLinus Torvalds NETSTAT_ENTRY(tx_heartbeat_errors); 3661da177e4SLinus Torvalds NETSTAT_ENTRY(tx_window_errors); 3671da177e4SLinus Torvalds NETSTAT_ENTRY(rx_compressed); 3681da177e4SLinus Torvalds NETSTAT_ENTRY(tx_compressed); 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds static struct attribute *netstat_attrs[] = { 37143cb76d9SGreg Kroah-Hartman &dev_attr_rx_packets.attr, 37243cb76d9SGreg Kroah-Hartman &dev_attr_tx_packets.attr, 37343cb76d9SGreg Kroah-Hartman &dev_attr_rx_bytes.attr, 37443cb76d9SGreg Kroah-Hartman &dev_attr_tx_bytes.attr, 37543cb76d9SGreg Kroah-Hartman &dev_attr_rx_errors.attr, 37643cb76d9SGreg Kroah-Hartman &dev_attr_tx_errors.attr, 37743cb76d9SGreg Kroah-Hartman &dev_attr_rx_dropped.attr, 37843cb76d9SGreg Kroah-Hartman &dev_attr_tx_dropped.attr, 37943cb76d9SGreg Kroah-Hartman &dev_attr_multicast.attr, 38043cb76d9SGreg Kroah-Hartman &dev_attr_collisions.attr, 38143cb76d9SGreg Kroah-Hartman &dev_attr_rx_length_errors.attr, 38243cb76d9SGreg Kroah-Hartman &dev_attr_rx_over_errors.attr, 38343cb76d9SGreg Kroah-Hartman &dev_attr_rx_crc_errors.attr, 38443cb76d9SGreg Kroah-Hartman &dev_attr_rx_frame_errors.attr, 38543cb76d9SGreg Kroah-Hartman &dev_attr_rx_fifo_errors.attr, 38643cb76d9SGreg Kroah-Hartman &dev_attr_rx_missed_errors.attr, 38743cb76d9SGreg Kroah-Hartman &dev_attr_tx_aborted_errors.attr, 38843cb76d9SGreg Kroah-Hartman &dev_attr_tx_carrier_errors.attr, 38943cb76d9SGreg Kroah-Hartman &dev_attr_tx_fifo_errors.attr, 39043cb76d9SGreg Kroah-Hartman &dev_attr_tx_heartbeat_errors.attr, 39143cb76d9SGreg Kroah-Hartman &dev_attr_tx_window_errors.attr, 39243cb76d9SGreg Kroah-Hartman &dev_attr_rx_compressed.attr, 39343cb76d9SGreg Kroah-Hartman &dev_attr_tx_compressed.attr, 3941da177e4SLinus Torvalds NULL 3951da177e4SLinus Torvalds }; 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds static struct attribute_group netstat_group = { 3991da177e4SLinus Torvalds .name = "statistics", 4001da177e4SLinus Torvalds .attrs = netstat_attrs, 4011da177e4SLinus Torvalds }; 4021da177e4SLinus Torvalds 40322bb1be4SJohannes Berg #ifdef CONFIG_WIRELESS_EXT_SYSFS 4041da177e4SLinus Torvalds /* helper function that does all the locking etc for wireless stats */ 40543cb76d9SGreg Kroah-Hartman static ssize_t wireless_show(struct device *d, char *buf, 4061da177e4SLinus Torvalds ssize_t (*format)(const struct iw_statistics *, 4071da177e4SLinus Torvalds char *)) 4081da177e4SLinus Torvalds { 40943cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 4108f1546caSJohannes Berg const struct iw_statistics *iw; 4111da177e4SLinus Torvalds ssize_t ret = -EINVAL; 4121da177e4SLinus Torvalds 413b8afe641SEric W. Biederman if (!rtnl_trylock()) 414b8afe641SEric W. Biederman return restart_syscall(); 4156dd214b5SAndrey Borzenkov if (dev_isalive(dev)) { 4168f1546caSJohannes Berg iw = get_wireless_stats(dev); 4178f1546caSJohannes Berg if (iw) 4181da177e4SLinus Torvalds ret = (*format)(iw, buf); 4196dd214b5SAndrey Borzenkov } 420a160ee69SJohannes Berg rtnl_unlock(); 4211da177e4SLinus Torvalds 4221da177e4SLinus Torvalds return ret; 4231da177e4SLinus Torvalds } 4241da177e4SLinus Torvalds 4251da177e4SLinus Torvalds /* show function template for wireless fields */ 4261da177e4SLinus Torvalds #define WIRELESS_SHOW(name, field, format_string) \ 4271da177e4SLinus Torvalds static ssize_t format_iw_##name(const struct iw_statistics *iw, char *buf) \ 4281da177e4SLinus Torvalds { \ 4291da177e4SLinus Torvalds return sprintf(buf, format_string, iw->field); \ 4301da177e4SLinus Torvalds } \ 43143cb76d9SGreg Kroah-Hartman static ssize_t show_iw_##name(struct device *d, \ 43243cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 4331da177e4SLinus Torvalds { \ 43443cb76d9SGreg Kroah-Hartman return wireless_show(d, buf, format_iw_##name); \ 4351da177e4SLinus Torvalds } \ 43643cb76d9SGreg Kroah-Hartman static DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL) 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds WIRELESS_SHOW(status, status, fmt_hex); 4391da177e4SLinus Torvalds WIRELESS_SHOW(link, qual.qual, fmt_dec); 4401da177e4SLinus Torvalds WIRELESS_SHOW(level, qual.level, fmt_dec); 4411da177e4SLinus Torvalds WIRELESS_SHOW(noise, qual.noise, fmt_dec); 4421da177e4SLinus Torvalds WIRELESS_SHOW(nwid, discard.nwid, fmt_dec); 4431da177e4SLinus Torvalds WIRELESS_SHOW(crypt, discard.code, fmt_dec); 4441da177e4SLinus Torvalds WIRELESS_SHOW(fragment, discard.fragment, fmt_dec); 4451da177e4SLinus Torvalds WIRELESS_SHOW(misc, discard.misc, fmt_dec); 4461da177e4SLinus Torvalds WIRELESS_SHOW(retries, discard.retries, fmt_dec); 4471da177e4SLinus Torvalds WIRELESS_SHOW(beacon, miss.beacon, fmt_dec); 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds static struct attribute *wireless_attrs[] = { 45043cb76d9SGreg Kroah-Hartman &dev_attr_status.attr, 45143cb76d9SGreg Kroah-Hartman &dev_attr_link.attr, 45243cb76d9SGreg Kroah-Hartman &dev_attr_level.attr, 45343cb76d9SGreg Kroah-Hartman &dev_attr_noise.attr, 45443cb76d9SGreg Kroah-Hartman &dev_attr_nwid.attr, 45543cb76d9SGreg Kroah-Hartman &dev_attr_crypt.attr, 45643cb76d9SGreg Kroah-Hartman &dev_attr_fragment.attr, 45743cb76d9SGreg Kroah-Hartman &dev_attr_retries.attr, 45843cb76d9SGreg Kroah-Hartman &dev_attr_misc.attr, 45943cb76d9SGreg Kroah-Hartman &dev_attr_beacon.attr, 4601da177e4SLinus Torvalds NULL 4611da177e4SLinus Torvalds }; 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds static struct attribute_group wireless_group = { 4641da177e4SLinus Torvalds .name = "wireless", 4651da177e4SLinus Torvalds .attrs = wireless_attrs, 4661da177e4SLinus Torvalds }; 4671da177e4SLinus Torvalds #endif 4681da177e4SLinus Torvalds 469*30bde1f5SStephen Rothwell #ifdef CONFIG_RPS 4700a9627f2STom Herbert /* 4710a9627f2STom Herbert * RX queue sysfs structures and functions. 4720a9627f2STom Herbert */ 4730a9627f2STom Herbert struct rx_queue_attribute { 4740a9627f2STom Herbert struct attribute attr; 4750a9627f2STom Herbert ssize_t (*show)(struct netdev_rx_queue *queue, 4760a9627f2STom Herbert struct rx_queue_attribute *attr, char *buf); 4770a9627f2STom Herbert ssize_t (*store)(struct netdev_rx_queue *queue, 4780a9627f2STom Herbert struct rx_queue_attribute *attr, const char *buf, size_t len); 4790a9627f2STom Herbert }; 4800a9627f2STom Herbert #define to_rx_queue_attr(_attr) container_of(_attr, \ 4810a9627f2STom Herbert struct rx_queue_attribute, attr) 4820a9627f2STom Herbert 4830a9627f2STom Herbert #define to_rx_queue(obj) container_of(obj, struct netdev_rx_queue, kobj) 4840a9627f2STom Herbert 4850a9627f2STom Herbert static ssize_t rx_queue_attr_show(struct kobject *kobj, struct attribute *attr, 4860a9627f2STom Herbert char *buf) 4870a9627f2STom Herbert { 4880a9627f2STom Herbert struct rx_queue_attribute *attribute = to_rx_queue_attr(attr); 4890a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 4900a9627f2STom Herbert 4910a9627f2STom Herbert if (!attribute->show) 4920a9627f2STom Herbert return -EIO; 4930a9627f2STom Herbert 4940a9627f2STom Herbert return attribute->show(queue, attribute, buf); 4950a9627f2STom Herbert } 4960a9627f2STom Herbert 4970a9627f2STom Herbert static ssize_t rx_queue_attr_store(struct kobject *kobj, struct attribute *attr, 4980a9627f2STom Herbert const char *buf, size_t count) 4990a9627f2STom Herbert { 5000a9627f2STom Herbert struct rx_queue_attribute *attribute = to_rx_queue_attr(attr); 5010a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 5020a9627f2STom Herbert 5030a9627f2STom Herbert if (!attribute->store) 5040a9627f2STom Herbert return -EIO; 5050a9627f2STom Herbert 5060a9627f2STom Herbert return attribute->store(queue, attribute, buf, count); 5070a9627f2STom Herbert } 5080a9627f2STom Herbert 5090a9627f2STom Herbert static struct sysfs_ops rx_queue_sysfs_ops = { 5100a9627f2STom Herbert .show = rx_queue_attr_show, 5110a9627f2STom Herbert .store = rx_queue_attr_store, 5120a9627f2STom Herbert }; 5130a9627f2STom Herbert 5140a9627f2STom Herbert static ssize_t show_rps_map(struct netdev_rx_queue *queue, 5150a9627f2STom Herbert struct rx_queue_attribute *attribute, char *buf) 5160a9627f2STom Herbert { 5170a9627f2STom Herbert struct rps_map *map; 5180a9627f2STom Herbert cpumask_var_t mask; 5190a9627f2STom Herbert size_t len = 0; 5200a9627f2STom Herbert int i; 5210a9627f2STom Herbert 5220a9627f2STom Herbert if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) 5230a9627f2STom Herbert return -ENOMEM; 5240a9627f2STom Herbert 5250a9627f2STom Herbert rcu_read_lock(); 5260a9627f2STom Herbert map = rcu_dereference(queue->rps_map); 5270a9627f2STom Herbert if (map) 5280a9627f2STom Herbert for (i = 0; i < map->len; i++) 5290a9627f2STom Herbert cpumask_set_cpu(map->cpus[i], mask); 5300a9627f2STom Herbert 5310a9627f2STom Herbert len += cpumask_scnprintf(buf + len, PAGE_SIZE, mask); 5320a9627f2STom Herbert if (PAGE_SIZE - len < 3) { 5330a9627f2STom Herbert rcu_read_unlock(); 5340a9627f2STom Herbert free_cpumask_var(mask); 5350a9627f2STom Herbert return -EINVAL; 5360a9627f2STom Herbert } 5370a9627f2STom Herbert rcu_read_unlock(); 5380a9627f2STom Herbert 5390a9627f2STom Herbert free_cpumask_var(mask); 5400a9627f2STom Herbert len += sprintf(buf + len, "\n"); 5410a9627f2STom Herbert return len; 5420a9627f2STom Herbert } 5430a9627f2STom Herbert 5440a9627f2STom Herbert static void rps_map_release(struct rcu_head *rcu) 5450a9627f2STom Herbert { 5460a9627f2STom Herbert struct rps_map *map = container_of(rcu, struct rps_map, rcu); 5470a9627f2STom Herbert 5480a9627f2STom Herbert kfree(map); 5490a9627f2STom Herbert } 5500a9627f2STom Herbert 5510a9627f2STom Herbert ssize_t store_rps_map(struct netdev_rx_queue *queue, 5520a9627f2STom Herbert struct rx_queue_attribute *attribute, 5530a9627f2STom Herbert const char *buf, size_t len) 5540a9627f2STom Herbert { 5550a9627f2STom Herbert struct rps_map *old_map, *map; 5560a9627f2STom Herbert cpumask_var_t mask; 5570a9627f2STom Herbert int err, cpu, i; 5580a9627f2STom Herbert static DEFINE_SPINLOCK(rps_map_lock); 5590a9627f2STom Herbert 5600a9627f2STom Herbert if (!capable(CAP_NET_ADMIN)) 5610a9627f2STom Herbert return -EPERM; 5620a9627f2STom Herbert 5630a9627f2STom Herbert if (!alloc_cpumask_var(&mask, GFP_KERNEL)) 5640a9627f2STom Herbert return -ENOMEM; 5650a9627f2STom Herbert 5660a9627f2STom Herbert err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); 5670a9627f2STom Herbert if (err) { 5680a9627f2STom Herbert free_cpumask_var(mask); 5690a9627f2STom Herbert return err; 5700a9627f2STom Herbert } 5710a9627f2STom Herbert 5720a9627f2STom Herbert map = kzalloc(max_t(unsigned, 5730a9627f2STom Herbert RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES), 5740a9627f2STom Herbert GFP_KERNEL); 5750a9627f2STom Herbert if (!map) { 5760a9627f2STom Herbert free_cpumask_var(mask); 5770a9627f2STom Herbert return -ENOMEM; 5780a9627f2STom Herbert } 5790a9627f2STom Herbert 5800a9627f2STom Herbert i = 0; 5810a9627f2STom Herbert for_each_cpu_and(cpu, mask, cpu_online_mask) 5820a9627f2STom Herbert map->cpus[i++] = cpu; 5830a9627f2STom Herbert 5840a9627f2STom Herbert if (i) 5850a9627f2STom Herbert map->len = i; 5860a9627f2STom Herbert else { 5870a9627f2STom Herbert kfree(map); 5880a9627f2STom Herbert map = NULL; 5890a9627f2STom Herbert } 5900a9627f2STom Herbert 5910a9627f2STom Herbert spin_lock(&rps_map_lock); 5920a9627f2STom Herbert old_map = queue->rps_map; 5930a9627f2STom Herbert rcu_assign_pointer(queue->rps_map, map); 5940a9627f2STom Herbert spin_unlock(&rps_map_lock); 5950a9627f2STom Herbert 5960a9627f2STom Herbert if (old_map) 5970a9627f2STom Herbert call_rcu(&old_map->rcu, rps_map_release); 5980a9627f2STom Herbert 5990a9627f2STom Herbert free_cpumask_var(mask); 6000a9627f2STom Herbert return len; 6010a9627f2STom Herbert } 6020a9627f2STom Herbert 6030a9627f2STom Herbert static struct rx_queue_attribute rps_cpus_attribute = 6040a9627f2STom Herbert __ATTR(rps_cpus, S_IRUGO | S_IWUSR, show_rps_map, store_rps_map); 6050a9627f2STom Herbert 6060a9627f2STom Herbert static struct attribute *rx_queue_default_attrs[] = { 6070a9627f2STom Herbert &rps_cpus_attribute.attr, 6080a9627f2STom Herbert NULL 6090a9627f2STom Herbert }; 6100a9627f2STom Herbert 6110a9627f2STom Herbert static void rx_queue_release(struct kobject *kobj) 6120a9627f2STom Herbert { 6130a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 6140a9627f2STom Herbert struct rps_map *map = queue->rps_map; 6150a9627f2STom Herbert struct netdev_rx_queue *first = queue->first; 6160a9627f2STom Herbert 6170a9627f2STom Herbert if (map) 6180a9627f2STom Herbert call_rcu(&map->rcu, rps_map_release); 6190a9627f2STom Herbert 6200a9627f2STom Herbert if (atomic_dec_and_test(&first->count)) 6210a9627f2STom Herbert kfree(first); 6220a9627f2STom Herbert } 6230a9627f2STom Herbert 6240a9627f2STom Herbert static struct kobj_type rx_queue_ktype = { 6250a9627f2STom Herbert .sysfs_ops = &rx_queue_sysfs_ops, 6260a9627f2STom Herbert .release = rx_queue_release, 6270a9627f2STom Herbert .default_attrs = rx_queue_default_attrs, 6280a9627f2STom Herbert }; 6290a9627f2STom Herbert 6300a9627f2STom Herbert static int rx_queue_add_kobject(struct net_device *net, int index) 6310a9627f2STom Herbert { 6320a9627f2STom Herbert struct netdev_rx_queue *queue = net->_rx + index; 6330a9627f2STom Herbert struct kobject *kobj = &queue->kobj; 6340a9627f2STom Herbert int error = 0; 6350a9627f2STom Herbert 6360a9627f2STom Herbert kobj->kset = net->queues_kset; 6370a9627f2STom Herbert error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, 6380a9627f2STom Herbert "rx-%u", index); 6390a9627f2STom Herbert if (error) { 6400a9627f2STom Herbert kobject_put(kobj); 6410a9627f2STom Herbert return error; 6420a9627f2STom Herbert } 6430a9627f2STom Herbert 6440a9627f2STom Herbert kobject_uevent(kobj, KOBJ_ADD); 6450a9627f2STom Herbert 6460a9627f2STom Herbert return error; 6470a9627f2STom Herbert } 6480a9627f2STom Herbert 6490a9627f2STom Herbert static int rx_queue_register_kobjects(struct net_device *net) 6500a9627f2STom Herbert { 6510a9627f2STom Herbert int i; 6520a9627f2STom Herbert int error = 0; 6530a9627f2STom Herbert 6540a9627f2STom Herbert net->queues_kset = kset_create_and_add("queues", 6550a9627f2STom Herbert NULL, &net->dev.kobj); 6560a9627f2STom Herbert if (!net->queues_kset) 6570a9627f2STom Herbert return -ENOMEM; 6580a9627f2STom Herbert for (i = 0; i < net->num_rx_queues; i++) { 6590a9627f2STom Herbert error = rx_queue_add_kobject(net, i); 6600a9627f2STom Herbert if (error) 6610a9627f2STom Herbert break; 6620a9627f2STom Herbert } 6630a9627f2STom Herbert 6640a9627f2STom Herbert if (error) 6650a9627f2STom Herbert while (--i >= 0) 6660a9627f2STom Herbert kobject_put(&net->_rx[i].kobj); 6670a9627f2STom Herbert 6680a9627f2STom Herbert return error; 6690a9627f2STom Herbert } 6700a9627f2STom Herbert 6710a9627f2STom Herbert static void rx_queue_remove_kobjects(struct net_device *net) 6720a9627f2STom Herbert { 6730a9627f2STom Herbert int i; 6740a9627f2STom Herbert 6750a9627f2STom Herbert for (i = 0; i < net->num_rx_queues; i++) 6760a9627f2STom Herbert kobject_put(&net->_rx[i].kobj); 6770a9627f2STom Herbert kset_unregister(net->queues_kset); 6780a9627f2STom Herbert } 679*30bde1f5SStephen Rothwell #endif /* CONFIG_RPS */ 6808b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 6818b41d188SEric W. Biederman 6821da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG 6837eff2e7aSKay Sievers static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) 6841da177e4SLinus Torvalds { 68543cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 6867eff2e7aSKay Sievers int retval; 6871da177e4SLinus Torvalds 68809bb5217SDaniel Lezcano if (!net_eq(dev_net(dev), &init_net)) 68909bb5217SDaniel Lezcano return 0; 69009bb5217SDaniel Lezcano 691312c004dSKay Sievers /* pass interface to uevent. */ 6927eff2e7aSKay Sievers retval = add_uevent_var(env, "INTERFACE=%s", dev->name); 693bf62456eSEric Rannaud if (retval) 694bf62456eSEric Rannaud goto exit; 6951da177e4SLinus Torvalds 696ca2f37dbSJean Tourrilhes /* pass ifindex to uevent. 697ca2f37dbSJean Tourrilhes * ifindex is useful as it won't change (interface name may change) 698ca2f37dbSJean Tourrilhes * and is what RtNetlink uses natively. */ 6997eff2e7aSKay Sievers retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex); 700ca2f37dbSJean Tourrilhes 701bf62456eSEric Rannaud exit: 702bf62456eSEric Rannaud return retval; 7031da177e4SLinus Torvalds } 7041da177e4SLinus Torvalds #endif 7051da177e4SLinus Torvalds 7061da177e4SLinus Torvalds /* 7071da177e4SLinus Torvalds * netdev_release -- destroy and free a dead device. 70843cb76d9SGreg Kroah-Hartman * Called when last reference to device kobject is gone. 7091da177e4SLinus Torvalds */ 71043cb76d9SGreg Kroah-Hartman static void netdev_release(struct device *d) 7111da177e4SLinus Torvalds { 71243cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 7131da177e4SLinus Torvalds 7141da177e4SLinus Torvalds BUG_ON(dev->reg_state != NETREG_RELEASED); 7151da177e4SLinus Torvalds 7160b815a1aSStephen Hemminger kfree(dev->ifalias); 7171da177e4SLinus Torvalds kfree((char *)dev - dev->padded); 7181da177e4SLinus Torvalds } 7191da177e4SLinus Torvalds 7201da177e4SLinus Torvalds static struct class net_class = { 7211da177e4SLinus Torvalds .name = "net", 72243cb76d9SGreg Kroah-Hartman .dev_release = netdev_release, 7238b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 72443cb76d9SGreg Kroah-Hartman .dev_attrs = net_class_attributes, 7258b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 7261da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG 72743cb76d9SGreg Kroah-Hartman .dev_uevent = netdev_uevent, 7281da177e4SLinus Torvalds #endif 7291da177e4SLinus Torvalds }; 7301da177e4SLinus Torvalds 7319093bbb2SStephen Hemminger /* Delete sysfs entries but hold kobject reference until after all 7329093bbb2SStephen Hemminger * netdev references are gone. 7339093bbb2SStephen Hemminger */ 7348b41d188SEric W. Biederman void netdev_unregister_kobject(struct net_device * net) 7351da177e4SLinus Torvalds { 7369093bbb2SStephen Hemminger struct device *dev = &(net->dev); 7379093bbb2SStephen Hemminger 7389093bbb2SStephen Hemminger kobject_get(&dev->kobj); 7393891845eSEric W. Biederman 74009ad9bc7SOctavian Purdila if (!net_eq(dev_net(net), &init_net)) 7413891845eSEric W. Biederman return; 7423891845eSEric W. Biederman 743*30bde1f5SStephen Rothwell #ifdef CONFIG_RPS 7440a9627f2STom Herbert rx_queue_remove_kobjects(net); 745e880eb6cSTom Herbert #endif 7460a9627f2STom Herbert 7479093bbb2SStephen Hemminger device_del(dev); 7481da177e4SLinus Torvalds } 7491da177e4SLinus Torvalds 7501da177e4SLinus Torvalds /* Create sysfs entries for network device. */ 7518b41d188SEric W. Biederman int netdev_register_kobject(struct net_device *net) 7521da177e4SLinus Torvalds { 75343cb76d9SGreg Kroah-Hartman struct device *dev = &(net->dev); 754a4dbd674SDavid Brownell const struct attribute_group **groups = net->sysfs_groups; 7550a9627f2STom Herbert int error = 0; 7561da177e4SLinus Torvalds 75743cb76d9SGreg Kroah-Hartman dev->class = &net_class; 75843cb76d9SGreg Kroah-Hartman dev->platform_data = net; 75943cb76d9SGreg Kroah-Hartman dev->groups = groups; 7601da177e4SLinus Torvalds 761a2205472SStephen Hemminger dev_set_name(dev, "%s", net->name); 7621da177e4SLinus Torvalds 7638b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 7640c509a6cSEric W. Biederman /* Allow for a device specific group */ 7650c509a6cSEric W. Biederman if (*groups) 7660c509a6cSEric W. Biederman groups++; 7671da177e4SLinus Torvalds 7680c509a6cSEric W. Biederman *groups++ = &netstat_group; 76922bb1be4SJohannes Berg #ifdef CONFIG_WIRELESS_EXT_SYSFS 7703d23e349SJohannes Berg if (net->ieee80211_ptr) 771fe9925b5SStephen Hemminger *groups++ = &wireless_group; 7723d23e349SJohannes Berg #ifdef CONFIG_WIRELESS_EXT 7733d23e349SJohannes Berg else if (net->wireless_handlers) 7743d23e349SJohannes Berg *groups++ = &wireless_group; 7753d23e349SJohannes Berg #endif 7761da177e4SLinus Torvalds #endif 7778b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 7781da177e4SLinus Torvalds 77909ad9bc7SOctavian Purdila if (!net_eq(dev_net(net), &init_net)) 7803891845eSEric W. Biederman return 0; 7813891845eSEric W. Biederman 7820a9627f2STom Herbert error = device_add(dev); 7830a9627f2STom Herbert if (error) 7840a9627f2STom Herbert return error; 7850a9627f2STom Herbert 786*30bde1f5SStephen Rothwell #ifdef CONFIG_RPS 7870a9627f2STom Herbert error = rx_queue_register_kobjects(net); 7880a9627f2STom Herbert if (error) { 7890a9627f2STom Herbert device_del(dev); 7900a9627f2STom Herbert return error; 7910a9627f2STom Herbert } 792e880eb6cSTom Herbert #endif 7930a9627f2STom Herbert 7940a9627f2STom Herbert return error; 7951da177e4SLinus Torvalds } 7961da177e4SLinus Torvalds 797b8a9787eSJay Vosburgh int netdev_class_create_file(struct class_attribute *class_attr) 798b8a9787eSJay Vosburgh { 799b8a9787eSJay Vosburgh return class_create_file(&net_class, class_attr); 800b8a9787eSJay Vosburgh } 801b8a9787eSJay Vosburgh 802b8a9787eSJay Vosburgh void netdev_class_remove_file(struct class_attribute *class_attr) 803b8a9787eSJay Vosburgh { 804b8a9787eSJay Vosburgh class_remove_file(&net_class, class_attr); 805b8a9787eSJay Vosburgh } 806b8a9787eSJay Vosburgh 807b8a9787eSJay Vosburgh EXPORT_SYMBOL(netdev_class_create_file); 808b8a9787eSJay Vosburgh EXPORT_SYMBOL(netdev_class_remove_file); 809b8a9787eSJay Vosburgh 810aaf8cdc3SDaniel Lezcano void netdev_initialize_kobject(struct net_device *net) 811aaf8cdc3SDaniel Lezcano { 812aaf8cdc3SDaniel Lezcano struct device *device = &(net->dev); 813aaf8cdc3SDaniel Lezcano device_initialize(device); 814aaf8cdc3SDaniel Lezcano } 815aaf8cdc3SDaniel Lezcano 8168b41d188SEric W. Biederman int netdev_kobject_init(void) 8171da177e4SLinus Torvalds { 8181da177e4SLinus Torvalds return class_register(&net_class); 8191da177e4SLinus Torvalds } 820