bridge: Check return of dev_set_promiscuity
[safe/jmp/linux-2.6] / net / bridge / br_sysfs_br.c
index 6f577f1..27d6a51 100644 (file)
 
 #include "br_private.h"
 
-#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)
+#define to_dev(obj)    container_of(obj, struct device, kobj)
 #define to_bridge(cd)  ((struct net_bridge *)(to_net_dev(cd)->priv))
 
 /*
  * Common code for storing bridge parameters.
  */
-static ssize_t store_bridge_parm(struct class_device *cd,
+static ssize_t store_bridge_parm(struct device *d,
                                 const char *buf, size_t len,
                                 void (*set)(struct net_bridge *, unsigned long))
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        char *endp;
        unsigned long val;
 
@@ -50,9 +49,10 @@ static ssize_t store_bridge_parm(struct class_device *cd,
 }
 
 
-static ssize_t show_forward_delay(struct class_device *cd, char *buf)
+static ssize_t show_forward_delay(struct device *d,
+                                 struct device_attribute *attr, char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
 }
 
@@ -64,18 +64,20 @@ static void set_forward_delay(struct net_bridge *br, unsigned long val)
                br->bridge_forward_delay = delay;
 }
 
-static ssize_t store_forward_delay(struct class_device *cd, const char *buf,
-                                  size_t len)
+static ssize_t store_forward_delay(struct device *d,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t len)
 {
-       return store_bridge_parm(cd, buf, len, set_forward_delay);
+       return store_bridge_parm(d, buf, len, set_forward_delay);
 }
-static CLASS_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
-                        show_forward_delay, store_forward_delay);
+static DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
+                  show_forward_delay, store_forward_delay);
 
-static ssize_t show_hello_time(struct class_device *cd, char *buf)
+static ssize_t show_hello_time(struct device *d, struct device_attribute *attr,
+                              char *buf)
 {
        return sprintf(buf, "%lu\n",
-                      jiffies_to_clock_t(to_bridge(cd)->hello_time));
+                      jiffies_to_clock_t(to_bridge(d)->hello_time));
 }
 
 static void set_hello_time(struct net_bridge *br, unsigned long val)
@@ -86,19 +88,20 @@ static void set_hello_time(struct net_bridge *br, unsigned long val)
                br->bridge_hello_time = t;
 }
 
-static ssize_t store_hello_time(struct class_device *cd, const char *buf,
+static ssize_t store_hello_time(struct device *d,
+                               struct device_attribute *attr, const char *buf,
                                size_t len)
 {
-       return store_bridge_parm(cd, buf, len, set_hello_time);
+       return store_bridge_parm(d, buf, len, set_hello_time);
 }
+static DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
+                  store_hello_time);
 
-static CLASS_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
-                        store_hello_time);
-
-static ssize_t show_max_age(struct class_device *cd, char *buf)
+static ssize_t show_max_age(struct device *d, struct device_attribute *attr,
+                           char *buf)
 {
        return sprintf(buf, "%lu\n",
-                      jiffies_to_clock_t(to_bridge(cd)->max_age));
+                      jiffies_to_clock_t(to_bridge(d)->max_age));
 }
 
 static void set_max_age(struct net_bridge *br, unsigned long val)
@@ -109,18 +112,17 @@ static void set_max_age(struct net_bridge *br, unsigned long val)
                br->bridge_max_age = t;
 }
 
-static ssize_t store_max_age(struct class_device *cd, const char *buf,
-                               size_t len)
+static ssize_t store_max_age(struct device *d, struct device_attribute *attr,
+                            const char *buf, size_t len)
 {
-       return store_bridge_parm(cd, buf, len, set_max_age);
+       return store_bridge_parm(d, buf, len, set_max_age);
 }
+static DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age);
 
-static CLASS_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age,
-                        store_max_age);
-
-static ssize_t show_ageing_time(struct class_device *cd, char *buf)
+static ssize_t show_ageing_time(struct device *d,
+                               struct device_attribute *attr, char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
 }
 
@@ -129,37 +131,51 @@ static void set_ageing_time(struct net_bridge *br, unsigned long val)
        br->ageing_time = clock_t_to_jiffies(val);
 }
 
-static ssize_t store_ageing_time(struct class_device *cd, const char *buf,
-                                size_t len)
+static ssize_t store_ageing_time(struct device *d,
+                                struct device_attribute *attr,
+                                const char *buf, size_t len)
 {
-       return store_bridge_parm(cd, buf, len, set_ageing_time);
+       return store_bridge_parm(d, buf, len, set_ageing_time);
 }
