Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at b75cdf388ecdcd5ab5e66178f19c39a4c94dea26 479 lines 13 kB view raw
1/* 2 * net-sysfs.c - network device class and attributes 3 * 4 * Copyright (c) 2003 Stephen Hemminger <shemminger@osdl.org> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12#include <linux/config.h> 13#include <linux/kernel.h> 14#include <linux/netdevice.h> 15#include <linux/if_arp.h> 16#include <net/sock.h> 17#include <linux/rtnetlink.h> 18#include <linux/wireless.h> 19 20#define to_class_dev(obj) container_of(obj,struct class_device,kobj) 21#define to_net_dev(class) container_of(class, struct net_device, class_dev) 22 23static const char fmt_hex[] = "%#x\n"; 24static const char fmt_long_hex[] = "%#lx\n"; 25static const char fmt_dec[] = "%d\n"; 26static const char fmt_ulong[] = "%lu\n"; 27 28static inline int dev_isalive(const struct net_device *dev) 29{ 30 return dev->reg_state == NETREG_REGISTERED; 31} 32 33/* use same locking rules as GIF* ioctl's */ 34static ssize_t netdev_show(const struct class_device *cd, char *buf, 35 ssize_t (*format)(const struct net_device *, char *)) 36{ 37 struct net_device *net = to_net_dev(cd); 38 ssize_t ret = -EINVAL; 39 40 read_lock(&dev_base_lock); 41 if (dev_isalive(net)) 42 ret = (*format)(net, buf); 43 read_unlock(&dev_base_lock); 44 45 return ret; 46} 47 48/* generate a show function for simple field */ 49#define NETDEVICE_SHOW(field, format_string) \ 50static ssize_t format_##field(const struct net_device *net, char *buf) \ 51{ \ 52 return sprintf(buf, format_string, net->field); \ 53} \ 54static ssize_t show_##field(struct class_device *cd, char *buf) \ 55{ \ 56 return netdev_show(cd, buf, format_##field); \ 57} 58 59 60/* use same locking and permission rules as SIF* ioctl's */ 61static ssize_t netdev_store(struct class_device *dev, 62 const char *buf, size_t len, 63 int (*set)(struct net_device *, unsigned long)) 64{ 65 struct net_device *net = to_net_dev(dev); 66 char *endp; 67 unsigned long new; 68 int ret = -EINVAL; 69 70 if (!capable(CAP_NET_ADMIN)) 71 return -EPERM; 72 73 new = simple_strtoul(buf, &endp, 0); 74 if (endp == buf) 75 goto err; 76 77 rtnl_lock(); 78 if (dev_isalive(net)) { 79 if ((ret = (*set)(net, new)) == 0) 80 ret = len; 81 } 82 rtnl_unlock(); 83 err: 84 return ret; 85} 86 87/* generate a read-only network device class attribute */ 88#define NETDEVICE_ATTR(field, format_string) \ 89NETDEVICE_SHOW(field, format_string) \ 90static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL) \ 91 92NETDEVICE_ATTR(addr_len, fmt_dec); 93NETDEVICE_ATTR(iflink, fmt_dec); 94NETDEVICE_ATTR(ifindex, fmt_dec); 95NETDEVICE_ATTR(features, fmt_long_hex); 96NETDEVICE_ATTR(type, fmt_dec); 97 98/* use same locking rules as GIFHWADDR ioctl's */ 99static ssize_t format_addr(char *buf, const unsigned char *addr, int len) 100{ 101 int i; 102 char *cp = buf; 103 104 for (i = 0; i < len; i++) 105 cp += sprintf(cp, "%02x%c", addr[i], 106 i == (len - 1) ? '\n' : ':'); 107 return cp - buf; 108} 109 110static ssize_t show_address(struct class_device *dev, char *buf) 111{ 112 struct net_device *net = to_net_dev(dev); 113 ssize_t ret = -EINVAL; 114 115 read_lock(&dev_base_lock); 116 if (dev_isalive(net)) 117 ret = format_addr(buf, net->dev_addr, net->addr_len); 118 read_unlock(&dev_base_lock); 119 return ret; 120} 121 122static ssize_t show_broadcast(struct class_device *dev, char *buf) 123{ 124 struct net_device *net = to_net_dev(dev); 125 if (dev_isalive(net)) 126 return format_addr(buf, net->broadcast, net->addr_len); 127 return -EINVAL; 128} 129 130static ssize_t show_carrier(struct class_device *dev, char *buf) 131{ 132 struct net_device *netdev = to_net_dev(dev); 133 if (netif_running(netdev)) { 134 return sprintf(buf, fmt_dec, !!netif_carrier_ok(netdev)); 135 } 136 return -EINVAL; 137} 138 139static CLASS_DEVICE_ATTR(address, S_IRUGO, show_address, NULL); 140static CLASS_DEVICE_ATTR(broadcast, S_IRUGO, show_broadcast, NULL); 141static CLASS_DEVICE_ATTR(carrier, S_IRUGO, show_carrier, NULL); 142 143/* read-write attributes */ 144NETDEVICE_SHOW(mtu, fmt_dec); 145 146static int change_mtu(struct net_device *net, unsigned long new_mtu) 147{ 148 return dev_set_mtu(net, (int) new_mtu); 149} 150 151static ssize_t store_mtu(struct class_device *dev, const char *buf, size_t len) 152{ 153 return netdev_store(dev, buf, len, change_mtu); 154} 155 156static CLASS_DEVICE_ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu); 157 158NETDEVICE_SHOW(flags, fmt_hex); 159 160static int change_flags(struct net_device *net, unsigned long new_flags) 161{ 162 return dev_change_flags(net, (unsigned) new_flags); 163} 164 165static ssize_t store_flags(struct class_device *dev, const char *buf, size_t len) 166{ 167 return netdev_store(dev, buf, len, change_flags); 168} 169 170static CLASS_DEVICE_ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags); 171 172NETDEVICE_SHOW(tx_queue_len, fmt_ulong); 173 174static int change_tx_queue_len(struct net_device *net, unsigned long new_len) 175{ 176 net->tx_queue_len = new_len; 177 return 0; 178} 179 180static ssize_t store_tx_queue_len(struct class_device *dev, const char *buf, size_t len) 181{ 182 return netdev_store(dev, buf, len, change_tx_queue_len); 183} 184 185static CLASS_DEVICE_ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len, 186 store_tx_queue_len); 187 188NETDEVICE_SHOW(weight, fmt_dec); 189 190static int change_weight(struct net_device *net, unsigned long new_weight) 191{ 192 net->weight = new_weight; 193 return 0; 194} 195 196static ssize_t store_weight(struct class_device *dev, const char *buf, size_t len) 197{ 198 return netdev_store(dev, buf, len, change_weight); 199} 200 201static CLASS_DEVICE_ATTR(weight, S_IRUGO | S_IWUSR, show_weight, 202 store_weight); 203 204 205static struct class_device_attribute *net_class_attributes[] = { 206 &class_device_attr_ifindex, 207 &class_device_attr_iflink, 208 &class_device_attr_addr_len, 209 &class_device_attr_tx_queue_len, 210 &class_device_attr_features, 211 &class_device_attr_mtu, 212 &class_device_attr_flags, 213 &class_device_attr_weight, 214 &class_device_attr_type, 215 &class_device_attr_address, 216 &class_device_attr_broadcast, 217 &class_device_attr_carrier, 218 NULL 219}; 220 221/* Show a given an attribute in the statistics group */ 222static ssize_t netstat_show(const struct class_device *cd, char *buf, 223 unsigned long offset) 224{ 225 struct net_device *dev = to_net_dev(cd); 226 struct net_device_stats *stats; 227 ssize_t ret = -EINVAL; 228 229 if (offset > sizeof(struct net_device_stats) || 230 offset % sizeof(unsigned long) != 0) 231 WARN_ON(1); 232 233 read_lock(&dev_base_lock); 234 if (dev_isalive(dev) && dev->get_stats && 235 (stats = (*dev->get_stats)(dev))) 236 ret = sprintf(buf, fmt_ulong, 237 *(unsigned long *)(((u8 *) stats) + offset)); 238 239 read_unlock(&dev_base_lock); 240 return ret; 241} 242 243/* generate a read-only statistics attribute */ 244#define NETSTAT_ENTRY(name) \ 245static ssize_t show_##name(struct class_device *cd, char *buf) \ 246{ \ 247 return netstat_show(cd, buf, \ 248 offsetof(struct net_device_stats, name)); \ 249} \ 250static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) 251 252NETSTAT_ENTRY(rx_packets); 253NETSTAT_ENTRY(tx_packets); 254NETSTAT_ENTRY(rx_bytes); 255NETSTAT_ENTRY(tx_bytes); 256NETSTAT_ENTRY(rx_errors); 257NETSTAT_ENTRY(tx_errors); 258NETSTAT_ENTRY(rx_dropped); 259NETSTAT_ENTRY(tx_dropped); 260NETSTAT_ENTRY(multicast); 261NETSTAT_ENTRY(collisions); 262NETSTAT_ENTRY(rx_length_errors); 263NETSTAT_ENTRY(rx_over_errors); 264NETSTAT_ENTRY(rx_crc_errors); 265NETSTAT_ENTRY(rx_frame_errors); 266NETSTAT_ENTRY(rx_fifo_errors); 267NETSTAT_ENTRY(rx_missed_errors); 268NETSTAT_ENTRY(tx_aborted_errors); 269NETSTAT_ENTRY(tx_carrier_errors); 270NETSTAT_ENTRY(tx_fifo_errors); 271NETSTAT_ENTRY(tx_heartbeat_errors); 272NETSTAT_ENTRY(tx_window_errors); 273NETSTAT_ENTRY(rx_compressed); 274NETSTAT_ENTRY(tx_compressed); 275 276static struct attribute *netstat_attrs[] = { 277 &class_device_attr_rx_packets.attr, 278 &class_device_attr_tx_packets.attr, 279 &class_device_attr_rx_bytes.attr, 280 &class_device_attr_tx_bytes.attr, 281 &class_device_attr_rx_errors.attr, 282 &class_device_attr_tx_errors.attr, 283 &class_device_attr_rx_dropped.attr, 284 &class_device_attr_tx_dropped.attr, 285 &class_device_attr_multicast.attr, 286 &class_device_attr_collisions.attr, 287 &class_device_attr_rx_length_errors.attr, 288 &class_device_attr_rx_over_errors.attr, 289 &class_device_attr_rx_crc_errors.attr, 290 &class_device_attr_rx_frame_errors.attr, 291 &class_device_attr_rx_fifo_errors.attr, 292 &class_device_attr_rx_missed_errors.attr, 293 &class_device_attr_tx_aborted_errors.attr, 294 &class_device_attr_tx_carrier_errors.attr, 295 &class_device_attr_tx_fifo_errors.attr, 296 &class_device_attr_tx_heartbeat_errors.attr, 297 &class_device_attr_tx_window_errors.attr, 298 &class_device_attr_rx_compressed.attr, 299 &class_device_attr_tx_compressed.attr, 300 NULL 301}; 302 303 304static struct attribute_group netstat_group = { 305 .name = "statistics", 306 .attrs = netstat_attrs, 307}; 308 309#ifdef WIRELESS_EXT 310/* helper function that does all the locking etc for wireless stats */ 311static ssize_t wireless_show(struct class_device *cd, char *buf, 312 ssize_t (*format)(const struct iw_statistics *, 313 char *)) 314{ 315 struct net_device *dev = to_net_dev(cd); 316 const struct iw_statistics *iw; 317 ssize_t ret = -EINVAL; 318 319 read_lock(&dev_base_lock); 320 if (dev_isalive(dev) && dev->get_wireless_stats 321 && (iw = dev->get_wireless_stats(dev)) != NULL) 322 ret = (*format)(iw, buf); 323 read_unlock(&dev_base_lock); 324 325 return ret; 326} 327 328/* show function template for wireless fields */ 329#define WIRELESS_SHOW(name, field, format_string) \ 330static ssize_t format_iw_##name(const struct iw_statistics *iw, char *buf) \ 331{ \ 332 return sprintf(buf, format_string, iw->field); \ 333} \ 334static ssize_t show_iw_##name(struct class_device *cd, char *buf) \ 335{ \ 336 return wireless_show(cd, buf, format_iw_##name); \ 337} \ 338static CLASS_DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL) 339 340WIRELESS_SHOW(status, status, fmt_hex); 341WIRELESS_SHOW(link, qual.qual, fmt_dec); 342WIRELESS_SHOW(level, qual.level, fmt_dec); 343WIRELESS_SHOW(noise, qual.noise, fmt_dec); 344WIRELESS_SHOW(nwid, discard.nwid, fmt_dec); 345WIRELESS_SHOW(crypt, discard.code, fmt_dec); 346WIRELESS_SHOW(fragment, discard.fragment, fmt_dec); 347WIRELESS_SHOW(misc, discard.misc, fmt_dec); 348WIRELESS_SHOW(retries, discard.retries, fmt_dec); 349WIRELESS_SHOW(beacon, miss.beacon, fmt_dec); 350 351static struct attribute *wireless_attrs[] = { 352 &class_device_attr_status.attr, 353 &class_device_attr_link.attr, 354 &class_device_attr_level.attr, 355 &class_device_attr_noise.attr, 356 &class_device_attr_nwid.attr, 357 &class_device_attr_crypt.attr, 358 &class_device_attr_fragment.attr, 359 &class_device_attr_retries.attr, 360 &class_device_attr_misc.attr, 361 &class_device_attr_beacon.attr, 362 NULL 363}; 364 365static struct attribute_group wireless_group = { 366 .name = "wireless", 367 .attrs = wireless_attrs, 368}; 369#endif 370 371#ifdef CONFIG_HOTPLUG 372static int netdev_hotplug(struct class_device *cd, char **envp, 373 int num_envp, char *buf, int size) 374{ 375 struct net_device *dev = to_net_dev(cd); 376 int i = 0; 377 int n; 378 379 /* pass interface in env to hotplug. */ 380 envp[i++] = buf; 381 n = snprintf(buf, size, "INTERFACE=%s", dev->name) + 1; 382 buf += n; 383 size -= n; 384 385 if ((size <= 0) || (i >= num_envp)) 386 return -ENOMEM; 387 388 envp[i] = NULL; 389 return 0; 390} 391#endif 392 393/* 394 * netdev_release -- destroy and free a dead device. 395 * Called when last reference to class_device kobject is gone. 396 */ 397static void netdev_release(struct class_device *cd) 398{ 399 struct net_device *dev 400 = container_of(cd, struct net_device, class_dev); 401 402 BUG_ON(dev->reg_state != NETREG_RELEASED); 403 404 kfree((char *)dev - dev->padded); 405} 406 407static struct class net_class = { 408 .name = "net", 409 .release = netdev_release, 410#ifdef CONFIG_HOTPLUG 411 .hotplug = netdev_hotplug, 412#endif 413}; 414 415void netdev_unregister_sysfs(struct net_device * net) 416{ 417 struct class_device * class_dev = &(net->class_dev); 418 419 if (net->get_stats) 420 sysfs_remove_group(&class_dev->kobj, &netstat_group); 421 422#ifdef WIRELESS_EXT 423 if (net->get_wireless_stats) 424 sysfs_remove_group(&class_dev->kobj, &wireless_group); 425#endif 426 class_device_del(class_dev); 427 428} 429 430/* Create sysfs entries for network device. */ 431int netdev_register_sysfs(struct net_device *net) 432{ 433 struct class_device *class_dev = &(net->class_dev); 434 int i; 435 struct class_device_attribute *attr; 436 int ret; 437 438 class_dev->class = &net_class; 439 class_dev->class_data = net; 440 441 strlcpy(class_dev->class_id, net->name, BUS_ID_SIZE); 442 if ((ret = class_device_register(class_dev))) 443 goto out; 444 445 for (i = 0; (attr = net_class_attributes[i]) != NULL; i++) { 446 if ((ret = class_device_create_file(class_dev, attr))) 447 goto out_unreg; 448 } 449 450 451 if (net->get_stats && 452 (ret = sysfs_create_group(&class_dev->kobj, &netstat_group))) 453 goto out_unreg; 454 455#ifdef WIRELESS_EXT 456 if (net->get_wireless_stats && 457 (ret = sysfs_create_group(&class_dev->kobj, &wireless_group))) 458 goto out_cleanup; 459 460 return 0; 461out_cleanup: 462 if (net->get_stats) 463 sysfs_remove_group(&class_dev->kobj, &netstat_group); 464#else 465 return 0; 466#endif 467 468out_unreg: 469 printk(KERN_WARNING "%s: sysfs attribute registration failed %d\n", 470 net->name, ret); 471 class_device_unregister(class_dev); 472out: 473 return ret; 474} 475 476int netdev_sysfs_init(void) 477{ 478 return class_register(&net_class); 479}