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, 33*9e781401SVladimir Oltean int (*set)(struct net_bridge *br, unsigned long val, 34*9e781401SVladimir Oltean struct netlink_ext_ack *extack)) 351da177e4SLinus Torvalds { 3643cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 37*9e781401SVladimir Oltean struct netlink_ext_ack extack = {0}; 381da177e4SLinus Torvalds unsigned long val; 39*9e781401SVladimir Oltean char *endp; 408d4698f7SStephen Hemminger int err; 411da177e4SLinus Torvalds 42cb990503SEric W. Biederman if (!ns_capable(dev_net(br->dev)->user_ns, CAP_NET_ADMIN)) 431da177e4SLinus Torvalds return -EPERM; 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds val = simple_strtoul(buf, &endp, 0); 461da177e4SLinus Torvalds if (endp == buf) 471da177e4SLinus Torvalds return -EINVAL; 481da177e4SLinus Torvalds 49047831a9SXin Long if (!rtnl_trylock()) 50047831a9SXin Long return restart_syscall(); 51047831a9SXin Long 52*9e781401SVladimir Oltean err = (*set)(br, val, &extack); 53047831a9SXin Long if (!err) 54047831a9SXin Long netdev_state_change(br->dev); 55*9e781401SVladimir Oltean if (extack._msg) { 56*9e781401SVladimir Oltean if (err) 57*9e781401SVladimir Oltean br_err(br, "%s\n", extack._msg); 58*9e781401SVladimir Oltean else 59*9e781401SVladimir Oltean br_warn(br, "%s\n", extack._msg); 60*9e781401SVladimir Oltean } 61047831a9SXin Long rtnl_unlock(); 62047831a9SXin Long 638d4698f7SStephen Hemminger return err ? err : len; 641da177e4SLinus Torvalds } 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds 67fbf2671bSsfeldma@cumulusnetworks.com static ssize_t forward_delay_show(struct device *d, 6843cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 691da177e4SLinus Torvalds { 7043cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 711da177e4SLinus Torvalds return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay)); 721da177e4SLinus Torvalds } 731da177e4SLinus Torvalds 74*9e781401SVladimir Oltean static int set_forward_delay(struct net_bridge *br, unsigned long val, 75*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 76*9e781401SVladimir Oltean { 77*9e781401SVladimir Oltean return br_set_forward_delay(br, val); 78*9e781401SVladimir Oltean } 79*9e781401SVladimir Oltean 80fbf2671bSsfeldma@cumulusnetworks.com static ssize_t forward_delay_store(struct device *d, 8143cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 8243cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 831da177e4SLinus Torvalds { 84*9e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_forward_delay); 851da177e4SLinus Torvalds } 86fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(forward_delay); 871da177e4SLinus Torvalds 88fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hello_time_show(struct device *d, struct device_attribute *attr, 8943cb76d9SGreg Kroah-Hartman char *buf) 901da177e4SLinus Torvalds { 911da177e4SLinus Torvalds return sprintf(buf, "%lu\n", 9243cb76d9SGreg Kroah-Hartman jiffies_to_clock_t(to_bridge(d)->hello_time)); 931da177e4SLinus Torvalds } 941da177e4SLinus Torvalds 95*9e781401SVladimir Oltean static int set_hello_time(struct net_bridge *br, unsigned long val, 96*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 97*9e781401SVladimir Oltean { 98*9e781401SVladimir Oltean return br_set_hello_time(br, val); 99*9e781401SVladimir Oltean } 100*9e781401SVladimir Oltean 101fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hello_time_store(struct device *d, 10243cb76d9SGreg Kroah-Hartman struct device_attribute *attr, const char *buf, 1031da177e4SLinus Torvalds size_t len) 1041da177e4SLinus Torvalds { 105*9e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_hello_time); 1061da177e4SLinus Torvalds } 107fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(hello_time); 1081da177e4SLinus Torvalds 109fbf2671bSsfeldma@cumulusnetworks.com static ssize_t max_age_show(struct device *d, struct device_attribute *attr, 11043cb76d9SGreg Kroah-Hartman char *buf) 1111da177e4SLinus Torvalds { 1121da177e4SLinus Torvalds return sprintf(buf, "%lu\n", 11343cb76d9SGreg Kroah-Hartman jiffies_to_clock_t(to_bridge(d)->max_age)); 1141da177e4SLinus Torvalds } 1151da177e4SLinus Torvalds 116*9e781401SVladimir Oltean static int set_max_age(struct net_bridge *br, unsigned long val, 117*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 118*9e781401SVladimir Oltean { 119*9e781401SVladimir Oltean return br_set_max_age(br, val); 120*9e781401SVladimir Oltean } 121*9e781401SVladimir Oltean 122fbf2671bSsfeldma@cumulusnetworks.com static ssize_t max_age_store(struct device *d, struct device_attribute *attr, 12343cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 1241da177e4SLinus Torvalds { 125*9e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_max_age); 1261da177e4SLinus Torvalds } 127fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(max_age); 1281da177e4SLinus Torvalds 129fbf2671bSsfeldma@cumulusnetworks.com static ssize_t ageing_time_show(struct device *d, 13043cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1311da177e4SLinus Torvalds { 13243cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 1331da177e4SLinus Torvalds return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time)); 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds 136*9e781401SVladimir Oltean static int set_ageing_time(struct net_bridge *br, unsigned long val, 137*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 1381da177e4SLinus Torvalds { 139047831a9SXin Long return br_set_ageing_time(br, val); 1401da177e4SLinus Torvalds } 1411da177e4SLinus Torvalds 142fbf2671bSsfeldma@cumulusnetworks.com static ssize_t ageing_time_store(struct device *d, 14343cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 14443cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 1451da177e4SLinus Torvalds { 14643cb76d9SGreg Kroah-Hartman return store_bridge_parm(d, buf, len, set_ageing_time); 1471da177e4SLinus Torvalds } 148fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(ageing_time); 14943cb76d9SGreg Kroah-Hartman 150fbf2671bSsfeldma@cumulusnetworks.com static ssize_t stp_state_show(struct device *d, 15143cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1521da177e4SLinus Torvalds { 15343cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 1541da177e4SLinus Torvalds return sprintf(buf, "%d\n", br->stp_enabled); 1551da177e4SLinus Torvalds } 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds 158*9e781401SVladimir Oltean static int set_stp_state(struct net_bridge *br, unsigned long val, 159*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 1601da177e4SLinus Torvalds { 161*9e781401SVladimir Oltean return br_stp_set_enabled(br, val, extack); 1624436156bSXin Long } 1634436156bSXin Long 1644436156bSXin Long static ssize_t stp_state_store(struct device *d, 1654436156bSXin Long struct device_attribute *attr, const char *buf, 1664436156bSXin Long size_t len) 1674436156bSXin Long { 1684436156bSXin Long return store_bridge_parm(d, buf, len, set_stp_state); 1691da177e4SLinus Torvalds } 170fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(stp_state); 1711da177e4SLinus Torvalds 172fbf2671bSsfeldma@cumulusnetworks.com static ssize_t group_fwd_mask_show(struct device *d, 173fbf2671bSsfeldma@cumulusnetworks.com struct device_attribute *attr, 174fbf2671bSsfeldma@cumulusnetworks.com char *buf) 175515853ccSstephen hemminger { 176515853ccSstephen hemminger struct net_bridge *br = to_bridge(d); 177515853ccSstephen hemminger return sprintf(buf, "%#x\n", br->group_fwd_mask); 178515853ccSstephen hemminger } 179515853ccSstephen hemminger 180*9e781401SVladimir Oltean static int set_group_fwd_mask(struct net_bridge *br, unsigned long val, 181*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 182347db6b4SXin Long { 183347db6b4SXin Long if (val & BR_GROUPFWD_RESTRICTED) 184347db6b4SXin Long return -EINVAL; 185347db6b4SXin Long 186347db6b4SXin Long br->group_fwd_mask = val; 187347db6b4SXin Long 188347db6b4SXin Long return 0; 189347db6b4SXin Long } 190515853ccSstephen hemminger 191fbf2671bSsfeldma@cumulusnetworks.com static ssize_t group_fwd_mask_store(struct device *d, 192fbf2671bSsfeldma@cumulusnetworks.com struct device_attribute *attr, 193fbf2671bSsfeldma@cumulusnetworks.com const char *buf, 194515853ccSstephen hemminger size_t len) 195515853ccSstephen hemminger { 196347db6b4SXin Long return store_bridge_parm(d, buf, len, set_group_fwd_mask); 197515853ccSstephen hemminger } 198fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(group_fwd_mask); 199515853ccSstephen hemminger 200fbf2671bSsfeldma@cumulusnetworks.com static ssize_t priority_show(struct device *d, struct device_attribute *attr, 20143cb76d9SGreg Kroah-Hartman char *buf) 2021da177e4SLinus Torvalds { 20343cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 2041da177e4SLinus Torvalds return sprintf(buf, "%d\n", 2051da177e4SLinus Torvalds (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]); 2061da177e4SLinus Torvalds } 2071da177e4SLinus Torvalds 208*9e781401SVladimir Oltean static int set_priority(struct net_bridge *br, unsigned long val, 209*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 2101da177e4SLinus Torvalds { 2111da177e4SLinus Torvalds br_stp_set_bridge_priority(br, (u16) val); 2128d4698f7SStephen Hemminger return 0; 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 215fbf2671bSsfeldma@cumulusnetworks.com static ssize_t priority_store(struct device *d, struct device_attribute *attr, 2161da177e4SLinus Torvalds const char *buf, size_t len) 2171da177e4SLinus Torvalds { 21843cb76d9SGreg Kroah-Hartman return store_bridge_parm(d, buf, len, set_priority); 2191da177e4SLinus Torvalds } 220fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(priority); 2211da177e4SLinus Torvalds 222fbf2671bSsfeldma@cumulusnetworks.com static ssize_t root_id_show(struct device *d, struct device_attribute *attr, 22343cb76d9SGreg Kroah-Hartman char *buf) 2241da177e4SLinus Torvalds { 22543cb76d9SGreg Kroah-Hartman return br_show_bridge_id(buf, &to_bridge(d)->designated_root); 2261da177e4SLinus Torvalds } 227fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(root_id); 2281da177e4SLinus Torvalds 229fbf2671bSsfeldma@cumulusnetworks.com static ssize_t bridge_id_show(struct device *d, struct device_attribute *attr, 23043cb76d9SGreg Kroah-Hartman char *buf) 2311da177e4SLinus Torvalds { 23243cb76d9SGreg Kroah-Hartman return br_show_bridge_id(buf, &to_bridge(d)->bridge_id); 2331da177e4SLinus Torvalds } 234fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(bridge_id); 2351da177e4SLinus Torvalds 236fbf2671bSsfeldma@cumulusnetworks.com static ssize_t root_port_show(struct device *d, struct device_attribute *attr, 23743cb76d9SGreg Kroah-Hartman char *buf) 2381da177e4SLinus Torvalds { 23943cb76d9SGreg Kroah-Hartman return sprintf(buf, "%d\n", to_bridge(d)->root_port); 2401da177e4SLinus Torvalds } 241fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(root_port); 2421da177e4SLinus Torvalds 243fbf2671bSsfeldma@cumulusnetworks.com static ssize_t root_path_cost_show(struct device *d, 24443cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 2451da177e4SLinus Torvalds { 24643cb76d9SGreg Kroah-Hartman return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost); 2471da177e4SLinus Torvalds } 248fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(root_path_cost); 2491da177e4SLinus Torvalds 250fbf2671bSsfeldma@cumulusnetworks.com static ssize_t topology_change_show(struct device *d, 25143cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 2521da177e4SLinus Torvalds { 25343cb76d9SGreg Kroah-Hartman return sprintf(buf, "%d\n", to_bridge(d)->topology_change); 2541da177e4SLinus Torvalds } 255fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(topology_change); 2561da177e4SLinus Torvalds 257fbf2671bSsfeldma@cumulusnetworks.com static ssize_t topology_change_detected_show(struct device *d, 25843cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 25943cb76d9SGreg Kroah-Hartman char *buf) 2601da177e4SLinus Torvalds { 26143cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 2621da177e4SLinus Torvalds return sprintf(buf, "%d\n", br->topology_change_detected); 2631da177e4SLinus Torvalds } 264fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(topology_change_detected); 2651da177e4SLinus Torvalds 266fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hello_timer_show(struct device *d, 26743cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 2681da177e4SLinus Torvalds { 26943cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 2701da177e4SLinus Torvalds return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer)); 2711da177e4SLinus Torvalds } 272fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(hello_timer); 2731da177e4SLinus Torvalds 274fbf2671bSsfeldma@cumulusnetworks.com static ssize_t tcn_timer_show(struct device *d, struct device_attribute *attr, 27543cb76d9SGreg Kroah-Hartman char *buf) 2761da177e4SLinus Torvalds { 27743cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 2781da177e4SLinus Torvalds return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer)); 2791da177e4SLinus Torvalds } 280fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(tcn_timer); 2811da177e4SLinus Torvalds 282fbf2671bSsfeldma@cumulusnetworks.com static ssize_t topology_change_timer_show(struct device *d, 28343cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 28443cb76d9SGreg Kroah-Hartman char *buf) 2851da177e4SLinus Torvalds { 28643cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 2871da177e4SLinus Torvalds return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer)); 2881da177e4SLinus Torvalds } 289fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(topology_change_timer); 2901da177e4SLinus Torvalds 291fbf2671bSsfeldma@cumulusnetworks.com static ssize_t gc_timer_show(struct device *d, struct device_attribute *attr, 29243cb76d9SGreg Kroah-Hartman char *buf) 2931da177e4SLinus Torvalds { 29443cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 295f7cdee8aSNikolay Aleksandrov return sprintf(buf, "%ld\n", br_timer_value(&br->gc_work.timer)); 2961da177e4SLinus Torvalds } 297fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RO(gc_timer); 2981da177e4SLinus Torvalds 299fbf2671bSsfeldma@cumulusnetworks.com static ssize_t group_addr_show(struct device *d, 30043cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 301fda93d92SStephen Hemminger { 30243cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 303223b229bSAndy Shevchenko return sprintf(buf, "%pM\n", br->group_addr); 304fda93d92SStephen Hemminger } 305fda93d92SStephen Hemminger 306fbf2671bSsfeldma@cumulusnetworks.com static ssize_t group_addr_store(struct device *d, 30743cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 30843cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 309fda93d92SStephen Hemminger { 31043cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(d); 3114197f24bSBen Hutchings u8 new_addr[6]; 312fda93d92SStephen Hemminger 313cb990503SEric W. Biederman if (!ns_capable(dev_net(br->dev)->user_ns, CAP_NET_ADMIN)) 314fda93d92SStephen Hemminger return -EPERM; 315fda93d92SStephen Hemminger 316223b229bSAndy Shevchenko if (!mac_pton(buf, new_addr)) 317fda93d92SStephen Hemminger return -EINVAL; 318fda93d92SStephen Hemminger 31946acc460SBen Hutchings if (!is_link_local_ether_addr(new_addr)) 320fda93d92SStephen Hemminger return -EINVAL; 321fda93d92SStephen Hemminger 322f64f9e71SJoe Perches if (new_addr[5] == 1 || /* 802.3x Pause address */ 323f64f9e71SJoe Perches new_addr[5] == 2 || /* 802.3ad Slow protocols */ 324f64f9e71SJoe Perches new_addr[5] == 3) /* 802.1X PAE address */ 325fda93d92SStephen Hemminger return -EINVAL; 326fda93d92SStephen Hemminger 327204177f3SToshiaki Makita if (!rtnl_trylock()) 328204177f3SToshiaki Makita return restart_syscall(); 329204177f3SToshiaki Makita 330fda93d92SStephen Hemminger spin_lock_bh(&br->lock); 331223b229bSAndy Shevchenko ether_addr_copy(br->group_addr, new_addr); 332fda93d92SStephen Hemminger spin_unlock_bh(&br->lock); 333204177f3SToshiaki Makita 334be3664a0SNikolay Aleksandrov br_opt_toggle(br, BROPT_GROUP_ADDR_SET, true); 335204177f3SToshiaki Makita br_recalculate_fwd_mask(br); 336047831a9SXin Long netdev_state_change(br->dev); 337204177f3SToshiaki Makita 338204177f3SToshiaki Makita rtnl_unlock(); 339204177f3SToshiaki Makita 340fda93d92SStephen Hemminger return len; 341fda93d92SStephen Hemminger } 342fda93d92SStephen Hemminger 343fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(group_addr); 344fda93d92SStephen Hemminger 345*9e781401SVladimir Oltean static int set_flush(struct net_bridge *br, unsigned long val, 346*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 34714f31bb3SXin Long { 34814f31bb3SXin Long br_fdb_flush(br); 34914f31bb3SXin Long return 0; 35014f31bb3SXin Long } 35114f31bb3SXin Long 352fbf2671bSsfeldma@cumulusnetworks.com static ssize_t flush_store(struct device *d, 3539cf63747SStephen Hemminger struct device_attribute *attr, 3549cf63747SStephen Hemminger const char *buf, size_t len) 3559cf63747SStephen Hemminger { 35614f31bb3SXin Long return store_bridge_parm(d, buf, len, set_flush); 3579cf63747SStephen Hemminger } 358fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_WO(flush); 359fda93d92SStephen Hemminger 36070e4272bSNikolay Aleksandrov static ssize_t no_linklocal_learn_show(struct device *d, 36170e4272bSNikolay Aleksandrov struct device_attribute *attr, 36270e4272bSNikolay Aleksandrov char *buf) 36370e4272bSNikolay Aleksandrov { 36470e4272bSNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 36570e4272bSNikolay Aleksandrov return sprintf(buf, "%d\n", br_boolopt_get(br, BR_BOOLOPT_NO_LL_LEARN)); 36670e4272bSNikolay Aleksandrov } 36770e4272bSNikolay Aleksandrov 368*9e781401SVladimir Oltean static int set_no_linklocal_learn(struct net_bridge *br, unsigned long val, 369*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 37070e4272bSNikolay Aleksandrov { 371*9e781401SVladimir Oltean return br_boolopt_toggle(br, BR_BOOLOPT_NO_LL_LEARN, !!val, extack); 37270e4272bSNikolay Aleksandrov } 37370e4272bSNikolay Aleksandrov 37470e4272bSNikolay Aleksandrov static ssize_t no_linklocal_learn_store(struct device *d, 37570e4272bSNikolay Aleksandrov struct device_attribute *attr, 37670e4272bSNikolay Aleksandrov const char *buf, size_t len) 37770e4272bSNikolay Aleksandrov { 37870e4272bSNikolay Aleksandrov return store_bridge_parm(d, buf, len, set_no_linklocal_learn); 37970e4272bSNikolay Aleksandrov } 38070e4272bSNikolay Aleksandrov static DEVICE_ATTR_RW(no_linklocal_learn); 38170e4272bSNikolay Aleksandrov 3820909e117SHerbert Xu #ifdef CONFIG_BRIDGE_IGMP_SNOOPING 383fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_router_show(struct device *d, 3840909e117SHerbert Xu struct device_attribute *attr, char *buf) 3850909e117SHerbert Xu { 3860909e117SHerbert Xu struct net_bridge *br = to_bridge(d); 3870909e117SHerbert Xu return sprintf(buf, "%d\n", br->multicast_router); 3880909e117SHerbert Xu } 3890909e117SHerbert Xu 390*9e781401SVladimir Oltean static int set_multicast_router(struct net_bridge *br, unsigned long val, 391*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 392*9e781401SVladimir Oltean { 393*9e781401SVladimir Oltean return br_multicast_set_router(br, val); 394*9e781401SVladimir Oltean } 395*9e781401SVladimir Oltean 396fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_router_store(struct device *d, 3970909e117SHerbert Xu struct device_attribute *attr, 3980909e117SHerbert Xu const char *buf, size_t len) 3990909e117SHerbert Xu { 400*9e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_multicast_router); 4010909e117SHerbert Xu } 402fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_router); 403561f1103SHerbert Xu 404fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_snooping_show(struct device *d, 405561f1103SHerbert Xu struct device_attribute *attr, 406561f1103SHerbert Xu char *buf) 407561f1103SHerbert Xu { 408561f1103SHerbert Xu struct net_bridge *br = to_bridge(d); 40913cefad2SNikolay Aleksandrov return sprintf(buf, "%d\n", br_opt_get(br, BROPT_MULTICAST_ENABLED)); 410561f1103SHerbert Xu } 411561f1103SHerbert Xu 412*9e781401SVladimir Oltean static int toggle_multicast(struct net_bridge *br, unsigned long val, 413*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 414*9e781401SVladimir Oltean { 415*9e781401SVladimir Oltean return br_multicast_toggle(br, val); 416*9e781401SVladimir Oltean } 417*9e781401SVladimir Oltean 418fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_snooping_store(struct device *d, 419561f1103SHerbert Xu struct device_attribute *attr, 420561f1103SHerbert Xu const char *buf, size_t len) 421561f1103SHerbert Xu { 422*9e781401SVladimir Oltean return store_bridge_parm(d, buf, len, toggle_multicast); 423561f1103SHerbert Xu } 424fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_snooping); 425b195167fSHerbert Xu 426fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_query_use_ifaddr_show(struct device *d, 4271c8ad5bfSCong Wang struct device_attribute *attr, 4281c8ad5bfSCong Wang char *buf) 4291c8ad5bfSCong Wang { 4301c8ad5bfSCong Wang struct net_bridge *br = to_bridge(d); 431675779adSNikolay Aleksandrov return sprintf(buf, "%d\n", 432675779adSNikolay Aleksandrov br_opt_get(br, BROPT_MULTICAST_QUERY_USE_IFADDR)); 4331c8ad5bfSCong Wang } 4341c8ad5bfSCong Wang 435*9e781401SVladimir Oltean static int set_query_use_ifaddr(struct net_bridge *br, unsigned long val, 436*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 4371c8ad5bfSCong Wang { 438675779adSNikolay Aleksandrov br_opt_toggle(br, BROPT_MULTICAST_QUERY_USE_IFADDR, !!val); 4391c8ad5bfSCong Wang return 0; 4401c8ad5bfSCong Wang } 4411c8ad5bfSCong Wang 4421c8ad5bfSCong Wang static ssize_t 443fbf2671bSsfeldma@cumulusnetworks.com multicast_query_use_ifaddr_store(struct device *d, 4441c8ad5bfSCong Wang struct device_attribute *attr, 4451c8ad5bfSCong Wang const char *buf, size_t len) 4461c8ad5bfSCong Wang { 4471c8ad5bfSCong Wang return store_bridge_parm(d, buf, len, set_query_use_ifaddr); 4481c8ad5bfSCong Wang } 449fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_query_use_ifaddr); 4501c8ad5bfSCong Wang 451fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_querier_show(struct device *d, 452c5c23260SHerbert Xu struct device_attribute *attr, 453c5c23260SHerbert Xu char *buf) 454c5c23260SHerbert Xu { 455c5c23260SHerbert Xu struct net_bridge *br = to_bridge(d); 456675779adSNikolay Aleksandrov return sprintf(buf, "%d\n", br_opt_get(br, BROPT_MULTICAST_QUERIER)); 457c5c23260SHerbert Xu } 458c5c23260SHerbert Xu 459*9e781401SVladimir Oltean static int set_multicast_querier(struct net_bridge *br, unsigned long val, 460*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 461*9e781401SVladimir Oltean { 462*9e781401SVladimir Oltean return br_multicast_set_querier(br, val); 463*9e781401SVladimir Oltean } 464*9e781401SVladimir Oltean 465fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_querier_store(struct device *d, 466c5c23260SHerbert Xu struct device_attribute *attr, 467c5c23260SHerbert Xu const char *buf, size_t len) 468c5c23260SHerbert Xu { 469*9e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_multicast_querier); 470c5c23260SHerbert Xu } 471fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_querier); 472c5c23260SHerbert Xu 473fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hash_elasticity_show(struct device *d, 474b195167fSHerbert Xu struct device_attribute *attr, char *buf) 475b195167fSHerbert Xu { 476cf332bcaSNikolay Aleksandrov return sprintf(buf, "%u\n", RHT_ELASTICITY); 477b195167fSHerbert Xu } 478b195167fSHerbert Xu 479*9e781401SVladimir Oltean static int set_elasticity(struct net_bridge *br, unsigned long val, 480*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 481b195167fSHerbert Xu { 482*9e781401SVladimir Oltean /* 16 is RHT_ELASTICITY */ 483*9e781401SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 484*9e781401SVladimir Oltean "the hash_elasticity option has been deprecated and is always 16"); 485b195167fSHerbert Xu return 0; 486b195167fSHerbert Xu } 487b195167fSHerbert Xu 488fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hash_elasticity_store(struct device *d, 489b195167fSHerbert Xu struct device_attribute *attr, 490b195167fSHerbert Xu const char *buf, size_t len) 491b195167fSHerbert Xu { 492b195167fSHerbert Xu return store_bridge_parm(d, buf, len, set_elasticity); 493b195167fSHerbert Xu } 494fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(hash_elasticity); 495b195167fSHerbert Xu 496fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hash_max_show(struct device *d, struct device_attribute *attr, 497b195167fSHerbert Xu char *buf) 498b195167fSHerbert Xu { 499b195167fSHerbert Xu struct net_bridge *br = to_bridge(d); 500b195167fSHerbert Xu return sprintf(buf, "%u\n", br->hash_max); 501b195167fSHerbert Xu } 502b195167fSHerbert Xu 503*9e781401SVladimir Oltean static int set_hash_max(struct net_bridge *br, unsigned long val, 504*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 50519e3a9c9SNikolay Aleksandrov { 50619e3a9c9SNikolay Aleksandrov br->hash_max = val; 50719e3a9c9SNikolay Aleksandrov return 0; 50819e3a9c9SNikolay Aleksandrov } 50919e3a9c9SNikolay Aleksandrov 510fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hash_max_store(struct device *d, struct device_attribute *attr, 511b195167fSHerbert Xu const char *buf, size_t len) 512b195167fSHerbert Xu { 51319e3a9c9SNikolay Aleksandrov return store_bridge_parm(d, buf, len, set_hash_max); 514b195167fSHerbert Xu } 515fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(hash_max); 516d902eee4SHerbert Xu 5175e923585SNikolay Aleksandrov static ssize_t multicast_igmp_version_show(struct device *d, 5185e923585SNikolay Aleksandrov struct device_attribute *attr, 5195e923585SNikolay Aleksandrov char *buf) 5205e923585SNikolay Aleksandrov { 5215e923585SNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 5225e923585SNikolay Aleksandrov 5235e923585SNikolay Aleksandrov return sprintf(buf, "%u\n", br->multicast_igmp_version); 5245e923585SNikolay Aleksandrov } 5255e923585SNikolay Aleksandrov 526*9e781401SVladimir Oltean static int set_multicast_igmp_version(struct net_bridge *br, unsigned long val, 527*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 528*9e781401SVladimir Oltean { 529*9e781401SVladimir Oltean return br_multicast_set_igmp_version(br, val); 530*9e781401SVladimir Oltean } 531*9e781401SVladimir Oltean 5325e923585SNikolay Aleksandrov static ssize_t multicast_igmp_version_store(struct device *d, 5335e923585SNikolay Aleksandrov struct device_attribute *attr, 5345e923585SNikolay Aleksandrov const char *buf, size_t len) 5355e923585SNikolay Aleksandrov { 536*9e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_multicast_igmp_version); 5375e923585SNikolay Aleksandrov } 5385e923585SNikolay Aleksandrov static DEVICE_ATTR_RW(multicast_igmp_version); 5395e923585SNikolay Aleksandrov 540fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_last_member_count_show(struct device *d, 541d902eee4SHerbert Xu struct device_attribute *attr, 542d902eee4SHerbert Xu char *buf) 543d902eee4SHerbert Xu { 544d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 545d902eee4SHerbert Xu return sprintf(buf, "%u\n", br->multicast_last_member_count); 546d902eee4SHerbert Xu } 547d902eee4SHerbert Xu 548*9e781401SVladimir Oltean static int set_last_member_count(struct net_bridge *br, unsigned long val, 549*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 550d902eee4SHerbert Xu { 551d902eee4SHerbert Xu br->multicast_last_member_count = val; 552d902eee4SHerbert Xu return 0; 553d902eee4SHerbert Xu } 554d902eee4SHerbert Xu 555fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_last_member_count_store(struct device *d, 556d902eee4SHerbert Xu struct device_attribute *attr, 557d902eee4SHerbert Xu const char *buf, size_t len) 558d902eee4SHerbert Xu { 559d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_last_member_count); 560d902eee4SHerbert Xu } 561fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_last_member_count); 562d902eee4SHerbert Xu 563fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_startup_query_count_show( 564d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, char *buf) 565d902eee4SHerbert Xu { 566d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 567d902eee4SHerbert Xu return sprintf(buf, "%u\n", br->multicast_startup_query_count); 568d902eee4SHerbert Xu } 569d902eee4SHerbert Xu 570*9e781401SVladimir Oltean static int set_startup_query_count(struct net_bridge *br, unsigned long val, 571*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 572d902eee4SHerbert Xu { 573d902eee4SHerbert Xu br->multicast_startup_query_count = val; 574d902eee4SHerbert Xu return 0; 575d902eee4SHerbert Xu } 576d902eee4SHerbert Xu 577fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_startup_query_count_store( 578d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, const char *buf, 579d902eee4SHerbert Xu size_t len) 580d902eee4SHerbert Xu { 581d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_startup_query_count); 582d902eee4SHerbert Xu } 583fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_startup_query_count); 584d902eee4SHerbert Xu 585fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_last_member_interval_show( 586d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, char *buf) 587d902eee4SHerbert Xu { 588d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 589d902eee4SHerbert Xu return sprintf(buf, "%lu\n", 590d902eee4SHerbert Xu jiffies_to_clock_t(br->multicast_last_member_interval)); 591d902eee4SHerbert Xu } 592d902eee4SHerbert Xu 593*9e781401SVladimir Oltean static int set_last_member_interval(struct net_bridge *br, unsigned long val, 594*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 595d902eee4SHerbert Xu { 596d902eee4SHerbert Xu br->multicast_last_member_interval = clock_t_to_jiffies(val); 597d902eee4SHerbert Xu return 0; 598d902eee4SHerbert Xu } 599d902eee4SHerbert Xu 600fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_last_member_interval_store( 601d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, const char *buf, 602d902eee4SHerbert Xu size_t len) 603d902eee4SHerbert Xu { 604d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_last_member_interval); 605d902eee4SHerbert Xu } 606fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_last_member_interval); 607d902eee4SHerbert Xu 608fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_membership_interval_show( 609d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, char *buf) 610d902eee4SHerbert Xu { 611d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 612d902eee4SHerbert Xu return sprintf(buf, "%lu\n", 613d902eee4SHerbert Xu jiffies_to_clock_t(br->multicast_membership_interval)); 614d902eee4SHerbert Xu } 615d902eee4SHerbert Xu 616*9e781401SVladimir Oltean static int set_membership_interval(struct net_bridge *br, unsigned long val, 617*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 618d902eee4SHerbert Xu { 619d902eee4SHerbert Xu br->multicast_membership_interval = clock_t_to_jiffies(val); 620d902eee4SHerbert Xu return 0; 621d902eee4SHerbert Xu } 622d902eee4SHerbert Xu 623fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_membership_interval_store( 624d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, const char *buf, 625d902eee4SHerbert Xu size_t len) 626d902eee4SHerbert Xu { 627d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_membership_interval); 628d902eee4SHerbert Xu } 629fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_membership_interval); 630d902eee4SHerbert Xu 631fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_querier_interval_show(struct device *d, 632d902eee4SHerbert Xu struct device_attribute *attr, 633d902eee4SHerbert Xu char *buf) 634d902eee4SHerbert Xu { 635d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 636d902eee4SHerbert Xu return sprintf(buf, "%lu\n", 637d902eee4SHerbert Xu jiffies_to_clock_t(br->multicast_querier_interval)); 638d902eee4SHerbert Xu } 639d902eee4SHerbert Xu 640*9e781401SVladimir Oltean static int set_querier_interval(struct net_bridge *br, unsigned long val, 641*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 642d902eee4SHerbert Xu { 643d902eee4SHerbert Xu br->multicast_querier_interval = clock_t_to_jiffies(val); 644d902eee4SHerbert Xu return 0; 645d902eee4SHerbert Xu } 646d902eee4SHerbert Xu 647fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_querier_interval_store(struct device *d, 648d902eee4SHerbert Xu struct device_attribute *attr, 649d902eee4SHerbert Xu const char *buf, size_t len) 650d902eee4SHerbert Xu { 651d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_querier_interval); 652d902eee4SHerbert Xu } 653fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_querier_interval); 654d902eee4SHerbert Xu 655fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_query_interval_show(struct device *d, 656d902eee4SHerbert Xu struct device_attribute *attr, 657d902eee4SHerbert Xu char *buf) 658d902eee4SHerbert Xu { 659d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 660d902eee4SHerbert Xu return sprintf(buf, "%lu\n", 661d902eee4SHerbert Xu jiffies_to_clock_t(br->multicast_query_interval)); 662d902eee4SHerbert Xu } 663d902eee4SHerbert Xu 664*9e781401SVladimir Oltean static int set_query_interval(struct net_bridge *br, unsigned long val, 665*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 666d902eee4SHerbert Xu { 667d902eee4SHerbert Xu br->multicast_query_interval = clock_t_to_jiffies(val); 668d902eee4SHerbert Xu return 0; 669d902eee4SHerbert Xu } 670d902eee4SHerbert Xu 671fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_query_interval_store(struct device *d, 672d902eee4SHerbert Xu struct device_attribute *attr, 673d902eee4SHerbert Xu const char *buf, size_t len) 674d902eee4SHerbert Xu { 675d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_query_interval); 676d902eee4SHerbert Xu } 677fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_query_interval); 678d902eee4SHerbert Xu 679fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_query_response_interval_show( 680d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, char *buf) 681d902eee4SHerbert Xu { 682d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 683d902eee4SHerbert Xu return sprintf( 684d902eee4SHerbert Xu buf, "%lu\n", 685d902eee4SHerbert Xu jiffies_to_clock_t(br->multicast_query_response_interval)); 686d902eee4SHerbert Xu } 687d902eee4SHerbert Xu 688*9e781401SVladimir Oltean static int set_query_response_interval(struct net_bridge *br, unsigned long val, 689*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 690d902eee4SHerbert Xu { 691d902eee4SHerbert Xu br->multicast_query_response_interval = clock_t_to_jiffies(val); 692d902eee4SHerbert Xu return 0; 693d902eee4SHerbert Xu } 694d902eee4SHerbert Xu 695fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_query_response_interval_store( 696d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, const char *buf, 697d902eee4SHerbert Xu size_t len) 698d902eee4SHerbert Xu { 699d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_query_response_interval); 700d902eee4SHerbert Xu } 701fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_query_response_interval); 702d902eee4SHerbert Xu 703fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_startup_query_interval_show( 704d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, char *buf) 705d902eee4SHerbert Xu { 706d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 707d902eee4SHerbert Xu return sprintf( 708d902eee4SHerbert Xu buf, "%lu\n", 709d902eee4SHerbert Xu jiffies_to_clock_t(br->multicast_startup_query_interval)); 710d902eee4SHerbert Xu } 711d902eee4SHerbert Xu 712*9e781401SVladimir Oltean static int set_startup_query_interval(struct net_bridge *br, unsigned long val, 713*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 714d902eee4SHerbert Xu { 715d902eee4SHerbert Xu br->multicast_startup_query_interval = clock_t_to_jiffies(val); 716d902eee4SHerbert Xu return 0; 717d902eee4SHerbert Xu } 718d902eee4SHerbert Xu 719fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_startup_query_interval_store( 720d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, const char *buf, 721d902eee4SHerbert Xu size_t len) 722d902eee4SHerbert Xu { 723d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_startup_query_interval); 724d902eee4SHerbert Xu } 725fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_startup_query_interval); 7261080ab95SNikolay Aleksandrov 7271080ab95SNikolay Aleksandrov static ssize_t multicast_stats_enabled_show(struct device *d, 7281080ab95SNikolay Aleksandrov struct device_attribute *attr, 7291080ab95SNikolay Aleksandrov char *buf) 7301080ab95SNikolay Aleksandrov { 7311080ab95SNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 7321080ab95SNikolay Aleksandrov 733675779adSNikolay Aleksandrov return sprintf(buf, "%d\n", 734675779adSNikolay Aleksandrov br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED)); 7351080ab95SNikolay Aleksandrov } 7361080ab95SNikolay Aleksandrov 737*9e781401SVladimir Oltean static int set_stats_enabled(struct net_bridge *br, unsigned long val, 738*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 7391080ab95SNikolay Aleksandrov { 740675779adSNikolay Aleksandrov br_opt_toggle(br, BROPT_MULTICAST_STATS_ENABLED, !!val); 7411080ab95SNikolay Aleksandrov return 0; 7421080ab95SNikolay Aleksandrov } 7431080ab95SNikolay Aleksandrov 7441080ab95SNikolay Aleksandrov static ssize_t multicast_stats_enabled_store(struct device *d, 7451080ab95SNikolay Aleksandrov struct device_attribute *attr, 7461080ab95SNikolay Aleksandrov const char *buf, 7471080ab95SNikolay Aleksandrov size_t len) 7481080ab95SNikolay Aleksandrov { 7491080ab95SNikolay Aleksandrov return store_bridge_parm(d, buf, len, set_stats_enabled); 7501080ab95SNikolay Aleksandrov } 7511080ab95SNikolay Aleksandrov static DEVICE_ATTR_RW(multicast_stats_enabled); 752aa2ae3e7SNikolay Aleksandrov 753aa2ae3e7SNikolay Aleksandrov #if IS_ENABLED(CONFIG_IPV6) 754aa2ae3e7SNikolay Aleksandrov static ssize_t multicast_mld_version_show(struct device *d, 755aa2ae3e7SNikolay Aleksandrov struct device_attribute *attr, 756aa2ae3e7SNikolay Aleksandrov char *buf) 757aa2ae3e7SNikolay Aleksandrov { 758aa2ae3e7SNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 759aa2ae3e7SNikolay Aleksandrov 760aa2ae3e7SNikolay Aleksandrov return sprintf(buf, "%u\n", br->multicast_mld_version); 761aa2ae3e7SNikolay Aleksandrov } 762aa2ae3e7SNikolay Aleksandrov 763*9e781401SVladimir Oltean static int set_multicast_mld_version(struct net_bridge *br, unsigned long val, 764*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 765*9e781401SVladimir Oltean { 766*9e781401SVladimir Oltean return br_multicast_set_mld_version(br, val); 767*9e781401SVladimir Oltean } 768*9e781401SVladimir Oltean 769aa2ae3e7SNikolay Aleksandrov static ssize_t multicast_mld_version_store(struct device *d, 770aa2ae3e7SNikolay Aleksandrov struct device_attribute *attr, 771aa2ae3e7SNikolay Aleksandrov const char *buf, size_t len) 772aa2ae3e7SNikolay Aleksandrov { 773*9e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_multicast_mld_version); 774aa2ae3e7SNikolay Aleksandrov } 775aa2ae3e7SNikolay Aleksandrov static DEVICE_ATTR_RW(multicast_mld_version); 776aa2ae3e7SNikolay Aleksandrov #endif 7770909e117SHerbert Xu #endif 77834666d46SPablo Neira Ayuso #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) 779fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_iptables_show( 7804df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, char *buf) 7814df53d8bSPatrick McHardy { 7824df53d8bSPatrick McHardy struct net_bridge *br = to_bridge(d); 7838df3510fSNikolay Aleksandrov return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_IPTABLES)); 7844df53d8bSPatrick McHardy } 7854df53d8bSPatrick McHardy 786*9e781401SVladimir Oltean static int set_nf_call_iptables(struct net_bridge *br, unsigned long val, 787*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 7884df53d8bSPatrick McHardy { 7898df3510fSNikolay Aleksandrov br_opt_toggle(br, BROPT_NF_CALL_IPTABLES, !!val); 7904df53d8bSPatrick McHardy return 0; 7914df53d8bSPatrick McHardy } 7924df53d8bSPatrick McHardy 793fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_iptables_store( 7944df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, const char *buf, 7954df53d8bSPatrick McHardy size_t len) 7964df53d8bSPatrick McHardy { 7974df53d8bSPatrick McHardy return store_bridge_parm(d, buf, len, set_nf_call_iptables); 7984df53d8bSPatrick McHardy } 799fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(nf_call_iptables); 8004df53d8bSPatrick McHardy 801fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_ip6tables_show( 8024df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, char *buf) 8034df53d8bSPatrick McHardy { 8044df53d8bSPatrick McHardy struct net_bridge *br = to_bridge(d); 8058df3510fSNikolay Aleksandrov return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_IP6TABLES)); 8064df53d8bSPatrick McHardy } 8074df53d8bSPatrick McHardy 808*9e781401SVladimir Oltean static int set_nf_call_ip6tables(struct net_bridge *br, unsigned long val, 809*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 8104df53d8bSPatrick McHardy { 8118df3510fSNikolay Aleksandrov br_opt_toggle(br, BROPT_NF_CALL_IP6TABLES, !!val); 8124df53d8bSPatrick McHardy return 0; 8134df53d8bSPatrick McHardy } 8144df53d8bSPatrick McHardy 815fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_ip6tables_store( 8164df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, const char *buf, 8174df53d8bSPatrick McHardy size_t len) 8184df53d8bSPatrick McHardy { 8194df53d8bSPatrick McHardy return store_bridge_parm(d, buf, len, set_nf_call_ip6tables); 8204df53d8bSPatrick McHardy } 821fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(nf_call_ip6tables); 8224df53d8bSPatrick McHardy 823fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_arptables_show( 8244df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, char *buf) 8254df53d8bSPatrick McHardy { 8264df53d8bSPatrick McHardy struct net_bridge *br = to_bridge(d); 8278df3510fSNikolay Aleksandrov return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_ARPTABLES)); 8284df53d8bSPatrick McHardy } 8294df53d8bSPatrick McHardy 830*9e781401SVladimir Oltean static int set_nf_call_arptables(struct net_bridge *br, unsigned long val, 831*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 8324df53d8bSPatrick McHardy { 8338df3510fSNikolay Aleksandrov br_opt_toggle(br, BROPT_NF_CALL_ARPTABLES, !!val); 8344df53d8bSPatrick McHardy return 0; 8354df53d8bSPatrick McHardy } 8364df53d8bSPatrick McHardy 837fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_arptables_store( 8384df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, const char *buf, 8394df53d8bSPatrick McHardy size_t len) 8404df53d8bSPatrick McHardy { 8414df53d8bSPatrick McHardy return store_bridge_parm(d, buf, len, set_nf_call_arptables); 8424df53d8bSPatrick McHardy } 843fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(nf_call_arptables); 8444df53d8bSPatrick McHardy #endif 845243a2e63SVlad Yasevich #ifdef CONFIG_BRIDGE_VLAN_FILTERING 846fbf2671bSsfeldma@cumulusnetworks.com static ssize_t vlan_filtering_show(struct device *d, 847243a2e63SVlad Yasevich struct device_attribute *attr, 848243a2e63SVlad Yasevich char *buf) 849243a2e63SVlad Yasevich { 850243a2e63SVlad Yasevich struct net_bridge *br = to_bridge(d); 851ae75767eSNikolay Aleksandrov return sprintf(buf, "%d\n", br_opt_get(br, BROPT_VLAN_ENABLED)); 852243a2e63SVlad Yasevich } 853243a2e63SVlad Yasevich 854fbf2671bSsfeldma@cumulusnetworks.com static ssize_t vlan_filtering_store(struct device *d, 855243a2e63SVlad Yasevich struct device_attribute *attr, 856243a2e63SVlad Yasevich const char *buf, size_t len) 857243a2e63SVlad Yasevich { 858243a2e63SVlad Yasevich return store_bridge_parm(d, buf, len, br_vlan_filter_toggle); 859243a2e63SVlad Yasevich } 860fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(vlan_filtering); 861204177f3SToshiaki Makita 862204177f3SToshiaki Makita static ssize_t vlan_protocol_show(struct device *d, 863204177f3SToshiaki Makita struct device_attribute *attr, 864204177f3SToshiaki Makita char *buf) 865204177f3SToshiaki Makita { 866204177f3SToshiaki Makita struct net_bridge *br = to_bridge(d); 867204177f3SToshiaki Makita return sprintf(buf, "%#06x\n", ntohs(br->vlan_proto)); 868204177f3SToshiaki Makita } 869204177f3SToshiaki Makita 870204177f3SToshiaki Makita static ssize_t vlan_protocol_store(struct device *d, 871204177f3SToshiaki Makita struct device_attribute *attr, 872204177f3SToshiaki Makita const char *buf, size_t len) 873204177f3SToshiaki Makita { 874204177f3SToshiaki Makita return store_bridge_parm(d, buf, len, br_vlan_set_proto); 875204177f3SToshiaki Makita } 876204177f3SToshiaki Makita static DEVICE_ATTR_RW(vlan_protocol); 87796a20d9dSVlad Yasevich 87896a20d9dSVlad Yasevich static ssize_t default_pvid_show(struct device *d, 87996a20d9dSVlad Yasevich struct device_attribute *attr, 88096a20d9dSVlad Yasevich char *buf) 88196a20d9dSVlad Yasevich { 88296a20d9dSVlad Yasevich struct net_bridge *br = to_bridge(d); 88396a20d9dSVlad Yasevich return sprintf(buf, "%d\n", br->default_pvid); 88496a20d9dSVlad Yasevich } 88596a20d9dSVlad Yasevich 88696a20d9dSVlad Yasevich static ssize_t default_pvid_store(struct device *d, 88796a20d9dSVlad Yasevich struct device_attribute *attr, 88896a20d9dSVlad Yasevich const char *buf, size_t len) 88996a20d9dSVlad Yasevich { 89096a20d9dSVlad Yasevich return store_bridge_parm(d, buf, len, br_vlan_set_default_pvid); 89196a20d9dSVlad Yasevich } 89296a20d9dSVlad Yasevich static DEVICE_ATTR_RW(default_pvid); 8936dada9b1SNikolay Aleksandrov 8946dada9b1SNikolay Aleksandrov static ssize_t vlan_stats_enabled_show(struct device *d, 8956dada9b1SNikolay Aleksandrov struct device_attribute *attr, 8966dada9b1SNikolay Aleksandrov char *buf) 8976dada9b1SNikolay Aleksandrov { 8986dada9b1SNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 899ae75767eSNikolay Aleksandrov return sprintf(buf, "%u\n", br_opt_get(br, BROPT_VLAN_STATS_ENABLED)); 9006dada9b1SNikolay Aleksandrov } 9016dada9b1SNikolay Aleksandrov 902*9e781401SVladimir Oltean static int set_vlan_stats_enabled(struct net_bridge *br, unsigned long val, 903*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 904*9e781401SVladimir Oltean { 905*9e781401SVladimir Oltean return br_vlan_set_stats(br, val); 906*9e781401SVladimir Oltean } 907*9e781401SVladimir Oltean 9086dada9b1SNikolay Aleksandrov static ssize_t vlan_stats_enabled_store(struct device *d, 9096dada9b1SNikolay Aleksandrov struct device_attribute *attr, 9106dada9b1SNikolay Aleksandrov const char *buf, size_t len) 9116dada9b1SNikolay Aleksandrov { 912*9e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_vlan_stats_enabled); 9136dada9b1SNikolay Aleksandrov } 9146dada9b1SNikolay Aleksandrov static DEVICE_ATTR_RW(vlan_stats_enabled); 9159163a0fcSNikolay Aleksandrov 9169163a0fcSNikolay Aleksandrov static ssize_t vlan_stats_per_port_show(struct device *d, 9179163a0fcSNikolay Aleksandrov struct device_attribute *attr, 9189163a0fcSNikolay Aleksandrov char *buf) 9199163a0fcSNikolay Aleksandrov { 9209163a0fcSNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 9219163a0fcSNikolay Aleksandrov return sprintf(buf, "%u\n", br_opt_get(br, BROPT_VLAN_STATS_PER_PORT)); 9229163a0fcSNikolay Aleksandrov } 9239163a0fcSNikolay Aleksandrov 924*9e781401SVladimir Oltean static int set_vlan_stats_per_port(struct net_bridge *br, unsigned long val, 925*9e781401SVladimir Oltean struct netlink_ext_ack *extack) 926*9e781401SVladimir Oltean { 927*9e781401SVladimir Oltean return br_vlan_set_stats_per_port(br, val); 928*9e781401SVladimir Oltean } 929*9e781401SVladimir Oltean 9309163a0fcSNikolay Aleksandrov static ssize_t vlan_stats_per_port_store(struct device *d, 9319163a0fcSNikolay Aleksandrov struct device_attribute *attr, 9329163a0fcSNikolay Aleksandrov const char *buf, size_t len) 9339163a0fcSNikolay Aleksandrov { 934*9e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_vlan_stats_per_port); 9359163a0fcSNikolay Aleksandrov } 9369163a0fcSNikolay Aleksandrov static DEVICE_ATTR_RW(vlan_stats_per_port); 937243a2e63SVlad Yasevich #endif 9380909e117SHerbert Xu 9391da177e4SLinus Torvalds static struct attribute *bridge_attrs[] = { 94043cb76d9SGreg Kroah-Hartman &dev_attr_forward_delay.attr, 94143cb76d9SGreg Kroah-Hartman &dev_attr_hello_time.attr, 94243cb76d9SGreg Kroah-Hartman &dev_attr_max_age.attr, 94343cb76d9SGreg Kroah-Hartman &dev_attr_ageing_time.attr, 94443cb76d9SGreg Kroah-Hartman &dev_attr_stp_state.attr, 945515853ccSstephen hemminger &dev_attr_group_fwd_mask.attr, 94643cb76d9SGreg Kroah-Hartman &dev_attr_priority.attr, 94743cb76d9SGreg Kroah-Hartman &dev_attr_bridge_id.attr, 94843cb76d9SGreg Kroah-Hartman &dev_attr_root_id.attr, 94943cb76d9SGreg Kroah-Hartman &dev_attr_root_path_cost.attr, 95043cb76d9SGreg Kroah-Hartman &dev_attr_root_port.attr, 95143cb76d9SGreg Kroah-Hartman &dev_attr_topology_change.attr, 95243cb76d9SGreg Kroah-Hartman &dev_attr_topology_change_detected.attr, 95343cb76d9SGreg Kroah-Hartman &dev_attr_hello_timer.attr, 95443cb76d9SGreg Kroah-Hartman &dev_attr_tcn_timer.attr, 95543cb76d9SGreg Kroah-Hartman &dev_attr_topology_change_timer.attr, 95643cb76d9SGreg Kroah-Hartman &dev_attr_gc_timer.attr, 95743cb76d9SGreg Kroah-Hartman &dev_attr_group_addr.attr, 9589cf63747SStephen Hemminger &dev_attr_flush.attr, 95970e4272bSNikolay Aleksandrov &dev_attr_no_linklocal_learn.attr, 9600909e117SHerbert Xu #ifdef CONFIG_BRIDGE_IGMP_SNOOPING 9610909e117SHerbert Xu &dev_attr_multicast_router.attr, 962561f1103SHerbert Xu &dev_attr_multicast_snooping.attr, 963c5c23260SHerbert Xu &dev_attr_multicast_querier.attr, 9641c8ad5bfSCong Wang &dev_attr_multicast_query_use_ifaddr.attr, 965b195167fSHerbert Xu &dev_attr_hash_elasticity.attr, 966b195167fSHerbert Xu &dev_attr_hash_max.attr, 967d902eee4SHerbert Xu &dev_attr_multicast_last_member_count.attr, 968d902eee4SHerbert Xu &dev_attr_multicast_startup_query_count.attr, 969d902eee4SHerbert Xu &dev_attr_multicast_last_member_interval.attr, 970d902eee4SHerbert Xu &dev_attr_multicast_membership_interval.attr, 971d902eee4SHerbert Xu &dev_attr_multicast_querier_interval.attr, 972d902eee4SHerbert Xu &dev_attr_multicast_query_interval.attr, 973d902eee4SHerbert Xu &dev_attr_multicast_query_response_interval.attr, 974d902eee4SHerbert Xu &dev_attr_multicast_startup_query_interval.attr, 9751080ab95SNikolay Aleksandrov &dev_attr_multicast_stats_enabled.attr, 9765e923585SNikolay Aleksandrov &dev_attr_multicast_igmp_version.attr, 977aa2ae3e7SNikolay Aleksandrov #if IS_ENABLED(CONFIG_IPV6) 978aa2ae3e7SNikolay Aleksandrov &dev_attr_multicast_mld_version.attr, 979aa2ae3e7SNikolay Aleksandrov #endif 9800909e117SHerbert Xu #endif 98134666d46SPablo Neira Ayuso #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) 9824df53d8bSPatrick McHardy &dev_attr_nf_call_iptables.attr, 9834df53d8bSPatrick McHardy &dev_attr_nf_call_ip6tables.attr, 9844df53d8bSPatrick McHardy &dev_attr_nf_call_arptables.attr, 9854df53d8bSPatrick McHardy #endif 986243a2e63SVlad Yasevich #ifdef CONFIG_BRIDGE_VLAN_FILTERING 987243a2e63SVlad Yasevich &dev_attr_vlan_filtering.attr, 988204177f3SToshiaki Makita &dev_attr_vlan_protocol.attr, 98996a20d9dSVlad Yasevich &dev_attr_default_pvid.attr, 9906dada9b1SNikolay Aleksandrov &dev_attr_vlan_stats_enabled.attr, 9919163a0fcSNikolay Aleksandrov &dev_attr_vlan_stats_per_port.attr, 992243a2e63SVlad Yasevich #endif 9931da177e4SLinus Torvalds NULL 9941da177e4SLinus Torvalds }; 9951da177e4SLinus Torvalds 996cddbb79fSArvind Yadav static const struct attribute_group bridge_group = { 9971da177e4SLinus Torvalds .name = SYSFS_BRIDGE_ATTR, 9981da177e4SLinus Torvalds .attrs = bridge_attrs, 9991da177e4SLinus Torvalds }; 10001da177e4SLinus Torvalds 10011da177e4SLinus Torvalds /* 10021da177e4SLinus Torvalds * Export the forwarding information table as a binary file 10031da177e4SLinus Torvalds * The records are struct __fdb_entry. 10041da177e4SLinus Torvalds * 10051da177e4SLinus Torvalds * Returns the number of bytes read. 10061da177e4SLinus Torvalds */ 10072c3c8beaSChris Wright static ssize_t brforward_read(struct file *filp, struct kobject *kobj, 100891a69029SZhang Rui struct bin_attribute *bin_attr, 100991a69029SZhang Rui char *buf, loff_t off, size_t count) 10101da177e4SLinus Torvalds { 1011aeb7ed14SGeliang Tang struct device *dev = kobj_to_dev(kobj); 101243cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(dev); 10131da177e4SLinus Torvalds int n; 10141da177e4SLinus Torvalds 10151da177e4SLinus Torvalds /* must read whole records */ 10161da177e4SLinus Torvalds if (off % sizeof(struct __fdb_entry) != 0) 10171da177e4SLinus Torvalds return -EINVAL; 10181da177e4SLinus Torvalds 10191da177e4SLinus Torvalds n = br_fdb_fillbuf(br, buf, 10201da177e4SLinus Torvalds count / sizeof(struct __fdb_entry), 10211da177e4SLinus Torvalds off / sizeof(struct __fdb_entry)); 10221da177e4SLinus Torvalds 10231da177e4SLinus Torvalds if (n > 0) 10241da177e4SLinus Torvalds n *= sizeof(struct __fdb_entry); 10251da177e4SLinus Torvalds 10261da177e4SLinus Torvalds return n; 10271da177e4SLinus Torvalds } 10281da177e4SLinus Torvalds 10291da177e4SLinus Torvalds static struct bin_attribute bridge_forward = { 10301da177e4SLinus Torvalds .attr = { .name = SYSFS_BRIDGE_FDB, 1031d6444062SJoe Perches .mode = 0444, }, 10321da177e4SLinus Torvalds .read = brforward_read, 10331da177e4SLinus Torvalds }; 10341da177e4SLinus Torvalds 10351da177e4SLinus Torvalds /* 10361da177e4SLinus Torvalds * Add entries in sysfs onto the existing network class device 10371da177e4SLinus Torvalds * for the bridge. 10381da177e4SLinus Torvalds * Adds a attribute group "bridge" containing tuning parameters. 10391da177e4SLinus Torvalds * Binary attribute containing the forward table 10401da177e4SLinus Torvalds * Sub directory to hold links to interfaces. 10411da177e4SLinus Torvalds * 10421da177e4SLinus Torvalds * Note: the ifobj exists only to be a subdirectory 10431da177e4SLinus Torvalds * to hold links. The ifobj exists in same data structure 10441da177e4SLinus Torvalds * as it's parent the bridge so reference counting works. 10451da177e4SLinus Torvalds */ 10461da177e4SLinus Torvalds int br_sysfs_addbr(struct net_device *dev) 10471da177e4SLinus Torvalds { 104843cb76d9SGreg Kroah-Hartman struct kobject *brobj = &dev->dev.kobj; 10491da177e4SLinus Torvalds struct net_bridge *br = netdev_priv(dev); 10501da177e4SLinus Torvalds int err; 10511da177e4SLinus Torvalds 10521da177e4SLinus Torvalds err = sysfs_create_group(brobj, &bridge_group); 10531da177e4SLinus Torvalds if (err) { 10541da177e4SLinus Torvalds pr_info("%s: can't create group %s/%s\n", 10550dc47877SHarvey Harrison __func__, dev->name, bridge_group.name); 10561da177e4SLinus Torvalds goto out1; 10571da177e4SLinus Torvalds } 10581da177e4SLinus Torvalds 10591da177e4SLinus Torvalds err = sysfs_create_bin_file(brobj, &bridge_forward); 10601da177e4SLinus Torvalds if (err) { 10611842c4beSRandy Dunlap pr_info("%s: can't create attribute file %s/%s\n", 10620dc47877SHarvey Harrison __func__, dev->name, bridge_forward.attr.name); 10631da177e4SLinus Torvalds goto out2; 10641da177e4SLinus Torvalds } 10651da177e4SLinus Torvalds 106643b98c4aSGreg Kroah-Hartman br->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, brobj); 106743b98c4aSGreg Kroah-Hartman if (!br->ifobj) { 10681da177e4SLinus Torvalds pr_info("%s: can't add kobject (directory) %s/%s\n", 10690dc47877SHarvey Harrison __func__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR); 1070b5958963SPan Bian err = -ENOMEM; 10711da177e4SLinus Torvalds goto out3; 10721da177e4SLinus Torvalds } 10731da177e4SLinus Torvalds return 0; 10741da177e4SLinus Torvalds out3: 107543cb76d9SGreg Kroah-Hartman sysfs_remove_bin_file(&dev->dev.kobj, &bridge_forward); 10761da177e4SLinus Torvalds out2: 107743cb76d9SGreg Kroah-Hartman sysfs_remove_group(&dev->dev.kobj, &bridge_group); 10781da177e4SLinus Torvalds out1: 10791da177e4SLinus Torvalds return err; 10801da177e4SLinus Torvalds 10811da177e4SLinus Torvalds } 10821da177e4SLinus Torvalds 10831da177e4SLinus Torvalds void br_sysfs_delbr(struct net_device *dev) 10841da177e4SLinus Torvalds { 108543cb76d9SGreg Kroah-Hartman struct kobject *kobj = &dev->dev.kobj; 10861da177e4SLinus Torvalds struct net_bridge *br = netdev_priv(dev); 10871da177e4SLinus Torvalds 108878a2d906SGreg Kroah-Hartman kobject_put(br->ifobj); 10891da177e4SLinus Torvalds sysfs_remove_bin_file(kobj, &bridge_forward); 10901da177e4SLinus Torvalds sysfs_remove_group(kobj, &bridge_group); 10911da177e4SLinus Torvalds } 1092