+static DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
+                  store_ageing_time);
 
-static CLASS_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
-                        store_ageing_time);
-static ssize_t show_stp_state(struct class_device *cd, char *buf)
+static ssize_t show_stp_state(struct device *d,
+                             struct device_attribute *attr, char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%d\n", br->stp_enabled);
 }
 
-static void set_stp_state(struct net_bridge *br, unsigned long val)
-{
-       br->stp_enabled = val;
-}
 
-static ssize_t store_stp_state(struct class_device *cd,
-                              const char *buf, size_t len)
+static ssize_t store_stp_state(struct device *d,
+                              struct device_attribute *attr, const char *buf,
+                              size_t len)
 {
-       return store_bridge_parm(cd, buf, len, set_stp_state);
-}
+       struct net_bridge *br = to_bridge(d);
+       char *endp;
+       unsigned long val;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       val = simple_strtoul(buf, &endp, 0);
+       if (endp == buf)
+               return -EINVAL;
 
-static CLASS_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
-                        store_stp_state);
+       rtnl_lock();
+       br_stp_set_enabled(br, val);
+       rtnl_unlock();
 
-static ssize_t show_priority(struct class_device *cd, char *buf)
+       return len;
+}
+static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
+                  store_stp_state);
+
+static ssize_t show_priority(struct device *d, struct device_attribute *attr,
+                            char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%d\n",
                       (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
 }
@@ -169,96 +185,174 @@ static void set_priority(struct net_bridge *br, unsigned long val)
        br_stp_set_bridge_priority(br, (u16) val);
 }
 
-static ssize_t store_priority(struct class_device *cd,
+static ssize_t store_priority(struct device *d, struct device_attribute *attr,
                               const char *buf, size_t len)
 {
-       return store_bridge_parm(cd, buf, len, set_priority);
+       return store_bridge_parm(d, buf, len, set_priority);
 }
-static CLASS_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority,
-                        store_priority);
+static DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority);
 
-static ssize_t show_root_id(struct class_device *cd, char *buf)
+static ssize_t show_root_id(struct device *d, struct device_attribute *attr,
+                           char *buf)
 {
-       return br_show_bridge_id(buf, &to_bridge(cd)->designated_root);
+       return br_show_bridge_id(buf, &to_bridge(d)->designated_root);
 }
-static CLASS_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
+static DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
 
-static ssize_t show_bridge_id(struct class_device *cd, char *buf)
+static ssize_t show_bridge_id(struct device *d, struct device_attribute *attr,
+                             char *buf)
 {
-       return br_show_bridge_id(buf, &to_bridge(cd)->bridge_id);
+       return br_show_bridge_id(buf, &to_bridge(d)->bridge_id);
 }
-static CLASS_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
+static DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
 
-static ssize_t show_root_port(struct class_device *cd, char *buf)
+static ssize_t show_root_port(struct device *d, struct device_attribute *attr,
+                             char *buf)
 {
-       return sprintf(buf, "%d\n", to_bridge(cd)->root_port);
+       return sprintf(buf, "%d\n", to_bridge(d)->root_port);
 }
-static CLASS_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
+static DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
 
-static ssize_t show_root_path_cost(struct class_device *cd, char *buf)
+static ssize_t show_root_path_cost(struct device *d,
+                                  struct device_attribute *attr, char *buf)
 {
-       return sprintf(buf, "%d\n", to_bridge(cd)->root_path_cost);
+       return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost);
 }
-static CLASS_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
+static DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
 
-static ssize_t show_topology_change(struct class_device *cd, char *buf)
+static ssize_t show_topology_change(struct device *d,
+                                   struct device_attribute *attr, char *buf)
 {
-       return sprintf(buf, "%d\n", to_bridge(cd)->topology_change);
+       return sprintf(buf, "%d\n", to_bridge(d)->topology_change);
 }
-static CLASS_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
+static DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
 
-static ssize_t show_topology_change_detected(struct class_device *cd, char *buf)
+static ssize_t show_topology_change_detected(struct device *d,
+                                            struct device_attribute *attr,
+                                            char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%d\n", br->topology_change_detected);
 }
