net-sysfs.c 13.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4
/*
 * net-sysfs.c - network device class and attributes
 *
 * Copyright (c) 2003 Stephen Hemminger <shemminger@osdl.org>
5
 *
L
Linus Torvalds 已提交
6 7 8 9 10 11
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License
 *	as published by the Free Software Foundation; either version
 *	2 of the License, or (at your option) any later version.
 */

12
#include <linux/capability.h>
L
Linus Torvalds 已提交
13 14 15 16 17 18
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <net/sock.h>
#include <linux/rtnetlink.h>
#include <linux/wireless.h>
19
#include <net/iw_handler.h>
L
Linus Torvalds 已提交
20

21 22
#include "net-sysfs.h"

23
#ifdef CONFIG_SYSFS
L
Linus Torvalds 已提交
24
static const char fmt_hex[] = "%#x\n";
25
static const char fmt_long_hex[] = "%#lx\n";
L
Linus Torvalds 已提交
26 27 28
static const char fmt_dec[] = "%d\n";
static const char fmt_ulong[] = "%lu\n";

29
static inline int dev_isalive(const struct net_device *dev)
L
Linus Torvalds 已提交
30
{
31
	return dev->reg_state <= NETREG_REGISTERED;
L
Linus Torvalds 已提交
32 33 34
}

/* use same locking rules as GIF* ioctl's */
35 36
static ssize_t netdev_show(const struct device *dev,
			   struct device_attribute *attr, char *buf,
L
Linus Torvalds 已提交
37 38
			   ssize_t (*format)(const struct net_device *, char *))
{
39
	struct net_device *net = to_net_dev(dev);
L
Linus Torvalds 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
	ssize_t ret = -EINVAL;

	read_lock(&dev_base_lock);
	if (dev_isalive(net))
		ret = (*format)(net, buf);
	read_unlock(&dev_base_lock);

	return ret;
}

/* generate a show function for simple field */
#define NETDEVICE_SHOW(field, format_string)				\
static ssize_t format_##field(const struct net_device *net, char *buf)	\
{									\
	return sprintf(buf, format_string, net->field);			\
}									\
56 57
static ssize_t show_##field(struct device *dev,				\
			    struct device_attribute *attr, char *buf)	\
