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 44*5a45ab3fSIdo 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 { 34714f31bb3SXin Long br_fdb_flush(br); 34814f31bb3SXin Long return 0; 34914f31bb3SXin Long } 35014f31bb3SXin Long 351fbf2671bSsfeldma@cumulusnetworks.com static ssize_t flush_store(struct device *d, 3529cf63747SStephen Hemminger struct device_attribute *attr, 3539cf63747SStephen Hemminger const char *buf, size_t len) 3549cf63747SStephen Hemminger { 35514f31bb3SXin Long return store_bridge_parm(d, buf, len, set_flush); 3569cf63747SStephen Hemminger } 357fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_WO(flush); 358fda93d92SStephen Hemminger 35970e4272bSNikolay Aleksandrov static ssize_t no_linklocal_learn_show(struct device *d, 36070e4272bSNikolay Aleksandrov struct device_attribute *attr, 36170e4272bSNikolay Aleksandrov char *buf) 36270e4272bSNikolay Aleksandrov { 36370e4272bSNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 36470e4272bSNikolay Aleksandrov return sprintf(buf, "%d\n", br_boolopt_get(br, BR_BOOLOPT_NO_LL_LEARN)); 36570e4272bSNikolay Aleksandrov } 36670e4272bSNikolay Aleksandrov 3679e781401SVladimir Oltean static int set_no_linklocal_learn(struct net_bridge *br, unsigned long val, 3689e781401SVladimir Oltean struct netlink_ext_ack *extack) 36970e4272bSNikolay Aleksandrov { 3709e781401SVladimir Oltean return br_boolopt_toggle(br, BR_BOOLOPT_NO_LL_LEARN, !!val, extack); 37170e4272bSNikolay Aleksandrov } 37270e4272bSNikolay Aleksandrov 37370e4272bSNikolay Aleksandrov static ssize_t no_linklocal_learn_store(struct device *d, 37470e4272bSNikolay Aleksandrov struct device_attribute *attr, 37570e4272bSNikolay Aleksandrov const char *buf, size_t len) 37670e4272bSNikolay Aleksandrov { 37770e4272bSNikolay Aleksandrov return store_bridge_parm(d, buf, len, set_no_linklocal_learn); 37870e4272bSNikolay Aleksandrov } 37970e4272bSNikolay Aleksandrov static DEVICE_ATTR_RW(no_linklocal_learn); 38070e4272bSNikolay Aleksandrov 3810909e117SHerbert Xu #ifdef CONFIG_BRIDGE_IGMP_SNOOPING 382fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_router_show(struct device *d, 3830909e117SHerbert Xu struct device_attribute *attr, char *buf) 3840909e117SHerbert Xu { 3850909e117SHerbert Xu struct net_bridge *br = to_bridge(d); 386d3d065c0SNikolay Aleksandrov return sprintf(buf, "%d\n", br->multicast_ctx.multicast_router); 3870909e117SHerbert Xu } 3880909e117SHerbert Xu 3899e781401SVladimir Oltean static int set_multicast_router(struct net_bridge *br, unsigned long val, 3909e781401SVladimir Oltean struct netlink_ext_ack *extack) 3919e781401SVladimir Oltean { 392a97df080SNikolay Aleksandrov return br_multicast_set_router(&br->multicast_ctx, val); 3939e781401SVladimir Oltean } 3949e781401SVladimir Oltean 395fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_router_store(struct device *d, 3960909e117SHerbert Xu struct device_attribute *attr, 3970909e117SHerbert Xu const char *buf, size_t len) 3980909e117SHerbert Xu { 3999e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_multicast_router); 4000909e117SHerbert Xu } 401fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_router); 402561f1103SHerbert Xu 403fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_snooping_show(struct device *d, 404561f1103SHerbert Xu struct device_attribute *attr, 405561f1103SHerbert Xu char *buf) 406561f1103SHerbert Xu { 407561f1103SHerbert Xu struct net_bridge *br = to_bridge(d); 40813cefad2SNikolay Aleksandrov return sprintf(buf, "%d\n", br_opt_get(br, BROPT_MULTICAST_ENABLED)); 409561f1103SHerbert Xu } 410561f1103SHerbert Xu 411fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_snooping_store(struct device *d, 412561f1103SHerbert Xu struct device_attribute *attr, 413561f1103SHerbert Xu const char *buf, size_t len) 414561f1103SHerbert Xu { 415ae1ea84bSFlorian Fainelli return store_bridge_parm(d, buf, len, br_multicast_toggle); 416561f1103SHerbert Xu } 417fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_snooping); 418b195167fSHerbert Xu 419fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_query_use_ifaddr_show(struct device *d, 4201c8ad5bfSCong Wang struct device_attribute *attr, 4211c8ad5bfSCong Wang char *buf) 4221c8ad5bfSCong Wang { 4231c8ad5bfSCong Wang struct net_bridge *br = to_bridge(d); 424675779adSNikolay Aleksandrov return sprintf(buf, "%d\n", 425675779adSNikolay Aleksandrov br_opt_get(br, BROPT_MULTICAST_QUERY_USE_IFADDR)); 4261c8ad5bfSCong Wang } 4271c8ad5bfSCong Wang 4289e781401SVladimir Oltean static int set_query_use_ifaddr(struct net_bridge *br, unsigned long val, 4299e781401SVladimir Oltean struct netlink_ext_ack *extack) 4301c8ad5bfSCong Wang { 431675779adSNikolay Aleksandrov br_opt_toggle(br, BROPT_MULTICAST_QUERY_USE_IFADDR, !!val); 4321c8ad5bfSCong Wang return 0; 4331c8ad5bfSCong Wang } 4341c8ad5bfSCong Wang 4351c8ad5bfSCong Wang static ssize_t 436fbf2671bSsfeldma@cumulusnetworks.com multicast_query_use_ifaddr_store(struct device *d, 4371c8ad5bfSCong Wang struct device_attribute *attr, 4381c8ad5bfSCong Wang const char *buf, size_t len) 4391c8ad5bfSCong Wang { 4401c8ad5bfSCong Wang return store_bridge_parm(d, buf, len, set_query_use_ifaddr); 4411c8ad5bfSCong Wang } 442fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_query_use_ifaddr); 4431c8ad5bfSCong Wang 444fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_querier_show(struct device *d, 445c5c23260SHerbert Xu struct device_attribute *attr, 446c5c23260SHerbert Xu char *buf) 447c5c23260SHerbert Xu { 448c5c23260SHerbert Xu struct net_bridge *br = to_bridge(d); 44962938182SNikolay Aleksandrov return sprintf(buf, "%d\n", br->multicast_ctx.multicast_querier); 450c5c23260SHerbert Xu } 451c5c23260SHerbert Xu 4529e781401SVladimir Oltean static int set_multicast_querier(struct net_bridge *br, unsigned long val, 4539e781401SVladimir Oltean struct netlink_ext_ack *extack) 4549e781401SVladimir Oltean { 45562938182SNikolay Aleksandrov return br_multicast_set_querier(&br->multicast_ctx, val); 4569e781401SVladimir Oltean } 4579e781401SVladimir Oltean 458fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_querier_store(struct device *d, 459c5c23260SHerbert Xu struct device_attribute *attr, 460c5c23260SHerbert Xu const char *buf, size_t len) 461c5c23260SHerbert Xu { 4629e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_multicast_querier); 463c5c23260SHerbert Xu } 464fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_querier); 465c5c23260SHerbert Xu 466fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hash_elasticity_show(struct device *d, 467b195167fSHerbert Xu struct device_attribute *attr, char *buf) 468b195167fSHerbert Xu { 469cf332bcaSNikolay Aleksandrov return sprintf(buf, "%u\n", RHT_ELASTICITY); 470b195167fSHerbert Xu } 471b195167fSHerbert Xu 4729e781401SVladimir Oltean static int set_elasticity(struct net_bridge *br, unsigned long val, 4739e781401SVladimir Oltean struct netlink_ext_ack *extack) 474b195167fSHerbert Xu { 4759e781401SVladimir Oltean /* 16 is RHT_ELASTICITY */ 4769e781401SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 4779e781401SVladimir Oltean "the hash_elasticity option has been deprecated and is always 16"); 478b195167fSHerbert Xu return 0; 479b195167fSHerbert Xu } 480b195167fSHerbert Xu 481fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hash_elasticity_store(struct device *d, 482b195167fSHerbert Xu struct device_attribute *attr, 483b195167fSHerbert Xu const char *buf, size_t len) 484b195167fSHerbert Xu { 485b195167fSHerbert Xu return store_bridge_parm(d, buf, len, set_elasticity); 486b195167fSHerbert Xu } 487fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(hash_elasticity); 488b195167fSHerbert Xu 489fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hash_max_show(struct device *d, struct device_attribute *attr, 490b195167fSHerbert Xu char *buf) 491b195167fSHerbert Xu { 492b195167fSHerbert Xu struct net_bridge *br = to_bridge(d); 493b195167fSHerbert Xu return sprintf(buf, "%u\n", br->hash_max); 494b195167fSHerbert Xu } 495b195167fSHerbert Xu 4969e781401SVladimir Oltean static int set_hash_max(struct net_bridge *br, unsigned long val, 4979e781401SVladimir Oltean struct netlink_ext_ack *extack) 49819e3a9c9SNikolay Aleksandrov { 49919e3a9c9SNikolay Aleksandrov br->hash_max = val; 50019e3a9c9SNikolay Aleksandrov return 0; 50119e3a9c9SNikolay Aleksandrov } 50219e3a9c9SNikolay Aleksandrov 503fbf2671bSsfeldma@cumulusnetworks.com static ssize_t hash_max_store(struct device *d, struct device_attribute *attr, 504b195167fSHerbert Xu const char *buf, size_t len) 505b195167fSHerbert Xu { 50619e3a9c9SNikolay Aleksandrov return store_bridge_parm(d, buf, len, set_hash_max); 507b195167fSHerbert Xu } 508fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(hash_max); 509d902eee4SHerbert Xu 5105e923585SNikolay Aleksandrov static ssize_t multicast_igmp_version_show(struct device *d, 5115e923585SNikolay Aleksandrov struct device_attribute *attr, 5125e923585SNikolay Aleksandrov char *buf) 5135e923585SNikolay Aleksandrov { 5145e923585SNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 5155e923585SNikolay Aleksandrov 516d3d065c0SNikolay Aleksandrov return sprintf(buf, "%u\n", br->multicast_ctx.multicast_igmp_version); 5175e923585SNikolay Aleksandrov } 5185e923585SNikolay Aleksandrov 5199e781401SVladimir Oltean static int set_multicast_igmp_version(struct net_bridge *br, unsigned long val, 5209e781401SVladimir Oltean struct netlink_ext_ack *extack) 5219e781401SVladimir Oltean { 522df271cd6SNikolay Aleksandrov return br_multicast_set_igmp_version(&br->multicast_ctx, val); 5239e781401SVladimir Oltean } 5249e781401SVladimir Oltean 5255e923585SNikolay Aleksandrov static ssize_t multicast_igmp_version_store(struct device *d, 5265e923585SNikolay Aleksandrov struct device_attribute *attr, 5275e923585SNikolay Aleksandrov const char *buf, size_t len) 5285e923585SNikolay Aleksandrov { 5299e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_multicast_igmp_version); 5305e923585SNikolay Aleksandrov } 5315e923585SNikolay Aleksandrov static DEVICE_ATTR_RW(multicast_igmp_version); 5325e923585SNikolay Aleksandrov 533fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_last_member_count_show(struct device *d, 534d902eee4SHerbert Xu struct device_attribute *attr, 535d902eee4SHerbert Xu char *buf) 536d902eee4SHerbert Xu { 537d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 538d3d065c0SNikolay Aleksandrov return sprintf(buf, "%u\n", br->multicast_ctx.multicast_last_member_count); 539d902eee4SHerbert Xu } 540d902eee4SHerbert Xu 5419e781401SVladimir Oltean static int set_last_member_count(struct net_bridge *br, unsigned long val, 5429e781401SVladimir Oltean struct netlink_ext_ack *extack) 543d902eee4SHerbert Xu { 544d3d065c0SNikolay Aleksandrov br->multicast_ctx.multicast_last_member_count = val; 545d902eee4SHerbert Xu return 0; 546d902eee4SHerbert Xu } 547d902eee4SHerbert Xu 548fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_last_member_count_store(struct device *d, 549d902eee4SHerbert Xu struct device_attribute *attr, 550d902eee4SHerbert Xu const char *buf, size_t len) 551d902eee4SHerbert Xu { 552d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_last_member_count); 553d902eee4SHerbert Xu } 554fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_last_member_count); 555d902eee4SHerbert Xu 556fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_startup_query_count_show( 557d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, char *buf) 558d902eee4SHerbert Xu { 559d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 560d3d065c0SNikolay Aleksandrov return sprintf(buf, "%u\n", br->multicast_ctx.multicast_startup_query_count); 561d902eee4SHerbert Xu } 562d902eee4SHerbert Xu 5639e781401SVladimir Oltean static int set_startup_query_count(struct net_bridge *br, unsigned long val, 5649e781401SVladimir Oltean struct netlink_ext_ack *extack) 565d902eee4SHerbert Xu { 566d3d065c0SNikolay Aleksandrov br->multicast_ctx.multicast_startup_query_count = val; 567d902eee4SHerbert Xu return 0; 568d902eee4SHerbert Xu } 569d902eee4SHerbert Xu 570fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_startup_query_count_store( 571d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, const char *buf, 572d902eee4SHerbert Xu size_t len) 573d902eee4SHerbert Xu { 574d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_startup_query_count); 575d902eee4SHerbert Xu } 576fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_startup_query_count); 577d902eee4SHerbert Xu 578fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_last_member_interval_show( 579d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, char *buf) 580d902eee4SHerbert Xu { 581d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 582d902eee4SHerbert Xu return sprintf(buf, "%lu\n", 583d3d065c0SNikolay Aleksandrov jiffies_to_clock_t(br->multicast_ctx.multicast_last_member_interval)); 584d902eee4SHerbert Xu } 585d902eee4SHerbert Xu 5869e781401SVladimir Oltean static int set_last_member_interval(struct net_bridge *br, unsigned long val, 5879e781401SVladimir Oltean struct netlink_ext_ack *extack) 588d902eee4SHerbert Xu { 589d3d065c0SNikolay Aleksandrov br->multicast_ctx.multicast_last_member_interval = clock_t_to_jiffies(val); 590d902eee4SHerbert Xu return 0; 591d902eee4SHerbert Xu } 592d902eee4SHerbert Xu 593fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_last_member_interval_store( 594d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, const char *buf, 595d902eee4SHerbert Xu size_t len) 596d902eee4SHerbert Xu { 597d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_last_member_interval); 598d902eee4SHerbert Xu } 599fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_last_member_interval); 600d902eee4SHerbert Xu 601fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_membership_interval_show( 602d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, char *buf) 603d902eee4SHerbert Xu { 604d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 605d902eee4SHerbert Xu return sprintf(buf, "%lu\n", 606d3d065c0SNikolay Aleksandrov jiffies_to_clock_t(br->multicast_ctx.multicast_membership_interval)); 607d902eee4SHerbert Xu } 608d902eee4SHerbert Xu 6099e781401SVladimir Oltean static int set_membership_interval(struct net_bridge *br, unsigned long val, 6109e781401SVladimir Oltean struct netlink_ext_ack *extack) 611d902eee4SHerbert Xu { 612d3d065c0SNikolay Aleksandrov br->multicast_ctx.multicast_membership_interval = clock_t_to_jiffies(val); 613d902eee4SHerbert Xu return 0; 614d902eee4SHerbert Xu } 615d902eee4SHerbert Xu 616fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_membership_interval_store( 617d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, const char *buf, 618d902eee4SHerbert Xu size_t len) 619d902eee4SHerbert Xu { 620d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_membership_interval); 621d902eee4SHerbert Xu } 622fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_membership_interval); 623d902eee4SHerbert Xu 624fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_querier_interval_show(struct device *d, 625d902eee4SHerbert Xu struct device_attribute *attr, 626d902eee4SHerbert Xu char *buf) 627d902eee4SHerbert Xu { 628d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 629d902eee4SHerbert Xu return sprintf(buf, "%lu\n", 630d3d065c0SNikolay Aleksandrov jiffies_to_clock_t(br->multicast_ctx.multicast_querier_interval)); 631d902eee4SHerbert Xu } 632d902eee4SHerbert Xu 6339e781401SVladimir Oltean static int set_querier_interval(struct net_bridge *br, unsigned long val, 6349e781401SVladimir Oltean struct netlink_ext_ack *extack) 635d902eee4SHerbert Xu { 636d3d065c0SNikolay Aleksandrov br->multicast_ctx.multicast_querier_interval = clock_t_to_jiffies(val); 637d902eee4SHerbert Xu return 0; 638d902eee4SHerbert Xu } 639d902eee4SHerbert Xu 640fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_querier_interval_store(struct device *d, 641d902eee4SHerbert Xu struct device_attribute *attr, 642d902eee4SHerbert Xu const char *buf, size_t len) 643d902eee4SHerbert Xu { 644d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_querier_interval); 645d902eee4SHerbert Xu } 646fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_querier_interval); 647d902eee4SHerbert Xu 648fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_query_interval_show(struct device *d, 649d902eee4SHerbert Xu struct device_attribute *attr, 650d902eee4SHerbert Xu char *buf) 651d902eee4SHerbert Xu { 652d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 653d902eee4SHerbert Xu return sprintf(buf, "%lu\n", 654d3d065c0SNikolay Aleksandrov jiffies_to_clock_t(br->multicast_ctx.multicast_query_interval)); 655d902eee4SHerbert Xu } 656d902eee4SHerbert Xu 6579e781401SVladimir Oltean static int set_query_interval(struct net_bridge *br, unsigned long val, 6589e781401SVladimir Oltean struct netlink_ext_ack *extack) 659d902eee4SHerbert Xu { 660d3d065c0SNikolay Aleksandrov br->multicast_ctx.multicast_query_interval = clock_t_to_jiffies(val); 661d902eee4SHerbert Xu return 0; 662d902eee4SHerbert Xu } 663d902eee4SHerbert Xu 664fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_query_interval_store(struct device *d, 665d902eee4SHerbert Xu struct device_attribute *attr, 666d902eee4SHerbert Xu const char *buf, size_t len) 667d902eee4SHerbert Xu { 668d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_query_interval); 669d902eee4SHerbert Xu } 670fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_query_interval); 671d902eee4SHerbert Xu 672fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_query_response_interval_show( 673d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, char *buf) 674d902eee4SHerbert Xu { 675d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 676d902eee4SHerbert Xu return sprintf( 677d902eee4SHerbert Xu buf, "%lu\n", 678d3d065c0SNikolay Aleksandrov jiffies_to_clock_t(br->multicast_ctx.multicast_query_response_interval)); 679d902eee4SHerbert Xu } 680d902eee4SHerbert Xu 6819e781401SVladimir Oltean static int set_query_response_interval(struct net_bridge *br, unsigned long val, 6829e781401SVladimir Oltean struct netlink_ext_ack *extack) 683d902eee4SHerbert Xu { 684d3d065c0SNikolay Aleksandrov br->multicast_ctx.multicast_query_response_interval = clock_t_to_jiffies(val); 685d902eee4SHerbert Xu return 0; 686d902eee4SHerbert Xu } 687d902eee4SHerbert Xu 688fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_query_response_interval_store( 689d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, const char *buf, 690d902eee4SHerbert Xu size_t len) 691d902eee4SHerbert Xu { 692d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_query_response_interval); 693d902eee4SHerbert Xu } 694fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_query_response_interval); 695d902eee4SHerbert Xu 696fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_startup_query_interval_show( 697d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, char *buf) 698d902eee4SHerbert Xu { 699d902eee4SHerbert Xu struct net_bridge *br = to_bridge(d); 700d902eee4SHerbert Xu return sprintf( 701d902eee4SHerbert Xu buf, "%lu\n", 702d3d065c0SNikolay Aleksandrov jiffies_to_clock_t(br->multicast_ctx.multicast_startup_query_interval)); 703d902eee4SHerbert Xu } 704d902eee4SHerbert Xu 7059e781401SVladimir Oltean static int set_startup_query_interval(struct net_bridge *br, unsigned long val, 7069e781401SVladimir Oltean struct netlink_ext_ack *extack) 707d902eee4SHerbert Xu { 708d3d065c0SNikolay Aleksandrov br->multicast_ctx.multicast_startup_query_interval = clock_t_to_jiffies(val); 709d902eee4SHerbert Xu return 0; 710d902eee4SHerbert Xu } 711d902eee4SHerbert Xu 712fbf2671bSsfeldma@cumulusnetworks.com static ssize_t multicast_startup_query_interval_store( 713d902eee4SHerbert Xu struct device *d, struct device_attribute *attr, const char *buf, 714d902eee4SHerbert Xu size_t len) 715d902eee4SHerbert Xu { 716d902eee4SHerbert Xu return store_bridge_parm(d, buf, len, set_startup_query_interval); 717d902eee4SHerbert Xu } 718fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(multicast_startup_query_interval); 7191080ab95SNikolay Aleksandrov 7201080ab95SNikolay Aleksandrov static ssize_t multicast_stats_enabled_show(struct device *d, 7211080ab95SNikolay Aleksandrov struct device_attribute *attr, 7221080ab95SNikolay Aleksandrov char *buf) 7231080ab95SNikolay Aleksandrov { 7241080ab95SNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 7251080ab95SNikolay Aleksandrov 726675779adSNikolay Aleksandrov return sprintf(buf, "%d\n", 727675779adSNikolay Aleksandrov br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED)); 7281080ab95SNikolay Aleksandrov } 7291080ab95SNikolay Aleksandrov 7309e781401SVladimir Oltean static int set_stats_enabled(struct net_bridge *br, unsigned long val, 7319e781401SVladimir Oltean struct netlink_ext_ack *extack) 7321080ab95SNikolay Aleksandrov { 733675779adSNikolay Aleksandrov br_opt_toggle(br, BROPT_MULTICAST_STATS_ENABLED, !!val); 7341080ab95SNikolay Aleksandrov return 0; 7351080ab95SNikolay Aleksandrov } 7361080ab95SNikolay Aleksandrov 7371080ab95SNikolay Aleksandrov static ssize_t multicast_stats_enabled_store(struct device *d, 7381080ab95SNikolay Aleksandrov struct device_attribute *attr, 7391080ab95SNikolay Aleksandrov const char *buf, 7401080ab95SNikolay Aleksandrov size_t len) 7411080ab95SNikolay Aleksandrov { 7421080ab95SNikolay Aleksandrov return store_bridge_parm(d, buf, len, set_stats_enabled); 7431080ab95SNikolay Aleksandrov } 7441080ab95SNikolay Aleksandrov static DEVICE_ATTR_RW(multicast_stats_enabled); 745aa2ae3e7SNikolay Aleksandrov 746aa2ae3e7SNikolay Aleksandrov #if IS_ENABLED(CONFIG_IPV6) 747aa2ae3e7SNikolay Aleksandrov static ssize_t multicast_mld_version_show(struct device *d, 748aa2ae3e7SNikolay Aleksandrov struct device_attribute *attr, 749aa2ae3e7SNikolay Aleksandrov char *buf) 750aa2ae3e7SNikolay Aleksandrov { 751aa2ae3e7SNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 752aa2ae3e7SNikolay Aleksandrov 753d3d065c0SNikolay Aleksandrov return sprintf(buf, "%u\n", br->multicast_ctx.multicast_mld_version); 754aa2ae3e7SNikolay Aleksandrov } 755aa2ae3e7SNikolay Aleksandrov 7569e781401SVladimir Oltean static int set_multicast_mld_version(struct net_bridge *br, unsigned long val, 7579e781401SVladimir Oltean struct netlink_ext_ack *extack) 7589e781401SVladimir Oltean { 759df271cd6SNikolay Aleksandrov return br_multicast_set_mld_version(&br->multicast_ctx, val); 7609e781401SVladimir Oltean } 7619e781401SVladimir Oltean 762aa2ae3e7SNikolay Aleksandrov static ssize_t multicast_mld_version_store(struct device *d, 763aa2ae3e7SNikolay Aleksandrov struct device_attribute *attr, 764aa2ae3e7SNikolay Aleksandrov const char *buf, size_t len) 765aa2ae3e7SNikolay Aleksandrov { 7669e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_multicast_mld_version); 767aa2ae3e7SNikolay Aleksandrov } 768aa2ae3e7SNikolay Aleksandrov static DEVICE_ATTR_RW(multicast_mld_version); 769aa2ae3e7SNikolay Aleksandrov #endif 7700909e117SHerbert Xu #endif 77134666d46SPablo Neira Ayuso #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) 772fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_iptables_show( 7734df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, char *buf) 7744df53d8bSPatrick McHardy { 7754df53d8bSPatrick McHardy struct net_bridge *br = to_bridge(d); 7768df3510fSNikolay Aleksandrov return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_IPTABLES)); 7774df53d8bSPatrick McHardy } 7784df53d8bSPatrick McHardy 7799e781401SVladimir Oltean static int set_nf_call_iptables(struct net_bridge *br, unsigned long val, 7809e781401SVladimir Oltean struct netlink_ext_ack *extack) 7814df53d8bSPatrick McHardy { 7828df3510fSNikolay Aleksandrov br_opt_toggle(br, BROPT_NF_CALL_IPTABLES, !!val); 7834df53d8bSPatrick McHardy return 0; 7844df53d8bSPatrick McHardy } 7854df53d8bSPatrick McHardy 786fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_iptables_store( 7874df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, const char *buf, 7884df53d8bSPatrick McHardy size_t len) 7894df53d8bSPatrick McHardy { 7904df53d8bSPatrick McHardy return store_bridge_parm(d, buf, len, set_nf_call_iptables); 7914df53d8bSPatrick McHardy } 792fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(nf_call_iptables); 7934df53d8bSPatrick McHardy 794fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_ip6tables_show( 7954df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, char *buf) 7964df53d8bSPatrick McHardy { 7974df53d8bSPatrick McHardy struct net_bridge *br = to_bridge(d); 7988df3510fSNikolay Aleksandrov return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_IP6TABLES)); 7994df53d8bSPatrick McHardy } 8004df53d8bSPatrick McHardy 8019e781401SVladimir Oltean static int set_nf_call_ip6tables(struct net_bridge *br, unsigned long val, 8029e781401SVladimir Oltean struct netlink_ext_ack *extack) 8034df53d8bSPatrick McHardy { 8048df3510fSNikolay Aleksandrov br_opt_toggle(br, BROPT_NF_CALL_IP6TABLES, !!val); 8054df53d8bSPatrick McHardy return 0; 8064df53d8bSPatrick McHardy } 8074df53d8bSPatrick McHardy 808fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_ip6tables_store( 8094df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, const char *buf, 8104df53d8bSPatrick McHardy size_t len) 8114df53d8bSPatrick McHardy { 8124df53d8bSPatrick McHardy return store_bridge_parm(d, buf, len, set_nf_call_ip6tables); 8134df53d8bSPatrick McHardy } 814fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(nf_call_ip6tables); 8154df53d8bSPatrick McHardy 816fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_arptables_show( 8174df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, char *buf) 8184df53d8bSPatrick McHardy { 8194df53d8bSPatrick McHardy struct net_bridge *br = to_bridge(d); 8208df3510fSNikolay Aleksandrov return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_ARPTABLES)); 8214df53d8bSPatrick McHardy } 8224df53d8bSPatrick McHardy 8239e781401SVladimir Oltean static int set_nf_call_arptables(struct net_bridge *br, unsigned long val, 8249e781401SVladimir Oltean struct netlink_ext_ack *extack) 8254df53d8bSPatrick McHardy { 8268df3510fSNikolay Aleksandrov br_opt_toggle(br, BROPT_NF_CALL_ARPTABLES, !!val); 8274df53d8bSPatrick McHardy return 0; 8284df53d8bSPatrick McHardy } 8294df53d8bSPatrick McHardy 830fbf2671bSsfeldma@cumulusnetworks.com static ssize_t nf_call_arptables_store( 8314df53d8bSPatrick McHardy struct device *d, struct device_attribute *attr, const char *buf, 8324df53d8bSPatrick McHardy size_t len) 8334df53d8bSPatrick McHardy { 8344df53d8bSPatrick McHardy return store_bridge_parm(d, buf, len, set_nf_call_arptables); 8354df53d8bSPatrick McHardy } 836fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(nf_call_arptables); 8374df53d8bSPatrick McHardy #endif 838243a2e63SVlad Yasevich #ifdef CONFIG_BRIDGE_VLAN_FILTERING 839fbf2671bSsfeldma@cumulusnetworks.com static ssize_t vlan_filtering_show(struct device *d, 840243a2e63SVlad Yasevich struct device_attribute *attr, 841243a2e63SVlad Yasevich char *buf) 842243a2e63SVlad Yasevich { 843243a2e63SVlad Yasevich struct net_bridge *br = to_bridge(d); 844ae75767eSNikolay Aleksandrov return sprintf(buf, "%d\n", br_opt_get(br, BROPT_VLAN_ENABLED)); 845243a2e63SVlad Yasevich } 846243a2e63SVlad Yasevich 847fbf2671bSsfeldma@cumulusnetworks.com static ssize_t vlan_filtering_store(struct device *d, 848243a2e63SVlad Yasevich struct device_attribute *attr, 849243a2e63SVlad Yasevich const char *buf, size_t len) 850243a2e63SVlad Yasevich { 851243a2e63SVlad Yasevich return store_bridge_parm(d, buf, len, br_vlan_filter_toggle); 852243a2e63SVlad Yasevich } 853fbf2671bSsfeldma@cumulusnetworks.com static DEVICE_ATTR_RW(vlan_filtering); 854204177f3SToshiaki Makita 855204177f3SToshiaki Makita static ssize_t vlan_protocol_show(struct device *d, 856204177f3SToshiaki Makita struct device_attribute *attr, 857204177f3SToshiaki Makita char *buf) 858204177f3SToshiaki Makita { 859204177f3SToshiaki Makita struct net_bridge *br = to_bridge(d); 860204177f3SToshiaki Makita return sprintf(buf, "%#06x\n", ntohs(br->vlan_proto)); 861204177f3SToshiaki Makita } 862204177f3SToshiaki Makita 863204177f3SToshiaki Makita static ssize_t vlan_protocol_store(struct device *d, 864204177f3SToshiaki Makita struct device_attribute *attr, 865204177f3SToshiaki Makita const char *buf, size_t len) 866204177f3SToshiaki Makita { 867204177f3SToshiaki Makita return store_bridge_parm(d, buf, len, br_vlan_set_proto); 868204177f3SToshiaki Makita } 869204177f3SToshiaki Makita static DEVICE_ATTR_RW(vlan_protocol); 87096a20d9dSVlad Yasevich 87196a20d9dSVlad Yasevich static ssize_t default_pvid_show(struct device *d, 87296a20d9dSVlad Yasevich struct device_attribute *attr, 87396a20d9dSVlad Yasevich char *buf) 87496a20d9dSVlad Yasevich { 87596a20d9dSVlad Yasevich struct net_bridge *br = to_bridge(d); 87696a20d9dSVlad Yasevich return sprintf(buf, "%d\n", br->default_pvid); 87796a20d9dSVlad Yasevich } 87896a20d9dSVlad Yasevich 87996a20d9dSVlad Yasevich static ssize_t default_pvid_store(struct device *d, 88096a20d9dSVlad Yasevich struct device_attribute *attr, 88196a20d9dSVlad Yasevich const char *buf, size_t len) 88296a20d9dSVlad Yasevich { 88396a20d9dSVlad Yasevich return store_bridge_parm(d, buf, len, br_vlan_set_default_pvid); 88496a20d9dSVlad Yasevich } 88596a20d9dSVlad Yasevich static DEVICE_ATTR_RW(default_pvid); 8866dada9b1SNikolay Aleksandrov 8876dada9b1SNikolay Aleksandrov static ssize_t vlan_stats_enabled_show(struct device *d, 8886dada9b1SNikolay Aleksandrov struct device_attribute *attr, 8896dada9b1SNikolay Aleksandrov char *buf) 8906dada9b1SNikolay Aleksandrov { 8916dada9b1SNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 892ae75767eSNikolay Aleksandrov return sprintf(buf, "%u\n", br_opt_get(br, BROPT_VLAN_STATS_ENABLED)); 8936dada9b1SNikolay Aleksandrov } 8946dada9b1SNikolay Aleksandrov 8959e781401SVladimir Oltean static int set_vlan_stats_enabled(struct net_bridge *br, unsigned long val, 8969e781401SVladimir Oltean struct netlink_ext_ack *extack) 8979e781401SVladimir Oltean { 8989e781401SVladimir Oltean return br_vlan_set_stats(br, val); 8999e781401SVladimir Oltean } 9009e781401SVladimir Oltean 9016dada9b1SNikolay Aleksandrov static ssize_t vlan_stats_enabled_store(struct device *d, 9026dada9b1SNikolay Aleksandrov struct device_attribute *attr, 9036dada9b1SNikolay Aleksandrov const char *buf, size_t len) 9046dada9b1SNikolay Aleksandrov { 9059e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_vlan_stats_enabled); 9066dada9b1SNikolay Aleksandrov } 9076dada9b1SNikolay Aleksandrov static DEVICE_ATTR_RW(vlan_stats_enabled); 9089163a0fcSNikolay Aleksandrov 9099163a0fcSNikolay Aleksandrov static ssize_t vlan_stats_per_port_show(struct device *d, 9109163a0fcSNikolay Aleksandrov struct device_attribute *attr, 9119163a0fcSNikolay Aleksandrov char *buf) 9129163a0fcSNikolay Aleksandrov { 9139163a0fcSNikolay Aleksandrov struct net_bridge *br = to_bridge(d); 9149163a0fcSNikolay Aleksandrov return sprintf(buf, "%u\n", br_opt_get(br, BROPT_VLAN_STATS_PER_PORT)); 9159163a0fcSNikolay Aleksandrov } 9169163a0fcSNikolay Aleksandrov 9179e781401SVladimir Oltean static int set_vlan_stats_per_port(struct net_bridge *br, unsigned long val, 9189e781401SVladimir Oltean struct netlink_ext_ack *extack) 9199e781401SVladimir Oltean { 9209e781401SVladimir Oltean return br_vlan_set_stats_per_port(br, val); 9219e781401SVladimir Oltean } 9229e781401SVladimir Oltean 9239163a0fcSNikolay Aleksandrov static ssize_t vlan_stats_per_port_store(struct device *d, 9249163a0fcSNikolay Aleksandrov struct device_attribute *attr, 9259163a0fcSNikolay Aleksandrov const char *buf, size_t len) 9269163a0fcSNikolay Aleksandrov { 9279e781401SVladimir Oltean return store_bridge_parm(d, buf, len, set_vlan_stats_per_port); 9289163a0fcSNikolay Aleksandrov } 9299163a0fcSNikolay Aleksandrov static DEVICE_ATTR_RW(vlan_stats_per_port); 930243a2e63SVlad Yasevich #endif 9310909e117SHerbert Xu 9321da177e4SLinus Torvalds static struct attribute *bridge_attrs[] = { 93343cb76d9SGreg Kroah-Hartman &dev_attr_forward_delay.attr, 93443cb76d9SGreg Kroah-Hartman &dev_attr_hello_time.attr, 93543cb76d9SGreg Kroah-Hartman &dev_attr_max_age.attr, 93643cb76d9SGreg Kroah-Hartman &dev_attr_ageing_time.attr, 93743cb76d9SGreg Kroah-Hartman &dev_attr_stp_state.attr, 938515853ccSstephen hemminger &dev_attr_group_fwd_mask.attr, 93943cb76d9SGreg Kroah-Hartman &dev_attr_priority.attr, 94043cb76d9SGreg Kroah-Hartman &dev_attr_bridge_id.attr, 94143cb76d9SGreg Kroah-Hartman &dev_attr_root_id.attr, 94243cb76d9SGreg Kroah-Hartman &dev_attr_root_path_cost.attr, 94343cb76d9SGreg Kroah-Hartman &dev_attr_root_port.attr, 94443cb76d9SGreg Kroah-Hartman &dev_attr_topology_change.attr, 94543cb76d9SGreg Kroah-Hartman &dev_attr_topology_change_detected.attr, 94643cb76d9SGreg Kroah-Hartman &dev_attr_hello_timer.attr, 94743cb76d9SGreg Kroah-Hartman &dev_attr_tcn_timer.attr, 94843cb76d9SGreg Kroah-Hartman &dev_attr_topology_change_timer.attr, 94943cb76d9SGreg Kroah-Hartman &dev_attr_gc_timer.attr, 95043cb76d9SGreg Kroah-Hartman &dev_attr_group_addr.attr, 9519cf63747SStephen Hemminger &dev_attr_flush.attr, 95270e4272bSNikolay Aleksandrov &dev_attr_no_linklocal_learn.attr, 9530909e117SHerbert Xu #ifdef CONFIG_BRIDGE_IGMP_SNOOPING 9540909e117SHerbert Xu &dev_attr_multicast_router.attr, 955561f1103SHerbert Xu &dev_attr_multicast_snooping.attr, 956c5c23260SHerbert Xu &dev_attr_multicast_querier.attr, 9571c8ad5bfSCong Wang &dev_attr_multicast_query_use_ifaddr.attr, 958b195167fSHerbert Xu &dev_attr_hash_elasticity.attr, 959b195167fSHerbert Xu &dev_attr_hash_max.attr, 960d902eee4SHerbert Xu &dev_attr_multicast_last_member_count.attr, 961d902eee4SHerbert Xu &dev_attr_multicast_startup_query_count.attr, 962d902eee4SHerbert Xu &dev_attr_multicast_last_member_interval.attr, 963d902eee4SHerbert Xu &dev_attr_multicast_membership_interval.attr, 964d902eee4SHerbert Xu &dev_attr_multicast_querier_interval.attr, 965d902eee4SHerbert Xu &dev_attr_multicast_query_interval.attr, 966d902eee4SHerbert Xu &dev_attr_multicast_query_response_interval.attr, 967d902eee4SHerbert Xu &dev_attr_multicast_startup_query_interval.attr, 9681080ab95SNikolay Aleksandrov &dev_attr_multicast_stats_enabled.attr, 9695e923585SNikolay Aleksandrov &dev_attr_multicast_igmp_version.attr, 970aa2ae3e7SNikolay Aleksandrov #if IS_ENABLED(CONFIG_IPV6) 971aa2ae3e7SNikolay Aleksandrov &dev_attr_multicast_mld_version.attr, 972aa2ae3e7SNikolay Aleksandrov #endif 9730909e117SHerbert Xu #endif 97434666d46SPablo Neira Ayuso #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) 9754df53d8bSPatrick McHardy &dev_attr_nf_call_iptables.attr, 9764df53d8bSPatrick McHardy &dev_attr_nf_call_ip6tables.attr, 9774df53d8bSPatrick McHardy &dev_attr_nf_call_arptables.attr, 9784df53d8bSPatrick McHardy #endif 979243a2e63SVlad Yasevich #ifdef CONFIG_BRIDGE_VLAN_FILTERING 980243a2e63SVlad Yasevich &dev_attr_vlan_filtering.attr, 981204177f3SToshiaki Makita &dev_attr_vlan_protocol.attr, 98296a20d9dSVlad Yasevich &dev_attr_default_pvid.attr, 9836dada9b1SNikolay Aleksandrov &dev_attr_vlan_stats_enabled.attr, 9849163a0fcSNikolay Aleksandrov &dev_attr_vlan_stats_per_port.attr, 985243a2e63SVlad Yasevich #endif 9861da177e4SLinus Torvalds NULL 9871da177e4SLinus Torvalds }; 9881da177e4SLinus Torvalds 989cddbb79fSArvind Yadav static const struct attribute_group bridge_group = { 9901da177e4SLinus Torvalds .name = SYSFS_BRIDGE_ATTR, 9911da177e4SLinus Torvalds .attrs = bridge_attrs, 9921da177e4SLinus Torvalds }; 9931da177e4SLinus Torvalds 9941da177e4SLinus Torvalds /* 9951da177e4SLinus Torvalds * Export the forwarding information table as a binary file 9961da177e4SLinus Torvalds * The records are struct __fdb_entry. 9971da177e4SLinus Torvalds * 9981da177e4SLinus Torvalds * Returns the number of bytes read. 9991da177e4SLinus Torvalds */ 10002c3c8beaSChris Wright static ssize_t brforward_read(struct file *filp, struct kobject *kobj, 100191a69029SZhang Rui struct bin_attribute *bin_attr, 100291a69029SZhang Rui char *buf, loff_t off, size_t count) 10031da177e4SLinus Torvalds { 1004aeb7ed14SGeliang Tang struct device *dev = kobj_to_dev(kobj); 100543cb76d9SGreg Kroah-Hartman struct net_bridge *br = to_bridge(dev); 10061da177e4SLinus Torvalds int n; 10071da177e4SLinus Torvalds 10081da177e4SLinus Torvalds /* must read whole records */ 10091da177e4SLinus Torvalds if (off % sizeof(struct __fdb_entry) != 0) 10101da177e4SLinus Torvalds return -EINVAL; 10111da177e4SLinus Torvalds 10121da177e4SLinus Torvalds n = br_fdb_fillbuf(br, buf, 10131da177e4SLinus Torvalds count / sizeof(struct __fdb_entry), 10141da177e4SLinus Torvalds off / sizeof(struct __fdb_entry)); 10151da177e4SLinus Torvalds 10161da177e4SLinus Torvalds if (n > 0) 10171da177e4SLinus Torvalds n *= sizeof(struct __fdb_entry); 10181da177e4SLinus Torvalds 10191da177e4SLinus Torvalds return n; 10201da177e4SLinus Torvalds } 10211da177e4SLinus Torvalds 10221da177e4SLinus Torvalds static struct bin_attribute bridge_forward = { 10231da177e4SLinus Torvalds .attr = { .name = SYSFS_BRIDGE_FDB, 1024d6444062SJoe Perches .mode = 0444, }, 10251da177e4SLinus Torvalds .read = brforward_read, 10261da177e4SLinus Torvalds }; 10271da177e4SLinus Torvalds 10281da177e4SLinus Torvalds /* 10291da177e4SLinus Torvalds * Add entries in sysfs onto the existing network class device 10301da177e4SLinus Torvalds * for the bridge. 10311da177e4SLinus Torvalds * Adds a attribute group "bridge" containing tuning parameters. 10321da177e4SLinus Torvalds * Binary attribute containing the forward table 10331da177e4SLinus Torvalds * Sub directory to hold links to interfaces. 10341da177e4SLinus Torvalds * 10351da177e4SLinus Torvalds * Note: the ifobj exists only to be a subdirectory 10361da177e4SLinus Torvalds * to hold links. The ifobj exists in same data structure 10371da177e4SLinus Torvalds * as it's parent the bridge so reference counting works. 10381da177e4SLinus Torvalds */ 10391da177e4SLinus Torvalds int br_sysfs_addbr(struct net_device *dev) 10401da177e4SLinus Torvalds { 104143cb76d9SGreg Kroah-Hartman struct kobject *brobj = &dev->dev.kobj; 10421da177e4SLinus Torvalds struct net_bridge *br = netdev_priv(dev); 10431da177e4SLinus Torvalds int err; 10441da177e4SLinus Torvalds 10451da177e4SLinus Torvalds err = sysfs_create_group(brobj, &bridge_group); 10461da177e4SLinus Torvalds if (err) { 10471da177e4SLinus Torvalds pr_info("%s: can't create group %s/%s\n", 10480dc47877SHarvey Harrison __func__, dev->name, bridge_group.name); 10491da177e4SLinus Torvalds goto out1; 10501da177e4SLinus Torvalds } 10511da177e4SLinus Torvalds 10521da177e4SLinus Torvalds err = sysfs_create_bin_file(brobj, &bridge_forward); 10531da177e4SLinus Torvalds if (err) { 10541842c4beSRandy Dunlap pr_info("%s: can't create attribute file %s/%s\n", 10550dc47877SHarvey Harrison __func__, dev->name, bridge_forward.attr.name); 10561da177e4SLinus Torvalds goto out2; 10571da177e4SLinus Torvalds } 10581da177e4SLinus Torvalds 105943b98c4aSGreg Kroah-Hartman br->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, brobj); 106043b98c4aSGreg Kroah-Hartman if (!br->ifobj) { 10611da177e4SLinus Torvalds pr_info("%s: can't add kobject (directory) %s/%s\n", 10620dc47877SHarvey Harrison __func__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR); 1063b5958963SPan Bian err = -ENOMEM; 10641da177e4SLinus Torvalds goto out3; 10651da177e4SLinus Torvalds } 10661da177e4SLinus Torvalds return 0; 10671da177e4SLinus Torvalds out3: 106843cb76d9SGreg Kroah-Hartman sysfs_remove_bin_file(&dev->dev.kobj, &bridge_forward); 10691da177e4SLinus Torvalds out2: 107043cb76d9SGreg Kroah-Hartman sysfs_remove_group(&dev->dev.kobj, &bridge_group); 10711da177e4SLinus Torvalds out1: 10721da177e4SLinus Torvalds return err; 10731da177e4SLinus Torvalds 10741da177e4SLinus Torvalds } 10751da177e4SLinus Torvalds 10761da177e4SLinus Torvalds void br_sysfs_delbr(struct net_device *dev) 10771da177e4SLinus Torvalds { 107843cb76d9SGreg Kroah-Hartman struct kobject *kobj = &dev->dev.kobj; 10791da177e4SLinus Torvalds struct net_bridge *br = netdev_priv(dev); 10801da177e4SLinus Torvalds 108178a2d906SGreg Kroah-Hartman kobject_put(br->ifobj); 10821da177e4SLinus Torvalds sysfs_remove_bin_file(kobj, &bridge_forward); 10831da177e4SLinus Torvalds sysfs_remove_group(kobj, &bridge_group); 10841da177e4SLinus Torvalds } 1085