Commit d934a707 authored by Stephen Hemminger's avatar Stephen Hemminger

[NET]: Cleanup net-sysfs show and change functions.

parent faf460c4
...@@ -3,10 +3,6 @@ ...@@ -3,10 +3,6 @@
* *
* Copyright (c) 2003 Stephen Hemminber <shemminger@osdl.org> * Copyright (c) 2003 Stephen Hemminber <shemminger@osdl.org>
* *
*
* TODO:
* last_tx
* last_rx
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -16,33 +12,61 @@ ...@@ -16,33 +12,61 @@
#include <net/sock.h> #include <net/sock.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#define to_net_dev(class) container_of((class), struct net_device, class_dev) #define to_class_dev(obj) container_of(obj,struct class_device,kobj)
#define to_net_dev(class) container_of(class, struct net_device, class_dev)
/* use same locking rules as GIF* ioctl's */
static ssize_t netdev_show(const struct class_device *cd, char *buf,
ssize_t (*format)(const struct net_device *, char *))
{
struct net_device *net = to_net_dev(cd);
ssize_t ret = -EINVAL;
read_lock(&dev_base_lock);
if (!net->deadbeaf)
ret = (*format)(net, buf);
read_unlock(&dev_base_lock);
return ret;
}
/* generate a show function for simple field */ /* generate a show function for simple field */
#define NETDEVICE_SHOW(field, format_string) \ #define NETDEVICE_SHOW(field, format_string) \
static ssize_t show_##field(struct class_device *dev, char *buf) \ static ssize_t format_##field(const struct net_device *net, char *buf) \
{ \ { \
return sprintf(buf, format_string, to_net_dev(dev)->field); \ return sprintf(buf, format_string, net->field); \
} \
static ssize_t show_##field(struct class_device *cd, char *buf) \
{ \
return netdev_show(cd, buf, format_##field); \
} }
/* generate a store function for a field with locking */
#define NETDEVICE_STORE(field) \ /* use same locking and permission rules as SIF* ioctl's */
static ssize_t \ static ssize_t netdev_store(struct class_device *dev,
store_##field(struct class_device *dev, const char *buf, size_t len) \ const char *buf, size_t len,
{ \ int (*set)(struct net_device *, unsigned long))
char *endp; \ {
long new = simple_strtol(buf, &endp, 16); \ struct net_device *net = to_net_dev(dev);
\ char *endp;
if (endp == buf || new < 0) \ unsigned long new;
return -EINVAL; \ int ret = -EINVAL;
\
if (!capable(CAP_NET_ADMIN)) \ if (!capable(CAP_NET_ADMIN))
return -EPERM; \ return -EPERM;
\
rtnl_lock(); \ new = simple_strtoul(buf, &endp, 0);
to_net_dev(dev)->field = new; \ if (endp == buf)
rtnl_unlock(); \ goto err;
return len; \
rtnl_lock();
if (!net->deadbeaf) {
if ((ret = (*set)(net, new)) == 0)
ret = len;
}
rtnl_unlock();
err:
return ret;
} }
/* generate a read-only network device class attribute */ /* generate a read-only network device class attribute */
...@@ -56,6 +80,7 @@ NETDEVICE_ATTR(ifindex, "%d\n"); ...@@ -56,6 +80,7 @@ NETDEVICE_ATTR(ifindex, "%d\n");
NETDEVICE_ATTR(features, "%#x\n"); NETDEVICE_ATTR(features, "%#x\n");
NETDEVICE_ATTR(type, "%d\n"); NETDEVICE_ATTR(type, "%d\n");
/* use same locking rules as GIFHWADDR ioctl's */
static ssize_t format_addr(char *buf, const unsigned char *addr, int len) static ssize_t format_addr(char *buf, const unsigned char *addr, int len)
{ {
int i; int i;
...@@ -72,12 +97,16 @@ static ssize_t format_addr(char *buf, const unsigned char *addr, int len) ...@@ -72,12 +97,16 @@ static ssize_t format_addr(char *buf, const unsigned char *addr, int len)
static ssize_t show_address(struct class_device *dev, char *buf) static ssize_t show_address(struct class_device *dev, char *buf)
{ {
struct net_device *net = to_net_dev(dev); struct net_device *net = to_net_dev(dev);
if (net->deadbeaf)
return -EINVAL;
return format_addr(buf, net->dev_addr, net->addr_len); return format_addr(buf, net->dev_addr, net->addr_len);
} }
static ssize_t show_broadcast(struct class_device *dev, char *buf) static ssize_t show_broadcast(struct class_device *dev, char *buf)
{ {
struct net_device *net = to_net_dev(dev); struct net_device *net = to_net_dev(dev);
if (net->deadbeaf)
return -EINVAL;
return format_addr(buf, net->broadcast, net->addr_len); return format_addr(buf, net->broadcast, net->addr_len);
} }
...@@ -87,54 +116,45 @@ static CLASS_DEVICE_ATTR(broadcast, S_IRUGO, show_broadcast, NULL); ...@@ -87,54 +116,45 @@ static CLASS_DEVICE_ATTR(broadcast, S_IRUGO, show_broadcast, NULL);
/* read-write attributes */ /* read-write attributes */
NETDEVICE_SHOW(mtu, "%d\n"); NETDEVICE_SHOW(mtu, "%d\n");
static ssize_t store_mtu(struct class_device *dev, const char *buf, size_t len) static int change_mtu(struct net_device *net, unsigned long new_mtu)
{ {
char *endp; return dev_set_mtu(net, (int) new_mtu);
int new_mtu; }
int err;
new_mtu = simple_strtoul(buf, &endp, 10);
if (endp == buf)
return -EINVAL;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
rtnl_lock();
err = dev_set_mtu(to_net_dev(dev), new_mtu);
rtnl_unlock();
return err == 0 ? len : err; static ssize_t store_mtu(struct class_device *dev, const char *buf, size_t len)
{
return netdev_store(dev, buf, len, change_mtu);
} }
static CLASS_DEVICE_ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu); static CLASS_DEVICE_ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu);
NETDEVICE_SHOW(flags, "%#x\n"); NETDEVICE_SHOW(flags, "%#x\n");
static ssize_t store_flags(struct class_device *dev, const char *buf, size_t len) static int change_flags(struct net_device *net, unsigned long new_flags)
{ {
unsigned long new_flags; return dev_change_flags(net, (unsigned) new_flags);
char *endp; }
int err = 0;
new_flags = simple_strtoul(buf, &endp, 16); static ssize_t store_flags(struct class_device *dev, const char *buf, size_t len)
if (endp == buf) {
return -EINVAL; return netdev_store(dev, buf, len, change_flags);
}
if (!capable(CAP_NET_ADMIN)) static CLASS_DEVICE_ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags);
return -EPERM;
rtnl_lock(); NETDEVICE_SHOW(tx_queue_len, "%lu\n");
err = dev_change_flags(to_net_dev(dev), new_flags);
rtnl_unlock();
return err ? err : len; static int change_tx_queue_len(struct net_device *net, unsigned long new_len)
{
net->tx_queue_len = new_len;
return 0;
} }
static CLASS_DEVICE_ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags); static ssize_t store_tx_queue_len(struct class_device *dev, const char *buf, size_t len)
{
return netdev_store(dev, buf,len, change_tx_queue_len);
}
NETDEVICE_SHOW(tx_queue_len, "%lu\n");
NETDEVICE_STORE(tx_queue_len);
static CLASS_DEVICE_ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len, static CLASS_DEVICE_ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len,
store_tx_queue_len); store_tx_queue_len);
...@@ -237,16 +257,17 @@ netstat_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) ...@@ -237,16 +257,17 @@ netstat_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
{ {
struct netstat_fs_entry *entry struct netstat_fs_entry *entry
= container_of(attr, struct netstat_fs_entry, attr); = container_of(attr, struct netstat_fs_entry, attr);
struct class_device *class_dev
= container_of(kobj->parent, struct class_device, kobj);
struct net_device *dev struct net_device *dev
= to_net_dev(class_dev); = to_net_dev(to_class_dev(kobj->parent));
struct net_device_stats *stats struct net_device_stats *stats;
= dev->get_stats ? dev->get_stats(dev) : NULL; ssize_t ret = -EINVAL;
if (stats && entry->show) read_lock(&dev_base_lock);
return entry->show(stats, buf); if (!dev->deadbeaf && entry->show && dev->get_stats &&
return -EINVAL; (stats = (*dev->get_stats)(dev)))
ret = entry->show(stats, buf);
read_unlock(&dev_base_lock);
return ret;
} }
static struct sysfs_ops netstat_sysfs_ops = { static struct sysfs_ops netstat_sysfs_ops = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment