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 413a160ee69SJohannes Berg rtnl_lock(); 4146dd214b5SAndrey Borzenkov if (dev_isalive(dev)) { 4158f1546caSJohannes Berg iw = get_wireless_stats(dev); 4168f1546caSJohannes Berg if (iw) 4171da177e4SLinus Torvalds ret = (*format)(iw, buf); 4186dd214b5SAndrey Borzenkov } 419a160ee69SJohannes Berg rtnl_unlock(); 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds return ret; 4221da177e4SLinus Torvalds } 4231da177e4SLinus Torvalds 4241da177e4SLinus Torvalds /* show function template for wireless fields */ 4251da177e4SLinus Torvalds #define WIRELESS_SHOW(name, field, format_string) \ 4261da177e4SLinus Torvalds static ssize_t format_iw_##name(const struct iw_statistics *iw, char *buf) \ 4271da177e4SLinus Torvalds { \ 4281da177e4SLinus Torvalds return sprintf(buf, format_string, iw->field); \ 4291da177e4SLinus Torvalds } \ 43043cb76d9SGreg Kroah-Hartman static ssize_t show_iw_##name(struct device *d, \ 43143cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 4321da177e4SLinus Torvalds { \ 43343cb76d9SGreg Kroah-Hartman return wireless_show(d, buf, format_iw_##name); \ 4341da177e4SLinus Torvalds } \ 43543cb76d9SGreg Kroah-Hartman static DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL) 4361da177e4SLinus Torvalds 4371da177e4SLinus Torvalds WIRELESS_SHOW(status, status, fmt_hex); 4381da177e4SLinus Torvalds WIRELESS_SHOW(link, qual.qual, fmt_dec); 4391da177e4SLinus Torvalds WIRELESS_SHOW(level, qual.level, fmt_dec); 4401da177e4SLinus Torvalds WIRELESS_SHOW(noise, qual.noise, fmt_dec); 4411da177e4SLinus Torvalds WIRELESS_SHOW(nwid, discard.nwid, fmt_dec); 4421da177e4SLinus Torvalds WIRELESS_SHOW(crypt, discard.code, fmt_dec); 4431da177e4SLinus Torvalds WIRELESS_SHOW(fragment, discard.fragment, fmt_dec); 4441da177e4SLinus Torvalds WIRELESS_SHOW(misc, discard.misc, fmt_dec); 4451da177e4SLinus Torvalds WIRELESS_SHOW(retries, discard.retries, fmt_dec); 4461da177e4SLinus Torvalds WIRELESS_SHOW(beacon, miss.beacon, fmt_dec); 4471da177e4SLinus Torvalds 4481da177e4SLinus Torvalds static struct attribute *wireless_attrs[] = { 44943cb76d9SGreg Kroah-Hartman &dev_attr_status.attr, 45043cb76d9SGreg Kroah-Hartman &dev_attr_link.attr, 45143cb76d9SGreg Kroah-Hartman &dev_attr_level.attr, 45243cb76d9SGreg Kroah-Hartman &dev_attr_noise.attr, 45343cb76d9SGreg Kroah-Hartman &dev_attr_nwid.attr, 45443cb76d9SGreg Kroah-Hartman &dev_attr_crypt.attr, 45543cb76d9SGreg Kroah-Hartman &dev_attr_fragment.attr, 45643cb76d9SGreg Kroah-Hartman &dev_attr_retries.attr, 45743cb76d9SGreg Kroah-Hartman &dev_attr_misc.attr, 45843cb76d9SGreg Kroah-Hartman &dev_attr_beacon.attr, 4591da177e4SLinus Torvalds NULL 4601da177e4SLinus Torvalds }; 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds static struct attribute_group wireless_group = { 4631da177e4SLinus Torvalds .name = "wireless", 4641da177e4SLinus Torvalds .attrs = wireless_attrs, 4651da177e4SLinus Torvalds }; 4661da177e4SLinus Torvalds #endif 4671da177e4SLinus Torvalds 4688b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 4698b41d188SEric W. Biederman 4701da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG 4717eff2e7aSKay Sievers static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) 4721da177e4SLinus Torvalds { 47343cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 4747eff2e7aSKay Sievers int retval; 4751da177e4SLinus Torvalds 47609bb5217SDaniel Lezcano if (!net_eq(dev_net(dev), &init_net)) 47709bb5217SDaniel Lezcano return 0; 47809bb5217SDaniel Lezcano 479312c004dSKay Sievers /* pass interface to uevent. */ 4807eff2e7aSKay Sievers retval = add_uevent_var(env, "INTERFACE=%s", dev->name); 481bf62456eSEric Rannaud if (retval) 482bf62456eSEric Rannaud goto exit; 4831da177e4SLinus Torvalds 484ca2f37dbSJean Tourrilhes /* pass ifindex to uevent. 485ca2f37dbSJean Tourrilhes * ifindex is useful as it won't change (interface name may change) 486ca2f37dbSJean Tourrilhes * and is what RtNetlink uses natively. */ 4877eff2e7aSKay Sievers retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex); 488ca2f37dbSJean Tourrilhes 489bf62456eSEric Rannaud exit: 490bf62456eSEric Rannaud return retval; 4911da177e4SLinus Torvalds } 4921da177e4SLinus Torvalds #endif 4931da177e4SLinus Torvalds 4941da177e4SLinus Torvalds /* 4951da177e4SLinus Torvalds * netdev_release -- destroy and free a dead device. 49643cb76d9SGreg Kroah-Hartman * Called when last reference to device kobject is gone. 4971da177e4SLinus Torvalds */ 49843cb76d9SGreg Kroah-Hartman static void netdev_release(struct device *d) 4991da177e4SLinus Torvalds { 50043cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 5011da177e4SLinus Torvalds 5021da177e4SLinus Torvalds BUG_ON(dev->reg_state != NETREG_RELEASED); 5031da177e4SLinus Torvalds 5040b815a1aSStephen Hemminger kfree(dev->ifalias); 5051da177e4SLinus Torvalds kfree((char *)dev - dev->padded); 5061da177e4SLinus Torvalds } 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds static struct class net_class = { 5091da177e4SLinus Torvalds .name = "net", 51043cb76d9SGreg Kroah-Hartman .dev_release = netdev_release, 5118b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 51243cb76d9SGreg Kroah-Hartman .dev_attrs = net_class_attributes, 5138b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 5141da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG 51543cb76d9SGreg Kroah-Hartman .dev_uevent = netdev_uevent, 5161da177e4SLinus Torvalds #endif 5171da177e4SLinus Torvalds }; 5181da177e4SLinus Torvalds 5199093bbb2SStephen Hemminger /* Delete sysfs entries but hold kobject reference until after all 5209093bbb2SStephen Hemminger * netdev references are gone. 5219093bbb2SStephen Hemminger */ 5228b41d188SEric W. Biederman void netdev_unregister_kobject(struct net_device * net) 5231da177e4SLinus Torvalds { 5249093bbb2SStephen Hemminger struct device *dev = &(net->dev); 5259093bbb2SStephen Hemminger 5269093bbb2SStephen Hemminger kobject_get(&dev->kobj); 5273891845eSEric W. Biederman 5283891845eSEric W. Biederman if (dev_net(net) != &init_net) 5293891845eSEric W. Biederman return; 5303891845eSEric W. Biederman 5319093bbb2SStephen Hemminger device_del(dev); 5321da177e4SLinus Torvalds } 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds /* Create sysfs entries for network device. */ 5358b41d188SEric W. Biederman int netdev_register_kobject(struct net_device *net) 5361da177e4SLinus Torvalds { 53743cb76d9SGreg Kroah-Hartman struct device *dev = &(net->dev); 538a4dbd674SDavid Brownell const struct attribute_group **groups = net->sysfs_groups; 5391da177e4SLinus Torvalds 54043cb76d9SGreg Kroah-Hartman dev->class = &net_class; 54143cb76d9SGreg Kroah-Hartman dev->platform_data = net; 54243cb76d9SGreg Kroah-Hartman dev->groups = groups; 5431da177e4SLinus Torvalds 544a2205472SStephen Hemminger dev_set_name(dev, "%s", net->name); 5451da177e4SLinus Torvalds 5468b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 5470c509a6cSEric W. Biederman /* Allow for a device specific group */ 5480c509a6cSEric W. Biederman if (*groups) 5490c509a6cSEric W. Biederman groups++; 5501da177e4SLinus Torvalds 5510c509a6cSEric W. Biederman *groups++ = &netstat_group; 55222bb1be4SJohannes Berg #ifdef CONFIG_WIRELESS_EXT_SYSFS 5533d23e349SJohannes Berg if (net->ieee80211_ptr) 554fe9925b5SStephen Hemminger *groups++ = &wireless_group; 5553d23e349SJohannes Berg #ifdef CONFIG_WIRELESS_EXT 5563d23e349SJohannes Berg else if (net->wireless_handlers) 5573d23e349SJohannes Berg *groups++ = &wireless_group; 5583d23e349SJohannes Berg #endif 5591da177e4SLinus Torvalds #endif 5608b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 5611da177e4SLinus Torvalds 5623891845eSEric W. Biederman if (dev_net(net) != &init_net) 5633891845eSEric W. Biederman return 0; 5643891845eSEric W. Biederman 56543cb76d9SGreg Kroah-Hartman return device_add(dev); 5661da177e4SLinus Torvalds } 5671da177e4SLinus Torvalds 568b8a9787eSJay Vosburgh int netdev_class_create_file(struct class_attribute *class_attr) 569b8a9787eSJay Vosburgh { 570b8a9787eSJay Vosburgh return class_create_file(&net_class, class_attr); 571b8a9787eSJay Vosburgh } 572b8a9787eSJay Vosburgh 573b8a9787eSJay Vosburgh void netdev_class_remove_file(struct class_attribute *class_attr) 574b8a9787eSJay Vosburgh { 575b8a9787eSJay Vosburgh class_remove_file(&net_class, class_attr); 576b8a9787eSJay Vosburgh } 577b8a9787eSJay Vosburgh 578b8a9787eSJay Vosburgh EXPORT_SYMBOL(netdev_class_create_file); 579b8a9787eSJay Vosburgh EXPORT_SYMBOL(netdev_class_remove_file); 580b8a9787eSJay Vosburgh 581aaf8cdc3SDaniel Lezcano void netdev_initialize_kobject(struct net_device *net) 582aaf8cdc3SDaniel Lezcano { 583aaf8cdc3SDaniel Lezcano struct device *device = &(net->dev); 584aaf8cdc3SDaniel Lezcano device_initialize(device); 585aaf8cdc3SDaniel Lezcano } 586aaf8cdc3SDaniel Lezcano 5878b41d188SEric W. Biederman int netdev_kobject_init(void) 5881da177e4SLinus Torvalds { 5891da177e4SLinus Torvalds return class_register(&net_class); 5901da177e4SLinus Torvalds } 591