L
Linus Torvalds 已提交
58
{									\
59
	return netdev_show(dev, attr, buf, format_##field);		\
L
Linus Torvalds 已提交
60 61 62 63
}


/* use same locking and permission rules as SIF* ioctl's */
64
static ssize_t netdev_store(struct device *dev, struct device_attribute *attr,
L
Linus Torvalds 已提交
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
			    const char *buf, size_t len,
			    int (*set)(struct net_device *, unsigned long))
{
	struct net_device *net = to_net_dev(dev);
	char *endp;
	unsigned long new;
	int ret = -EINVAL;

	if (!capable(CAP_NET_ADMIN))
		return -EPERM;

	new = simple_strtoul(buf, &endp, 0);
	if (endp == buf)
		goto err;

80 81 82
	if (!rtnl_trylock())
		return -ERESTARTSYS;

L
Linus Torvalds 已提交
83 84 85 86 87 88 89 90 91
	if (dev_isalive(net)) {
		if ((ret = (*set)(net, new)) == 0)
			ret = len;
	}
	rtnl_unlock();
 err:
	return ret;
}

92
NETDEVICE_SHOW(dev_id, fmt_hex);
93 94 95 96 97
NETDEVICE_SHOW(addr_len, fmt_dec);
NETDEVICE_SHOW(iflink, fmt_dec);
NETDEVICE_SHOW(ifindex, fmt_dec);
NETDEVICE_SHOW(features, fmt_long_hex);
NETDEVICE_SHOW(type, fmt_dec);
S
Stefan Rompf 已提交
98
NETDEVICE_SHOW(link_mode, fmt_dec);
L
Linus Torvalds 已提交
99 100

/* use same locking rules as GIFHWADDR ioctl's */
101 102
static ssize_t show_address(struct device *dev, struct device_attribute *attr,
			    char *buf)
L
Linus Torvalds 已提交
103 104 105 106 107 108
{
	struct net_device *net = to_net_dev(dev);
	ssize_t ret = -EINVAL;

	read_lock(&dev_base_lock);
	if (dev_isalive(net))
109
		ret = sysfs_format_mac(buf, net->dev_addr, net->addr_len);
L
Linus Torvalds 已提交
110 111 112 113
	read_unlock(&dev_base_lock);
	return ret;
}

114 115
static ssize_t show_broadcast(struct device *dev,
			    struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
116 117 118
{
	struct net_device *net = to_net_dev(dev);
	if (dev_isalive(net))
119
		return sysfs_format_mac(buf, net->broadcast, net->addr_len);
L
Linus Torvalds 已提交
120 121 122
	return -EINVAL;
}

123 124
static ssize_t show_carrier(struct device *dev,
			    struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
125 126 127 128 129 130 131 132
{
	struct net_device *netdev = to_net_dev(dev);
	if (netif_running(netdev)) {
		return sprintf(buf, fmt_dec, !!netif_carrier_ok(netdev));
	}
	return -EINVAL;
}

133 134
static ssize_t show_dormant(struct device *dev,
			    struct device_attribute *attr, char *buf)
S
Stefan Rompf 已提交
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
{
	struct net_device *netdev = to_net_dev(dev);

	if (netif_running(netdev))
		return sprintf(buf, fmt_dec, !!netif_dormant(netdev));

	return -EINVAL;
}

static const char *operstates[] = {
	"unknown",
	"notpresent", /* currently unused */
	"down",
	"lowerlayerdown",
	"testing", /* currently unused */
	"dormant",
	"up"
};

154 155
static ssize_t show_operstate(struct device *dev,
			      struct device_attribute *attr, char *buf)
S
Stefan Rompf 已提交
156 157 158 159 160 161 162 163 164 165
{
	const struct net_device *netdev = to_net_dev(dev);
	unsigned char operstate;

	read_lock(&dev_base_lock);
	operstate = netdev->operstate;
	if (!netif_running(netdev))
		operstate = IF_OPER_DOWN;
	read_unlock(&dev_base_lock);

166
	if (operstate >= ARRAY_SIZE(operstates))
S
Stefan Rompf 已提交
167 168 169 170 171
		return -EINVAL; /* should not happen */

	return sprintf(buf, "%s\n", operstates[operstate]);
}

L
Linus Torvalds 已提交
172 173 174 175 176 177 178 179
/* read-write attributes */
NETDEVICE_SHOW(mtu, fmt_dec);

static int change_mtu(struct net_device *net, unsigned long new_mtu)
{
	return dev_set_mtu(net, (int) new_mtu);
}

180 181
static ssize_t store_mtu(struct device *dev, struct device_attribute *attr,
			 const char *buf, size_t len)
L
Linus Torvalds 已提交
182
{
183
	return netdev_store(dev, attr, buf, len, change_mtu);
L
Linus Torvalds 已提交
184 185 186 187 188 189 190 191 192
}

NETDEVICE_SHOW(flags, fmt_hex);

static int change_flags(struct net_device *net, unsigned long new_flags)
{
	return dev_change_flags(net, (unsigned) new_flags);
}

193 194
static ssize_t store_flags(struct device *dev, struct device_attribute *attr,
			   const char *buf, size_t len)
L
Linus Torvalds 已提交
195
{
196
	return netdev_store(dev, attr, buf, len, change_flags);
L
Linus Torvalds 已提交
197 198 199 200 201 202 203 204 205 206
}

NETDEVICE_SHOW(tx_queue_len, fmt_ulong);

static int change_tx_queue_len(struct net_device *net, unsigned long new_len)
{
	net->tx_queue_len = new_len;
	return 0;
}

207 208 209
static ssize_t store_tx_queue_len(struct device *dev,
				  struct device_attribute *attr,
				  const char *buf, size_t len)
L
Linus Torvalds 已提交
210
{
211
	return netdev_store(dev, attr, buf, len, change_tx_queue_len);
L
Linus Torvalds 已提交
212 213
}

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
static ssize_t store_ifalias(struct device *dev, struct device_attribute *attr,
			     const char *buf, size_t len)
{
	struct net_device *netdev = to_net_dev(dev);
	size_t count = len;
	ssize_t ret;

	if (!capable(CAP_NET_ADMIN))
		return -EPERM;

	/* ignore trailing newline */
	if (len >  0 && buf[len - 1] == '\n')
		--count;

	rtnl_lock();
	ret = dev_set_alias(netdev, buf, count);
	rtnl_unlock();

	return ret < 0 ? ret : len;
}

static ssize_t show_ifalias(struct device *dev,
			    struct device_attribute *attr, char *buf)
{
	const struct net_device *netdev = to_net_dev(dev);
	ssize_t ret = 0;

	rtnl_lock();
	if (netdev->ifalias)
		ret = sprintf(buf, "%s\n", netdev->ifalias);
	rtnl_unlock();
	return ret;
}

248
static struct device_attribute net_class_attributes[] = {
249
	__ATTR(addr_len, S_IRUGO, show_addr_len, NULL),
250
	__ATTR(dev_id, S_IRUGO, show_dev_id, NULL),
251
	__ATTR(ifalias, S_IRUGO | S_IWUSR, show_ifalias, store_ifalias),
252 253 254 255
	__ATTR(iflink, S_IRUGO, show_iflink, NULL),
	__ATTR(ifindex, S_IRUGO, show_ifindex, NULL),
	__ATTR(features, S_IRUGO, show_features, NULL),
	__ATTR(type, S_IRUGO, show_type, NULL),
S
Stefan Rompf 已提交
256
	__ATTR(link_mode, S_IRUGO, show_link_mode, NULL),
257 258 259
	__ATTR(address, S_IRUGO, show_address, NULL),
	__ATTR(broadcast, S_IRUGO, show_broadcast, NULL),
	__ATTR(carrier, S_IRUGO, show_carrier, NULL),
S
Stefan Rompf 已提交
260 261
	__ATTR(dormant, S_IRUGO, show_dormant, NULL),
	__ATTR(operstate, S_IRUGO, show_operstate, NULL),
262 263 264 265 266
	__ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu),
	__ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags),
	__ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len,
	       store_tx_queue_len),
	{}
L
Linus Torvalds 已提交
267 268 269
};

/* Show a given an attribute in the statistics group */
270 271
static ssize_t netstat_show(const struct device *d,
			    struct device_attribute *attr, char *buf,
L
Linus Torvalds 已提交
272 273
			    unsigned long offset)
{
274
	struct net_device *dev = to_net_dev(d);
L
Linus Torvalds 已提交
275 276
	ssize_t ret = -EINVAL;

277 278
	WARN_ON(offset > sizeof(struct net_device_stats) ||
			offset % sizeof(unsigned long) != 0);
L
Linus Torvalds 已提交
279 280

	read_lock(&dev_base_lock);
281
	if (dev_isalive(dev)) {
282
		const struct net_device_stats *stats = dev_get_stats(dev);
L
Linus Torvalds 已提交
283 284
		ret = sprintf(buf, fmt_ulong,
			      *(unsigned long *)(((u8 *) stats) + offset));
285
	}
L
Linus Torvalds 已提交
286 287 288 289 290 291
	read_unlock(&dev_base_lock);
	return ret;
}

/* generate a read-only statistics attribute */
#define NETSTAT_ENTRY(name)						\
292 293
static ssize_t show_##name(struct device *d,				\
			   struct device_attribute *attr, char *buf) 	\
L
Linus Torvalds 已提交
294
{									\
295
	return netstat_show(d, attr, buf,				\
L
Linus Torvalds 已提交
296 297
			    offsetof(struct net_device_stats, name));	\
}									\
298
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
L
Linus Torvalds 已提交
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324

NETSTAT_ENTRY(rx_packets);
NETSTAT_ENTRY(tx_packets);
NETSTAT_ENTRY(rx_bytes);
NETSTAT_ENTRY(tx_bytes);
NETSTAT_ENTRY(rx_errors);
NETSTAT_ENTRY(tx_errors);
NETSTAT_ENTRY(rx_dropped);
NETSTAT_ENTRY(tx_dropped);
NETSTAT_ENTRY(multicast);
NETSTAT_ENTRY(collisions);
NETSTAT_ENTRY(rx_length_errors);
NETSTAT_ENTRY(rx_over_errors);
NETSTAT_ENTRY(rx_crc_errors);
NETSTAT_ENTRY(rx_frame_errors);
NETSTAT_ENTRY(rx_fifo_errors);
NETSTAT_ENTRY(rx_missed_errors);
NETSTAT_ENTRY(tx_aborted_errors);
NETSTAT_ENTRY(tx_carrier_errors);
NETSTAT_ENTRY(tx_fifo_errors);
NETSTAT_ENTRY(tx_heartbeat_errors);
NETSTAT_ENTRY(tx_window_errors);
NETSTAT_ENTRY(rx_compressed);
NETSTAT_ENTRY(tx_compressed);

