162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Userspace interface 462306a36Sopenharmony_ci * Linux ethernet bridge 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Authors: 762306a36Sopenharmony_ci * Lennert Buytenhek <buytenh@gnu.org> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/netdevice.h> 1262306a36Sopenharmony_ci#include <linux/etherdevice.h> 1362306a36Sopenharmony_ci#include <linux/netpoll.h> 1462306a36Sopenharmony_ci#include <linux/ethtool.h> 1562306a36Sopenharmony_ci#include <linux/if_arp.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/init.h> 1862306a36Sopenharmony_ci#include <linux/rtnetlink.h> 1962306a36Sopenharmony_ci#include <linux/if_ether.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci#include <net/dsa.h> 2262306a36Sopenharmony_ci#include <net/sock.h> 2362306a36Sopenharmony_ci#include <linux/if_vlan.h> 2462306a36Sopenharmony_ci#include <net/switchdev.h> 2562306a36Sopenharmony_ci#include <net/net_namespace.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "br_private.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* 3062306a36Sopenharmony_ci * Determine initial path cost based on speed. 3162306a36Sopenharmony_ci * using recommendations from 802.1d standard 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * Since driver might sleep need to not be holding any locks. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_cistatic int port_cost(struct net_device *dev) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct ethtool_link_ksettings ecmd; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (!__ethtool_get_link_ksettings(dev, &ecmd)) { 4062306a36Sopenharmony_ci switch (ecmd.base.speed) { 4162306a36Sopenharmony_ci case SPEED_10000: 4262306a36Sopenharmony_ci return 2; 4362306a36Sopenharmony_ci case SPEED_5000: 4462306a36Sopenharmony_ci return 3; 4562306a36Sopenharmony_ci case SPEED_2500: 4662306a36Sopenharmony_ci return 4; 4762306a36Sopenharmony_ci case SPEED_1000: 4862306a36Sopenharmony_ci return 5; 4962306a36Sopenharmony_ci case SPEED_100: 5062306a36Sopenharmony_ci return 19; 5162306a36Sopenharmony_ci case SPEED_10: 5262306a36Sopenharmony_ci return 100; 5362306a36Sopenharmony_ci case SPEED_UNKNOWN: 5462306a36Sopenharmony_ci return 100; 5562306a36Sopenharmony_ci default: 5662306a36Sopenharmony_ci if (ecmd.base.speed > SPEED_10000) 5762306a36Sopenharmony_ci return 1; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* Old silly heuristics based on name */ 6262306a36Sopenharmony_ci if (!strncmp(dev->name, "lec", 3)) 6362306a36Sopenharmony_ci return 7; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (!strncmp(dev->name, "plip", 4)) 6662306a36Sopenharmony_ci return 2500; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return 100; /* assume old 10Mbps */ 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* Check for port carrier transitions. */ 7362306a36Sopenharmony_civoid br_port_carrier_check(struct net_bridge_port *p, bool *notified) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct net_device *dev = p->dev; 7662306a36Sopenharmony_ci struct net_bridge *br = p->br; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (!(p->flags & BR_ADMIN_COST) && 7962306a36Sopenharmony_ci netif_running(dev) && netif_oper_up(dev)) 8062306a36Sopenharmony_ci p->path_cost = port_cost(dev); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci *notified = false; 8362306a36Sopenharmony_ci if (!netif_running(br->dev)) 8462306a36Sopenharmony_ci return; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci spin_lock_bh(&br->lock); 8762306a36Sopenharmony_ci if (netif_running(dev) && netif_oper_up(dev)) { 8862306a36Sopenharmony_ci if (p->state == BR_STATE_DISABLED) { 8962306a36Sopenharmony_ci br_stp_enable_port(p); 9062306a36Sopenharmony_ci *notified = true; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci } else { 9362306a36Sopenharmony_ci if (p->state != BR_STATE_DISABLED) { 9462306a36Sopenharmony_ci br_stp_disable_port(p); 9562306a36Sopenharmony_ci *notified = true; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci spin_unlock_bh(&br->lock); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic void br_port_set_promisc(struct net_bridge_port *p) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci int err = 0; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (br_promisc_port(p)) 10662306a36Sopenharmony_ci return; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci err = dev_set_promiscuity(p->dev, 1); 10962306a36Sopenharmony_ci if (err) 11062306a36Sopenharmony_ci return; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci br_fdb_unsync_static(p->br, p); 11362306a36Sopenharmony_ci p->flags |= BR_PROMISC; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic void br_port_clear_promisc(struct net_bridge_port *p) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci int err; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* Check if the port is already non-promisc or if it doesn't 12162306a36Sopenharmony_ci * support UNICAST filtering. Without unicast filtering support 12262306a36Sopenharmony_ci * we'll end up re-enabling promisc mode anyway, so just check for 12362306a36Sopenharmony_ci * it here. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ci if (!br_promisc_port(p) || !(p->dev->priv_flags & IFF_UNICAST_FLT)) 12662306a36Sopenharmony_ci return; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* Since we'll be clearing the promisc mode, program the port 12962306a36Sopenharmony_ci * first so that we don't have interruption in traffic. 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_ci err = br_fdb_sync_static(p->br, p); 13262306a36Sopenharmony_ci if (err) 13362306a36Sopenharmony_ci return; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci dev_set_promiscuity(p->dev, -1); 13662306a36Sopenharmony_ci p->flags &= ~BR_PROMISC; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* When a port is added or removed or when certain port flags 14062306a36Sopenharmony_ci * change, this function is called to automatically manage 14162306a36Sopenharmony_ci * promiscuity setting of all the bridge ports. We are always called 14262306a36Sopenharmony_ci * under RTNL so can skip using rcu primitives. 14362306a36Sopenharmony_ci */ 14462306a36Sopenharmony_civoid br_manage_promisc(struct net_bridge *br) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct net_bridge_port *p; 14762306a36Sopenharmony_ci bool set_all = false; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* If vlan filtering is disabled or bridge interface is placed 15062306a36Sopenharmony_ci * into promiscuous mode, place all ports in promiscuous mode. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_ci if ((br->dev->flags & IFF_PROMISC) || !br_vlan_enabled(br->dev)) 15362306a36Sopenharmony_ci set_all = true; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) { 15662306a36Sopenharmony_ci if (set_all) { 15762306a36Sopenharmony_ci br_port_set_promisc(p); 15862306a36Sopenharmony_ci } else { 15962306a36Sopenharmony_ci /* If the number of auto-ports is <= 1, then all other 16062306a36Sopenharmony_ci * ports will have their output configuration 16162306a36Sopenharmony_ci * statically specified through fdbs. Since ingress 16262306a36Sopenharmony_ci * on the auto-port becomes forwarding/egress to other 16362306a36Sopenharmony_ci * ports and egress configuration is statically known, 16462306a36Sopenharmony_ci * we can say that ingress configuration of the 16562306a36Sopenharmony_ci * auto-port is also statically known. 16662306a36Sopenharmony_ci * This lets us disable promiscuous mode and write 16762306a36Sopenharmony_ci * this config to hw. 16862306a36Sopenharmony_ci */ 16962306a36Sopenharmony_ci if ((p->dev->priv_flags & IFF_UNICAST_FLT) && 17062306a36Sopenharmony_ci (br->auto_cnt == 0 || 17162306a36Sopenharmony_ci (br->auto_cnt == 1 && br_auto_port(p)))) 17262306a36Sopenharmony_ci br_port_clear_promisc(p); 17362306a36Sopenharmony_ci else 17462306a36Sopenharmony_ci br_port_set_promisc(p); 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ciint nbp_backup_change(struct net_bridge_port *p, 18062306a36Sopenharmony_ci struct net_device *backup_dev) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci struct net_bridge_port *old_backup = rtnl_dereference(p->backup_port); 18362306a36Sopenharmony_ci struct net_bridge_port *backup_p = NULL; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci ASSERT_RTNL(); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (backup_dev) { 18862306a36Sopenharmony_ci if (!netif_is_bridge_port(backup_dev)) 18962306a36Sopenharmony_ci return -ENOENT; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci backup_p = br_port_get_rtnl(backup_dev); 19262306a36Sopenharmony_ci if (backup_p->br != p->br) 19362306a36Sopenharmony_ci return -EINVAL; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (p == backup_p) 19762306a36Sopenharmony_ci return -EINVAL; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (old_backup == backup_p) 20062306a36Sopenharmony_ci return 0; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* if the backup link is already set, clear it */ 20362306a36Sopenharmony_ci if (old_backup) 20462306a36Sopenharmony_ci old_backup->backup_redirected_cnt--; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (backup_p) 20762306a36Sopenharmony_ci backup_p->backup_redirected_cnt++; 20862306a36Sopenharmony_ci rcu_assign_pointer(p->backup_port, backup_p); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci return 0; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic void nbp_backup_clear(struct net_bridge_port *p) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci nbp_backup_change(p, NULL); 21662306a36Sopenharmony_ci if (p->backup_redirected_cnt) { 21762306a36Sopenharmony_ci struct net_bridge_port *cur_p; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci list_for_each_entry(cur_p, &p->br->port_list, list) { 22062306a36Sopenharmony_ci struct net_bridge_port *backup_p; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci backup_p = rtnl_dereference(cur_p->backup_port); 22362306a36Sopenharmony_ci if (backup_p == p) 22462306a36Sopenharmony_ci nbp_backup_change(cur_p, NULL); 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci WARN_ON(rcu_access_pointer(p->backup_port) || p->backup_redirected_cnt); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic void nbp_update_port_count(struct net_bridge *br) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct net_bridge_port *p; 23462306a36Sopenharmony_ci u32 cnt = 0; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) { 23762306a36Sopenharmony_ci if (br_auto_port(p)) 23862306a36Sopenharmony_ci cnt++; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci if (br->auto_cnt != cnt) { 24162306a36Sopenharmony_ci br->auto_cnt = cnt; 24262306a36Sopenharmony_ci br_manage_promisc(br); 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic void nbp_delete_promisc(struct net_bridge_port *p) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci /* If port is currently promiscuous, unset promiscuity. 24962306a36Sopenharmony_ci * Otherwise, it is a static port so remove all addresses 25062306a36Sopenharmony_ci * from it. 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_ci dev_set_allmulti(p->dev, -1); 25362306a36Sopenharmony_ci if (br_promisc_port(p)) 25462306a36Sopenharmony_ci dev_set_promiscuity(p->dev, -1); 25562306a36Sopenharmony_ci else 25662306a36Sopenharmony_ci br_fdb_unsync_static(p->br, p); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic void release_nbp(struct kobject *kobj) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct net_bridge_port *p 26262306a36Sopenharmony_ci = container_of(kobj, struct net_bridge_port, kobj); 26362306a36Sopenharmony_ci kfree(p); 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic void brport_get_ownership(const struct kobject *kobj, kuid_t *uid, kgid_t *gid) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct net_bridge_port *p = kobj_to_brport(kobj); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci net_ns_get_ownership(dev_net(p->dev), uid, gid); 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic const struct kobj_type brport_ktype = { 27462306a36Sopenharmony_ci#ifdef CONFIG_SYSFS 27562306a36Sopenharmony_ci .sysfs_ops = &brport_sysfs_ops, 27662306a36Sopenharmony_ci#endif 27762306a36Sopenharmony_ci .release = release_nbp, 27862306a36Sopenharmony_ci .get_ownership = brport_get_ownership, 27962306a36Sopenharmony_ci}; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic void destroy_nbp(struct net_bridge_port *p) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct net_device *dev = p->dev; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci p->br = NULL; 28662306a36Sopenharmony_ci p->dev = NULL; 28762306a36Sopenharmony_ci netdev_put(dev, &p->dev_tracker); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci kobject_put(&p->kobj); 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic void destroy_nbp_rcu(struct rcu_head *head) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci struct net_bridge_port *p = 29562306a36Sopenharmony_ci container_of(head, struct net_bridge_port, rcu); 29662306a36Sopenharmony_ci destroy_nbp(p); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic unsigned get_max_headroom(struct net_bridge *br) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci unsigned max_headroom = 0; 30262306a36Sopenharmony_ci struct net_bridge_port *p; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) { 30562306a36Sopenharmony_ci unsigned dev_headroom = netdev_get_fwd_headroom(p->dev); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (dev_headroom > max_headroom) 30862306a36Sopenharmony_ci max_headroom = dev_headroom; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci return max_headroom; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic void update_headroom(struct net_bridge *br, int new_hr) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct net_bridge_port *p; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) 31962306a36Sopenharmony_ci netdev_set_rx_headroom(p->dev, new_hr); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci br->dev->needed_headroom = new_hr; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci/* Delete port(interface) from bridge is done in two steps. 32562306a36Sopenharmony_ci * via RCU. First step, marks device as down. That deletes 32662306a36Sopenharmony_ci * all the timers and stops new packets from flowing through. 32762306a36Sopenharmony_ci * 32862306a36Sopenharmony_ci * Final cleanup doesn't occur until after all CPU's finished 32962306a36Sopenharmony_ci * processing packets. 33062306a36Sopenharmony_ci * 33162306a36Sopenharmony_ci * Protected from multiple admin operations by RTNL mutex 33262306a36Sopenharmony_ci */ 33362306a36Sopenharmony_cistatic void del_nbp(struct net_bridge_port *p) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct net_bridge *br = p->br; 33662306a36Sopenharmony_ci struct net_device *dev = p->dev; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci sysfs_remove_link(br->ifobj, p->dev->name); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci nbp_delete_promisc(p); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci spin_lock_bh(&br->lock); 34362306a36Sopenharmony_ci br_stp_disable_port(p); 34462306a36Sopenharmony_ci spin_unlock_bh(&br->lock); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci br_mrp_port_del(br, p); 34762306a36Sopenharmony_ci br_cfm_port_del(br, p); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci br_ifinfo_notify(RTM_DELLINK, NULL, p); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci list_del_rcu(&p->list); 35262306a36Sopenharmony_ci if (netdev_get_fwd_headroom(dev) == br->dev->needed_headroom) 35362306a36Sopenharmony_ci update_headroom(br, get_max_headroom(br)); 35462306a36Sopenharmony_ci netdev_reset_rx_headroom(dev); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci nbp_vlan_flush(p); 35762306a36Sopenharmony_ci br_fdb_delete_by_port(br, p, 0, 1); 35862306a36Sopenharmony_ci switchdev_deferred_process(); 35962306a36Sopenharmony_ci nbp_backup_clear(p); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci nbp_update_port_count(br); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci netdev_upper_dev_unlink(dev, br->dev); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci dev->priv_flags &= ~IFF_BRIDGE_PORT; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci netdev_rx_handler_unregister(dev); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci br_multicast_del_port(p); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci kobject_uevent(&p->kobj, KOBJ_REMOVE); 37262306a36Sopenharmony_ci kobject_del(&p->kobj); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci br_netpoll_disable(p); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci call_rcu(&p->rcu, destroy_nbp_rcu); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci/* Delete bridge device */ 38062306a36Sopenharmony_civoid br_dev_delete(struct net_device *dev, struct list_head *head) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 38362306a36Sopenharmony_ci struct net_bridge_port *p, *n; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci list_for_each_entry_safe(p, n, &br->port_list, list) { 38662306a36Sopenharmony_ci del_nbp(p); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci br_recalculate_neigh_suppress_enabled(br); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci br_fdb_delete_by_port(br, NULL, 0, 1); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci cancel_delayed_work_sync(&br->gc_work); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci br_sysfs_delbr(br->dev); 39662306a36Sopenharmony_ci unregister_netdevice_queue(br->dev, head); 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci/* find an available port number */ 40062306a36Sopenharmony_cistatic int find_portno(struct net_bridge *br) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci int index; 40362306a36Sopenharmony_ci struct net_bridge_port *p; 40462306a36Sopenharmony_ci unsigned long *inuse; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci inuse = bitmap_zalloc(BR_MAX_PORTS, GFP_KERNEL); 40762306a36Sopenharmony_ci if (!inuse) 40862306a36Sopenharmony_ci return -ENOMEM; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci __set_bit(0, inuse); /* zero is reserved */ 41162306a36Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) 41262306a36Sopenharmony_ci __set_bit(p->port_no, inuse); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci index = find_first_zero_bit(inuse, BR_MAX_PORTS); 41562306a36Sopenharmony_ci bitmap_free(inuse); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci return (index >= BR_MAX_PORTS) ? -EXFULL : index; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci/* called with RTNL but without bridge lock */ 42162306a36Sopenharmony_cistatic struct net_bridge_port *new_nbp(struct net_bridge *br, 42262306a36Sopenharmony_ci struct net_device *dev) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci struct net_bridge_port *p; 42562306a36Sopenharmony_ci int index, err; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci index = find_portno(br); 42862306a36Sopenharmony_ci if (index < 0) 42962306a36Sopenharmony_ci return ERR_PTR(index); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci p = kzalloc(sizeof(*p), GFP_KERNEL); 43262306a36Sopenharmony_ci if (p == NULL) 43362306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci p->br = br; 43662306a36Sopenharmony_ci netdev_hold(dev, &p->dev_tracker, GFP_KERNEL); 43762306a36Sopenharmony_ci p->dev = dev; 43862306a36Sopenharmony_ci p->path_cost = port_cost(dev); 43962306a36Sopenharmony_ci p->priority = 0x8000 >> BR_PORT_BITS; 44062306a36Sopenharmony_ci p->port_no = index; 44162306a36Sopenharmony_ci p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; 44262306a36Sopenharmony_ci br_init_port(p); 44362306a36Sopenharmony_ci br_set_state(p, BR_STATE_DISABLED); 44462306a36Sopenharmony_ci br_stp_port_timer_init(p); 44562306a36Sopenharmony_ci err = br_multicast_add_port(p); 44662306a36Sopenharmony_ci if (err) { 44762306a36Sopenharmony_ci netdev_put(dev, &p->dev_tracker); 44862306a36Sopenharmony_ci kfree(p); 44962306a36Sopenharmony_ci p = ERR_PTR(err); 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return p; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ciint br_add_bridge(struct net *net, const char *name) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci struct net_device *dev; 45862306a36Sopenharmony_ci int res; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci dev = alloc_netdev(sizeof(struct net_bridge), name, NET_NAME_UNKNOWN, 46162306a36Sopenharmony_ci br_dev_setup); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (!dev) 46462306a36Sopenharmony_ci return -ENOMEM; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci dev_net_set(dev, net); 46762306a36Sopenharmony_ci dev->rtnl_link_ops = &br_link_ops; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci res = register_netdevice(dev); 47062306a36Sopenharmony_ci if (res) 47162306a36Sopenharmony_ci free_netdev(dev); 47262306a36Sopenharmony_ci return res; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ciint br_del_bridge(struct net *net, const char *name) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct net_device *dev; 47862306a36Sopenharmony_ci int ret = 0; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci dev = __dev_get_by_name(net, name); 48162306a36Sopenharmony_ci if (dev == NULL) 48262306a36Sopenharmony_ci ret = -ENXIO; /* Could not find device */ 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci else if (!netif_is_bridge_master(dev)) { 48562306a36Sopenharmony_ci /* Attempt to delete non bridge device! */ 48662306a36Sopenharmony_ci ret = -EPERM; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci else if (dev->flags & IFF_UP) { 49062306a36Sopenharmony_ci /* Not shutdown yet. */ 49162306a36Sopenharmony_ci ret = -EBUSY; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci else 49562306a36Sopenharmony_ci br_dev_delete(dev, NULL); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return ret; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci/* MTU of the bridge pseudo-device: ETH_DATA_LEN or the minimum of the ports */ 50162306a36Sopenharmony_cistatic int br_mtu_min(const struct net_bridge *br) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci const struct net_bridge_port *p; 50462306a36Sopenharmony_ci int ret_mtu = 0; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) 50762306a36Sopenharmony_ci if (!ret_mtu || ret_mtu > p->dev->mtu) 50862306a36Sopenharmony_ci ret_mtu = p->dev->mtu; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci return ret_mtu ? ret_mtu : ETH_DATA_LEN; 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_civoid br_mtu_auto_adjust(struct net_bridge *br) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci ASSERT_RTNL(); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* if the bridge MTU was manually configured don't mess with it */ 51862306a36Sopenharmony_ci if (br_opt_get(br, BROPT_MTU_SET_BY_USER)) 51962306a36Sopenharmony_ci return; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* change to the minimum MTU and clear the flag which was set by 52262306a36Sopenharmony_ci * the bridge ndo_change_mtu callback 52362306a36Sopenharmony_ci */ 52462306a36Sopenharmony_ci dev_set_mtu(br->dev, br_mtu_min(br)); 52562306a36Sopenharmony_ci br_opt_toggle(br, BROPT_MTU_SET_BY_USER, false); 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic void br_set_gso_limits(struct net_bridge *br) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci unsigned int tso_max_size = TSO_MAX_SIZE; 53162306a36Sopenharmony_ci const struct net_bridge_port *p; 53262306a36Sopenharmony_ci u16 tso_max_segs = TSO_MAX_SEGS; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) { 53562306a36Sopenharmony_ci tso_max_size = min(tso_max_size, p->dev->tso_max_size); 53662306a36Sopenharmony_ci tso_max_segs = min(tso_max_segs, p->dev->tso_max_segs); 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci netif_set_tso_max_size(br->dev, tso_max_size); 53962306a36Sopenharmony_ci netif_set_tso_max_segs(br->dev, tso_max_segs); 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci/* 54362306a36Sopenharmony_ci * Recomputes features using slave's features 54462306a36Sopenharmony_ci */ 54562306a36Sopenharmony_cinetdev_features_t br_features_recompute(struct net_bridge *br, 54662306a36Sopenharmony_ci netdev_features_t features) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci struct net_bridge_port *p; 54962306a36Sopenharmony_ci netdev_features_t mask; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (list_empty(&br->port_list)) 55262306a36Sopenharmony_ci return features; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci mask = features; 55562306a36Sopenharmony_ci features &= ~NETIF_F_ONE_FOR_ALL; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) { 55862306a36Sopenharmony_ci features = netdev_increment_features(features, 55962306a36Sopenharmony_ci p->dev->features, mask); 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci features = netdev_add_tso_features(features, mask); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci return features; 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci/* called with RTNL */ 56762306a36Sopenharmony_ciint br_add_if(struct net_bridge *br, struct net_device *dev, 56862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci struct net_bridge_port *p; 57162306a36Sopenharmony_ci int err = 0; 57262306a36Sopenharmony_ci unsigned br_hr, dev_hr; 57362306a36Sopenharmony_ci bool changed_addr, fdb_synced = false; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* Don't allow bridging non-ethernet like devices. */ 57662306a36Sopenharmony_ci if ((dev->flags & IFF_LOOPBACK) || 57762306a36Sopenharmony_ci dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN || 57862306a36Sopenharmony_ci !is_valid_ether_addr(dev->dev_addr)) 57962306a36Sopenharmony_ci return -EINVAL; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* No bridging of bridges */ 58262306a36Sopenharmony_ci if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit) { 58362306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, 58462306a36Sopenharmony_ci "Can not enslave a bridge to a bridge"); 58562306a36Sopenharmony_ci return -ELOOP; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* Device has master upper dev */ 58962306a36Sopenharmony_ci if (netdev_master_upper_dev_get(dev)) 59062306a36Sopenharmony_ci return -EBUSY; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* No bridging devices that dislike that (e.g. wireless) */ 59362306a36Sopenharmony_ci if (dev->priv_flags & IFF_DONT_BRIDGE) { 59462306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, 59562306a36Sopenharmony_ci "Device does not allow enslaving to a bridge"); 59662306a36Sopenharmony_ci return -EOPNOTSUPP; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci p = new_nbp(br, dev); 60062306a36Sopenharmony_ci if (IS_ERR(p)) 60162306a36Sopenharmony_ci return PTR_ERR(p); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci call_netdevice_notifiers(NETDEV_JOIN, dev); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci err = dev_set_allmulti(dev, 1); 60662306a36Sopenharmony_ci if (err) { 60762306a36Sopenharmony_ci br_multicast_del_port(p); 60862306a36Sopenharmony_ci netdev_put(dev, &p->dev_tracker); 60962306a36Sopenharmony_ci kfree(p); /* kobject not yet init'd, manually free */ 61062306a36Sopenharmony_ci goto err1; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj), 61462306a36Sopenharmony_ci SYSFS_BRIDGE_PORT_ATTR); 61562306a36Sopenharmony_ci if (err) 61662306a36Sopenharmony_ci goto err2; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci err = br_sysfs_addif(p); 61962306a36Sopenharmony_ci if (err) 62062306a36Sopenharmony_ci goto err2; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci err = br_netpoll_enable(p); 62362306a36Sopenharmony_ci if (err) 62462306a36Sopenharmony_ci goto err3; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci err = netdev_rx_handler_register(dev, br_get_rx_handler(dev), p); 62762306a36Sopenharmony_ci if (err) 62862306a36Sopenharmony_ci goto err4; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci dev->priv_flags |= IFF_BRIDGE_PORT; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci err = netdev_master_upper_dev_link(dev, br->dev, NULL, NULL, extack); 63362306a36Sopenharmony_ci if (err) 63462306a36Sopenharmony_ci goto err5; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci dev_disable_lro(dev); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci list_add_rcu(&p->list, &br->port_list); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci nbp_update_port_count(br); 64162306a36Sopenharmony_ci if (!br_promisc_port(p) && (p->dev->priv_flags & IFF_UNICAST_FLT)) { 64262306a36Sopenharmony_ci /* When updating the port count we also update all ports' 64362306a36Sopenharmony_ci * promiscuous mode. 64462306a36Sopenharmony_ci * A port leaving promiscuous mode normally gets the bridge's 64562306a36Sopenharmony_ci * fdb synced to the unicast filter (if supported), however, 64662306a36Sopenharmony_ci * `br_port_clear_promisc` does not distinguish between 64762306a36Sopenharmony_ci * non-promiscuous ports and *new* ports, so we need to 64862306a36Sopenharmony_ci * sync explicitly here. 64962306a36Sopenharmony_ci */ 65062306a36Sopenharmony_ci fdb_synced = br_fdb_sync_static(br, p) == 0; 65162306a36Sopenharmony_ci if (!fdb_synced) 65262306a36Sopenharmony_ci netdev_err(dev, "failed to sync bridge static fdb addresses to this port\n"); 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci netdev_update_features(br->dev); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci br_hr = br->dev->needed_headroom; 65862306a36Sopenharmony_ci dev_hr = netdev_get_fwd_headroom(dev); 65962306a36Sopenharmony_ci if (br_hr < dev_hr) 66062306a36Sopenharmony_ci update_headroom(br, dev_hr); 66162306a36Sopenharmony_ci else 66262306a36Sopenharmony_ci netdev_set_rx_headroom(dev, br_hr); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (br_fdb_add_local(br, p, dev->dev_addr, 0)) 66562306a36Sopenharmony_ci netdev_err(dev, "failed insert local address bridge forwarding table\n"); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (br->dev->addr_assign_type != NET_ADDR_SET) { 66862306a36Sopenharmony_ci /* Ask for permission to use this MAC address now, even if we 66962306a36Sopenharmony_ci * don't end up choosing it below. 67062306a36Sopenharmony_ci */ 67162306a36Sopenharmony_ci err = dev_pre_changeaddr_notify(br->dev, dev->dev_addr, extack); 67262306a36Sopenharmony_ci if (err) 67362306a36Sopenharmony_ci goto err6; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci err = nbp_vlan_init(p, extack); 67762306a36Sopenharmony_ci if (err) { 67862306a36Sopenharmony_ci netdev_err(dev, "failed to initialize vlan filtering on this port\n"); 67962306a36Sopenharmony_ci goto err6; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci spin_lock_bh(&br->lock); 68362306a36Sopenharmony_ci changed_addr = br_stp_recalculate_bridge_id(br); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (netif_running(dev) && netif_oper_up(dev) && 68662306a36Sopenharmony_ci (br->dev->flags & IFF_UP)) 68762306a36Sopenharmony_ci br_stp_enable_port(p); 68862306a36Sopenharmony_ci spin_unlock_bh(&br->lock); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci br_ifinfo_notify(RTM_NEWLINK, NULL, p); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci if (changed_addr) 69362306a36Sopenharmony_ci call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci br_mtu_auto_adjust(br); 69662306a36Sopenharmony_ci br_set_gso_limits(br); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci kobject_uevent(&p->kobj, KOBJ_ADD); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci return 0; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cierr6: 70362306a36Sopenharmony_ci if (fdb_synced) 70462306a36Sopenharmony_ci br_fdb_unsync_static(br, p); 70562306a36Sopenharmony_ci list_del_rcu(&p->list); 70662306a36Sopenharmony_ci br_fdb_delete_by_port(br, p, 0, 1); 70762306a36Sopenharmony_ci nbp_update_port_count(br); 70862306a36Sopenharmony_ci netdev_upper_dev_unlink(dev, br->dev); 70962306a36Sopenharmony_cierr5: 71062306a36Sopenharmony_ci dev->priv_flags &= ~IFF_BRIDGE_PORT; 71162306a36Sopenharmony_ci netdev_rx_handler_unregister(dev); 71262306a36Sopenharmony_cierr4: 71362306a36Sopenharmony_ci br_netpoll_disable(p); 71462306a36Sopenharmony_cierr3: 71562306a36Sopenharmony_ci sysfs_remove_link(br->ifobj, p->dev->name); 71662306a36Sopenharmony_cierr2: 71762306a36Sopenharmony_ci br_multicast_del_port(p); 71862306a36Sopenharmony_ci netdev_put(dev, &p->dev_tracker); 71962306a36Sopenharmony_ci kobject_put(&p->kobj); 72062306a36Sopenharmony_ci dev_set_allmulti(dev, -1); 72162306a36Sopenharmony_cierr1: 72262306a36Sopenharmony_ci return err; 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci/* called with RTNL */ 72662306a36Sopenharmony_ciint br_del_if(struct net_bridge *br, struct net_device *dev) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci struct net_bridge_port *p; 72962306a36Sopenharmony_ci bool changed_addr; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci p = br_port_get_rtnl(dev); 73262306a36Sopenharmony_ci if (!p || p->br != br) 73362306a36Sopenharmony_ci return -EINVAL; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci /* Since more than one interface can be attached to a bridge, 73662306a36Sopenharmony_ci * there still maybe an alternate path for netconsole to use; 73762306a36Sopenharmony_ci * therefore there is no reason for a NETDEV_RELEASE event. 73862306a36Sopenharmony_ci */ 73962306a36Sopenharmony_ci del_nbp(p); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci br_mtu_auto_adjust(br); 74262306a36Sopenharmony_ci br_set_gso_limits(br); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci spin_lock_bh(&br->lock); 74562306a36Sopenharmony_ci changed_addr = br_stp_recalculate_bridge_id(br); 74662306a36Sopenharmony_ci spin_unlock_bh(&br->lock); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (changed_addr) 74962306a36Sopenharmony_ci call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci netdev_update_features(br->dev); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci return 0; 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_civoid br_port_flags_change(struct net_bridge_port *p, unsigned long mask) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci struct net_bridge *br = p->br; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if (mask & BR_AUTO_MASK) 76162306a36Sopenharmony_ci nbp_update_port_count(br); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (mask & (BR_NEIGH_SUPPRESS | BR_NEIGH_VLAN_SUPPRESS)) 76462306a36Sopenharmony_ci br_recalculate_neigh_suppress_enabled(br); 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cibool br_port_flag_is_set(const struct net_device *dev, unsigned long flag) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci struct net_bridge_port *p; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci p = br_port_get_rtnl_rcu(dev); 77262306a36Sopenharmony_ci if (!p) 77362306a36Sopenharmony_ci return false; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci return p->flags & flag; 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(br_port_flag_is_set); 778