net-sysfs.c 13.6 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 80 81 82 83 84 85 86 87 88 89
			    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;

	rtnl_lock();
	if (dev_isalive(net)) {
		if ((ret = (*set)(net, new)) == 0)
			ret = len;
	}
	rtnl_unlock();
 err:
	return ret;
}

90
NETDEVICE_SHOW(dev_id, fmt_hex);
91 92 93 94 95
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 已提交
96
NETDEVICE_SHOW(link_mode, fmt_dec);
L
Linus Torvalds 已提交
97 98

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

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

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

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

131 132
static ssize_t show_dormant(struct device *dev,
			    struct device_attribute *attr, char *buf)
S
Stefan Rompf 已提交
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
{
	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"
};

152 153
static ssize_t show_operstate(struct device *dev,
			      struct device_attribute *attr, char *buf)
S
Stefan Rompf 已提交
154 155 156 157 158 159 160 161 162 163
{
	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);

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

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

L
Linus Torvalds 已提交
170 171 172 173 174 175 176 177
/* 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);
}

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

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);
}

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

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;
}

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

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
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;
}

246
static struct device_attribute net_class_attributes[] = {
247
	__ATTR(addr_len, S_IRUGO, show_addr_len, NULL),
248
	__ATTR(dev_id, S_IRUGO, show_dev_id, NULL),
249
	__ATTR(ifalias, S_IRUGO | S_IWUSR, show_ifalias, store_ifalias),
250 251 252 253
	__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 已提交
254
	__ATTR(link_mode, S_IRUGO, show_link_mode, NULL),
255 256 257
	__ATTR(address, S_IRUGO, show_address, NULL),
	__ATTR(broadcast, S_IRUGO, show_broadcast, NULL),
	__ATTR(carrier, S_IRUGO, show_carrier, NULL),
S
Stefan Rompf 已提交
258 259
	__ATTR(dormant, S_IRUGO, show_dormant, NULL),
	__ATTR(operstate, S_IRUGO, show_operstate, NULL),
260 261 262 263 264
	__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 已提交
265 266 267
};

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

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

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

/* generate a read-only statistics attribute */
#define NETSTAT_ENTRY(name)						\
291 292
static ssize_t show_##name(struct device *d,				\
			   struct device_attribute *attr, char *buf) 	\
L
Linus Torvalds 已提交
293
{									\
294
	return netstat_show(d, attr, buf,				\
L
Linus Torvalds 已提交
295 296
			    offsetof(struct net_device_stats, name));	\
}									\
297
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
L
Linus Torvalds 已提交
298 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

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[] = {
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
	&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 已提交
347 348 349 350 351 352 353 354 355
	NULL
};


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

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

L
Linus Torvalds 已提交
366
	read_lock(&dev_base_lock);
367
	if (dev_isalive(dev)) {
368 369
		if (dev->wireless_handlers &&
		    dev->wireless_handlers->get_wireless_stats)
370 371 372 373
			iw = dev->wireless_handlers->get_wireless_stats(dev);
		if (iw != NULL)
			ret = (*format)(iw, buf);
	}
L
Linus Torvalds 已提交
374 375 376 377 378 379 380 381 382 383 384
	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);			\
}									\
385 386
static ssize_t show_iw_##name(struct device *d,				\
			      struct device_attribute *attr, char *buf)	\
L
Linus Torvalds 已提交
387
{									\
388
	return wireless_show(d, buf, format_iw_##name);			\
L
Linus Torvalds 已提交
389
}									\
390
static DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL)
L
Linus Torvalds 已提交
391 392 393 394 395 396 397 398 399 400 401 402 403

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[] = {
404 405 406 407 408 409 410 411 412 413
	&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 已提交
414 415 416 417 418 419 420 421 422
	NULL
};

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

423 424
#endif /* CONFIG_SYSFS */

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

431
	/* pass interface to uevent. */
432
	retval = add_uevent_var(env, "INTERFACE=%s", dev->name);
433 434
	if (retval)
		goto exit;
435 436 437 438

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

441 442
exit:
	return retval;
L
Linus Torvalds 已提交
443 444 445 446
}
#endif

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

	BUG_ON(dev->reg_state != NETREG_RELEASED);

456
	kfree(dev->ifalias);
L
Linus Torvalds 已提交
457 458 459 460 461
	kfree((char *)dev - dev->padded);
}

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

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

	kobject_get(&dev->kobj);
	device_del(dev);
L
Linus Torvalds 已提交
480 481 482
}

/* Create sysfs entries for network device. */
483
int netdev_register_kobject(struct net_device *net)
L
Linus Torvalds 已提交
484
{
485
	struct device *dev = &(net->dev);
486
	struct attribute_group **groups = net->sysfs_groups;
L
Linus Torvalds 已提交
487

488 489 490
	dev->class = &net_class;
	dev->platform_data = net;
	dev->groups = groups;
L
Linus Torvalds 已提交
491

492
	BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ);
493
	strlcpy(dev->bus_id, net->name, BUS_ID_SIZE);
L
Linus Torvalds 已提交
494

495
#ifdef CONFIG_SYSFS
496
	*groups++ = &netstat_group;
L
Linus Torvalds 已提交
497

498
#ifdef CONFIG_WIRELESS_EXT_SYSFS
499
	if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)
500
		*groups++ = &wireless_group;
L
Linus Torvalds 已提交
501
#endif
502
#endif /* CONFIG_SYSFS */
L
Linus Torvalds 已提交
503

504
	return device_add(dev);
L
Linus Torvalds 已提交
505 506
}

507 508 509 510 511 512 513 514 515 516 517 518 519
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);

520 521 522 523 524 525
void netdev_initialize_kobject(struct net_device *net)
{
	struct device *device = &(net->dev);
	device_initialize(device);
}

526
int netdev_kobject_init(void)
L
Linus Torvalds 已提交
527 528 529
{
	return class_register(&net_class);
}