static struct attribute *netstat_attrs[] = {
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
	&dev_attr_rx_packets.attr,
	&dev_attr_tx_packets.attr,
	&dev_attr_rx_bytes.attr,
	&dev_attr_tx_bytes.attr,
	&dev_attr_rx_errors.attr,
	&dev_attr_tx_errors.attr,
	&dev_attr_rx_dropped.attr,
	&dev_attr_tx_dropped.attr,
	&dev_attr_multicast.attr,
	&dev_attr_collisions.attr,
	&dev_attr_rx_length_errors.attr,
	&dev_attr_rx_over_errors.attr,
	&dev_attr_rx_crc_errors.attr,
	&dev_attr_rx_frame_errors.attr,
	&dev_attr_rx_fifo_errors.attr,
	&dev_attr_rx_missed_errors.attr,
	&dev_attr_tx_aborted_errors.attr,
	&dev_attr_tx_carrier_errors.attr,
	&dev_attr_tx_fifo_errors.attr,
	&dev_attr_tx_heartbeat_errors.attr,
	&dev_attr_tx_window_errors.attr,
	&dev_attr_rx_compressed.attr,
	&dev_attr_tx_compressed.attr,
L
Linus Torvalds 已提交
348 349 350 351 352 353 354 355 356
	NULL
};


static struct attribute_group netstat_group = {
	.name  = "statistics",
	.attrs  = netstat_attrs,
};

357
#ifdef CONFIG_WIRELESS_EXT_SYSFS
L
Linus Torvalds 已提交
358
/* helper function that does all the locking etc for wireless stats */
359
static ssize_t wireless_show(struct device *d, char *buf,
L
Linus Torvalds 已提交
360 361 362
			     ssize_t (*format)(const struct iw_statistics *,
					       char *))
{
363
	struct net_device *dev = to_net_dev(d);
364
	const struct iw_statistics *iw = NULL;
L
Linus Torvalds 已提交
365
	ssize_t ret = -EINVAL;
366

L
Linus Torvalds 已提交
367
	read_lock(&dev_base_lock);
368
	if (dev_isalive(dev)) {
369 370
		if (dev->wireless_handlers &&
		    dev->wireless_handlers->get_wireless_stats)
371 372 373 374
			iw = dev->wireless_handlers->get_wireless_stats(dev);
		if (iw != NULL)
			ret = (*format)(iw, buf);
	}
L
Linus Torvalds 已提交
375 376 377 378 379 380 381 382 383 384 385
	read_unlock(&dev_base_lock);

	return ret;
}

/* show function template for wireless fields */
#define WIRELESS_SHOW(name, field, format_string)			\
static ssize_t format_iw_##name(const struct iw_statistics *iw, char *buf) \
{									\
	return sprintf(buf, format_string, iw->field);			\
}									\
386 387
static ssize_t show_iw_##name(struct device *d,				\
			      struct device_attribute *attr, char *buf)	\
L
Linus Torvalds 已提交
388
{									\
389
	return wireless_show(d, buf, format_iw_##name);			\
L
Linus Torvalds 已提交
390
}									\
391
static DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL)
L
Linus Torvalds 已提交
392 393 394 395 396 397 398 399 400 401 402 403 404

WIRELESS_SHOW(status, status, fmt_hex);
WIRELESS_SHOW(link, qual.qual, fmt_dec);
WIRELESS_SHOW(level, qual.level, fmt_dec);
WIRELESS_SHOW(noise, qual.noise, fmt_dec);
WIRELESS_SHOW(nwid, discard.nwid, fmt_dec);
WIRELESS_SHOW(crypt, discard.code, fmt_dec);
WIRELESS_SHOW(fragment, discard.fragment, fmt_dec);
WIRELESS_SHOW(misc, discard.misc, fmt_dec);
WIRELESS_SHOW(retries, discard.retries, fmt_dec);
WIRELESS_SHOW(beacon, miss.beacon, fmt_dec);

static struct attribute *wireless_attrs[] = {
405 406 407 408 409 410 411 412 413 414
	&dev_attr_status.attr,
	&dev_attr_link.attr,
	&dev_attr_level.attr,
	&dev_attr_noise.attr,
	&dev_attr_nwid.attr,
	&dev_attr_crypt.attr,
	&dev_attr_fragment.attr,
	&dev_attr_retries.attr,
	&dev_attr_misc.attr,
	&dev_attr_beacon.attr,
L
Linus Torvalds 已提交
415 416 417 418 419 420 421 422 423
	NULL
};