-static CLASS_DEVICE_ATTR(topology_change_detected, S_IRUGO, show_topology_change_detected, NULL);
+static DEVICE_ATTR(topology_change_detected, S_IRUGO,
+                  show_topology_change_detected, NULL);
 
-static ssize_t show_hello_timer(struct class_device *cd, char *buf)
+static ssize_t show_hello_timer(struct device *d,
+                               struct device_attribute *attr, char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer));
 }
-static CLASS_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
+static DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
 
-static ssize_t show_tcn_timer(struct class_device *cd, char *buf)
+static ssize_t show_tcn_timer(struct device *d, struct device_attribute *attr,
+                             char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer));
 }
-static CLASS_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
+static DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
 
-static ssize_t show_topology_change_timer(struct class_device *cd, char *buf)
+static ssize_t show_topology_change_timer(struct device *d,
+                                         struct device_attribute *attr,
+                                         char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer));
 }
-static CLASS_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer, NULL);
+static DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer,
+                  NULL);
 
-static ssize_t show_gc_timer(struct class_device *cd, char *buf)
+static ssize_t show_gc_timer(struct device *d, struct device_attribute *attr,
+                            char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer));
 }
-static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
+static DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
+
+static ssize_t show_group_addr(struct device *d,
+                              struct device_attribute *attr, char *buf)
+{
+       struct net_bridge *br = to_bridge(d);
+       return sprintf(buf, "%x:%x:%x:%x:%x:%x\n",
+                      br->group_addr[0], br->group_addr[1],
+                      br->group_addr[2], br->group_addr[3],
+                      br->group_addr[4], br->group_addr[5]);
+}
+
+static ssize_t store_group_addr(struct device *d,
+                               struct device_attribute *attr,
+                               const char *buf, size_t len)
+{
+       struct net_bridge *br = to_bridge(d);
+       unsigned new_addr[6];
+       int i;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (sscanf(buf, "%x:%x:%x:%x:%x:%x",
+                  &new_addr[0], &new_addr[1], &new_addr[2],
+                  &new_addr[3], &new_addr[4], &new_addr[5]) != 6)
+               return -EINVAL;
+
+       /* Must be 01:80:c2:00:00:0X */
+       for (i = 0; i < 5; i++)
+               if (new_addr[i] != br_group_address[i])
+                       return -EINVAL;
+
+       if (new_addr[5] & ~0xf)
+               return -EINVAL;
+
+       if (new_addr[5] == 1    /* 802.3x Pause address */
+           || new_addr[5] == 2 /* 802.3ad Slow protocols */
+           || new_addr[5] == 3) /* 802.1X PAE address */
+               return -EINVAL;
+
+       spin_lock_bh(&br->lock);
+       for (i = 0; i < 6; i++)
+               br->group_addr[i] = new_addr[i];
+       spin_unlock_bh(&br->lock);
+       return len;
+}
+
+static DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
+                  show_group_addr, store_group_addr);
+
+static ssize_t store_flush(struct device *d,
+                          struct device_attribute *attr,
+                          const char *buf, size_t len)
+{
+       struct net_bridge *br = to_bridge(d);
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       br_fdb_flush(br);
+       return len;
+}
+static DEVICE_ATTR(flush, S_IWUSR, NULL, store_flush);
 
 static struct attribute *bridge_attrs[] = {
-       &class_device_attr_forward_delay.attr,
-       &class_device_attr_hello_time.attr,
-       &class_device_attr_max_age.attr,
-       &class_device_attr_ageing_time.attr,
-       &class_device_attr_stp_state.attr,
-       &class_device_attr_priority.attr,
-       &class_device_attr_bridge_id.attr,
-       &class_device_attr_root_id.attr,
-       &class_device_attr_root_path_cost.attr,
-       &class_device_attr_root_port.attr,
-       &class_device_attr_topology_change.attr,
-       &class_device_attr_topology_change_detected.attr,
-       &class_device_attr_hello_timer.attr,
-       &class_device_attr_tcn_timer.attr,
-       &class_device_attr_topology_change_timer.attr,
-       &class_device_attr_gc_timer.attr,
+       &dev_attr_forward_delay.attr,
+       &dev_attr_hello_time.attr,
+       &dev_attr_max_age.attr,
+       &dev_attr_ageing_time.attr,
+       &dev_attr_stp_state.attr,
+       &dev_attr_priority.attr,
+       &dev_attr_bridge_id.attr,
+       &dev_attr_root_id.attr,
+       &dev_attr_root_path_cost.attr,
+       &dev_attr_root_port.attr,
+       &dev_attr_topology_change.attr,
+       &dev_attr_topology_change_detected.attr,
+       &dev_attr_hello_timer.attr,
+       &dev_attr_tcn_timer.attr,
+       &dev_attr_topology_change_timer.attr,
+       &dev_attr_gc_timer.attr,
+       &dev_attr_group_addr.attr,
+       &dev_attr_flush.attr,
        NULL
 };
 
