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> 165a0e3ad6STejun Heo #include <linux/slab.h> 171da177e4SLinus Torvalds #include <net/sock.h> 181da177e4SLinus Torvalds #include <linux/rtnetlink.h> 191da177e4SLinus Torvalds #include <linux/wireless.h> 208f1546caSJohannes Berg #include <net/wext.h> 211da177e4SLinus Torvalds 22342709efSPavel Emelyanov #include "net-sysfs.h" 23342709efSPavel Emelyanov 248b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 251da177e4SLinus Torvalds static const char fmt_hex[] = "%#x\n"; 26d1102b59SDavid S. Miller static const char fmt_long_hex[] = "%#lx\n"; 271da177e4SLinus Torvalds static const char fmt_dec[] = "%d\n"; 281da177e4SLinus Torvalds static const char fmt_ulong[] = "%lu\n"; 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds static inline int dev_isalive(const struct net_device *dev) 311da177e4SLinus Torvalds { 32fe9925b5SStephen Hemminger return dev->reg_state <= NETREG_REGISTERED; 331da177e4SLinus Torvalds } 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds /* use same locking rules as GIF* ioctl's */ 3643cb76d9SGreg Kroah-Hartman static ssize_t netdev_show(const struct device *dev, 3743cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 381da177e4SLinus Torvalds ssize_t (*format)(const struct net_device *, char *)) 391da177e4SLinus Torvalds { 4043cb76d9SGreg Kroah-Hartman struct net_device *net = to_net_dev(dev); 411da177e4SLinus Torvalds ssize_t ret = -EINVAL; 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds read_lock(&dev_base_lock); 441da177e4SLinus Torvalds if (dev_isalive(net)) 451da177e4SLinus Torvalds ret = (*format)(net, buf); 461da177e4SLinus Torvalds read_unlock(&dev_base_lock); 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds return ret; 491da177e4SLinus Torvalds } 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds /* generate a show function for simple field */ 521da177e4SLinus Torvalds #define NETDEVICE_SHOW(field, format_string) \ 531da177e4SLinus Torvalds static ssize_t format_##field(const struct net_device *net, char *buf) \ 541da177e4SLinus Torvalds { \ 551da177e4SLinus Torvalds return sprintf(buf, format_string, net->field); \ 561da177e4SLinus Torvalds } \ 5743cb76d9SGreg Kroah-Hartman static ssize_t show_##field(struct device *dev, \ 5843cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 591da177e4SLinus Torvalds { \ 6043cb76d9SGreg Kroah-Hartman return netdev_show(dev, attr, buf, format_##field); \ 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds /* use same locking and permission rules as SIF* ioctl's */ 6543cb76d9SGreg Kroah-Hartman static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, 661da177e4SLinus Torvalds const char *buf, size_t len, 671da177e4SLinus Torvalds int (*set)(struct net_device *, unsigned long)) 681da177e4SLinus Torvalds { 691da177e4SLinus Torvalds struct net_device *net = to_net_dev(dev); 701da177e4SLinus Torvalds char *endp; 711da177e4SLinus Torvalds unsigned long new; 721da177e4SLinus Torvalds int ret = -EINVAL; 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) 751da177e4SLinus Torvalds return -EPERM; 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds new = simple_strtoul(buf, &endp, 0); 781da177e4SLinus Torvalds if (endp == buf) 791da177e4SLinus Torvalds goto err; 801da177e4SLinus Torvalds 815a5990d3SStephen Hemminger if (!rtnl_trylock()) 82336ca57cSEric W. Biederman return restart_syscall(); 835a5990d3SStephen Hemminger 841da177e4SLinus Torvalds if (dev_isalive(net)) { 851da177e4SLinus Torvalds if ((ret = (*set)(net, new)) == 0) 861da177e4SLinus Torvalds ret = len; 871da177e4SLinus Torvalds } 881da177e4SLinus Torvalds rtnl_unlock(); 891da177e4SLinus Torvalds err: 901da177e4SLinus Torvalds return ret; 911da177e4SLinus Torvalds } 921da177e4SLinus Torvalds 939d29672cSDavid Woodhouse NETDEVICE_SHOW(dev_id, fmt_hex); 94fd586bacSKay Sievers NETDEVICE_SHOW(addr_len, fmt_dec); 95fd586bacSKay Sievers NETDEVICE_SHOW(iflink, fmt_dec); 96fd586bacSKay Sievers NETDEVICE_SHOW(ifindex, fmt_dec); 97fd586bacSKay Sievers NETDEVICE_SHOW(features, fmt_long_hex); 98fd586bacSKay Sievers NETDEVICE_SHOW(type, fmt_dec); 99b00055aaSStefan Rompf NETDEVICE_SHOW(link_mode, fmt_dec); 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds /* use same locking rules as GIFHWADDR ioctl's */ 10243cb76d9SGreg Kroah-Hartman static ssize_t show_address(struct device *dev, struct device_attribute *attr, 10343cb76d9SGreg Kroah-Hartman char *buf) 1041da177e4SLinus Torvalds { 1051da177e4SLinus Torvalds struct net_device *net = to_net_dev(dev); 1061da177e4SLinus Torvalds ssize_t ret = -EINVAL; 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds read_lock(&dev_base_lock); 1091da177e4SLinus Torvalds if (dev_isalive(net)) 1107ffc49a6SMichael Chan ret = sysfs_format_mac(buf, net->dev_addr, net->addr_len); 1111da177e4SLinus Torvalds read_unlock(&dev_base_lock); 1121da177e4SLinus Torvalds return ret; 1131da177e4SLinus Torvalds } 1141da177e4SLinus Torvalds 11543cb76d9SGreg Kroah-Hartman static ssize_t show_broadcast(struct device *dev, 11643cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1171da177e4SLinus Torvalds { 1181da177e4SLinus Torvalds struct net_device *net = to_net_dev(dev); 1191da177e4SLinus Torvalds if (dev_isalive(net)) 1207ffc49a6SMichael Chan return sysfs_format_mac(buf, net->broadcast, net->addr_len); 1211da177e4SLinus Torvalds return -EINVAL; 1221da177e4SLinus Torvalds } 1231da177e4SLinus Torvalds 12443cb76d9SGreg Kroah-Hartman static ssize_t show_carrier(struct device *dev, 12543cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1261da177e4SLinus Torvalds { 1271da177e4SLinus Torvalds struct net_device *netdev = to_net_dev(dev); 1281da177e4SLinus Torvalds if (netif_running(netdev)) { 1291da177e4SLinus Torvalds return sprintf(buf, fmt_dec, !!netif_carrier_ok(netdev)); 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds return -EINVAL; 1321da177e4SLinus Torvalds } 1331da177e4SLinus Torvalds 134d519e17eSAndy Gospodarek static ssize_t show_speed(struct device *dev, 135d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 136d519e17eSAndy Gospodarek { 137d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 138d519e17eSAndy Gospodarek int ret = -EINVAL; 139d519e17eSAndy Gospodarek 140d519e17eSAndy Gospodarek if (!rtnl_trylock()) 141d519e17eSAndy Gospodarek return restart_syscall(); 142d519e17eSAndy Gospodarek 143ac5e3af9SEric Dumazet if (netif_running(netdev) && 144ac5e3af9SEric Dumazet netdev->ethtool_ops && 145ac5e3af9SEric Dumazet netdev->ethtool_ops->get_settings) { 146d519e17eSAndy Gospodarek struct ethtool_cmd cmd = { ETHTOOL_GSET }; 147d519e17eSAndy Gospodarek 148d519e17eSAndy Gospodarek if (!netdev->ethtool_ops->get_settings(netdev, &cmd)) 149d519e17eSAndy Gospodarek ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd)); 150d519e17eSAndy Gospodarek } 151d519e17eSAndy Gospodarek rtnl_unlock(); 152d519e17eSAndy Gospodarek return ret; 153d519e17eSAndy Gospodarek } 154d519e17eSAndy Gospodarek 155d519e17eSAndy Gospodarek static ssize_t show_duplex(struct device *dev, 156d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 157d519e17eSAndy Gospodarek { 158d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 159d519e17eSAndy Gospodarek int ret = -EINVAL; 160d519e17eSAndy Gospodarek 161d519e17eSAndy Gospodarek if (!rtnl_trylock()) 162d519e17eSAndy Gospodarek return restart_syscall(); 163d519e17eSAndy Gospodarek 164ac5e3af9SEric Dumazet if (netif_running(netdev) && 165ac5e3af9SEric Dumazet netdev->ethtool_ops && 166ac5e3af9SEric Dumazet netdev->ethtool_ops->get_settings) { 167d519e17eSAndy Gospodarek struct ethtool_cmd cmd = { ETHTOOL_GSET }; 168d519e17eSAndy Gospodarek 169d519e17eSAndy Gospodarek if (!netdev->ethtool_ops->get_settings(netdev, &cmd)) 170d519e17eSAndy Gospodarek ret = sprintf(buf, "%s\n", cmd.duplex ? "full" : "half"); 171d519e17eSAndy Gospodarek } 172d519e17eSAndy Gospodarek rtnl_unlock(); 173d519e17eSAndy Gospodarek return ret; 174d519e17eSAndy Gospodarek } 175d519e17eSAndy Gospodarek 17643cb76d9SGreg Kroah-Hartman static ssize_t show_dormant(struct device *dev, 17743cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 178b00055aaSStefan Rompf { 179b00055aaSStefan Rompf struct net_device *netdev = to_net_dev(dev); 180b00055aaSStefan Rompf 181b00055aaSStefan Rompf if (netif_running(netdev)) 182b00055aaSStefan Rompf return sprintf(buf, fmt_dec, !!netif_dormant(netdev)); 183b00055aaSStefan Rompf 184b00055aaSStefan Rompf return -EINVAL; 185b00055aaSStefan Rompf } 186b00055aaSStefan Rompf 18736cbd3dcSJan Engelhardt static const char *const operstates[] = { 188b00055aaSStefan Rompf "unknown", 189b00055aaSStefan Rompf "notpresent", /* currently unused */ 190b00055aaSStefan Rompf "down", 191b00055aaSStefan Rompf "lowerlayerdown", 192b00055aaSStefan Rompf "testing", /* currently unused */ 193b00055aaSStefan Rompf "dormant", 194b00055aaSStefan Rompf "up" 195b00055aaSStefan Rompf }; 196b00055aaSStefan Rompf 19743cb76d9SGreg Kroah-Hartman static ssize_t show_operstate(struct device *dev, 19843cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 199b00055aaSStefan Rompf { 200b00055aaSStefan Rompf const struct net_device *netdev = to_net_dev(dev); 201b00055aaSStefan Rompf unsigned char operstate; 202b00055aaSStefan Rompf 203b00055aaSStefan Rompf read_lock(&dev_base_lock); 204b00055aaSStefan Rompf operstate = netdev->operstate; 205b00055aaSStefan Rompf if (!netif_running(netdev)) 206b00055aaSStefan Rompf operstate = IF_OPER_DOWN; 207b00055aaSStefan Rompf read_unlock(&dev_base_lock); 208b00055aaSStefan Rompf 209e3a5cd9eSAdrian Bunk if (operstate >= ARRAY_SIZE(operstates)) 210b00055aaSStefan Rompf return -EINVAL; /* should not happen */ 211b00055aaSStefan Rompf 212b00055aaSStefan Rompf return sprintf(buf, "%s\n", operstates[operstate]); 213b00055aaSStefan Rompf } 214b00055aaSStefan Rompf 2151da177e4SLinus Torvalds /* read-write attributes */ 2161da177e4SLinus Torvalds NETDEVICE_SHOW(mtu, fmt_dec); 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds static int change_mtu(struct net_device *net, unsigned long new_mtu) 2191da177e4SLinus Torvalds { 2201da177e4SLinus Torvalds return dev_set_mtu(net, (int) new_mtu); 2211da177e4SLinus Torvalds } 2221da177e4SLinus Torvalds 22343cb76d9SGreg Kroah-Hartman static ssize_t store_mtu(struct device *dev, struct device_attribute *attr, 22443cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 2251da177e4SLinus Torvalds { 22643cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_mtu); 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds NETDEVICE_SHOW(flags, fmt_hex); 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds static int change_flags(struct net_device *net, unsigned long new_flags) 2321da177e4SLinus Torvalds { 2331da177e4SLinus Torvalds return dev_change_flags(net, (unsigned) new_flags); 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds 23643cb76d9SGreg Kroah-Hartman static ssize_t store_flags(struct device *dev, struct device_attribute *attr, 23743cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 2381da177e4SLinus Torvalds { 23943cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_flags); 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds NETDEVICE_SHOW(tx_queue_len, fmt_ulong); 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds static int change_tx_queue_len(struct net_device *net, unsigned long new_len) 2451da177e4SLinus Torvalds { 2461da177e4SLinus Torvalds net->tx_queue_len = new_len; 2471da177e4SLinus Torvalds return 0; 2481da177e4SLinus Torvalds } 2491da177e4SLinus Torvalds 25043cb76d9SGreg Kroah-Hartman static ssize_t store_tx_queue_len(struct device *dev, 25143cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 25243cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 2531da177e4SLinus Torvalds { 25443cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_tx_queue_len); 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds 2570b815a1aSStephen Hemminger static ssize_t store_ifalias(struct device *dev, struct device_attribute *attr, 2580b815a1aSStephen Hemminger const char *buf, size_t len) 2590b815a1aSStephen Hemminger { 2600b815a1aSStephen Hemminger struct net_device *netdev = to_net_dev(dev); 2610b815a1aSStephen Hemminger size_t count = len; 2620b815a1aSStephen Hemminger ssize_t ret; 2630b815a1aSStephen Hemminger 2640b815a1aSStephen Hemminger if (!capable(CAP_NET_ADMIN)) 2650b815a1aSStephen Hemminger return -EPERM; 2660b815a1aSStephen Hemminger 2670b815a1aSStephen Hemminger /* ignore trailing newline */ 2680b815a1aSStephen Hemminger if (len > 0 && buf[len - 1] == '\n') 2690b815a1aSStephen Hemminger --count; 2700b815a1aSStephen Hemminger 271336ca57cSEric W. Biederman if (!rtnl_trylock()) 272336ca57cSEric W. Biederman return restart_syscall(); 2730b815a1aSStephen Hemminger ret = dev_set_alias(netdev, buf, count); 2740b815a1aSStephen Hemminger rtnl_unlock(); 2750b815a1aSStephen Hemminger 2760b815a1aSStephen Hemminger return ret < 0 ? ret : len; 2770b815a1aSStephen Hemminger } 2780b815a1aSStephen Hemminger 2790b815a1aSStephen Hemminger static ssize_t show_ifalias(struct device *dev, 2800b815a1aSStephen Hemminger struct device_attribute *attr, char *buf) 2810b815a1aSStephen Hemminger { 2820b815a1aSStephen Hemminger const struct net_device *netdev = to_net_dev(dev); 2830b815a1aSStephen Hemminger ssize_t ret = 0; 2840b815a1aSStephen Hemminger 285336ca57cSEric W. Biederman if (!rtnl_trylock()) 286336ca57cSEric W. Biederman return restart_syscall(); 2870b815a1aSStephen Hemminger if (netdev->ifalias) 2880b815a1aSStephen Hemminger ret = sprintf(buf, "%s\n", netdev->ifalias); 2890b815a1aSStephen Hemminger rtnl_unlock(); 2900b815a1aSStephen Hemminger return ret; 2910b815a1aSStephen Hemminger } 2920b815a1aSStephen Hemminger 29343cb76d9SGreg Kroah-Hartman static struct device_attribute net_class_attributes[] = { 294fd586bacSKay Sievers __ATTR(addr_len, S_IRUGO, show_addr_len, NULL), 2959d29672cSDavid Woodhouse __ATTR(dev_id, S_IRUGO, show_dev_id, NULL), 2960b815a1aSStephen Hemminger __ATTR(ifalias, S_IRUGO | S_IWUSR, show_ifalias, store_ifalias), 297fd586bacSKay Sievers __ATTR(iflink, S_IRUGO, show_iflink, NULL), 298fd586bacSKay Sievers __ATTR(ifindex, S_IRUGO, show_ifindex, NULL), 299fd586bacSKay Sievers __ATTR(features, S_IRUGO, show_features, NULL), 300fd586bacSKay Sievers __ATTR(type, S_IRUGO, show_type, NULL), 301b00055aaSStefan Rompf __ATTR(link_mode, S_IRUGO, show_link_mode, NULL), 302fd586bacSKay Sievers __ATTR(address, S_IRUGO, show_address, NULL), 303fd586bacSKay Sievers __ATTR(broadcast, S_IRUGO, show_broadcast, NULL), 304fd586bacSKay Sievers __ATTR(carrier, S_IRUGO, show_carrier, NULL), 305d519e17eSAndy Gospodarek __ATTR(speed, S_IRUGO, show_speed, NULL), 306d519e17eSAndy Gospodarek __ATTR(duplex, S_IRUGO, show_duplex, NULL), 307b00055aaSStefan Rompf __ATTR(dormant, S_IRUGO, show_dormant, NULL), 308b00055aaSStefan Rompf __ATTR(operstate, S_IRUGO, show_operstate, NULL), 309fd586bacSKay Sievers __ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu), 310fd586bacSKay Sievers __ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags), 311fd586bacSKay Sievers __ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len, 312fd586bacSKay Sievers store_tx_queue_len), 313fd586bacSKay Sievers {} 3141da177e4SLinus Torvalds }; 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds /* Show a given an attribute in the statistics group */ 31743cb76d9SGreg Kroah-Hartman static ssize_t netstat_show(const struct device *d, 31843cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 3191da177e4SLinus Torvalds unsigned long offset) 3201da177e4SLinus Torvalds { 32143cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 3221da177e4SLinus Torvalds ssize_t ret = -EINVAL; 3231da177e4SLinus Torvalds 324df1b86c5SPavel Emelyanov WARN_ON(offset > sizeof(struct net_device_stats) || 325df1b86c5SPavel Emelyanov offset % sizeof(unsigned long) != 0); 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds read_lock(&dev_base_lock); 32896e74088SPavel Emelyanov if (dev_isalive(dev)) { 329eeda3fd6SStephen Hemminger const struct net_device_stats *stats = dev_get_stats(dev); 3301da177e4SLinus Torvalds ret = sprintf(buf, fmt_ulong, 3311da177e4SLinus Torvalds *(unsigned long *)(((u8 *) stats) + offset)); 33296e74088SPavel Emelyanov } 3331da177e4SLinus Torvalds read_unlock(&dev_base_lock); 3341da177e4SLinus Torvalds return ret; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds /* generate a read-only statistics attribute */ 3381da177e4SLinus Torvalds #define NETSTAT_ENTRY(name) \ 33943cb76d9SGreg Kroah-Hartman static ssize_t show_##name(struct device *d, \ 34043cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 3411da177e4SLinus Torvalds { \ 34243cb76d9SGreg Kroah-Hartman return netstat_show(d, attr, buf, \ 3431da177e4SLinus Torvalds offsetof(struct net_device_stats, name)); \ 3441da177e4SLinus Torvalds } \ 34543cb76d9SGreg Kroah-Hartman static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds NETSTAT_ENTRY(rx_packets); 3481da177e4SLinus Torvalds NETSTAT_ENTRY(tx_packets); 3491da177e4SLinus Torvalds NETSTAT_ENTRY(rx_bytes); 3501da177e4SLinus Torvalds NETSTAT_ENTRY(tx_bytes); 3511da177e4SLinus Torvalds NETSTAT_ENTRY(rx_errors); 3521da177e4SLinus Torvalds NETSTAT_ENTRY(tx_errors); 3531da177e4SLinus Torvalds NETSTAT_ENTRY(rx_dropped); 3541da177e4SLinus Torvalds NETSTAT_ENTRY(tx_dropped); 3551da177e4SLinus Torvalds NETSTAT_ENTRY(multicast); 3561da177e4SLinus Torvalds NETSTAT_ENTRY(collisions); 3571da177e4SLinus Torvalds NETSTAT_ENTRY(rx_length_errors); 3581da177e4SLinus Torvalds NETSTAT_ENTRY(rx_over_errors); 3591da177e4SLinus Torvalds NETSTAT_ENTRY(rx_crc_errors); 3601da177e4SLinus Torvalds NETSTAT_ENTRY(rx_frame_errors); 3611da177e4SLinus Torvalds NETSTAT_ENTRY(rx_fifo_errors); 3621da177e4SLinus Torvalds NETSTAT_ENTRY(rx_missed_errors); 3631da177e4SLinus Torvalds NETSTAT_ENTRY(tx_aborted_errors); 3641da177e4SLinus Torvalds NETSTAT_ENTRY(tx_carrier_errors); 3651da177e4SLinus Torvalds NETSTAT_ENTRY(tx_fifo_errors); 3661da177e4SLinus Torvalds NETSTAT_ENTRY(tx_heartbeat_errors); 3671da177e4SLinus Torvalds NETSTAT_ENTRY(tx_window_errors); 3681da177e4SLinus Torvalds NETSTAT_ENTRY(rx_compressed); 3691da177e4SLinus Torvalds NETSTAT_ENTRY(tx_compressed); 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds static struct attribute *netstat_attrs[] = { 37243cb76d9SGreg Kroah-Hartman &dev_attr_rx_packets.attr, 37343cb76d9SGreg Kroah-Hartman &dev_attr_tx_packets.attr, 37443cb76d9SGreg Kroah-Hartman &dev_attr_rx_bytes.attr, 37543cb76d9SGreg Kroah-Hartman &dev_attr_tx_bytes.attr, 37643cb76d9SGreg Kroah-Hartman &dev_attr_rx_errors.attr, 37743cb76d9SGreg Kroah-Hartman &dev_attr_tx_errors.attr, 37843cb76d9SGreg Kroah-Hartman &dev_attr_rx_dropped.attr, 37943cb76d9SGreg Kroah-Hartman &dev_attr_tx_dropped.attr, 38043cb76d9SGreg Kroah-Hartman &dev_attr_multicast.attr, 38143cb76d9SGreg Kroah-Hartman &dev_attr_collisions.attr, 38243cb76d9SGreg Kroah-Hartman &dev_attr_rx_length_errors.attr, 38343cb76d9SGreg Kroah-Hartman &dev_attr_rx_over_errors.attr, 38443cb76d9SGreg Kroah-Hartman &dev_attr_rx_crc_errors.attr, 38543cb76d9SGreg Kroah-Hartman &dev_attr_rx_frame_errors.attr, 38643cb76d9SGreg Kroah-Hartman &dev_attr_rx_fifo_errors.attr, 38743cb76d9SGreg Kroah-Hartman &dev_attr_rx_missed_errors.attr, 38843cb76d9SGreg Kroah-Hartman &dev_attr_tx_aborted_errors.attr, 38943cb76d9SGreg Kroah-Hartman &dev_attr_tx_carrier_errors.attr, 39043cb76d9SGreg Kroah-Hartman &dev_attr_tx_fifo_errors.attr, 39143cb76d9SGreg Kroah-Hartman &dev_attr_tx_heartbeat_errors.attr, 39243cb76d9SGreg Kroah-Hartman &dev_attr_tx_window_errors.attr, 39343cb76d9SGreg Kroah-Hartman &dev_attr_rx_compressed.attr, 39443cb76d9SGreg Kroah-Hartman &dev_attr_tx_compressed.attr, 3951da177e4SLinus Torvalds NULL 3961da177e4SLinus Torvalds }; 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds static struct attribute_group netstat_group = { 4001da177e4SLinus Torvalds .name = "statistics", 4011da177e4SLinus Torvalds .attrs = netstat_attrs, 4021da177e4SLinus Torvalds }; 4031da177e4SLinus Torvalds 40422bb1be4SJohannes Berg #ifdef CONFIG_WIRELESS_EXT_SYSFS 4051da177e4SLinus Torvalds /* helper function that does all the locking etc for wireless stats */ 40643cb76d9SGreg Kroah-Hartman static ssize_t wireless_show(struct device *d, char *buf, 4071da177e4SLinus Torvalds ssize_t (*format)(const struct iw_statistics *, 4081da177e4SLinus Torvalds char *)) 4091da177e4SLinus Torvalds { 41043cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 4118f1546caSJohannes Berg const struct iw_statistics *iw; 4121da177e4SLinus Torvalds ssize_t ret = -EINVAL; 4131da177e4SLinus Torvalds 414b8afe641SEric W. Biederman if (!rtnl_trylock()) 415b8afe641SEric W. Biederman return restart_syscall(); 4166dd214b5SAndrey Borzenkov if (dev_isalive(dev)) { 4178f1546caSJohannes Berg iw = get_wireless_stats(dev); 4188f1546caSJohannes Berg if (iw) 4191da177e4SLinus Torvalds ret = (*format)(iw, buf); 4206dd214b5SAndrey Borzenkov } 421a160ee69SJohannes Berg rtnl_unlock(); 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds return ret; 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds /* show function template for wireless fields */ 4271da177e4SLinus Torvalds #define WIRELESS_SHOW(name, field, format_string) \ 4281da177e4SLinus Torvalds static ssize_t format_iw_##name(const struct iw_statistics *iw, char *buf) \ 4291da177e4SLinus Torvalds { \ 4301da177e4SLinus Torvalds return sprintf(buf, format_string, iw->field); \ 4311da177e4SLinus Torvalds } \ 43243cb76d9SGreg Kroah-Hartman static ssize_t show_iw_##name(struct device *d, \ 43343cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 4341da177e4SLinus Torvalds { \ 43543cb76d9SGreg Kroah-Hartman return wireless_show(d, buf, format_iw_##name); \ 4361da177e4SLinus Torvalds } \ 43743cb76d9SGreg Kroah-Hartman static DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL) 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds WIRELESS_SHOW(status, status, fmt_hex); 4401da177e4SLinus Torvalds WIRELESS_SHOW(link, qual.qual, fmt_dec); 4411da177e4SLinus Torvalds WIRELESS_SHOW(level, qual.level, fmt_dec); 4421da177e4SLinus Torvalds WIRELESS_SHOW(noise, qual.noise, fmt_dec); 4431da177e4SLinus Torvalds WIRELESS_SHOW(nwid, discard.nwid, fmt_dec); 4441da177e4SLinus Torvalds WIRELESS_SHOW(crypt, discard.code, fmt_dec); 4451da177e4SLinus Torvalds WIRELESS_SHOW(fragment, discard.fragment, fmt_dec); 4461da177e4SLinus Torvalds WIRELESS_SHOW(misc, discard.misc, fmt_dec); 4471da177e4SLinus Torvalds WIRELESS_SHOW(retries, discard.retries, fmt_dec); 4481da177e4SLinus Torvalds WIRELESS_SHOW(beacon, miss.beacon, fmt_dec); 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds static struct attribute *wireless_attrs[] = { 45143cb76d9SGreg Kroah-Hartman &dev_attr_status.attr, 45243cb76d9SGreg Kroah-Hartman &dev_attr_link.attr, 45343cb76d9SGreg Kroah-Hartman &dev_attr_level.attr, 45443cb76d9SGreg Kroah-Hartman &dev_attr_noise.attr, 45543cb76d9SGreg Kroah-Hartman &dev_attr_nwid.attr, 45643cb76d9SGreg Kroah-Hartman &dev_attr_crypt.attr, 45743cb76d9SGreg Kroah-Hartman &dev_attr_fragment.attr, 45843cb76d9SGreg Kroah-Hartman &dev_attr_retries.attr, 45943cb76d9SGreg Kroah-Hartman &dev_attr_misc.attr, 46043cb76d9SGreg Kroah-Hartman &dev_attr_beacon.attr, 4611da177e4SLinus Torvalds NULL 4621da177e4SLinus Torvalds }; 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds static struct attribute_group wireless_group = { 4651da177e4SLinus Torvalds .name = "wireless", 4661da177e4SLinus Torvalds .attrs = wireless_attrs, 4671da177e4SLinus Torvalds }; 4681da177e4SLinus Torvalds #endif 4691da177e4SLinus Torvalds 4708b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 4718b41d188SEric W. Biederman 4721da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG 4737eff2e7aSKay Sievers static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) 4741da177e4SLinus Torvalds { 47543cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 4767eff2e7aSKay Sievers int retval; 4771da177e4SLinus Torvalds 47809bb5217SDaniel Lezcano if (!net_eq(dev_net(dev), &init_net)) 47909bb5217SDaniel Lezcano return 0; 48009bb5217SDaniel Lezcano 481312c004dSKay Sievers /* pass interface to uevent. */ 4827eff2e7aSKay Sievers retval = add_uevent_var(env, "INTERFACE=%s", dev->name); 483bf62456eSEric Rannaud if (retval) 484bf62456eSEric Rannaud goto exit; 4851da177e4SLinus Torvalds 486ca2f37dbSJean Tourrilhes /* pass ifindex to uevent. 487ca2f37dbSJean Tourrilhes * ifindex is useful as it won't change (interface name may change) 488ca2f37dbSJean Tourrilhes * and is what RtNetlink uses natively. */ 4897eff2e7aSKay Sievers retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex); 490ca2f37dbSJean Tourrilhes 491bf62456eSEric Rannaud exit: 492bf62456eSEric Rannaud return retval; 4931da177e4SLinus Torvalds } 4941da177e4SLinus Torvalds #endif 4951da177e4SLinus Torvalds 4961da177e4SLinus Torvalds /* 4971da177e4SLinus Torvalds * netdev_release -- destroy and free a dead device. 49843cb76d9SGreg Kroah-Hartman * Called when last reference to device kobject is gone. 4991da177e4SLinus Torvalds */ 50043cb76d9SGreg Kroah-Hartman static void netdev_release(struct device *d) 5011da177e4SLinus Torvalds { 50243cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds BUG_ON(dev->reg_state != NETREG_RELEASED); 5051da177e4SLinus Torvalds 5060b815a1aSStephen Hemminger kfree(dev->ifalias); 5071da177e4SLinus Torvalds kfree((char *)dev - dev->padded); 5081da177e4SLinus Torvalds } 5091da177e4SLinus Torvalds 5101da177e4SLinus Torvalds static struct class net_class = { 5111da177e4SLinus Torvalds .name = "net", 51243cb76d9SGreg Kroah-Hartman .dev_release = netdev_release, 5138b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 51443cb76d9SGreg Kroah-Hartman .dev_attrs = net_class_attributes, 5158b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 5161da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG 51743cb76d9SGreg Kroah-Hartman .dev_uevent = netdev_uevent, 5181da177e4SLinus Torvalds #endif 5191da177e4SLinus Torvalds }; 5201da177e4SLinus Torvalds 5219093bbb2SStephen Hemminger /* Delete sysfs entries but hold kobject reference until after all 5229093bbb2SStephen Hemminger * netdev references are gone. 5239093bbb2SStephen Hemminger */ 5248b41d188SEric W. Biederman void netdev_unregister_kobject(struct net_device * net) 5251da177e4SLinus Torvalds { 5269093bbb2SStephen Hemminger struct device *dev = &(net->dev); 5279093bbb2SStephen Hemminger 5289093bbb2SStephen Hemminger kobject_get(&dev->kobj); 5293891845eSEric W. Biederman 53009ad9bc7SOctavian Purdila if (!net_eq(dev_net(net), &init_net)) 5313891845eSEric W. Biederman return; 5323891845eSEric W. Biederman 5339093bbb2SStephen Hemminger device_del(dev); 5341da177e4SLinus Torvalds } 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds /* Create sysfs entries for network device. */ 5378b41d188SEric W. Biederman int netdev_register_kobject(struct net_device *net) 5381da177e4SLinus Torvalds { 53943cb76d9SGreg Kroah-Hartman struct device *dev = &(net->dev); 540a4dbd674SDavid Brownell const struct attribute_group **groups = net->sysfs_groups; 5411da177e4SLinus Torvalds 54243cb76d9SGreg Kroah-Hartman dev->class = &net_class; 54343cb76d9SGreg Kroah-Hartman dev->platform_data = net; 54443cb76d9SGreg Kroah-Hartman dev->groups = groups; 5451da177e4SLinus Torvalds 546a2205472SStephen Hemminger dev_set_name(dev, "%s", net->name); 5471da177e4SLinus Torvalds 5488b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 5490c509a6cSEric W. Biederman /* Allow for a device specific group */ 5500c509a6cSEric W. Biederman if (*groups) 5510c509a6cSEric W. Biederman groups++; 5521da177e4SLinus Torvalds 5530c509a6cSEric W. Biederman *groups++ = &netstat_group; 55422bb1be4SJohannes Berg #ifdef CONFIG_WIRELESS_EXT_SYSFS 5553d23e349SJohannes Berg if (net->ieee80211_ptr) 556fe9925b5SStephen Hemminger *groups++ = &wireless_group; 5573d23e349SJohannes Berg #ifdef CONFIG_WIRELESS_EXT 5583d23e349SJohannes Berg else if (net->wireless_handlers) 5593d23e349SJohannes Berg *groups++ = &wireless_group; 5603d23e349SJohannes Berg #endif 5611da177e4SLinus Torvalds #endif 5628b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 5631da177e4SLinus Torvalds 56409ad9bc7SOctavian Purdila if (!net_eq(dev_net(net), &init_net)) 5653891845eSEric W. Biederman return 0; 5663891845eSEric W. Biederman 56743cb76d9SGreg Kroah-Hartman return device_add(dev); 5681da177e4SLinus Torvalds } 5691da177e4SLinus Torvalds 570b8a9787eSJay Vosburgh int netdev_class_create_file(struct class_attribute *class_attr) 571b8a9787eSJay Vosburgh { 572b8a9787eSJay Vosburgh return class_create_file(&net_class, class_attr); 573b8a9787eSJay Vosburgh } 574b8a9787eSJay Vosburgh 575b8a9787eSJay Vosburgh void netdev_class_remove_file(struct class_attribute *class_attr) 576b8a9787eSJay Vosburgh { 577b8a9787eSJay Vosburgh class_remove_file(&net_class, class_attr); 578b8a9787eSJay Vosburgh } 579b8a9787eSJay Vosburgh 580b8a9787eSJay Vosburgh EXPORT_SYMBOL(netdev_class_create_file); 581b8a9787eSJay Vosburgh EXPORT_SYMBOL(netdev_class_remove_file); 582b8a9787eSJay Vosburgh 583aaf8cdc3SDaniel Lezcano void netdev_initialize_kobject(struct net_device *net) 584aaf8cdc3SDaniel Lezcano { 585aaf8cdc3SDaniel Lezcano struct device *device = &(net->dev); 586aaf8cdc3SDaniel Lezcano device_initialize(device); 587aaf8cdc3SDaniel Lezcano } 588aaf8cdc3SDaniel Lezcano 5898b41d188SEric W. Biederman int netdev_kobject_init(void) 5901da177e4SLinus Torvalds { 5911da177e4SLinus Torvalds return class_register(&net_class); 5921da177e4SLinus Torvalds } 593