static struct attribute_group wireless_group = {
	.name = "wireless",
	.attrs = wireless_attrs,
};
#endif

424 425
#endif /* CONFIG_SYSFS */

L
Linus Torvalds 已提交
426
#ifdef CONFIG_HOTPLUG
427
static int netdev_uevent(struct device *d, struct kobj_uevent_env *env)
L
Linus Torvalds 已提交
428
{
429
	struct net_device *dev = to_net_dev(d);
430
	int retval;
L
Linus Torvalds 已提交
431

432 433 434
	if (!net_eq(dev_net(dev), &init_net))
		return 0;

435
	/* pass interface to uevent. */
436
	retval = add_uevent_var(env, "INTERFACE=%s", dev->name);
437 438
	if (retval)
		goto exit;
439 440 441 442

	/* pass ifindex to uevent.
	 * ifindex is useful as it won't change (interface name may change)
	 * and is what RtNetlink uses natively. */
443
	retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex);
L
Linus Torvalds 已提交
444

445 446
exit:
	return retval;
L
Linus Torvalds 已提交
447 448 449 450
}
#endif

/*
451
 *	netdev_release -- destroy and free a dead device.
452
 *	Called when last reference to device kobject is gone.
L
Linus Torvalds 已提交
453
 */
454
static void netdev_release(struct device *d)
L
Linus Torvalds 已提交
455
{
456
	struct net_device *dev = to_net_dev(d);
L
Linus Torvalds 已提交
457 458 459

	BUG_ON(dev->reg_state != NETREG_RELEASED);

460
	kfree(dev->ifalias);
L
Linus Torvalds 已提交
461 462 463 464 465
	kfree((char *)dev - dev->padded);
}

static struct class net_class = {
	.name = "net",
466
	.dev_release = netdev_release,
467
#ifdef CONFIG_SYSFS
468
	.dev_attrs = net_class_attributes,
469
#endif /* CONFIG_SYSFS */
L
Linus Torvalds 已提交
470
#ifdef CONFIG_HOTPLUG
471
	.dev_uevent = netdev_uevent,
L
Linus Torvalds 已提交
472 473 474
#endif
};

475 476 477
/* Delete sysfs entries but hold kobject reference until after all
 * netdev references are gone.
 */
478
void netdev_unregister_kobject(struct net_device * net)
L
Linus Torvalds 已提交
479
{
480 481 482
	struct device *dev = &(net->dev);

	kobject_get(&dev->kobj);
483 484 485 486

	if (dev_net(net) != &init_net)
		return;

487
	device_del(dev);
L
Linus Torvalds 已提交
488 489 490
}

/* Create sysfs entries for network device. */
491
int netdev_register_kobject(struct net_device *net)
L
Linus Torvalds 已提交
492
{
493
	struct device *dev = &(net->dev);
494
	struct attribute_group **groups = net->sysfs_groups;
L
Linus Torvalds 已提交
495

496 497 498
	dev->class = &net_class;
	dev->platform_data = net;
	dev->groups = groups;
L
Linus Torvalds 已提交
499

500
	BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ);
501
	dev_set_name(dev, net->name);
L
Linus Torvalds 已提交
502

503
#ifdef CONFIG_SYSFS
504
	*groups++ = &netstat_group;
L
Linus Torvalds 已提交
505

506
#ifdef CONFIG_WIRELESS_EXT_SYSFS
507
	if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)
508
		*groups++ = &wireless_group;
L
Linus Torvalds 已提交
509
#endif
510
#endif /* CONFIG_SYSFS */
L
Linus Torvalds 已提交
511

512 513 514
	if (dev_net(net) != &init_net)
		return 0;

515
	return device_add(dev);
L
Linus Torvalds 已提交
516 517
}

518 519 520 521 522 523 524 525 526 527 528 529 530
int netdev_class_create_file(struct class_attribute *class_attr)
{
	return class_create_file(&net_class, class_attr);
}

void netdev_class_remove_file(struct class_attribute *class_attr)
{
	class_remove_file(&net_class, class_attr);
}

EXPORT_SYMBOL(netdev_class_create_file);
EXPORT_SYMBOL(netdev_class_remove_file);

531 532 533 534 535 536
void netdev_initialize_kobject(struct net_device *net)
{
	struct device *device = &(net->dev);
	device_initialize(device);
}

537
int netdev_kobject_init(void)
L
Linus Torvalds 已提交
538 539 540
{
	return class_register(&net_class);
}