@@ -273,31 +367,31 @@ static struct attribute_group bridge_group = {
  *
  * Returns the number of bytes read.
  */
-static ssize_t brforward_read(struct kobject *kobj, char *buf,
-                          loff_t off, size_t count)
+static ssize_t brforward_read(struct kobject *kobj,
+                             struct bin_attribute *bin_attr,
+                             char *buf, loff_t off, size_t count)
 {
-       struct class_device *cdev = to_class_dev(kobj);
-       struct net_bridge *br = to_bridge(cdev);
+       struct device *dev = to_dev(kobj);
+       struct net_bridge *br = to_bridge(dev);
        int n;
 
        /* must read whole records */
        if (off % sizeof(struct __fdb_entry) != 0)
                return -EINVAL;
 
-       n =  br_fdb_fillbuf(br, buf, 
+       n =  br_fdb_fillbuf(br, buf,
                            count / sizeof(struct __fdb_entry),
                            off / sizeof(struct __fdb_entry));
 
        if (n > 0)
                n *= sizeof(struct __fdb_entry);
-       
+
        return n;
 }
 
 static struct bin_attribute bridge_forward = {
        .attr = { .name = SYSFS_BRIDGE_FDB,
-                 .mode = S_IRUGO, 
-                 .owner = THIS_MODULE, },
+                 .mode = S_IRUGO, },
        .read = brforward_read,
 };
 
@@ -314,41 +408,35 @@ static struct bin_attribute bridge_forward = {
  */
 int br_sysfs_addbr(struct net_device *dev)
 {
-       struct kobject *brobj = &dev->class_dev.kobj;
+       struct kobject *brobj = &dev->dev.kobj;
        struct net_bridge *br = netdev_priv(dev);
        int err;
 
        err = sysfs_create_group(brobj, &bridge_group);
        if (err) {
                pr_info("%s: can't create group %s/%s\n",
-                       __FUNCTION__, dev->name, bridge_group.name);
+                       __func__, dev->name, bridge_group.name);
                goto out1;
        }
 
        err = sysfs_create_bin_file(brobj, &bridge_forward);
        if (err) {
-               pr_info("%s: can't create attribue file %s/%s\n",
-                       __FUNCTION__, dev->name, bridge_forward.attr.name);
+               pr_info("%s: can't create attribute file %s/%s\n",
+                       __func__, dev->name, bridge_forward.attr.name);
                goto out2;
        }
 
-       
-       kobject_set_name(&br->ifobj, SYSFS_BRIDGE_PORT_SUBDIR);
-       br->ifobj.ktype = NULL;
-       br->ifobj.kset = NULL;
-       br->ifobj.parent = brobj;
-
-       err = kobject_register(&br->ifobj);
-       if (err) {
+       br->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, brobj);
+       if (!br->ifobj) {
                pr_info("%s: can't add kobject (directory) %s/%s\n",
-                       __FUNCTION__, dev->name, br->ifobj.name);
+                       __func__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR);
                goto out3;
        }
        return 0;
  out3:
-       sysfs_remove_bin_file(&dev->class_dev.kobj, &bridge_forward);
+       sysfs_remove_bin_file(&dev->dev.kobj, &bridge_forward);
  out2:
-       sysfs_remove_group(&dev->class_dev.kobj, &bridge_group);
+       sysfs_remove_group(&dev->dev.kobj, &bridge_group);
  out1:
        return err;
 
@@ -356,10 +444,10 @@ int br_sysfs_addbr(struct net_device *dev)
 
 void br_sysfs_delbr(struct net_device *dev)
 {
-       struct kobject *kobj = &dev->class_dev.kobj;
+       struct kobject *kobj = &dev->dev.kobj;
        struct net_bridge *br = netdev_priv(dev);
 
-       kobject_unregister(&br->ifobj);
+       kobject_put(br->ifobj);
        sysfs_remove_bin_file(kobj, &bridge_forward);
        sysfs_remove_group(kobj, &bridge_group);
 }