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 142d519e17eSAndy Gospodarek if (netif_running(netdev) && netdev->ethtool_ops->get_settings) { 143d519e17eSAndy Gospodarek struct ethtool_cmd cmd = { ETHTOOL_GSET }; 144d519e17eSAndy Gospodarek 145d519e17eSAndy Gospodarek if (!netdev->ethtool_ops->get_settings(netdev, &cmd)) 146d519e17eSAndy Gospodarek ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd)); 147d519e17eSAndy Gospodarek } 148d519e17eSAndy Gospodarek rtnl_unlock(); 149d519e17eSAndy Gospodarek return ret; 150d519e17eSAndy Gospodarek } 151d519e17eSAndy Gospodarek 152d519e17eSAndy Gospodarek static ssize_t show_duplex(struct device *dev, 153d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 154d519e17eSAndy Gospodarek { 155d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 156d519e17eSAndy Gospodarek int ret = -EINVAL; 157d519e17eSAndy Gospodarek 158d519e17eSAndy Gospodarek if (!rtnl_trylock()) 159d519e17eSAndy Gospodarek return restart_syscall(); 160d519e17eSAndy Gospodarek 161d519e17eSAndy Gospodarek if (netif_running(netdev) && netdev->ethtool_ops->get_settings) { 162d519e17eSAndy Gospodarek struct ethtool_cmd cmd = { ETHTOOL_GSET }; 163d519e17eSAndy Gospodarek 164d519e17eSAndy Gospodarek if (!netdev->ethtool_ops->get_settings(netdev, &cmd)) 165d519e17eSAndy Gospodarek ret = sprintf(buf, "%s\n", cmd.duplex ? "full" : "half"); 166d519e17eSAndy Gospodarek } 167d519e17eSAndy Gospodarek rtnl_unlock(); 168d519e17eSAndy Gospodarek return ret; 169d519e17eSAndy Gospodarek } 170d519e17eSAndy Gospodarek 17143cb76d9SGreg Kroah-Hartman static ssize_t show_dormant(struct device *dev, 17243cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 173b00055aaSStefan Rompf { 174b00055aaSStefan Rompf struct net_device *netdev = to_net_dev(dev); 175b00055aaSStefan Rompf 176b00055aaSStefan Rompf if (netif_running(netdev)) 177b00055aaSStefan Rompf return sprintf(buf, fmt_dec, !!netif_dormant(netdev)); 178b00055aaSStefan Rompf 179b00055aaSStefan Rompf return -EINVAL; 180b00055aaSStefan Rompf } 181b00055aaSStefan Rompf 18236cbd3dcSJan Engelhardt static const char *const operstates[] = { 183b00055aaSStefan Rompf "unknown", 184b00055aaSStefan Rompf "notpresent", /* currently unused */ 185b00055aaSStefan Rompf "down", 186b00055aaSStefan Rompf "lowerlayerdown", 187b00055aaSStefan Rompf "testing", /* currently unused */ 188b00055aaSStefan Rompf "dormant", 189b00055aaSStefan Rompf "up" 190b00055aaSStefan Rompf }; 191b00055aaSStefan Rompf 19243cb76d9SGreg Kroah-Hartman static ssize_t show_operstate(struct device *dev, 19343cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 194b00055aaSStefan Rompf { 195b00055aaSStefan Rompf const struct net_device *netdev = to_net_dev(dev); 196b00055aaSStefan Rompf unsigned char operstate; 197b00055aaSStefan Rompf 198b00055aaSStefan Rompf read_lock(&dev_base_lock); 199b00055aaSStefan Rompf operstate = netdev->operstate; 200b00055aaSStefan Rompf if (!netif_running(netdev)) 201b00055aaSStefan Rompf operstate = IF_OPER_DOWN; 202b00055aaSStefan Rompf read_unlock(&dev_base_lock); 203b00055aaSStefan Rompf 204e3a5cd9eSAdrian Bunk if (operstate >= ARRAY_SIZE(operstates)) 205b00055aaSStefan Rompf return -EINVAL; /* should not happen */ 206b00055aaSStefan Rompf 207b00055aaSStefan Rompf return sprintf(buf, "%s\n", operstates[operstate]); 208b00055aaSStefan Rompf } 209b00055aaSStefan Rompf 2101da177e4SLinus Torvalds /* read-write attributes */ 2111da177e4SLinus Torvalds NETDEVICE_SHOW(mtu, fmt_dec); 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds static int change_mtu(struct net_device *net, unsigned long new_mtu) 2141da177e4SLinus Torvalds { 2151da177e4SLinus Torvalds return dev_set_mtu(net, (int) new_mtu); 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds 21843cb76d9SGreg Kroah-Hartman static ssize_t store_mtu(struct device *dev, struct device_attribute *attr, 21943cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 2201da177e4SLinus Torvalds { 22143cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_mtu); 2221da177e4SLinus Torvalds } 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds NETDEVICE_SHOW(flags, fmt_hex); 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds static int change_flags(struct net_device *net, unsigned long new_flags) 2271da177e4SLinus Torvalds { 2281da177e4SLinus Torvalds return dev_change_flags(net, (unsigned) new_flags); 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds 23143cb76d9SGreg Kroah-Hartman static ssize_t store_flags(struct device *dev, struct device_attribute *attr, 23243cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 2331da177e4SLinus Torvalds { 23443cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_flags); 2351da177e4SLinus Torvalds } 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds NETDEVICE_SHOW(tx_queue_len, fmt_ulong); 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds static int change_tx_queue_len(struct net_device *net, unsigned long new_len) 2401da177e4SLinus Torvalds { 2411da177e4SLinus Torvalds net->tx_queue_len = new_len; 2421da177e4SLinus Torvalds return 0; 2431da177e4SLinus Torvalds } 2441da177e4SLinus Torvalds 24543cb76d9SGreg Kroah-Hartman static ssize_t store_tx_queue_len(struct device *dev, 24643cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 24743cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 2481da177e4SLinus Torvalds { 24943cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_tx_queue_len); 2501da177e4SLinus Torvalds } 2511da177e4SLinus Torvalds 2520b815a1aSStephen Hemminger static ssize_t store_ifalias(struct device *dev, struct device_attribute *attr, 2530b815a1aSStephen Hemminger const char *buf, size_t len) 2540b815a1aSStephen Hemminger { 2550b815a1aSStephen Hemminger struct net_device *netdev = to_net_dev(dev); 2560b815a1aSStephen Hemminger size_t count = len; 2570b815a1aSStephen Hemminger ssize_t ret; 2580b815a1aSStephen Hemminger 2590b815a1aSStephen Hemminger if (!capable(CAP_NET_ADMIN)) 2600b815a1aSStephen Hemminger return -EPERM; 2610b815a1aSStephen Hemminger 2620b815a1aSStephen Hemminger /* ignore trailing newline */ 2630b815a1aSStephen Hemminger if (len > 0 && buf[len - 1] == '\n') 2640b815a1aSStephen Hemminger --count; 2650b815a1aSStephen Hemminger 266336ca57cSEric W. Biederman if (!rtnl_trylock()) 267336ca57cSEric W. Biederman return restart_syscall(); 2680b815a1aSStephen Hemminger ret = dev_set_alias(netdev, buf, count); 2690b815a1aSStephen Hemminger rtnl_unlock(); 2700b815a1aSStephen Hemminger 2710b815a1aSStephen Hemminger return ret < 0 ? ret : len; 2720b815a1aSStephen Hemminger } 2730b815a1aSStephen Hemminger 2740b815a1aSStephen Hemminger static ssize_t show_ifalias(struct device *dev, 2750b815a1aSStephen Hemminger struct device_attribute *attr, char *buf) 2760b815a1aSStephen Hemminger { 2770b815a1aSStephen Hemminger const struct net_device *netdev = to_net_dev(dev); 2780b815a1aSStephen Hemminger ssize_t ret = 0; 2790b815a1aSStephen Hemminger 280336ca57cSEric W. Biederman if (!rtnl_trylock()) 281336ca57cSEric W. Biederman return restart_syscall(); 2820b815a1aSStephen Hemminger if (netdev->ifalias) 2830b815a1aSStephen Hemminger ret = sprintf(buf, "%s\n", netdev->ifalias); 2840b815a1aSStephen Hemminger rtnl_unlock(); 2850b815a1aSStephen Hemminger return ret; 2860b815a1aSStephen Hemminger } 2870b815a1aSStephen Hemminger 28843cb76d9SGreg Kroah-Hartman static struct device_attribute net_class_attributes[] = { 289fd586bacSKay Sievers __ATTR(addr_len, S_IRUGO, show_addr_len, NULL), 2909d29672cSDavid Woodhouse __ATTR(dev_id, S_IRUGO, show_dev_id, NULL), 2910b815a1aSStephen Hemminger __ATTR(ifalias, S_IRUGO | S_IWUSR, show_ifalias, store_ifalias), 292fd586bacSKay Sievers __ATTR(iflink, S_IRUGO, show_iflink, NULL), 293fd586bacSKay Sievers __ATTR(ifindex, S_IRUGO, show_ifindex, NULL), 294fd586bacSKay Sievers __ATTR(features, S_IRUGO, show_features, NULL), 295fd586bacSKay Sievers __ATTR(type, S_IRUGO, show_type, NULL), 296b00055aaSStefan Rompf __ATTR(link_mode, S_IRUGO, show_link_mode, NULL), 297fd586bacSKay Sievers __ATTR(address, S_IRUGO, show_address, NULL), 298fd586bacSKay Sievers __ATTR(broadcast, S_IRUGO, show_broadcast, NULL), 299fd586bacSKay Sievers __ATTR(carrier, S_IRUGO, show_carrier, NULL), 300d519e17eSAndy Gospodarek __ATTR(speed, S_IRUGO, show_speed, NULL), 301d519e17eSAndy Gospodarek __ATTR(duplex, S_IRUGO, show_duplex, NULL), 302b00055aaSStefan Rompf __ATTR(dormant, S_IRUGO, show_dormant, NULL), 303b00055aaSStefan Rompf __ATTR(operstate, S_IRUGO, show_operstate, NULL), 304fd586bacSKay Sievers __ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu), 305fd586bacSKay Sievers __ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags), 306fd586bacSKay Sievers __ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len, 307fd586bacSKay Sievers store_tx_queue_len), 308fd586bacSKay Sievers {} 3091da177e4SLinus Torvalds }; 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds /* Show a given an attribute in the statistics group */ 31243cb76d9SGreg Kroah-Hartman static ssize_t netstat_show(const struct device *d, 31343cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 3141da177e4SLinus Torvalds unsigned long offset) 3151da177e4SLinus Torvalds { 31643cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 3171da177e4SLinus Torvalds ssize_t ret = -EINVAL; 3181da177e4SLinus Torvalds 319df1b86c5SPavel Emelyanov WARN_ON(offset > sizeof(struct net_device_stats) || 320df1b86c5SPavel Emelyanov offset % sizeof(unsigned long) != 0); 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds read_lock(&dev_base_lock); 32396e74088SPavel Emelyanov if (dev_isalive(dev)) { 324eeda3fd6SStephen Hemminger const struct net_device_stats *stats = dev_get_stats(dev); 3251da177e4SLinus Torvalds ret = sprintf(buf, fmt_ulong, 3261da177e4SLinus Torvalds *(unsigned long *)(((u8 *) stats) + offset)); 32796e74088SPavel Emelyanov } 3281da177e4SLinus Torvalds read_unlock(&dev_base_lock); 3291da177e4SLinus Torvalds return ret; 3301da177e4SLinus Torvalds } 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds /* generate a read-only statistics attribute */ 3331da177e4SLinus Torvalds #define NETSTAT_ENTRY(name) \ 33443cb76d9SGreg Kroah-Hartman static ssize_t show_##name(struct device *d, \ 33543cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 3361da177e4SLinus Torvalds { \ 33743cb76d9SGreg Kroah-Hartman return netstat_show(d, attr, buf, \ 3381da177e4SLinus Torvalds offsetof(struct net_device_stats, name)); \ 3391da177e4SLinus Torvalds } \ 34043cb76d9SGreg Kroah-Hartman static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds NETSTAT_ENTRY(rx_packets); 3431da177e4SLinus Torvalds NETSTAT_ENTRY(tx_packets); 3441da177e4SLinus Torvalds NETSTAT_ENTRY(rx_bytes); 3451da177e4SLinus Torvalds NETSTAT_ENTRY(tx_bytes); 3461da177e4SLinus Torvalds NETSTAT_ENTRY(rx_errors); 3471da177e4SLinus Torvalds NETSTAT_ENTRY(tx_errors); 3481da177e4SLinus Torvalds NETSTAT_ENTRY(rx_dropped); 3491da177e4SLinus Torvalds NETSTAT_ENTRY(tx_dropped); 3501da177e4SLinus Torvalds NETSTAT_ENTRY(multicast); 3511da177e4SLinus Torvalds NETSTAT_ENTRY(collisions); 3521da177e4SLinus Torvalds NETSTAT_ENTRY(rx_length_errors); 3531da177e4SLinus Torvalds NETSTAT_ENTRY(rx_over_errors); 3541da177e4SLinus Torvalds NETSTAT_ENTRY(rx_crc_errors); 3551da177e4SLinus Torvalds NETSTAT_ENTRY(rx_frame_errors); 3561da177e4SLinus Torvalds NETSTAT_ENTRY(rx_fifo_errors); 3571da177e4SLinus Torvalds NETSTAT_ENTRY(rx_missed_errors); 3581da177e4SLinus Torvalds NETSTAT_ENTRY(tx_aborted_errors); 3591da177e4SLinus Torvalds NETSTAT_ENTRY(tx_carrier_errors); 3601da177e4SLinus Torvalds NETSTAT_ENTRY(tx_fifo_errors); 3611da177e4SLinus Torvalds NETSTAT_ENTRY(tx_heartbeat_errors); 3621da177e4SLinus Torvalds NETSTAT_ENTRY(tx_window_errors); 3631da177e4SLinus Torvalds NETSTAT_ENTRY(rx_compressed); 3641da177e4SLinus Torvalds NETSTAT_ENTRY(tx_compressed); 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds static struct attribute *netstat_attrs[] = { 36743cb76d9SGreg Kroah-Hartman &dev_attr_rx_packets.attr, 36843cb76d9SGreg Kroah-Hartman &dev_attr_tx_packets.attr, 36943cb76d9SGreg Kroah-Hartman &dev_attr_rx_bytes.attr, 37043cb76d9SGreg Kroah-Hartman &dev_attr_tx_bytes.attr, 37143cb76d9SGreg Kroah-Hartman &dev_attr_rx_errors.attr, 37243cb76d9SGreg Kroah-Hartman &dev_attr_tx_errors.attr, 37343cb76d9SGreg Kroah-Hartman &dev_attr_rx_dropped.attr, 37443cb76d9SGreg Kroah-Hartman &dev_attr_tx_dropped.attr, 37543cb76d9SGreg Kroah-Hartman &dev_attr_multicast.attr, 37643cb76d9SGreg Kroah-Hartman &dev_attr_collisions.attr, 37743cb76d9SGreg Kroah-Hartman &dev_attr_rx_length_errors.attr, 37843cb76d9SGreg Kroah-Hartman &dev_attr_rx_over_errors.attr, 37943cb76d9SGreg Kroah-Hartman &dev_attr_rx_crc_errors.attr, 38043cb76d9SGreg Kroah-Hartman &dev_attr_rx_frame_errors.attr, 38143cb76d9SGreg Kroah-Hartman &dev_attr_rx_fifo_errors.attr, 38243cb76d9SGreg Kroah-Hartman &dev_attr_rx_missed_errors.attr, 38343cb76d9SGreg Kroah-Hartman &dev_attr_tx_aborted_errors.attr, 38443cb76d9SGreg Kroah-Hartman &dev_attr_tx_carrier_errors.attr, 38543cb76d9SGreg Kroah-Hartman &dev_attr_tx_fifo_errors.attr, 38643cb76d9SGreg Kroah-Hartman &dev_attr_tx_heartbeat_errors.attr, 38743cb76d9SGreg Kroah-Hartman &dev_attr_tx_window_errors.attr, 38843cb76d9SGreg Kroah-Hartman &dev_attr_rx_compressed.attr, 38943cb76d9SGreg Kroah-Hartman &dev_attr_tx_compressed.attr, 3901da177e4SLinus Torvalds NULL 3911da177e4SLinus Torvalds }; 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds static struct attribute_group netstat_group = { 3951da177e4SLinus Torvalds .name = "statistics", 3961da177e4SLinus Torvalds .attrs = netstat_attrs, 3971da177e4SLinus Torvalds }; 3981da177e4SLinus Torvalds 39922bb1be4SJohannes Berg #ifdef CONFIG_WIRELESS_EXT_SYSFS 4001da177e4SLinus Torvalds /* helper function that does all the locking etc for wireless stats */ 40143cb76d9SGreg Kroah-Hartman static ssize_t wireless_show(struct device *d, char *buf, 4021da177e4SLinus Torvalds ssize_t (*format)(const struct iw_statistics *, 4031da177e4SLinus Torvalds char *)) 4041da177e4SLinus Torvalds { 40543cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 4068f1546caSJohannes Berg const struct iw_statistics *iw; 4071da177e4SLinus Torvalds ssize_t ret = -EINVAL; 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds read_lock(&dev_base_lock); 4106dd214b5SAndrey Borzenkov if (dev_isalive(dev)) { 4118f1546caSJohannes Berg iw = get_wireless_stats(dev); 4128f1546caSJohannes Berg if (iw) 4131da177e4SLinus Torvalds ret = (*format)(iw, buf); 4146dd214b5SAndrey Borzenkov } 4151da177e4SLinus Torvalds read_unlock(&dev_base_lock); 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds return ret; 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds /* show function template for wireless fields */ 4211da177e4SLinus Torvalds #define WIRELESS_SHOW(name, field, format_string) \ 4221da177e4SLinus Torvalds static ssize_t format_iw_##name(const struct iw_statistics *iw, char *buf) \ 4231da177e4SLinus Torvalds { \ 4241da177e4SLinus Torvalds return sprintf(buf, format_string, iw->field); \ 4251da177e4SLinus Torvalds } \ 42643cb76d9SGreg Kroah-Hartman static ssize_t show_iw_##name(struct device *d, \ 42743cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 4281da177e4SLinus Torvalds { \ 42943cb76d9SGreg Kroah-Hartman return wireless_show(d, buf, format_iw_##name); \ 4301da177e4SLinus Torvalds } \ 43143cb76d9SGreg Kroah-Hartman static DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL) 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds WIRELESS_SHOW(status, status, fmt_hex); 4341da177e4SLinus Torvalds WIRELESS_SHOW(link, qual.qual, fmt_dec); 4351da177e4SLinus Torvalds WIRELESS_SHOW(level, qual.level, fmt_dec); 4361da177e4SLinus Torvalds WIRELESS_SHOW(noise, qual.noise, fmt_dec); 4371da177e4SLinus Torvalds WIRELESS_SHOW(nwid, discard.nwid, fmt_dec); 4381da177e4SLinus Torvalds WIRELESS_SHOW(crypt, discard.code, fmt_dec); 4391da177e4SLinus Torvalds WIRELESS_SHOW(fragment, discard.fragment, fmt_dec); 4401da177e4SLinus Torvalds WIRELESS_SHOW(misc, discard.misc, fmt_dec); 4411da177e4SLinus Torvalds WIRELESS_SHOW(retries, discard.retries, fmt_dec); 4421da177e4SLinus Torvalds WIRELESS_SHOW(beacon, miss.beacon, fmt_dec); 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds static struct attribute *wireless_attrs[] = { 44543cb76d9SGreg Kroah-Hartman &dev_attr_status.attr, 44643cb76d9SGreg Kroah-Hartman &dev_attr_link.attr, 44743cb76d9SGreg Kroah-Hartman &dev_attr_level.attr, 44843cb76d9SGreg Kroah-Hartman &dev_attr_noise.attr, 44943cb76d9SGreg Kroah-Hartman &dev_attr_nwid.attr, 45043cb76d9SGreg Kroah-Hartman &dev_attr_crypt.attr, 45143cb76d9SGreg Kroah-Hartman &dev_attr_fragment.attr, 45243cb76d9SGreg Kroah-Hartman &dev_attr_retries.attr, 45343cb76d9SGreg Kroah-Hartman &dev_attr_misc.attr, 45443cb76d9SGreg Kroah-Hartman &dev_attr_beacon.attr, 4551da177e4SLinus Torvalds NULL 4561da177e4SLinus Torvalds }; 4571da177e4SLinus Torvalds 4581da177e4SLinus Torvalds static struct attribute_group wireless_group = { 4591da177e4SLinus Torvalds .name = "wireless", 4601da177e4SLinus Torvalds .attrs = wireless_attrs, 4611da177e4SLinus Torvalds }; 4621da177e4SLinus Torvalds #endif 4631da177e4SLinus Torvalds 4648b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 4658b41d188SEric W. Biederman 4661da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG 4677eff2e7aSKay Sievers static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) 4681da177e4SLinus Torvalds { 46943cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 4707eff2e7aSKay Sievers int retval; 4711da177e4SLinus Torvalds 47209bb5217SDaniel Lezcano if (!net_eq(dev_net(dev), &init_net)) 47309bb5217SDaniel Lezcano return 0; 47409bb5217SDaniel Lezcano 475312c004dSKay Sievers /* pass interface to uevent. */ 4767eff2e7aSKay Sievers retval = add_uevent_var(env, "INTERFACE=%s", dev->name); 477bf62456eSEric Rannaud if (retval) 478bf62456eSEric Rannaud goto exit; 4791da177e4SLinus Torvalds 480ca2f37dbSJean Tourrilhes /* pass ifindex to uevent. 481ca2f37dbSJean Tourrilhes * ifindex is useful as it won't change (interface name may change) 482ca2f37dbSJean Tourrilhes * and is what RtNetlink uses natively. */ 4837eff2e7aSKay Sievers retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex); 484ca2f37dbSJean Tourrilhes 485bf62456eSEric Rannaud exit: 486bf62456eSEric Rannaud return retval; 4871da177e4SLinus Torvalds } 4881da177e4SLinus Torvalds #endif 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds /* 4911da177e4SLinus Torvalds * netdev_release -- destroy and free a dead device. 49243cb76d9SGreg Kroah-Hartman * Called when last reference to device kobject is gone. 4931da177e4SLinus Torvalds */ 49443cb76d9SGreg Kroah-Hartman static void netdev_release(struct device *d) 4951da177e4SLinus Torvalds { 49643cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 4971da177e4SLinus Torvalds 4981da177e4SLinus Torvalds BUG_ON(dev->reg_state != NETREG_RELEASED); 4991da177e4SLinus Torvalds 5000b815a1aSStephen Hemminger kfree(dev->ifalias); 5011da177e4SLinus Torvalds kfree((char *)dev - dev->padded); 5021da177e4SLinus Torvalds } 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds static struct class net_class = { 5051da177e4SLinus Torvalds .name = "net", 50643cb76d9SGreg Kroah-Hartman .dev_release = netdev_release, 5078b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 50843cb76d9SGreg Kroah-Hartman .dev_attrs = net_class_attributes, 5098b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 5101da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG 51143cb76d9SGreg Kroah-Hartman .dev_uevent = netdev_uevent, 5121da177e4SLinus Torvalds #endif 5131da177e4SLinus Torvalds }; 5141da177e4SLinus Torvalds 5159093bbb2SStephen Hemminger /* Delete sysfs entries but hold kobject reference until after all 5169093bbb2SStephen Hemminger * netdev references are gone. 5179093bbb2SStephen Hemminger */ 5188b41d188SEric W. Biederman void netdev_unregister_kobject(struct net_device * net) 5191da177e4SLinus Torvalds { 5209093bbb2SStephen Hemminger struct device *dev = &(net->dev); 5219093bbb2SStephen Hemminger 5229093bbb2SStephen Hemminger kobject_get(&dev->kobj); 5233891845eSEric W. Biederman 5243891845eSEric W. Biederman if (dev_net(net) != &init_net) 5253891845eSEric W. Biederman return; 5263891845eSEric W. Biederman 5279093bbb2SStephen Hemminger device_del(dev); 5281da177e4SLinus Torvalds } 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds /* Create sysfs entries for network device. */ 5318b41d188SEric W. Biederman int netdev_register_kobject(struct net_device *net) 5321da177e4SLinus Torvalds { 53343cb76d9SGreg Kroah-Hartman struct device *dev = &(net->dev); 534a4dbd674SDavid Brownell const struct attribute_group **groups = net->sysfs_groups; 5351da177e4SLinus Torvalds 53643cb76d9SGreg Kroah-Hartman dev->class = &net_class; 53743cb76d9SGreg Kroah-Hartman dev->platform_data = net; 53843cb76d9SGreg Kroah-Hartman dev->groups = groups; 5391da177e4SLinus Torvalds 540a2205472SStephen Hemminger dev_set_name(dev, "%s", net->name); 5411da177e4SLinus Torvalds 5428b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 543fe9925b5SStephen Hemminger *groups++ = &netstat_group; 5441da177e4SLinus Torvalds 54522bb1be4SJohannes Berg #ifdef CONFIG_WIRELESS_EXT_SYSFS 546*3d23e349SJohannes Berg if (net->ieee80211_ptr) 547fe9925b5SStephen Hemminger *groups++ = &wireless_group; 548*3d23e349SJohannes Berg #ifdef CONFIG_WIRELESS_EXT 549*3d23e349SJohannes Berg else if (net->wireless_handlers) 550*3d23e349SJohannes Berg *groups++ = &wireless_group; 551*3d23e349SJohannes Berg #endif 5521da177e4SLinus Torvalds #endif 5538b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 5541da177e4SLinus Torvalds 5553891845eSEric W. Biederman if (dev_net(net) != &init_net) 5563891845eSEric W. Biederman return 0; 5573891845eSEric W. Biederman 55843cb76d9SGreg Kroah-Hartman return device_add(dev); 5591da177e4SLinus Torvalds } 5601da177e4SLinus Torvalds 561b8a9787eSJay Vosburgh int netdev_class_create_file(struct class_attribute *class_attr) 562b8a9787eSJay Vosburgh { 563b8a9787eSJay Vosburgh return class_create_file(&net_class, class_attr); 564b8a9787eSJay Vosburgh } 565b8a9787eSJay Vosburgh 566b8a9787eSJay Vosburgh void netdev_class_remove_file(struct class_attribute *class_attr) 567b8a9787eSJay Vosburgh { 568b8a9787eSJay Vosburgh class_remove_file(&net_class, class_attr); 569b8a9787eSJay Vosburgh } 570b8a9787eSJay Vosburgh 571b8a9787eSJay Vosburgh EXPORT_SYMBOL(netdev_class_create_file); 572b8a9787eSJay Vosburgh EXPORT_SYMBOL(netdev_class_remove_file); 573b8a9787eSJay Vosburgh 574aaf8cdc3SDaniel Lezcano void netdev_initialize_kobject(struct net_device *net) 575aaf8cdc3SDaniel Lezcano { 576aaf8cdc3SDaniel Lezcano struct device *device = &(net->dev); 577aaf8cdc3SDaniel Lezcano device_initialize(device); 578aaf8cdc3SDaniel Lezcano } 579aaf8cdc3SDaniel Lezcano 5808b41d188SEric W. Biederman int netdev_kobject_init(void) 5811da177e4SLinus Torvalds { 5821da177e4SLinus Torvalds return class_register(&net_class); 5831da177e4SLinus Torvalds } 584