11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Sysfs attributes of bridge ports 31da177e4SLinus Torvalds * Linux ethernet bridge 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Authors: 61da177e4SLinus Torvalds * Stephen Hemminger <shemminger@osdl.org> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 91da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 101da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 111da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 144fc268d2SRandy Dunlap #include <linux/capability.h> 151da177e4SLinus Torvalds #include <linux/kernel.h> 161da177e4SLinus Torvalds #include <linux/netdevice.h> 171da177e4SLinus Torvalds #include <linux/if_bridge.h> 181da177e4SLinus Torvalds #include <linux/rtnetlink.h> 191da177e4SLinus Torvalds #include <linux/spinlock.h> 201da177e4SLinus Torvalds #include <linux/times.h> 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #include "br_private.h" 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds #define to_class_dev(obj) container_of(obj,struct class_device,kobj) 251da177e4SLinus Torvalds #define to_net_dev(class) container_of(class, struct net_device, class_dev) 261da177e4SLinus Torvalds #define to_bridge(cd) ((struct net_bridge *)(to_net_dev(cd)->priv)) 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds /* 291da177e4SLinus Torvalds * Common code for storing bridge parameters. 301da177e4SLinus Torvalds */ 311da177e4SLinus Torvalds static ssize_t store_bridge_parm(struct class_device *cd, 321da177e4SLinus Torvalds const char *buf, size_t len, 331da177e4SLinus Torvalds void (*set)(struct net_bridge *, unsigned long)) 341da177e4SLinus Torvalds { 351da177e4SLinus Torvalds struct net_bridge *br = to_bridge(cd); 361da177e4SLinus Torvalds char *endp; 371da177e4SLinus Torvalds unsigned long val; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) 401da177e4SLinus Torvalds return -EPERM; 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds val = simple_strtoul(buf, &endp, 0); 431da177e4SLinus Torvalds if (endp == buf) 441da177e4SLinus Torvalds return -EINVAL; 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds spin_lock_bh(&br->lock); 471da177e4SLinus Torvalds (*set)(br, val); 481da177e4SLinus Torvalds spin_unlock_bh(&br->lock); 491da177e4SLinus Torvalds return len; 501da177e4SLinus Torvalds } 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds static ssize_t show_forward_delay(struct class_device *cd, char *buf) 541da177e4SLinus Torvalds { 551da177e4SLinus Torvalds struct net_bridge *br = to_bridge(cd); 561da177e4SLinus Torvalds return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay)); 571da177e4SLinus Torvalds } 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds static void set_forward_delay(struct net_bridge *br, unsigned long val) 601da177e4SLinus Torvalds { 611da177e4SLinus Torvalds unsigned long delay = clock_t_to_jiffies(val); 621da177e4SLinus Torvalds br->forward_delay = delay; 631da177e4SLinus Torvalds if (br_is_root_bridge(br)) 641da177e4SLinus Torvalds br->bridge_forward_delay = delay; 651da177e4SLinus Torvalds } 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds static ssize_t store_forward_delay(struct class_device *cd, const char *buf, 681da177e4SLinus Torvalds size_t len) 691da177e4SLinus Torvalds { 701da177e4SLinus Torvalds return store_bridge_parm(cd, buf, len, set_forward_delay); 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR, 731da177e4SLinus Torvalds show_forward_delay, store_forward_delay); 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds static ssize_t show_hello_time(struct class_device *cd, char *buf) 761da177e4SLinus Torvalds { 771da177e4SLinus Torvalds return sprintf(buf, "%lu\n", 781da177e4SLinus Torvalds jiffies_to_clock_t(to_bridge(cd)->hello_time)); 791da177e4SLinus Torvalds } 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds static void set_hello_time(struct net_bridge *br, unsigned long val) 821da177e4SLinus Torvalds { 831da177e4SLinus Torvalds unsigned long t = clock_t_to_jiffies(val); 841da177e4SLinus Torvalds br->hello_time = t; 851da177e4SLinus Torvalds if (br_is_root_bridge(br)) 861da177e4SLinus Torvalds br->bridge_hello_time = t; 871da177e4SLinus Torvalds } 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds static ssize_t store_hello_time(struct class_device *cd, const char *buf, 901da177e4SLinus Torvalds size_t len) 911da177e4SLinus Torvalds { 921da177e4SLinus Torvalds return store_bridge_parm(cd, buf, len, set_hello_time); 931da177e4SLinus Torvalds } 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time, 961da177e4SLinus Torvalds store_hello_time); 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds static ssize_t show_max_age(struct class_device *cd, char *buf) 991da177e4SLinus Torvalds { 1001da177e4SLinus Torvalds return sprintf(buf, "%lu\n", 1011da177e4SLinus Torvalds jiffies_to_clock_t(to_bridge(cd)->max_age)); 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds static void set_max_age(struct net_bridge *br, unsigned long val) 1051da177e4SLinus Torvalds { 1061da177e4SLinus Torvalds unsigned long t = clock_t_to_jiffies(val); 1071da177e4SLinus Torvalds br->max_age = t; 1081da177e4SLinus Torvalds if (br_is_root_bridge(br)) 1091da177e4SLinus Torvalds br->bridge_max_age = t; 1101da177e4SLinus Torvalds } 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds static ssize_t store_max_age(struct class_device *cd, const char *buf, 1131da177e4SLinus Torvalds size_t len) 1141da177e4SLinus Torvalds { 1151da177e4SLinus Torvalds return store_bridge_parm(cd, buf, len, set_max_age); 1161da177e4SLinus Torvalds } 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, 1191da177e4SLinus Torvalds store_max_age); 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds static ssize_t show_ageing_time(struct class_device *cd, char *buf) 1221da177e4SLinus Torvalds { 1231da177e4SLinus Torvalds struct net_bridge *br = to_bridge(cd); 1241da177e4SLinus Torvalds return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time)); 1251da177e4SLinus Torvalds } 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds static void set_ageing_time(struct net_bridge *br, unsigned long val) 1281da177e4SLinus Torvalds { 1291da177e4SLinus Torvalds br->ageing_time = clock_t_to_jiffies(val); 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds static ssize_t store_ageing_time(struct class_device *cd, const char *buf, 1331da177e4SLinus Torvalds size_t len) 1341da177e4SLinus Torvalds { 1351da177e4SLinus Torvalds return store_bridge_parm(cd, buf, len, set_ageing_time); 1361da177e4SLinus Torvalds } 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time, 1391da177e4SLinus Torvalds store_ageing_time); 1401da177e4SLinus Torvalds static ssize_t show_stp_state(struct class_device *cd, char *buf) 1411da177e4SLinus Torvalds { 1421da177e4SLinus Torvalds struct net_bridge *br = to_bridge(cd); 1431da177e4SLinus Torvalds return sprintf(buf, "%d\n", br->stp_enabled); 1441da177e4SLinus Torvalds } 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds static void set_stp_state(struct net_bridge *br, unsigned long val) 1471da177e4SLinus Torvalds { 1481da177e4SLinus Torvalds br->stp_enabled = val; 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds static ssize_t store_stp_state(struct class_device *cd, 1521da177e4SLinus Torvalds const char *buf, size_t len) 1531da177e4SLinus Torvalds { 1541da177e4SLinus Torvalds return store_bridge_parm(cd, buf, len, set_stp_state); 1551da177e4SLinus Torvalds } 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state, 1581da177e4SLinus Torvalds store_stp_state); 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds static ssize_t show_priority(struct class_device *cd, char *buf) 1611da177e4SLinus Torvalds { 1621da177e4SLinus Torvalds struct net_bridge *br = to_bridge(cd); 1631da177e4SLinus Torvalds return sprintf(buf, "%d\n", 1641da177e4SLinus Torvalds (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]); 1651da177e4SLinus Torvalds } 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds static void set_priority(struct net_bridge *br, unsigned long val) 1681da177e4SLinus Torvalds { 1691da177e4SLinus Torvalds br_stp_set_bridge_priority(br, (u16) val); 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds static ssize_t store_priority(struct class_device *cd, 1731da177e4SLinus Torvalds const char *buf, size_t len) 1741da177e4SLinus Torvalds { 1751da177e4SLinus Torvalds return store_bridge_parm(cd, buf, len, set_priority); 1761da177e4SLinus Torvalds } 1771da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, 1781da177e4SLinus Torvalds store_priority); 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds static ssize_t show_root_id(struct class_device *cd, char *buf) 1811da177e4SLinus Torvalds { 1821da177e4SLinus Torvalds return br_show_bridge_id(buf, &to_bridge(cd)->designated_root); 1831da177e4SLinus Torvalds } 1841da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL); 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds static ssize_t show_bridge_id(struct class_device *cd, char *buf) 1871da177e4SLinus Torvalds { 1881da177e4SLinus Torvalds return br_show_bridge_id(buf, &to_bridge(cd)->bridge_id); 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL); 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds static ssize_t show_root_port(struct class_device *cd, char *buf) 1931da177e4SLinus Torvalds { 1941da177e4SLinus Torvalds return sprintf(buf, "%d\n", to_bridge(cd)->root_port); 1951da177e4SLinus Torvalds } 1961da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL); 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds static ssize_t show_root_path_cost(struct class_device *cd, char *buf) 1991da177e4SLinus Torvalds { 2001da177e4SLinus Torvalds return sprintf(buf, "%d\n", to_bridge(cd)->root_path_cost); 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL); 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds static ssize_t show_topology_change(struct class_device *cd, char *buf) 2051da177e4SLinus Torvalds { 2061da177e4SLinus Torvalds return sprintf(buf, "%d\n", to_bridge(cd)->topology_change); 2071da177e4SLinus Torvalds } 2081da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL); 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds static ssize_t show_topology_change_detected(struct class_device *cd, char *buf) 2111da177e4SLinus Torvalds { 2121da177e4SLinus Torvalds struct net_bridge *br = to_bridge(cd); 2131da177e4SLinus Torvalds return sprintf(buf, "%d\n", br->topology_change_detected); 2141da177e4SLinus Torvalds } 2151da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(topology_change_detected, S_IRUGO, show_topology_change_detected, NULL); 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds static ssize_t show_hello_timer(struct class_device *cd, char *buf) 2181da177e4SLinus Torvalds { 2191da177e4SLinus Torvalds struct net_bridge *br = to_bridge(cd); 2201da177e4SLinus Torvalds return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer)); 2211da177e4SLinus Torvalds } 2221da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL); 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds static ssize_t show_tcn_timer(struct class_device *cd, char *buf) 2251da177e4SLinus Torvalds { 2261da177e4SLinus Torvalds struct net_bridge *br = to_bridge(cd); 2271da177e4SLinus Torvalds return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer)); 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL); 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds static ssize_t show_topology_change_timer(struct class_device *cd, char *buf) 2321da177e4SLinus Torvalds { 2331da177e4SLinus Torvalds struct net_bridge *br = to_bridge(cd); 2341da177e4SLinus Torvalds return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer)); 2351da177e4SLinus Torvalds } 2361da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer, NULL); 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds static ssize_t show_gc_timer(struct class_device *cd, char *buf) 2391da177e4SLinus Torvalds { 2401da177e4SLinus Torvalds struct net_bridge *br = to_bridge(cd); 2411da177e4SLinus Torvalds return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer)); 2421da177e4SLinus Torvalds } 2431da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); 2441da177e4SLinus Torvalds 245*fda93d92SStephen Hemminger static ssize_t show_group_addr(struct class_device *cd, char *buf) 246*fda93d92SStephen Hemminger { 247*fda93d92SStephen Hemminger struct net_bridge *br = to_bridge(cd); 248*fda93d92SStephen Hemminger return sprintf(buf, "%x:%x:%x:%x:%x:%x\n", 249*fda93d92SStephen Hemminger br->group_addr[0], br->group_addr[1], 250*fda93d92SStephen Hemminger br->group_addr[2], br->group_addr[3], 251*fda93d92SStephen Hemminger br->group_addr[4], br->group_addr[5]); 252*fda93d92SStephen Hemminger } 253*fda93d92SStephen Hemminger 254*fda93d92SStephen Hemminger static ssize_t store_group_addr(struct class_device *cd, const char *buf, 255*fda93d92SStephen Hemminger size_t len) 256*fda93d92SStephen Hemminger { 257*fda93d92SStephen Hemminger struct net_bridge *br = to_bridge(cd); 258*fda93d92SStephen Hemminger unsigned new_addr[6]; 259*fda93d92SStephen Hemminger int i; 260*fda93d92SStephen Hemminger 261*fda93d92SStephen Hemminger if (!capable(CAP_NET_ADMIN)) 262*fda93d92SStephen Hemminger return -EPERM; 263*fda93d92SStephen Hemminger 264*fda93d92SStephen Hemminger if (sscanf(buf, "%x:%x:%x:%x:%x:%x", 265*fda93d92SStephen Hemminger &new_addr[0], &new_addr[1], &new_addr[2], 266*fda93d92SStephen Hemminger &new_addr[3], &new_addr[4], &new_addr[5]) != 6) 267*fda93d92SStephen Hemminger return -EINVAL; 268*fda93d92SStephen Hemminger 269*fda93d92SStephen Hemminger /* Must be 01:80:c2:00:00:0X */ 270*fda93d92SStephen Hemminger for (i = 0; i < 5; i++) 271*fda93d92SStephen Hemminger if (new_addr[i] != br_group_address[i]) 272*fda93d92SStephen Hemminger return -EINVAL; 273*fda93d92SStephen Hemminger 274*fda93d92SStephen Hemminger if (new_addr[5] & ~0xf) 275*fda93d92SStephen Hemminger return -EINVAL; 276*fda93d92SStephen Hemminger 277*fda93d92SStephen Hemminger if (new_addr[5] == 1 /* 802.3x Pause address */ 278*fda93d92SStephen Hemminger || new_addr[5] == 2 /* 802.3ad Slow protocols */ 279*fda93d92SStephen Hemminger || new_addr[5] == 3) /* 802.1X PAE address */ 280*fda93d92SStephen Hemminger return -EINVAL; 281*fda93d92SStephen Hemminger 282*fda93d92SStephen Hemminger spin_lock_bh(&br->lock); 283*fda93d92SStephen Hemminger for (i = 0; i < 6; i++) 284*fda93d92SStephen Hemminger br->group_addr[i] = new_addr[i]; 285*fda93d92SStephen Hemminger spin_unlock_bh(&br->lock); 286*fda93d92SStephen Hemminger return len; 287*fda93d92SStephen Hemminger } 288*fda93d92SStephen Hemminger 289*fda93d92SStephen Hemminger static CLASS_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR, 290*fda93d92SStephen Hemminger show_group_addr, store_group_addr); 291*fda93d92SStephen Hemminger 292*fda93d92SStephen Hemminger 2931da177e4SLinus Torvalds static struct attribute *bridge_attrs[] = { 2941da177e4SLinus Torvalds &class_device_attr_forward_delay.attr, 2951da177e4SLinus Torvalds &class_device_attr_hello_time.attr, 2961da177e4SLinus Torvalds &class_device_attr_max_age.attr, 2971da177e4SLinus Torvalds &class_device_attr_ageing_time.attr, 2981da177e4SLinus Torvalds &class_device_attr_stp_state.attr, 2991da177e4SLinus Torvalds &class_device_attr_priority.attr, 3001da177e4SLinus Torvalds &class_device_attr_bridge_id.attr, 3011da177e4SLinus Torvalds &class_device_attr_root_id.attr, 3021da177e4SLinus Torvalds &class_device_attr_root_path_cost.attr, 3031da177e4SLinus Torvalds &class_device_attr_root_port.attr, 3041da177e4SLinus Torvalds &class_device_attr_topology_change.attr, 3051da177e4SLinus Torvalds &class_device_attr_topology_change_detected.attr, 3061da177e4SLinus Torvalds &class_device_attr_hello_timer.attr, 3071da177e4SLinus Torvalds &class_device_attr_tcn_timer.attr, 3081da177e4SLinus Torvalds &class_device_attr_topology_change_timer.attr, 3091da177e4SLinus Torvalds &class_device_attr_gc_timer.attr, 310*fda93d92SStephen Hemminger &class_device_attr_group_addr.attr, 3111da177e4SLinus Torvalds NULL 3121da177e4SLinus Torvalds }; 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds static struct attribute_group bridge_group = { 3151da177e4SLinus Torvalds .name = SYSFS_BRIDGE_ATTR, 3161da177e4SLinus Torvalds .attrs = bridge_attrs, 3171da177e4SLinus Torvalds }; 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds /* 3201da177e4SLinus Torvalds * Export the forwarding information table as a binary file 3211da177e4SLinus Torvalds * The records are struct __fdb_entry. 3221da177e4SLinus Torvalds * 3231da177e4SLinus Torvalds * Returns the number of bytes read. 3241da177e4SLinus Torvalds */ 3251da177e4SLinus Torvalds static ssize_t brforward_read(struct kobject *kobj, char *buf, 3261da177e4SLinus Torvalds loff_t off, size_t count) 3271da177e4SLinus Torvalds { 3281da177e4SLinus Torvalds struct class_device *cdev = to_class_dev(kobj); 3291da177e4SLinus Torvalds struct net_bridge *br = to_bridge(cdev); 3301da177e4SLinus Torvalds int n; 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds /* must read whole records */ 3331da177e4SLinus Torvalds if (off % sizeof(struct __fdb_entry) != 0) 3341da177e4SLinus Torvalds return -EINVAL; 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds n = br_fdb_fillbuf(br, buf, 3371da177e4SLinus Torvalds count / sizeof(struct __fdb_entry), 3381da177e4SLinus Torvalds off / sizeof(struct __fdb_entry)); 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds if (n > 0) 3411da177e4SLinus Torvalds n *= sizeof(struct __fdb_entry); 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds return n; 3441da177e4SLinus Torvalds } 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds static struct bin_attribute bridge_forward = { 3471da177e4SLinus Torvalds .attr = { .name = SYSFS_BRIDGE_FDB, 3481da177e4SLinus Torvalds .mode = S_IRUGO, 3491da177e4SLinus Torvalds .owner = THIS_MODULE, }, 3501da177e4SLinus Torvalds .read = brforward_read, 3511da177e4SLinus Torvalds }; 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds /* 3541da177e4SLinus Torvalds * Add entries in sysfs onto the existing network class device 3551da177e4SLinus Torvalds * for the bridge. 3561da177e4SLinus Torvalds * Adds a attribute group "bridge" containing tuning parameters. 3571da177e4SLinus Torvalds * Binary attribute containing the forward table 3581da177e4SLinus Torvalds * Sub directory to hold links to interfaces. 3591da177e4SLinus Torvalds * 3601da177e4SLinus Torvalds * Note: the ifobj exists only to be a subdirectory 3611da177e4SLinus Torvalds * to hold links. The ifobj exists in same data structure 3621da177e4SLinus Torvalds * as it's parent the bridge so reference counting works. 3631da177e4SLinus Torvalds */ 3641da177e4SLinus Torvalds int br_sysfs_addbr(struct net_device *dev) 3651da177e4SLinus Torvalds { 3661da177e4SLinus Torvalds struct kobject *brobj = &dev->class_dev.kobj; 3671da177e4SLinus Torvalds struct net_bridge *br = netdev_priv(dev); 3681da177e4SLinus Torvalds int err; 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds err = sysfs_create_group(brobj, &bridge_group); 3711da177e4SLinus Torvalds if (err) { 3721da177e4SLinus Torvalds pr_info("%s: can't create group %s/%s\n", 3731da177e4SLinus Torvalds __FUNCTION__, dev->name, bridge_group.name); 3741da177e4SLinus Torvalds goto out1; 3751da177e4SLinus Torvalds } 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds err = sysfs_create_bin_file(brobj, &bridge_forward); 3781da177e4SLinus Torvalds if (err) { 3791da177e4SLinus Torvalds pr_info("%s: can't create attribue file %s/%s\n", 3801da177e4SLinus Torvalds __FUNCTION__, dev->name, bridge_forward.attr.name); 3811da177e4SLinus Torvalds goto out2; 3821da177e4SLinus Torvalds } 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds kobject_set_name(&br->ifobj, SYSFS_BRIDGE_PORT_SUBDIR); 3861da177e4SLinus Torvalds br->ifobj.ktype = NULL; 3871da177e4SLinus Torvalds br->ifobj.kset = NULL; 3881da177e4SLinus Torvalds br->ifobj.parent = brobj; 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds err = kobject_register(&br->ifobj); 3911da177e4SLinus Torvalds if (err) { 3921da177e4SLinus Torvalds pr_info("%s: can't add kobject (directory) %s/%s\n", 3931da177e4SLinus Torvalds __FUNCTION__, dev->name, br->ifobj.name); 3941da177e4SLinus Torvalds goto out3; 3951da177e4SLinus Torvalds } 3961da177e4SLinus Torvalds return 0; 3971da177e4SLinus Torvalds out3: 3981da177e4SLinus Torvalds sysfs_remove_bin_file(&dev->class_dev.kobj, &bridge_forward); 3991da177e4SLinus Torvalds out2: 4001da177e4SLinus Torvalds sysfs_remove_group(&dev->class_dev.kobj, &bridge_group); 4011da177e4SLinus Torvalds out1: 4021da177e4SLinus Torvalds return err; 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds } 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds void br_sysfs_delbr(struct net_device *dev) 4071da177e4SLinus Torvalds { 4081da177e4SLinus Torvalds struct kobject *kobj = &dev->class_dev.kobj; 4091da177e4SLinus Torvalds struct net_bridge *br = netdev_priv(dev); 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds kobject_unregister(&br->ifobj); 4121da177e4SLinus Torvalds sysfs_remove_bin_file(kobj, &bridge_forward); 4131da177e4SLinus Torvalds sysfs_remove_group(kobj, &bridge_group); 4141da177e4SLinus Torvalds } 415