12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 315401946SWang Sheng-Hui * Sysfs attributes of bridge 41da177e4SLinus Torvalds * Linux ethernet bridge 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Authors: 71da177e4SLinus Torvalds * Stephen Hemminger <shemminger@osdl.org> 81da177e4SLinus Torvalds */ 91da177e4SLinus Torvalds 104fc268d2SRandy Dunlap #include <linux/capability.h> 111da177e4SLinus Torvalds #include <linux/kernel.h> 121da177e4SLinus Torvalds #include <linux/netdevice.h> 13b3343a2aSJohn Fastabend #include <linux/etherdevice.h> 141da177e4SLinus Torvalds #include <linux/if_bridge.h> 151da177e4SLinus Torvalds #include <linux/rtnetlink.h> 161da177e4SLinus Torvalds #include <linux/spinlock.h> 171da177e4SLinus Torvalds #include <linux/times.h> 18174cd4b1SIngo Molnar #include <linux/sched/signal.h> 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds #include "br_private.h" 211da177e4SLinus Torvalds 221e16f382SNikolay Aleksandrov /* IMPORTANT: new bridge options must be added with netlink support only 231e16f382SNikolay Aleksandrov * please do not add new sysfs entries 241e16f382SNikolay Aleksandrov */ 251e16f382SNikolay Aleksandrov 26524ad0a7SWang Chen #define to_bridge(cd) ((struct net_bridge *)netdev_priv(to_net_dev(cd))) 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds /* 291da177e4SLinus Torvalds * Common code for storing bridge parameters. 301da177e4SLinus Torvalds */ 3143cb76d9SGreg Kroah-Hartman static ssize_t store_bridge_parm(struct device *d, 321da177e4SLinus Torvalds const char *buf, size_t len, 339e781401SVladimir Oltean int (*set)(struct net_bridge *br, unsigned long val, 349e781401SVladimir Oltean struct netlink_ext_ack *extack)) 351da177e4SLinus Torvalds { 3643cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 379e781401SVladimir Oltean struct netlink_ext_ack extack = {0}; 381da177e4SLinus Torvalds unsigned long val; 398d4698f7SStephen Hemminger int err; 401da177e4SLinus Torvalds 41cb990503SEric W. Biederman if (!ns_capable(dev_net(br->dev)->user_ns, CAP_NET_ADMIN)) 421da177e4SLinus Torvalds return -EPERM; 431da177e4SLinus Torvalds 445a45ab3fSIdo Schimmel err = kstrtoul(buf, 0, &val); 45520fbdf7SBernard Zhao if (err != 0) 46520fbdf7SBernard Zhao return err; 471da177e4SLinus Torvalds 48047831a9SXin Long if (!rtnl_trylock()) 49047831a9SXin Long return restart_syscall(); 50047831a9SXin Long 519e781401SVladimir Oltean err = (*set)(br, val, &extack); 52047831a9SXin Long if (!err) 53047831a9SXin Long netdev_state_change(br->dev); 549e781401SVladimir Oltean if (extack._msg) { 559e781401SVladimir Oltean if (err) 569e781401SVladimir Oltean br_err(br, "%s\n", extack._msg); 579e781401SVladimir Oltean else 589e781401SVladimir Oltean br_warn(br, "%s\n", extack._msg); 599e781401SVladimir Oltean } 60047831a9SXin Long rtnl_unlock(); 61047831a9SXin Long 628d4698f7SStephen Hemminger return err ? err : len; 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds 66fbf2671bSsfeldma@cumulusnetworks.com static ssize_t forward_delay_show(struct device *d, 6743cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 681da177e4SLinus Torvalds { 6943cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 701da177e4SLinus Torvalds return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay)); 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds 739e781401SVladimir Oltean static int set_forward_delay(struct net_bridge *br, unsigned long val, 749e781401SVladimir Oltean struct netlink_ext_ack *extack) 759e781401SVladimir Oltean { 769e781401SVladimir Oltean return br_set_forward_delay(br, val); 779e781401SVladimir Oltean } 789e781401SVladimir Oltean 79fbf2671bSsfeldma@cumulusnetworks.com static ssize_t forward_delay_store(struct device *d, 8043cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 8143cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 821da177e4SLinus Torvalds { 839e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_forward_delay); 841da177e4SLinus Torvalds } 85fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(forward_delay); 861da177e4SLinus Torvalds 87fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hello_time_show(struct device *d, struct device_attribute *attr, 8843cb76d9SGreg Kroah-Hartman char *buf) 891da177e4SLinus Torvalds { 901da177e4SLinus Torvalds return sprintf(buf, "%lu\n", 9143cb76d9SGreg Kroah-Hartman jiffies_to_clock_t(to_bridge(d)->hello_time)); 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds 949e781401SVladimir Oltean static int set_hello_time(struct net_bridge *br, unsigned long val, 959e781401SVladimir Oltean struct netlink_ext_ack *extack) 969e781401SVladimir Oltean { 979e781401SVladimir Oltean return br_set_hello_time(br, val); 989e781401SVladimir Oltean } 999e781401SVladimir Oltean 100fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hello_time_store(struct device *d, 10143cb76d9SGreg Kroah-Hartman struct device_attribute *attr, const char *buf, 1021da177e4SLinus Torvalds size_t len) 1031da177e4SLinus Torvalds { 1049e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_hello_time); 1051da177e4SLinus Torvalds } 106fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(hello_time); 1071da177e4SLinus Torvalds 108fbf2671bSsfeldma@cumulusnetworks.com static ssize_t max_age_show(struct device *d, struct device_attribute *attr, 10943cb76d9SGreg Kroah-Hartman char *buf) 1101da177e4SLinus Torvalds { 1111da177e4SLinus Torvalds return sprintf(buf, "%lu\n", 11243cb76d9SGreg Kroah-Hartman jiffies_to_clock_t(to_bridge(d)->max_age)); 1131da177e4SLinus Torvalds } 1141da177e4SLinus Torvalds 1159e781401SVladimir Oltean static int set_max_age(struct net_bridge *br, unsigned long val, 1169e781401SVladimir Oltean struct netlink_ext_ack *extack) 1179e781401SVladimir Oltean { 1189e781401SVladimir Oltean return br_set_max_age(br, val); 1199e781401SVladimir Oltean } 1209e781401SVladimir Oltean 121fbf2671bSsfeldma@cumulusnetworks.com static ssize_t max_age_store(struct device *d, struct device_attribute *attr, 12243cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 1231da177e4SLinus Torvalds { 1249e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_max_age); 1251da177e4SLinus Torvalds } 126fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(max_age); 1271da177e4SLinus Torvalds 128fbf2671bSsfeldma@cumulusnetworks.com static ssize_t ageing_time_show(struct device *d, 12943cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1301da177e4SLinus Torvalds { 13143cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 1321da177e4SLinus Torvalds return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time)); 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds 1359e781401SVladimir Oltean static int set_ageing_time(struct net_bridge *br, unsigned long val, 1369e781401SVladimir Oltean struct netlink_ext_ack *extack) 1371da177e4SLinus Torvalds { 138047831a9SXin Long return br_set_ageing_time(br, val); 1391da177e4SLinus Torvalds } 1401da177e4SLinus Torvalds 141fbf2671bSsfeldma@cumulusnetworks.com static ssize_t ageing_time_store(struct device *d, 14243cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 14343cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 1441da177e4SLinus Torvalds { 14543cb76d9SGreg Kroah-Hartman return store_bridge_parm(d, buf, len, set_ageing_time); 1461da177e4SLinus Torvalds } 147fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(ageing_time); 14843cb76d9SGreg Kroah-Hartman 149fbf2671bSsfeldma@cumulusnetworks.com static ssize_t stp_state_show(struct device *d, 15043cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1511da177e4SLinus Torvalds { 15243cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 1531da177e4SLinus Torvalds return sprintf(buf, "%d\n", br->stp_enabled); 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds 1579e781401SVladimir Oltean static int set_stp_state(struct net_bridge *br, unsigned long val, 1589e781401SVladimir Oltean struct netlink_ext_ack *extack) 1591da177e4SLinus Torvalds { 1609e781401SVladimir Oltean return br_stp_set_enabled(br, val, extack); 1614436156bSXin Long } 1624436156bSXin Long 1634436156bSXin Long static ssize_t stp_state_store(struct device *d, 1644436156bSXin Long struct device_attribute *attr, const char *buf, 1654436156bSXin Long size_t len) 1664436156bSXin Long { 1674436156bSXin Long return store_bridge_parm(d, buf, len, set_stp_state); 1681da177e4SLinus Torvalds } 169fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(stp_state); 1701da177e4SLinus Torvalds 171fbf2671bSsfeldma@cumulusnetworks.com static ssize_t group_fwd_mask_show(struct device *d, 172fbf2671bSsfeldma@cumulusnetworks.com struct device_attribute *attr, 173fbf2671bSsfeldma@cumulusnetworks.com char *buf) 174515853ccSstephen hemminger { 175515853ccSstephen hemminger struct net_bridge *br = to_bridge(d); 176515853ccSstephen hemminger return sprintf(buf, "%#x\n", br->group_fwd_mask); 177515853ccSstephen hemminger } 178515853ccSstephen hemminger 1799e781401SVladimir Oltean static int set_group_fwd_mask(struct net_bridge *br, unsigned long val, 1809e781401SVladimir Oltean struct netlink_ext_ack *extack) 181347db6b4SXin Long { 182347db6b4SXin Long if (val & BR_GROUPFWD_RESTRICTED) 183347db6b4SXin Long return -EINVAL; 184347db6b4SXin Long 185347db6b4SXin Long br->group_fwd_mask = val; 186347db6b4SXin Long 187347db6b4SXin Long return 0; 188347db6b4SXin Long } 189515853ccSstephen hemminger 190fbf2671bSsfeldma@cumulusnetworks.com static ssize_t group_fwd_mask_store(struct device *d, 191fbf2671bSsfeldma@cumulusnetworks.com struct device_attribute *attr, 192fbf2671bSsfeldma@cumulusnetworks.com const char *buf, 193515853ccSstephen hemminger size_t len) 194515853ccSstephen hemminger { 195347db6b4SXin Long return store_bridge_parm(d, buf, len, set_group_fwd_mask); 196515853ccSstephen hemminger } 197fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(group_fwd_mask); 198515853ccSstephen hemminger 199fbf2671bSsfeldma@cumulusnetworks.com static ssize_t priority_show(struct device *d, struct device_attribute *attr, 20043cb76d9SGreg Kroah-Hartman char *buf) 2011da177e4SLinus Torvalds { 20243cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 2031da177e4SLinus Torvalds return sprintf(buf, "%d\n", 2041da177e4SLinus Torvalds (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]); 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds 2079e781401SVladimir Oltean static int set_priority(struct net_bridge *br, unsigned long val, 2089e781401SVladimir Oltean struct netlink_ext_ack *extack) 2091da177e4SLinus Torvalds { 2101da177e4SLinus Torvalds br_stp_set_bridge_priority(br, (u16) val); 2118d4698f7SStephen Hemminger return 0; 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds 214fbf2671bSsfeldma@cumulusnetworks.com static ssize_t priority_store(struct device *d, struct device_attribute *attr, 2151da177e4SLinus Torvalds const char *buf, size_t len) 2161da177e4SLinus Torvalds { 21743cb76d9SGreg Kroah-Hartman return store_bridge_parm(d, buf, len, set_priority); 2181da177e4SLinus Torvalds } 219fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(priority); 2201da177e4SLinus Torvalds 221fbf2671bSsfeldma@cumulusnetworks.com static ssize_t root_id_show(struct device *d, struct device_attribute *attr, 22243cb76d9SGreg Kroah-Hartman char *buf) 2231da177e4SLinus Torvalds { 22443cb76d9SGreg Kroah-Hartman return br_show_bridge_id(buf, &to_bridge(d)->designated_root); 2251da177e4SLinus Torvalds } 226fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(root_id); 2271da177e4SLinus Torvalds 228fbf2671bSsfeldma@cumulusnetworks.com static ssize_t bridge_id_show(struct device *d, struct device_attribute *attr, 22943cb76d9SGreg Kroah-Hartman char *buf) 2301da177e4SLinus Torvalds { 23143cb76d9SGreg Kroah-Hartman return br_show_bridge_id(buf, &to_bridge(d)->bridge_id); 2321da177e4SLinus Torvalds } 233fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(bridge_id); 2341da177e4SLinus Torvalds 235fbf2671bSsfeldma@cumulusnetworks.com static ssize_t root_port_show(struct device *d, struct device_attribute *attr, 23643cb76d9SGreg Kroah-Hartman char *buf) 2371da177e4SLinus Torvalds { 23843cb76d9SGreg Kroah-Hartman return sprintf(buf, "%d\n", to_bridge(d)->root_port); 2391da177e4SLinus Torvalds } 240fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(root_port); 2411da177e4SLinus Torvalds 242fbf2671bSsfeldma@cumulusnetworks.com static ssize_t root_path_cost_show(struct device *d, 24343cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 2441da177e4SLinus Torvalds { 24543cb76d9SGreg Kroah-Hartman return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost); 2461da177e4SLinus Torvalds } 247fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(root_path_cost); 2481da177e4SLinus Torvalds 249fbf2671bSsfeldma@cumulusnetworks.com static ssize_t topology_change_show(struct device *d, 25043cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 2511da177e4SLinus Torvalds { 25243cb76d9SGreg Kroah-Hartman return sprintf(buf, "%d\n", to_bridge(d)->topology_change); 2531da177e4SLinus Torvalds } 254fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(topology_change); 2551da177e4SLinus Torvalds 256fbf2671bSsfeldma@cumulusnetworks.com static ssize_t topology_change_detected_show(struct device *d, 25743cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 25843cb76d9SGreg Kroah-Hartman char *buf) 2591da177e4SLinus Torvalds { 26043cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 2611da177e4SLinus Torvalds return sprintf(buf, "%d\n", br->topology_change_detected); 2621da177e4SLinus Torvalds } 263fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(topology_change_detected); 2641da177e4SLinus Torvalds 265fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hello_timer_show(struct device *d, 26643cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 2671da177e4SLinus Torvalds { 26843cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 2691da177e4SLinus Torvalds return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer)); 2701da177e4SLinus Torvalds } 271fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(hello_timer); 2721da177e4SLinus Torvalds 273fbf2671bSsfeldma@cumulusnetworks.com static ssize_t tcn_timer_show(struct device *d, struct device_attribute *attr, 27443cb76d9SGreg Kroah-Hartman char *buf) 2751da177e4SLinus Torvalds { 27643cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 2771da177e4SLinus Torvalds return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer)); 2781da177e4SLinus Torvalds } 279fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(tcn_timer); 2801da177e4SLinus Torvalds 281fbf2671bSsfeldma@cumulusnetworks.com static ssize_t topology_change_timer_show(struct device *d, 28243cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 28343cb76d9SGreg Kroah-Hartman char *buf) 2841da177e4SLinus Torvalds { 28543cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 2861da177e4SLinus Torvalds return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer)); 2871da177e4SLinus Torvalds } 288fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(topology_change_timer); 2891da177e4SLinus Torvalds 290fbf2671bSsfeldma@cumulusnetworks.com static ssize_t gc_timer_show(struct device *d, struct device_attribute *attr, 29143cb76d9SGreg Kroah-Hartman char *buf) 2921da177e4SLinus Torvalds { 29343cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 294f7cdee8aSNikolay Aleksandrov return sprintf(buf, "%ld\n", br_timer_value(&br->gc_work.timer)); 2951da177e4SLinus Torvalds } 296fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(gc_timer); 2971da177e4SLinus Torvalds 298fbf2671bSsfeldma@cumulusnetworks.com static ssize_t group_addr_show(struct device *d, 29943cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 300fda93d92SStephen Hemminger { 30143cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 302223b229bSAndy Shevchenko return sprintf(buf, "%pM\n", br->group_addr); 303fda93d92SStephen Hemminger } 304fda93d92SStephen Hemminger 305fbf2671bSsfeldma@cumulusnetworks.com static ssize_t group_addr_store(struct device *d, 30643cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 30743cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 308fda93d92SStephen Hemminger { 30943cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 3104197f24bSBen Hutchings u8 new_addr[6]; 311fda93d92SStephen Hemminger 312cb990503SEric W. Biederman if (!ns_capable(dev_net(br->dev)->user_ns, CAP_NET_ADMIN)) 313fda93d92SStephen Hemminger return -EPERM; 314fda93d92SStephen Hemminger 315223b229bSAndy Shevchenko if (!mac_pton(buf, new_addr)) 316fda93d92SStephen Hemminger return -EINVAL; 317fda93d92SStephen Hemminger 31846acc460SBen Hutchings if (!is_link_local_ether_addr(new_addr)) 319fda93d92SStephen Hemminger return -EINVAL; 320fda93d92SStephen Hemminger 321f64f9e71SJoe Perches if (new_addr[5] == 1 || /* 802.3x Pause address */ 322f64f9e71SJoe Perches new_addr[5] == 2 || /* 802.3ad Slow protocols */ 323f64f9e71SJoe Perches new_addr[5] == 3) /* 802.1X PAE address */ 324fda93d92SStephen Hemminger return -EINVAL; 325fda93d92SStephen Hemminger 326204177f3SToshiaki Makita if (!rtnl_trylock()) 327204177f3SToshiaki Makita return restart_syscall(); 328204177f3SToshiaki Makita 329fda93d92SStephen Hemminger spin_lock_bh(&br->lock); 330223b229bSAndy Shevchenko ether_addr_copy(br->group_addr, new_addr); 331fda93d92SStephen Hemminger spin_unlock_bh(&br->lock); 332204177f3SToshiaki Makita 333be3664a0SNikolay Aleksandrov br_opt_toggle(br, BROPT_GROUP_ADDR_SET, true); 334204177f3SToshiaki Makita br_recalculate_fwd_mask(br); 335047831a9SXin Long netdev_state_change(br->dev); 336204177f3SToshiaki Makita 337204177f3SToshiaki Makita rtnl_unlock(); 338204177f3SToshiaki Makita 339fda93d92SStephen Hemminger return len; 340fda93d92SStephen Hemminger } 341fda93d92SStephen Hemminger 342fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(group_addr); 343fda93d92SStephen Hemminger 3449e781401SVladimir Oltean static int set_flush(struct net_bridge *br, unsigned long val, 3459e781401SVladimir Oltean struct netlink_ext_ack *extack) 34614f31bb3SXin Long { 3471f78ee14SNikolay Aleksandrov struct net_bridge_fdb_flush_desc desc = { 348*628ac04aSIdo Schimmel .flags_mask = BIT(BR_FDB_STATIC) 3491f78ee14SNikolay Aleksandrov }; 3501f78ee14SNikolay Aleksandrov 3511f78ee14SNikolay Aleksandrov br_fdb_flush(br, &desc); 35214f31bb3SXin Long return 0; 35314f31bb3SXin Long } 35414f31bb3SXin Long 355fbf2671bSsfeldma@cumulusnetworks.com static ssize_t flush_store(struct device *d, 3569cf63747SStephen Hemminger struct device_attribute *attr, 3579cf63747SStephen Hemminger const char *buf, size_t len) 3589cf63747SStephen Hemminger { 35914f31bb3SXin Long return store_bridge_parm(d, buf, len, set_flush); 3609cf63747SStephen Hemminger } 361fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_WO(flush); 362fda93d92SStephen Hemminger 36370e4272bSNikolay Aleksandrov static ssize_t no_linklocal_learn_show(struct device *d, 36470e4272bSNikolay Aleksandrov struct device_attribute *attr, 36570e4272bSNikolay Aleksandrov char *buf) 36670e4272bSNikolay Aleksandrov { 36770e4272bSNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 36870e4272bSNikolay Aleksandrov return sprintf(buf, "%d\n", br_boolopt_get(br, BR_BOOLOPT_NO_LL_LEARN)); 36970e4272bSNikolay Aleksandrov } 37070e4272bSNikolay Aleksandrov 3719e781401SVladimir Oltean static int set_no_linklocal_learn(struct net_bridge *br, unsigned long val, 3729e781401SVladimir Oltean struct netlink_ext_ack *extack) 37370e4272bSNikolay Aleksandrov { 3749e781401SVladimir Oltean return br_boolopt_toggle(br, BR_BOOLOPT_NO_LL_LEARN, !!val, extack); 37570e4272bSNikolay Aleksandrov } 37670e4272bSNikolay Aleksandrov 37770e4272bSNikolay Aleksandrov static ssize_t no_linklocal_learn_store(struct device *d, 37870e4272bSNikolay Aleksandrov struct device_attribute *attr, 37970e4272bSNikolay Aleksandrov const char *buf, size_t len) 38070e4272bSNikolay Aleksandrov { 38170e4272bSNikolay Aleksandrov return store_bridge_parm(d, buf, len, set_no_linklocal_learn); 38270e4272bSNikolay Aleksandrov } 38370e4272bSNikolay Aleksandrov static DEVICE_ATTR_RW(no_linklocal_learn); 38470e4272bSNikolay Aleksandrov 3850909e117SHerbert Xu #ifdef CONFIG_BRIDGE_IGMP_SNOOPING 386fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_router_show(struct device *d, 3870909e117SHerbert Xu struct device_attribute *attr, char *buf) 3880909e117SHerbert Xu { 3890909e117SHerbert Xu struct net_bridge *br = to_bridge(d); 390d3d065c0SNikolay Aleksandrov return sprintf(buf, "%d\n", br->multicast_ctx.multicast_router); 3910909e117SHerbert Xu } 3920909e117SHerbert Xu 3939e781401SVladimir Oltean static int set_multicast_router(struct net_bridge *br, unsigned long val, 3949e781401SVladimir Oltean struct netlink_ext_ack *extack) 3959e781401SVladimir Oltean { 396a97df080SNikolay Aleksandrov return br_multicast_set_router(&br->multicast_ctx, val); 3979e781401SVladimir Oltean } 3989e781401SVladimir Oltean 399fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_router_store(struct device *d, 4000909e117SHerbert Xu struct device_attribute *attr, 4010909e117SHerbert Xu const char *buf, size_t len) 4020909e117SHerbert Xu { 4039e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_multicast_router); 4040909e117SHerbert Xu } 405fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_router); 406561f1103SHerbert Xu 407fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_snooping_show(struct device *d, 408561f1103SHerbert Xu struct device_attribute *attr, 409561f1103SHerbert Xu char *buf) 410561f1103SHerbert Xu { 411561f1103SHerbert Xu struct net_bridge *br = to_bridge(d); 41213cefad2SNikolay Aleksandrov return sprintf(buf, "%d\n", br_opt_get(br, BROPT_MULTICAST_ENABLED)); 413561f1103SHerbert Xu } 414561f1103SHerbert Xu 415fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_snooping_store(struct device *d, 416561f1103SHerbert Xu struct device_attribute *attr, 417561f1103SHerbert Xu const char *buf, size_t len) 418561f1103SHerbert Xu { 419ae1ea84bSFlorian Fainelli return store_bridge_parm(d, buf, len, br_multicast_toggle); 420561f1103SHerbert Xu } 421fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_snooping); 422b195167fSHerbert Xu 423fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_query_use_ifaddr_show(struct device *d, 4241c8ad5bfSCong Wang struct device_attribute *attr, 4251c8ad5bfSCong Wang char *buf) 4261c8ad5bfSCong Wang { 4271c8ad5bfSCong Wang struct net_bridge *br = to_bridge(d); 428675779adSNikolay Aleksandrov return sprintf(buf, "%d\n", 429675779adSNikolay Aleksandrov br_opt_get(br, BROPT_MULTICAST_QUERY_USE_IFADDR)); 4301c8ad5bfSCong Wang } 4311c8ad5bfSCong Wang 4329e781401SVladimir Oltean static int set_query_use_ifaddr(struct net_bridge *br, unsigned long val, 4339e781401SVladimir Oltean struct netlink_ext_ack *extack) 4341c8ad5bfSCong Wang { 435675779adSNikolay Aleksandrov br_opt_toggle(br, BROPT_MULTICAST_QUERY_USE_IFADDR, !!val); 4361c8ad5bfSCong Wang return 0; 4371c8ad5bfSCong Wang } 4381c8ad5bfSCong Wang 4391c8ad5bfSCong Wang static ssize_t 440fbf2671bSsfeldma@cumulusnetworks.com multicast_query_use_ifaddr_store(struct device *d, 4411c8ad5bfSCong Wang struct device_attribute *attr, 4421c8ad5bfSCong Wang const char *buf, size_t len) 4431c8ad5bfSCong Wang { 4441c8ad5bfSCong Wang return store_bridge_parm(d, buf, len, set_query_use_ifaddr); 4451c8ad5bfSCong Wang } 446fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_query_use_ifaddr); 4471c8ad5bfSCong Wang 448fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_querier_show(struct device *d, 449c5c23260SHerbert Xu struct device_attribute *attr, 450c5c23260SHerbert Xu char *buf) 451c5c23260SHerbert Xu { 452c5c23260SHerbert Xu struct net_bridge *br = to_bridge(d); 45362938182SNikolay Aleksandrov return sprintf(buf, "%d\n", br->multicast_ctx.multicast_querier); 454c5c23260SHerbert Xu } 455c5c23260SHerbert Xu 4569e781401SVladimir Oltean static int set_multicast_querier(struct net_bridge *br, unsigned long val, 4579e781401SVladimir Oltean struct netlink_ext_ack *extack) 4589e781401SVladimir Oltean { 45962938182SNikolay Aleksandrov return br_multicast_set_querier(&br->multicast_ctx, val); 4609e781401SVladimir Oltean } 4619e781401SVladimir Oltean 462fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_querier_store(struct device *d, 463c5c23260SHerbert Xu struct device_attribute *attr, 464c5c23260SHerbert Xu const char *buf, size_t len) 465c5c23260SHerbert Xu { 4669e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_multicast_querier); 467c5c23260SHerbert Xu } 468fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_querier); 469c5c23260SHerbert Xu 470fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hash_elasticity_show(struct device *d, 471b195167fSHerbert Xu struct device_attribute *attr, char *buf) 472b195167fSHerbert Xu { 473cf332bcaSNikolay Aleksandrov return sprintf(buf, "%u\n", RHT_ELASTICITY); 474b195167fSHerbert Xu } 475b195167fSHerbert Xu 4769e781401SVladimir Oltean static int set_elasticity(struct net_bridge *br, unsigned long val, 4779e781401SVladimir Oltean struct netlink_ext_ack *extack) 478b195167fSHerbert Xu { 4799e781401SVladimir Oltean /* 16 is RHT_ELASTICITY */ 4809e781401SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 4819e781401SVladimir Oltean "the hash_elasticity option has been deprecated and is always 16"); 482b195167fSHerbert Xu return 0; 483b195167fSHerbert Xu } 484b195167fSHerbert Xu 485fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hash_elasticity_store(struct device *d, 486b195167fSHerbert Xu struct device_attribute *attr, 487b195167fSHerbert Xu const char *buf, size_t len) 488b195167fSHerbert Xu { 489b195167fSHerbert Xu return store_bridge_parm(d, buf, len, set_elasticity); 490b195167fSHerbert Xu } 491fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(hash_elasticity); 492b195167fSHerbert Xu 493fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hash_max_show(struct device *d, struct device_attribute *attr, 494b195167fSHerbert Xu char *buf) 495b195167fSHerbert Xu { 496b195167fSHerbert Xu struct net_bridge *br = to_bridge(d); 497b195167fSHerbert Xu return sprintf(buf, "%u\n", br->hash_max); 498b195167fSHerbert Xu } 499b195167fSHerbert Xu 5009e781401SVladimir Oltean static int set_hash_max(struct net_bridge *br, unsigned long val, 5019e781401SVladimir Oltean struct netlink_ext_ack *extack) 50219e3a9c9SNikolay Aleksandrov { 50319e3a9c9SNikolay Aleksandrov br->hash_max = val; 50419e3a9c9SNikolay Aleksandrov return 0; 50519e3a9c9SNikolay Aleksandrov } 50619e3a9c9SNikolay Aleksandrov 507fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hash_max_store(struct device *d, struct device_attribute *attr, 508b195167fSHerbert Xu const char *buf, size_t len) 509b195167fSHerbert Xu { 51019e3a9c9SNikolay Aleksandrov return store_bridge_parm(d, buf, len, set_hash_max); 511b195167fSHerbert Xu } 512fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(hash_max); 513d902eee4SHerbert Xu 5145e923585SNikolay Aleksandrov static ssize_t multicast_igmp_version_show(struct device *d, 5155e923585SNikolay Aleksandrov struct device_attribute *attr, 5165e923585SNikolay Aleksandrov char *buf) 5175e923585SNikolay Aleksandrov { 5185e923585SNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 5195e923585SNikolay Aleksandrov 520d3d065c0SNikolay Aleksandrov return sprintf(buf, "%u\n", br->multicast_ctx.multicast_igmp_version); 5215e923585SNikolay Aleksandrov } 5225e923585SNikolay Aleksandrov 5239e781401SVladimir Oltean static int set_multicast_igmp_version(struct net_bridge *br, unsigned long val, 5249e781401SVladimir Oltean struct netlink_ext_ack *extack) 5259e781401SVladimir Oltean { 526df271cd6SNikolay Aleksandrov return br_multicast_set_igmp_version(&br->multicast_ctx, val); 5279e781401SVladimir Oltean } 5289e781401SVladimir Oltean 5295e923585SNikolay Aleksandrov static ssize_t multicast_igmp_version_store(struct device *d, 5305e923585SNikolay Aleksandrov struct device_attribute *attr, 5315e923585SNikolay Aleksandrov const char *buf, size_t len) 5325e923585SNikolay Aleksandrov { 5339e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_multicast_igmp_version); 5345e923585SNikolay Aleksandrov } 5355e923585SNikolay Aleksandrov static DEVICE_ATTR_RW(multicast_igmp_version); 5365e923585SNikolay Aleksandrov 537fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_last_member_count_show(struct device *d, 538d902eee4SHerbert Xu struct device_attribute *attr, 539d902eee4SHerbert Xu char *buf) 540d902eee4SHerbert Xu { 541d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 542d3d065c0SNikolay Aleksandrov return sprintf(buf, "%u\n", br->multicast_ctx.multicast_last_member_count); 543d902eee4SHerbert Xu } 544d902eee4SHerbert Xu 5459e781401SVladimir Oltean static int set_last_member_count(struct net_bridge *br, unsigned long val, 5469e781401SVladimir Oltean struct netlink_ext_ack *extack) 547d902eee4SHerbert Xu { 548d3d065c0SNikolay Aleksandrov br->multicast_ctx.multicast_last_member_count = val; 549d902eee4SHerbert Xu return 0; 550d902eee4SHerbert Xu } 551d902eee4SHerbert Xu 552fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_last_member_count_store(struct device *d, 553d902eee4SHerbert Xu struct device_attribute *attr, 554d902eee4SHerbert Xu const char *buf, size_t len) 555d902eee4SHerbert Xu { 556d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_last_member_count); 557d902eee4SHerbert Xu } 558fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_last_member_count); 559d902eee4SHerbert Xu 560fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_startup_query_count_show( 561d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, char *buf) 562d902eee4SHerbert Xu { 563d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 564d3d065c0SNikolay Aleksandrov return sprintf(buf, "%u\n", br->multicast_ctx.multicast_startup_query_count); 565d902eee4SHerbert Xu } 566d902eee4SHerbert Xu 5679e781401SVladimir Oltean static int set_startup_query_count(struct net_bridge *br, unsigned long val, 5689e781401SVladimir Oltean struct netlink_ext_ack *extack) 569d902eee4SHerbert Xu { 570d3d065c0SNikolay Aleksandrov br->multicast_ctx.multicast_startup_query_count = val; 571d902eee4SHerbert Xu return 0; 572d902eee4SHerbert Xu } 573d902eee4SHerbert Xu 574fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_startup_query_count_store( 575d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, const char *buf, 576d902eee4SHerbert Xu size_t len) 577d902eee4SHerbert Xu { 578d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_startup_query_count); 579d902eee4SHerbert Xu } 580fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_startup_query_count); 581d902eee4SHerbert Xu 582fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_last_member_interval_show( 583d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, char *buf) 584d902eee4SHerbert Xu { 585d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 586d902eee4SHerbert Xu return sprintf(buf, "%lu\n", 587d3d065c0SNikolay Aleksandrov jiffies_to_clock_t(br->multicast_ctx.multicast_last_member_interval)); 588d902eee4SHerbert Xu } 589d902eee4SHerbert Xu 5909e781401SVladimir Oltean static int set_last_member_interval(struct net_bridge *br, unsigned long val, 5919e781401SVladimir Oltean struct netlink_ext_ack *extack) 592d902eee4SHerbert Xu { 593d3d065c0SNikolay Aleksandrov br->multicast_ctx.multicast_last_member_interval = clock_t_to_jiffies(val); 594d902eee4SHerbert Xu return 0; 595d902eee4SHerbert Xu } 596d902eee4SHerbert Xu 597fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_last_member_interval_store( 598d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, const char *buf, 599d902eee4SHerbert Xu size_t len) 600d902eee4SHerbert Xu { 601d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_last_member_interval); 602d902eee4SHerbert Xu } 603fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_last_member_interval); 604d902eee4SHerbert Xu 605fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_membership_interval_show( 606d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, char *buf) 607d902eee4SHerbert Xu { 608d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 609d902eee4SHerbert Xu return sprintf(buf, "%lu\n", 610d3d065c0SNikolay Aleksandrov jiffies_to_clock_t(br->multicast_ctx.multicast_membership_interval)); 611d902eee4SHerbert Xu } 612d902eee4SHerbert Xu 6139e781401SVladimir Oltean static int set_membership_interval(struct net_bridge *br, unsigned long val, 6149e781401SVladimir Oltean struct netlink_ext_ack *extack) 615d902eee4SHerbert Xu { 616d3d065c0SNikolay Aleksandrov br->multicast_ctx.multicast_membership_interval = clock_t_to_jiffies(val); 617d902eee4SHerbert Xu return 0; 618d902eee4SHerbert Xu } 619d902eee4SHerbert Xu 620fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_membership_interval_store( 621d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, const char *buf, 622d902eee4SHerbert Xu size_t len) 623d902eee4SHerbert Xu { 624d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_membership_interval); 625d902eee4SHerbert Xu } 626fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_membership_interval); 627d902eee4SHerbert Xu 628fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_querier_interval_show(struct device *d, 629d902eee4SHerbert Xu struct device_attribute *attr, 630d902eee4SHerbert Xu char *buf) 631d902eee4SHerbert Xu { 632d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 633d902eee4SHerbert Xu return sprintf(buf, "%lu\n", 634d3d065c0SNikolay Aleksandrov jiffies_to_clock_t(br->multicast_ctx.multicast_querier_interval)); 635d902eee4SHerbert Xu } 636d902eee4SHerbert Xu 6379e781401SVladimir Oltean static int set_querier_interval(struct net_bridge *br, unsigned long val, 6389e781401SVladimir Oltean struct netlink_ext_ack *extack) 639d902eee4SHerbert Xu { 640d3d065c0SNikolay Aleksandrov br->multicast_ctx.multicast_querier_interval = clock_t_to_jiffies(val); 641d902eee4SHerbert Xu return 0; 642d902eee4SHerbert Xu } 643d902eee4SHerbert Xu 644fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_querier_interval_store(struct device *d, 645d902eee4SHerbert Xu struct device_attribute *attr, 646d902eee4SHerbert Xu const char *buf, size_t len) 647d902eee4SHerbert Xu { 648d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_querier_interval); 649d902eee4SHerbert Xu } 650fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_querier_interval); 651d902eee4SHerbert Xu 652fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_query_interval_show(struct device *d, 653d902eee4SHerbert Xu struct device_attribute *attr, 654d902eee4SHerbert Xu char *buf) 655d902eee4SHerbert Xu { 656d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 657d902eee4SHerbert Xu return sprintf(buf, "%lu\n", 658d3d065c0SNikolay Aleksandrov jiffies_to_clock_t(br->multicast_ctx.multicast_query_interval)); 659d902eee4SHerbert Xu } 660d902eee4SHerbert Xu 6619e781401SVladimir Oltean static int set_query_interval(struct net_bridge *br, unsigned long val, 6629e781401SVladimir Oltean struct netlink_ext_ack *extack) 663d902eee4SHerbert Xu { 66499b40610SNikolay Aleksandrov br_multicast_set_query_intvl(&br->multicast_ctx, val); 665d902eee4SHerbert Xu return 0; 666d902eee4SHerbert Xu } 667d902eee4SHerbert Xu 668fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_query_interval_store(struct device *d, 669d902eee4SHerbert Xu struct device_attribute *attr, 670d902eee4SHerbert Xu const char *buf, size_t len) 671d902eee4SHerbert Xu { 672d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_query_interval); 673d902eee4SHerbert Xu } 674fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_query_interval); 675d902eee4SHerbert Xu 676fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_query_response_interval_show( 677d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, char *buf) 678d902eee4SHerbert Xu { 679d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 680d902eee4SHerbert Xu return sprintf( 681d902eee4SHerbert Xu buf, "%lu\n", 682d3d065c0SNikolay Aleksandrov jiffies_to_clock_t(br->multicast_ctx.multicast_query_response_interval)); 683d902eee4SHerbert Xu } 684d902eee4SHerbert Xu 6859e781401SVladimir Oltean static int set_query_response_interval(struct net_bridge *br, unsigned long val, 6869e781401SVladimir Oltean struct netlink_ext_ack *extack) 687d902eee4SHerbert Xu { 688d3d065c0SNikolay Aleksandrov br->multicast_ctx.multicast_query_response_interval = clock_t_to_jiffies(val); 689d902eee4SHerbert Xu return 0; 690d902eee4SHerbert Xu } 691d902eee4SHerbert Xu 692fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_query_response_interval_store( 693d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, const char *buf, 694d902eee4SHerbert Xu size_t len) 695d902eee4SHerbert Xu { 696d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_query_response_interval); 697d902eee4SHerbert Xu } 698fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_query_response_interval); 699d902eee4SHerbert Xu 700fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_startup_query_interval_show( 701d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, char *buf) 702d902eee4SHerbert Xu { 703d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 704d902eee4SHerbert Xu return sprintf( 705d902eee4SHerbert Xu buf, "%lu\n", 706d3d065c0SNikolay Aleksandrov jiffies_to_clock_t(br->multicast_ctx.multicast_startup_query_interval)); 707d902eee4SHerbert Xu } 708d902eee4SHerbert Xu 7099e781401SVladimir Oltean static int set_startup_query_interval(struct net_bridge *br, unsigned long val, 7109e781401SVladimir Oltean struct netlink_ext_ack *extack) 711d902eee4SHerbert Xu { 712f83a112bSNikolay Aleksandrov br_multicast_set_startup_query_intvl(&br->multicast_ctx, val); 713d902eee4SHerbert Xu return 0; 714d902eee4SHerbert Xu } 715d902eee4SHerbert Xu 716fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_startup_query_interval_store( 717d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, const char *buf, 718d902eee4SHerbert Xu size_t len) 719d902eee4SHerbert Xu { 720d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_startup_query_interval); 721d902eee4SHerbert Xu } 722fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_startup_query_interval); 7231080ab95SNikolay Aleksandrov 7241080ab95SNikolay Aleksandrov static ssize_t multicast_stats_enabled_show(struct device *d, 7251080ab95SNikolay Aleksandrov struct device_attribute *attr, 7261080ab95SNikolay Aleksandrov char *buf) 7271080ab95SNikolay Aleksandrov { 7281080ab95SNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 7291080ab95SNikolay Aleksandrov 730675779adSNikolay Aleksandrov return sprintf(buf, "%d\n", 731675779adSNikolay Aleksandrov br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED)); 7321080ab95SNikolay Aleksandrov } 7331080ab95SNikolay Aleksandrov 7349e781401SVladimir Oltean static int set_stats_enabled(struct net_bridge *br, unsigned long val, 7359e781401SVladimir Oltean struct netlink_ext_ack *extack) 7361080ab95SNikolay Aleksandrov { 737675779adSNikolay Aleksandrov br_opt_toggle(br, BROPT_MULTICAST_STATS_ENABLED, !!val); 7381080ab95SNikolay Aleksandrov return 0; 7391080ab95SNikolay Aleksandrov } 7401080ab95SNikolay Aleksandrov 7411080ab95SNikolay Aleksandrov static ssize_t multicast_stats_enabled_store(struct device *d, 7421080ab95SNikolay Aleksandrov struct device_attribute *attr, 7431080ab95SNikolay Aleksandrov const char *buf, 7441080ab95SNikolay Aleksandrov size_t len) 7451080ab95SNikolay Aleksandrov { 7461080ab95SNikolay Aleksandrov return store_bridge_parm(d, buf, len, set_stats_enabled); 7471080ab95SNikolay Aleksandrov } 7481080ab95SNikolay Aleksandrov static DEVICE_ATTR_RW(multicast_stats_enabled); 749aa2ae3e7SNikolay Aleksandrov 750aa2ae3e7SNikolay Aleksandrov #if IS_ENABLED(CONFIG_IPV6) 751aa2ae3e7SNikolay Aleksandrov static ssize_t multicast_mld_version_show(struct device *d, 752aa2ae3e7SNikolay Aleksandrov struct device_attribute *attr, 753aa2ae3e7SNikolay Aleksandrov char *buf) 754aa2ae3e7SNikolay Aleksandrov { 755aa2ae3e7SNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 756aa2ae3e7SNikolay Aleksandrov 757d3d065c0SNikolay Aleksandrov return sprintf(buf, "%u\n", br->multicast_ctx.multicast_mld_version); 758aa2ae3e7SNikolay Aleksandrov } 759aa2ae3e7SNikolay Aleksandrov 7609e781401SVladimir Oltean static int set_multicast_mld_version(struct net_bridge *br, unsigned long val, 7619e781401SVladimir Oltean struct netlink_ext_ack *extack) 7629e781401SVladimir Oltean { 763df271cd6SNikolay Aleksandrov return br_multicast_set_mld_version(&br->multicast_ctx, val); 7649e781401SVladimir Oltean } 7659e781401SVladimir Oltean 766aa2ae3e7SNikolay Aleksandrov static ssize_t multicast_mld_version_store(struct device *d, 767aa2ae3e7SNikolay Aleksandrov struct device_attribute *attr, 768aa2ae3e7SNikolay Aleksandrov const char *buf, size_t len) 769aa2ae3e7SNikolay Aleksandrov { 7709e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_multicast_mld_version); 771aa2ae3e7SNikolay Aleksandrov } 772aa2ae3e7SNikolay Aleksandrov static DEVICE_ATTR_RW(multicast_mld_version); 773aa2ae3e7SNikolay Aleksandrov #endif 7740909e117SHerbert Xu #endif 77534666d46SPablo Neira Ayuso #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) 776fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_iptables_show( 7774df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, char *buf) 7784df53d8bSPatrick McHardy { 7794df53d8bSPatrick McHardy struct net_bridge *br = to_bridge(d); 7808df3510fSNikolay Aleksandrov return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_IPTABLES)); 7814df53d8bSPatrick McHardy } 7824df53d8bSPatrick McHardy 7839e781401SVladimir Oltean static int set_nf_call_iptables(struct net_bridge *br, unsigned long val, 7849e781401SVladimir Oltean struct netlink_ext_ack *extack) 7854df53d8bSPatrick McHardy { 7868df3510fSNikolay Aleksandrov br_opt_toggle(br, BROPT_NF_CALL_IPTABLES, !!val); 7874df53d8bSPatrick McHardy return 0; 7884df53d8bSPatrick McHardy } 7894df53d8bSPatrick McHardy 790fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_iptables_store( 7914df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, const char *buf, 7924df53d8bSPatrick McHardy size_t len) 7934df53d8bSPatrick McHardy { 7944df53d8bSPatrick McHardy return store_bridge_parm(d, buf, len, set_nf_call_iptables); 7954df53d8bSPatrick McHardy } 796fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(nf_call_iptables); 7974df53d8bSPatrick McHardy 798fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_ip6tables_show( 7994df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, char *buf) 8004df53d8bSPatrick McHardy { 8014df53d8bSPatrick McHardy struct net_bridge *br = to_bridge(d); 8028df3510fSNikolay Aleksandrov return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_IP6TABLES)); 8034df53d8bSPatrick McHardy } 8044df53d8bSPatrick McHardy 8059e781401SVladimir Oltean static int set_nf_call_ip6tables(struct net_bridge *br, unsigned long val, 8069e781401SVladimir Oltean struct netlink_ext_ack *extack) 8074df53d8bSPatrick McHardy { 8088df3510fSNikolay Aleksandrov br_opt_toggle(br, BROPT_NF_CALL_IP6TABLES, !!val); 8094df53d8bSPatrick McHardy return 0; 8104df53d8bSPatrick McHardy } 8114df53d8bSPatrick McHardy 812fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_ip6tables_store( 8134df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, const char *buf, 8144df53d8bSPatrick McHardy size_t len) 8154df53d8bSPatrick McHardy { 8164df53d8bSPatrick McHardy return store_bridge_parm(d, buf, len, set_nf_call_ip6tables); 8174df53d8bSPatrick McHardy } 818fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(nf_call_ip6tables); 8194df53d8bSPatrick McHardy 820fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_arptables_show( 8214df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, char *buf) 8224df53d8bSPatrick McHardy { 8234df53d8bSPatrick McHardy struct net_bridge *br = to_bridge(d); 8248df3510fSNikolay Aleksandrov return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_ARPTABLES)); 8254df53d8bSPatrick McHardy } 8264df53d8bSPatrick McHardy 8279e781401SVladimir Oltean static int set_nf_call_arptables(struct net_bridge *br, unsigned long val, 8289e781401SVladimir Oltean struct netlink_ext_ack *extack) 8294df53d8bSPatrick McHardy { 8308df3510fSNikolay Aleksandrov br_opt_toggle(br, BROPT_NF_CALL_ARPTABLES, !!val); 8314df53d8bSPatrick McHardy return 0; 8324df53d8bSPatrick McHardy } 8334df53d8bSPatrick McHardy 834fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_arptables_store( 8354df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, const char *buf, 8364df53d8bSPatrick McHardy size_t len) 8374df53d8bSPatrick McHardy { 8384df53d8bSPatrick McHardy return store_bridge_parm(d, buf, len, set_nf_call_arptables); 8394df53d8bSPatrick McHardy } 840fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(nf_call_arptables); 8414df53d8bSPatrick McHardy #endif 842243a2e63SVlad Yasevich #ifdef CONFIG_BRIDGE_VLAN_FILTERING 843fbf2671bSsfeldma@cumulusnetworks.com static ssize_t vlan_filtering_show(struct device *d, 844243a2e63SVlad Yasevich struct device_attribute *attr, 845243a2e63SVlad Yasevich char *buf) 846243a2e63SVlad Yasevich { 847243a2e63SVlad Yasevich struct net_bridge *br = to_bridge(d); 848ae75767eSNikolay Aleksandrov return sprintf(buf, "%d\n", br_opt_get(br, BROPT_VLAN_ENABLED)); 849243a2e63SVlad Yasevich } 850243a2e63SVlad Yasevich 851fbf2671bSsfeldma@cumulusnetworks.com static ssize_t vlan_filtering_store(struct device *d, 852243a2e63SVlad Yasevich struct device_attribute *attr, 853243a2e63SVlad Yasevich const char *buf, size_t len) 854243a2e63SVlad Yasevich { 855243a2e63SVlad Yasevich return store_bridge_parm(d, buf, len, br_vlan_filter_toggle); 856243a2e63SVlad Yasevich } 857fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(vlan_filtering); 858204177f3SToshiaki Makita 859204177f3SToshiaki Makita static ssize_t vlan_protocol_show(struct device *d, 860204177f3SToshiaki Makita struct device_attribute *attr, 861204177f3SToshiaki Makita char *buf) 862204177f3SToshiaki Makita { 863204177f3SToshiaki Makita struct net_bridge *br = to_bridge(d); 864204177f3SToshiaki Makita return sprintf(buf, "%#06x\n", ntohs(br->vlan_proto)); 865204177f3SToshiaki Makita } 866204177f3SToshiaki Makita 867204177f3SToshiaki Makita static ssize_t vlan_protocol_store(struct device *d, 868204177f3SToshiaki Makita struct device_attribute *attr, 869204177f3SToshiaki Makita const char *buf, size_t len) 870204177f3SToshiaki Makita { 871204177f3SToshiaki Makita return store_bridge_parm(d, buf, len, br_vlan_set_proto); 872204177f3SToshiaki Makita } 873204177f3SToshiaki Makita static DEVICE_ATTR_RW(vlan_protocol); 87496a20d9dSVlad Yasevich 87596a20d9dSVlad Yasevich static ssize_t default_pvid_show(struct device *d, 87696a20d9dSVlad Yasevich struct device_attribute *attr, 87796a20d9dSVlad Yasevich char *buf) 87896a20d9dSVlad Yasevich { 87996a20d9dSVlad Yasevich struct net_bridge *br = to_bridge(d); 88096a20d9dSVlad Yasevich return sprintf(buf, "%d\n", br->default_pvid); 88196a20d9dSVlad Yasevich } 88296a20d9dSVlad Yasevich 88396a20d9dSVlad Yasevich static ssize_t default_pvid_store(struct device *d, 88496a20d9dSVlad Yasevich struct device_attribute *attr, 88596a20d9dSVlad Yasevich const char *buf, size_t len) 88696a20d9dSVlad Yasevich { 88796a20d9dSVlad Yasevich return store_bridge_parm(d, buf, len, br_vlan_set_default_pvid); 88896a20d9dSVlad Yasevich } 88996a20d9dSVlad Yasevich static DEVICE_ATTR_RW(default_pvid); 8906dada9b1SNikolay Aleksandrov 8916dada9b1SNikolay Aleksandrov static ssize_t vlan_stats_enabled_show(struct device *d, 8926dada9b1SNikolay Aleksandrov struct device_attribute *attr, 8936dada9b1SNikolay Aleksandrov char *buf) 8946dada9b1SNikolay Aleksandrov { 8956dada9b1SNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 896ae75767eSNikolay Aleksandrov return sprintf(buf, "%u\n", br_opt_get(br, BROPT_VLAN_STATS_ENABLED)); 8976dada9b1SNikolay Aleksandrov } 8986dada9b1SNikolay Aleksandrov 8999e781401SVladimir Oltean static int set_vlan_stats_enabled(struct net_bridge *br, unsigned long val, 9009e781401SVladimir Oltean struct netlink_ext_ack *extack) 9019e781401SVladimir Oltean { 9029e781401SVladimir Oltean return br_vlan_set_stats(br, val); 9039e781401SVladimir Oltean } 9049e781401SVladimir Oltean 9056dada9b1SNikolay Aleksandrov static ssize_t vlan_stats_enabled_store(struct device *d, 9066dada9b1SNikolay Aleksandrov struct device_attribute *attr, 9076dada9b1SNikolay Aleksandrov const char *buf, size_t len) 9086dada9b1SNikolay Aleksandrov { 9099e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_vlan_stats_enabled); 9106dada9b1SNikolay Aleksandrov } 9116dada9b1SNikolay Aleksandrov static DEVICE_ATTR_RW(vlan_stats_enabled); 9129163a0fcSNikolay Aleksandrov 9139163a0fcSNikolay Aleksandrov static ssize_t vlan_stats_per_port_show(struct device *d, 9149163a0fcSNikolay Aleksandrov struct device_attribute *attr, 9159163a0fcSNikolay Aleksandrov char *buf) 9169163a0fcSNikolay Aleksandrov { 9179163a0fcSNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 9189163a0fcSNikolay Aleksandrov return sprintf(buf, "%u\n", br_opt_get(br, BROPT_VLAN_STATS_PER_PORT)); 9199163a0fcSNikolay Aleksandrov } 9209163a0fcSNikolay Aleksandrov 9219e781401SVladimir Oltean static int set_vlan_stats_per_port(struct net_bridge *br, unsigned long val, 9229e781401SVladimir Oltean struct netlink_ext_ack *extack) 9239e781401SVladimir Oltean { 9249e781401SVladimir Oltean return br_vlan_set_stats_per_port(br, val); 9259e781401SVladimir Oltean } 9269e781401SVladimir Oltean 9279163a0fcSNikolay Aleksandrov static ssize_t vlan_stats_per_port_store(struct device *d, 9289163a0fcSNikolay Aleksandrov struct device_attribute *attr, 9299163a0fcSNikolay Aleksandrov const char *buf, size_t len) 9309163a0fcSNikolay Aleksandrov { 9319e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_vlan_stats_per_port); 9329163a0fcSNikolay Aleksandrov } 9339163a0fcSNikolay Aleksandrov static DEVICE_ATTR_RW(vlan_stats_per_port); 934243a2e63SVlad Yasevich #endif 9350909e117SHerbert Xu 9361da177e4SLinus Torvalds static struct attribute *bridge_attrs[] = { 93743cb76d9SGreg Kroah-Hartman &dev_attr_forward_delay.attr, 93843cb76d9SGreg Kroah-Hartman &dev_attr_hello_time.attr, 93943cb76d9SGreg Kroah-Hartman &dev_attr_max_age.attr, 94043cb76d9SGreg Kroah-Hartman &dev_attr_ageing_time.attr, 94143cb76d9SGreg Kroah-Hartman &dev_attr_stp_state.attr, 942515853ccSstephen hemminger &dev_attr_group_fwd_mask.attr, 94343cb76d9SGreg Kroah-Hartman &dev_attr_priority.attr, 94443cb76d9SGreg Kroah-Hartman &dev_attr_bridge_id.attr, 94543cb76d9SGreg Kroah-Hartman &dev_attr_root_id.attr, 94643cb76d9SGreg Kroah-Hartman &dev_attr_root_path_cost.attr, 94743cb76d9SGreg Kroah-Hartman &dev_attr_root_port.attr, 94843cb76d9SGreg Kroah-Hartman &dev_attr_topology_change.attr, 94943cb76d9SGreg Kroah-Hartman &dev_attr_topology_change_detected.attr, 95043cb76d9SGreg Kroah-Hartman &dev_attr_hello_timer.attr, 95143cb76d9SGreg Kroah-Hartman &dev_attr_tcn_timer.attr, 95243cb76d9SGreg Kroah-Hartman &dev_attr_topology_change_timer.attr, 95343cb76d9SGreg Kroah-Hartman &dev_attr_gc_timer.attr, 95443cb76d9SGreg Kroah-Hartman &dev_attr_group_addr.attr, 9559cf63747SStephen Hemminger &dev_attr_flush.attr, 95670e4272bSNikolay Aleksandrov &dev_attr_no_linklocal_learn.attr, 9570909e117SHerbert Xu #ifdef CONFIG_BRIDGE_IGMP_SNOOPING 9580909e117SHerbert Xu &dev_attr_multicast_router.attr, 959561f1103SHerbert Xu &dev_attr_multicast_snooping.attr, 960c5c23260SHerbert Xu &dev_attr_multicast_querier.attr, 9611c8ad5bfSCong Wang &dev_attr_multicast_query_use_ifaddr.attr, 962b195167fSHerbert Xu &dev_attr_hash_elasticity.attr, 963b195167fSHerbert Xu &dev_attr_hash_max.attr, 964d902eee4SHerbert Xu &dev_attr_multicast_last_member_count.attr, 965d902eee4SHerbert Xu &dev_attr_multicast_startup_query_count.attr, 966d902eee4SHerbert Xu &dev_attr_multicast_last_member_interval.attr, 967d902eee4SHerbert Xu &dev_attr_multicast_membership_interval.attr, 968d902eee4SHerbert Xu &dev_attr_multicast_querier_interval.attr, 969d902eee4SHerbert Xu &dev_attr_multicast_query_interval.attr, 970d902eee4SHerbert Xu &dev_attr_multicast_query_response_interval.attr, 971d902eee4SHerbert Xu &dev_attr_multicast_startup_query_interval.attr, 9721080ab95SNikolay Aleksandrov &dev_attr_multicast_stats_enabled.attr, 9735e923585SNikolay Aleksandrov &dev_attr_multicast_igmp_version.attr, 974aa2ae3e7SNikolay Aleksandrov #if IS_ENABLED(CONFIG_IPV6) 975aa2ae3e7SNikolay Aleksandrov &dev_attr_multicast_mld_version.attr, 976aa2ae3e7SNikolay Aleksandrov #endif 9770909e117SHerbert Xu #endif 97834666d46SPablo Neira Ayuso #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) 9794df53d8bSPatrick McHardy &dev_attr_nf_call_iptables.attr, 9804df53d8bSPatrick McHardy &dev_attr_nf_call_ip6tables.attr, 9814df53d8bSPatrick McHardy &dev_attr_nf_call_arptables.attr, 9824df53d8bSPatrick McHardy #endif 983243a2e63SVlad Yasevich #ifdef CONFIG_BRIDGE_VLAN_FILTERING 984243a2e63SVlad Yasevich &dev_attr_vlan_filtering.attr, 985204177f3SToshiaki Makita &dev_attr_vlan_protocol.attr, 98696a20d9dSVlad Yasevich &dev_attr_default_pvid.attr, 9876dada9b1SNikolay Aleksandrov &dev_attr_vlan_stats_enabled.attr, 9889163a0fcSNikolay Aleksandrov &dev_attr_vlan_stats_per_port.attr, 989243a2e63SVlad Yasevich #endif 9901da177e4SLinus Torvalds NULL 9911da177e4SLinus Torvalds }; 9921da177e4SLinus Torvalds 993cddbb79fSArvind Yadav static const struct attribute_group bridge_group = { 9941da177e4SLinus Torvalds .name = SYSFS_BRIDGE_ATTR, 9951da177e4SLinus Torvalds .attrs = bridge_attrs, 9961da177e4SLinus Torvalds }; 9971da177e4SLinus Torvalds 9981da177e4SLinus Torvalds /* 9991da177e4SLinus Torvalds * Export the forwarding information table as a binary file 10001da177e4SLinus Torvalds * The records are struct __fdb_entry. 10011da177e4SLinus Torvalds * 10021da177e4SLinus Torvalds * Returns the number of bytes read. 10031da177e4SLinus Torvalds */ 10042c3c8beaSChris Wright static ssize_t brforward_read(struct file *filp, struct kobject *kobj, 100591a69029SZhang Rui struct bin_attribute *bin_attr, 100691a69029SZhang Rui char *buf, loff_t off, size_t count) 10071da177e4SLinus Torvalds { 1008aeb7ed14SGeliang Tang struct device *dev = kobj_to_dev(kobj); 100943cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(dev); 10101da177e4SLinus Torvalds int n; 10111da177e4SLinus Torvalds 10121da177e4SLinus Torvalds /* must read whole records */ 10131da177e4SLinus Torvalds if (off % sizeof(struct __fdb_entry) != 0) 10141da177e4SLinus Torvalds return -EINVAL; 10151da177e4SLinus Torvalds 10161da177e4SLinus Torvalds n = br_fdb_fillbuf(br, buf, 10171da177e4SLinus Torvalds count / sizeof(struct __fdb_entry), 10181da177e4SLinus Torvalds off / sizeof(struct __fdb_entry)); 10191da177e4SLinus Torvalds 10201da177e4SLinus Torvalds if (n > 0) 10211da177e4SLinus Torvalds n *= sizeof(struct __fdb_entry); 10221da177e4SLinus Torvalds 10231da177e4SLinus Torvalds return n; 10241da177e4SLinus Torvalds } 10251da177e4SLinus Torvalds 10261da177e4SLinus Torvalds static struct bin_attribute bridge_forward = { 10271da177e4SLinus Torvalds .attr = { .name = SYSFS_BRIDGE_FDB, 1028d6444062SJoe Perches .mode = 0444, }, 10291da177e4SLinus Torvalds .read = brforward_read, 10301da177e4SLinus Torvalds }; 10311da177e4SLinus Torvalds 10321da177e4SLinus Torvalds /* 10331da177e4SLinus Torvalds * Add entries in sysfs onto the existing network class device 10341da177e4SLinus Torvalds * for the bridge. 10351da177e4SLinus Torvalds * Adds a attribute group "bridge" containing tuning parameters. 10361da177e4SLinus Torvalds * Binary attribute containing the forward table 10371da177e4SLinus Torvalds * Sub directory to hold links to interfaces. 10381da177e4SLinus Torvalds * 10391da177e4SLinus Torvalds * Note: the ifobj exists only to be a subdirectory 10401da177e4SLinus Torvalds * to hold links. The ifobj exists in same data structure 10411da177e4SLinus Torvalds * as it's parent the bridge so reference counting works. 10421da177e4SLinus Torvalds */ 10431da177e4SLinus Torvalds int br_sysfs_addbr(struct net_device *dev) 10441da177e4SLinus Torvalds { 104543cb76d9SGreg Kroah-Hartman struct kobject *brobj = &dev->dev.kobj; 10461da177e4SLinus Torvalds struct net_bridge *br = netdev_priv(dev); 10471da177e4SLinus Torvalds int err; 10481da177e4SLinus Torvalds 10491da177e4SLinus Torvalds err = sysfs_create_group(brobj, &bridge_group); 10501da177e4SLinus Torvalds if (err) { 10511da177e4SLinus Torvalds pr_info("%s: can't create group %s/%s\n", 10520dc47877SHarvey Harrison __func__, dev->name, bridge_group.name); 10531da177e4SLinus Torvalds goto out1; 10541da177e4SLinus Torvalds } 10551da177e4SLinus Torvalds 10561da177e4SLinus Torvalds err = sysfs_create_bin_file(brobj, &bridge_forward); 10571da177e4SLinus Torvalds if (err) { 10581842c4beSRandy Dunlap pr_info("%s: can't create attribute file %s/%s\n", 10590dc47877SHarvey Harrison __func__, dev->name, bridge_forward.attr.name); 10601da177e4SLinus Torvalds goto out2; 10611da177e4SLinus Torvalds } 10621da177e4SLinus Torvalds 106343b98c4aSGreg Kroah-Hartman br->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, brobj); 106443b98c4aSGreg Kroah-Hartman if (!br->ifobj) { 10651da177e4SLinus Torvalds pr_info("%s: can't add kobject (directory) %s/%s\n", 10660dc47877SHarvey Harrison __func__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR); 1067b5958963SPan Bian err = -ENOMEM; 10681da177e4SLinus Torvalds goto out3; 10691da177e4SLinus Torvalds } 10701da177e4SLinus Torvalds return 0; 10711da177e4SLinus Torvalds out3: 107243cb76d9SGreg Kroah-Hartman sysfs_remove_bin_file(&dev->dev.kobj, &bridge_forward); 10731da177e4SLinus Torvalds out2: 107443cb76d9SGreg Kroah-Hartman sysfs_remove_group(&dev->dev.kobj, &bridge_group); 10751da177e4SLinus Torvalds out1: 10761da177e4SLinus Torvalds return err; 10771da177e4SLinus Torvalds 10781da177e4SLinus Torvalds } 10791da177e4SLinus Torvalds 10801da177e4SLinus Torvalds void br_sysfs_delbr(struct net_device *dev) 10811da177e4SLinus Torvalds { 108243cb76d9SGreg Kroah-Hartman struct kobject *kobj = &dev->dev.kobj; 10831da177e4SLinus Torvalds struct net_bridge *br = netdev_priv(dev); 10841da177e4SLinus Torvalds 108578a2d906SGreg Kroah-Hartman kobject_put(br->ifobj); 10861da177e4SLinus Torvalds sysfs_remove_bin_file(kobj, &bridge_forward); 10871da177e4SLinus Torvalds sysfs_remove_group(kobj, &bridge_group); 10881da177e4SLinus Torvalds } 1089