18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *	Userspace interface
48c2ecf20Sopenharmony_ci *	Linux ethernet bridge
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *	Authors:
78c2ecf20Sopenharmony_ci *	Lennert Buytenhek		<buytenh@gnu.org>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
128c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
138c2ecf20Sopenharmony_ci#include <linux/netpoll.h>
148c2ecf20Sopenharmony_ci#include <linux/ethtool.h>
158c2ecf20Sopenharmony_ci#include <linux/if_arp.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/init.h>
188c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h>
198c2ecf20Sopenharmony_ci#include <linux/if_ether.h>
208c2ecf20Sopenharmony_ci#include <linux/slab.h>
218c2ecf20Sopenharmony_ci#include <net/dsa.h>
228c2ecf20Sopenharmony_ci#include <net/sock.h>
238c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
248c2ecf20Sopenharmony_ci#include <net/switchdev.h>
258c2ecf20Sopenharmony_ci#include <net/net_namespace.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include "br_private.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/*
308c2ecf20Sopenharmony_ci * Determine initial path cost based on speed.
318c2ecf20Sopenharmony_ci * using recommendations from 802.1d standard
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci * Since driver might sleep need to not be holding any locks.
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_cistatic int port_cost(struct net_device *dev)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	struct ethtool_link_ksettings ecmd;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	if (!__ethtool_get_link_ksettings(dev, &ecmd)) {
408c2ecf20Sopenharmony_ci		switch (ecmd.base.speed) {
418c2ecf20Sopenharmony_ci		case SPEED_10000:
428c2ecf20Sopenharmony_ci			return 2;
438c2ecf20Sopenharmony_ci		case SPEED_1000:
448c2ecf20Sopenharmony_ci			return 4;
458c2ecf20Sopenharmony_ci		case SPEED_100:
468c2ecf20Sopenharmony_ci			return 19;
478c2ecf20Sopenharmony_ci		case SPEED_10:
488c2ecf20Sopenharmony_ci			return 100;
498c2ecf20Sopenharmony_ci		}
508c2ecf20Sopenharmony_ci	}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	/* Old silly heuristics based on name */
538c2ecf20Sopenharmony_ci	if (!strncmp(dev->name, "lec", 3))
548c2ecf20Sopenharmony_ci		return 7;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	if (!strncmp(dev->name, "plip", 4))
578c2ecf20Sopenharmony_ci		return 2500;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	return 100;	/* assume old 10Mbps */
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* Check for port carrier transitions. */
648c2ecf20Sopenharmony_civoid br_port_carrier_check(struct net_bridge_port *p, bool *notified)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct net_device *dev = p->dev;
678c2ecf20Sopenharmony_ci	struct net_bridge *br = p->br;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	if (!(p->flags & BR_ADMIN_COST) &&
708c2ecf20Sopenharmony_ci	    netif_running(dev) && netif_oper_up(dev))
718c2ecf20Sopenharmony_ci		p->path_cost = port_cost(dev);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	*notified = false;
748c2ecf20Sopenharmony_ci	if (!netif_running(br->dev))
758c2ecf20Sopenharmony_ci		return;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	spin_lock_bh(&br->lock);
788c2ecf20Sopenharmony_ci	if (netif_running(dev) && netif_oper_up(dev)) {
798c2ecf20Sopenharmony_ci		if (p->state == BR_STATE_DISABLED) {
808c2ecf20Sopenharmony_ci			br_stp_enable_port(p);
818c2ecf20Sopenharmony_ci			*notified = true;
828c2ecf20Sopenharmony_ci		}
838c2ecf20Sopenharmony_ci	} else {
848c2ecf20Sopenharmony_ci		if (p->state != BR_STATE_DISABLED) {
858c2ecf20Sopenharmony_ci			br_stp_disable_port(p);
868c2ecf20Sopenharmony_ci			*notified = true;
878c2ecf20Sopenharmony_ci		}
888c2ecf20Sopenharmony_ci	}
898c2ecf20Sopenharmony_ci	spin_unlock_bh(&br->lock);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic void br_port_set_promisc(struct net_bridge_port *p)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	int err = 0;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	if (br_promisc_port(p))
978c2ecf20Sopenharmony_ci		return;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	err = dev_set_promiscuity(p->dev, 1);
1008c2ecf20Sopenharmony_ci	if (err)
1018c2ecf20Sopenharmony_ci		return;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	br_fdb_unsync_static(p->br, p);
1048c2ecf20Sopenharmony_ci	p->flags |= BR_PROMISC;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic void br_port_clear_promisc(struct net_bridge_port *p)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	int err;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	/* Check if the port is already non-promisc or if it doesn't
1128c2ecf20Sopenharmony_ci	 * support UNICAST filtering.  Without unicast filtering support
1138c2ecf20Sopenharmony_ci	 * we'll end up re-enabling promisc mode anyway, so just check for
1148c2ecf20Sopenharmony_ci	 * it here.
1158c2ecf20Sopenharmony_ci	 */
1168c2ecf20Sopenharmony_ci	if (!br_promisc_port(p) || !(p->dev->priv_flags & IFF_UNICAST_FLT))
1178c2ecf20Sopenharmony_ci		return;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	/* Since we'll be clearing the promisc mode, program the port
1208c2ecf20Sopenharmony_ci	 * first so that we don't have interruption in traffic.
1218c2ecf20Sopenharmony_ci	 */
1228c2ecf20Sopenharmony_ci	err = br_fdb_sync_static(p->br, p);
1238c2ecf20Sopenharmony_ci	if (err)
1248c2ecf20Sopenharmony_ci		return;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	dev_set_promiscuity(p->dev, -1);
1278c2ecf20Sopenharmony_ci	p->flags &= ~BR_PROMISC;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci/* When a port is added or removed or when certain port flags
1318c2ecf20Sopenharmony_ci * change, this function is called to automatically manage
1328c2ecf20Sopenharmony_ci * promiscuity setting of all the bridge ports.  We are always called
1338c2ecf20Sopenharmony_ci * under RTNL so can skip using rcu primitives.
1348c2ecf20Sopenharmony_ci */
1358c2ecf20Sopenharmony_civoid br_manage_promisc(struct net_bridge *br)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	struct net_bridge_port *p;
1388c2ecf20Sopenharmony_ci	bool set_all = false;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	/* If vlan filtering is disabled or bridge interface is placed
1418c2ecf20Sopenharmony_ci	 * into promiscuous mode, place all ports in promiscuous mode.
1428c2ecf20Sopenharmony_ci	 */
1438c2ecf20Sopenharmony_ci	if ((br->dev->flags & IFF_PROMISC) || !br_vlan_enabled(br->dev))
1448c2ecf20Sopenharmony_ci		set_all = true;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	list_for_each_entry(p, &br->port_list, list) {
1478c2ecf20Sopenharmony_ci		if (set_all) {
1488c2ecf20Sopenharmony_ci			br_port_set_promisc(p);
1498c2ecf20Sopenharmony_ci		} else {
1508c2ecf20Sopenharmony_ci			/* If the number of auto-ports is <= 1, then all other
1518c2ecf20Sopenharmony_ci			 * ports will have their output configuration
1528c2ecf20Sopenharmony_ci			 * statically specified through fdbs.  Since ingress
1538c2ecf20Sopenharmony_ci			 * on the auto-port becomes forwarding/egress to other
1548c2ecf20Sopenharmony_ci			 * ports and egress configuration is statically known,
1558c2ecf20Sopenharmony_ci			 * we can say that ingress configuration of the
1568c2ecf20Sopenharmony_ci			 * auto-port is also statically known.
1578c2ecf20Sopenharmony_ci			 * This lets us disable promiscuous mode and write
1588c2ecf20Sopenharmony_ci			 * this config to hw.
1598c2ecf20Sopenharmony_ci			 */
1608c2ecf20Sopenharmony_ci			if ((p->dev->priv_flags & IFF_UNICAST_FLT) &&
1618c2ecf20Sopenharmony_ci			    (br->auto_cnt == 0 ||
1628c2ecf20Sopenharmony_ci			     (br->auto_cnt == 1 && br_auto_port(p))))
1638c2ecf20Sopenharmony_ci				br_port_clear_promisc(p);
1648c2ecf20Sopenharmony_ci			else
1658c2ecf20Sopenharmony_ci				br_port_set_promisc(p);
1668c2ecf20Sopenharmony_ci		}
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ciint nbp_backup_change(struct net_bridge_port *p,
1718c2ecf20Sopenharmony_ci		      struct net_device *backup_dev)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	struct net_bridge_port *old_backup = rtnl_dereference(p->backup_port);
1748c2ecf20Sopenharmony_ci	struct net_bridge_port *backup_p = NULL;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	ASSERT_RTNL();
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	if (backup_dev) {
1798c2ecf20Sopenharmony_ci		if (!netif_is_bridge_port(backup_dev))
1808c2ecf20Sopenharmony_ci			return -ENOENT;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci		backup_p = br_port_get_rtnl(backup_dev);
1838c2ecf20Sopenharmony_ci		if (backup_p->br != p->br)
1848c2ecf20Sopenharmony_ci			return -EINVAL;
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	if (p == backup_p)
1888c2ecf20Sopenharmony_ci		return -EINVAL;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	if (old_backup == backup_p)
1918c2ecf20Sopenharmony_ci		return 0;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	/* if the backup link is already set, clear it */
1948c2ecf20Sopenharmony_ci	if (old_backup)
1958c2ecf20Sopenharmony_ci		old_backup->backup_redirected_cnt--;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (backup_p)
1988c2ecf20Sopenharmony_ci		backup_p->backup_redirected_cnt++;
1998c2ecf20Sopenharmony_ci	rcu_assign_pointer(p->backup_port, backup_p);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	return 0;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic void nbp_backup_clear(struct net_bridge_port *p)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	nbp_backup_change(p, NULL);
2078c2ecf20Sopenharmony_ci	if (p->backup_redirected_cnt) {
2088c2ecf20Sopenharmony_ci		struct net_bridge_port *cur_p;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci		list_for_each_entry(cur_p, &p->br->port_list, list) {
2118c2ecf20Sopenharmony_ci			struct net_bridge_port *backup_p;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci			backup_p = rtnl_dereference(cur_p->backup_port);
2148c2ecf20Sopenharmony_ci			if (backup_p == p)
2158c2ecf20Sopenharmony_ci				nbp_backup_change(cur_p, NULL);
2168c2ecf20Sopenharmony_ci		}
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	WARN_ON(rcu_access_pointer(p->backup_port) || p->backup_redirected_cnt);
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic void nbp_update_port_count(struct net_bridge *br)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	struct net_bridge_port *p;
2258c2ecf20Sopenharmony_ci	u32 cnt = 0;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	list_for_each_entry(p, &br->port_list, list) {
2288c2ecf20Sopenharmony_ci		if (br_auto_port(p))
2298c2ecf20Sopenharmony_ci			cnt++;
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci	if (br->auto_cnt != cnt) {
2328c2ecf20Sopenharmony_ci		br->auto_cnt = cnt;
2338c2ecf20Sopenharmony_ci		br_manage_promisc(br);
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic void nbp_delete_promisc(struct net_bridge_port *p)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	/* If port is currently promiscuous, unset promiscuity.
2408c2ecf20Sopenharmony_ci	 * Otherwise, it is a static port so remove all addresses
2418c2ecf20Sopenharmony_ci	 * from it.
2428c2ecf20Sopenharmony_ci	 */
2438c2ecf20Sopenharmony_ci	dev_set_allmulti(p->dev, -1);
2448c2ecf20Sopenharmony_ci	if (br_promisc_port(p))
2458c2ecf20Sopenharmony_ci		dev_set_promiscuity(p->dev, -1);
2468c2ecf20Sopenharmony_ci	else
2478c2ecf20Sopenharmony_ci		br_fdb_unsync_static(p->br, p);
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic void release_nbp(struct kobject *kobj)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	struct net_bridge_port *p
2538c2ecf20Sopenharmony_ci		= container_of(kobj, struct net_bridge_port, kobj);
2548c2ecf20Sopenharmony_ci	kfree(p);
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic void brport_get_ownership(struct kobject *kobj, kuid_t *uid, kgid_t *gid)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	struct net_bridge_port *p = kobj_to_brport(kobj);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	net_ns_get_ownership(dev_net(p->dev), uid, gid);
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic struct kobj_type brport_ktype = {
2658c2ecf20Sopenharmony_ci#ifdef CONFIG_SYSFS
2668c2ecf20Sopenharmony_ci	.sysfs_ops = &brport_sysfs_ops,
2678c2ecf20Sopenharmony_ci#endif
2688c2ecf20Sopenharmony_ci	.release = release_nbp,
2698c2ecf20Sopenharmony_ci	.get_ownership = brport_get_ownership,
2708c2ecf20Sopenharmony_ci};
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic void destroy_nbp(struct net_bridge_port *p)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	struct net_device *dev = p->dev;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	p->br = NULL;
2778c2ecf20Sopenharmony_ci	p->dev = NULL;
2788c2ecf20Sopenharmony_ci	dev_put(dev);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	kobject_put(&p->kobj);
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic void destroy_nbp_rcu(struct rcu_head *head)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	struct net_bridge_port *p =
2868c2ecf20Sopenharmony_ci			container_of(head, struct net_bridge_port, rcu);
2878c2ecf20Sopenharmony_ci	destroy_nbp(p);
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic unsigned get_max_headroom(struct net_bridge *br)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	unsigned max_headroom = 0;
2938c2ecf20Sopenharmony_ci	struct net_bridge_port *p;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	list_for_each_entry(p, &br->port_list, list) {
2968c2ecf20Sopenharmony_ci		unsigned dev_headroom = netdev_get_fwd_headroom(p->dev);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci		if (dev_headroom > max_headroom)
2998c2ecf20Sopenharmony_ci			max_headroom = dev_headroom;
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	return max_headroom;
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistatic void update_headroom(struct net_bridge *br, int new_hr)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	struct net_bridge_port *p;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	list_for_each_entry(p, &br->port_list, list)
3108c2ecf20Sopenharmony_ci		netdev_set_rx_headroom(p->dev, new_hr);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	br->dev->needed_headroom = new_hr;
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci/* Delete port(interface) from bridge is done in two steps.
3168c2ecf20Sopenharmony_ci * via RCU. First step, marks device as down. That deletes
3178c2ecf20Sopenharmony_ci * all the timers and stops new packets from flowing through.
3188c2ecf20Sopenharmony_ci *
3198c2ecf20Sopenharmony_ci * Final cleanup doesn't occur until after all CPU's finished
3208c2ecf20Sopenharmony_ci * processing packets.
3218c2ecf20Sopenharmony_ci *
3228c2ecf20Sopenharmony_ci * Protected from multiple admin operations by RTNL mutex
3238c2ecf20Sopenharmony_ci */
3248c2ecf20Sopenharmony_cistatic void del_nbp(struct net_bridge_port *p)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	struct net_bridge *br = p->br;
3278c2ecf20Sopenharmony_ci	struct net_device *dev = p->dev;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	sysfs_remove_link(br->ifobj, p->dev->name);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	nbp_delete_promisc(p);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	spin_lock_bh(&br->lock);
3348c2ecf20Sopenharmony_ci	br_stp_disable_port(p);
3358c2ecf20Sopenharmony_ci	spin_unlock_bh(&br->lock);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	br_mrp_port_del(br, p);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	br_ifinfo_notify(RTM_DELLINK, NULL, p);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	list_del_rcu(&p->list);
3428c2ecf20Sopenharmony_ci	if (netdev_get_fwd_headroom(dev) == br->dev->needed_headroom)
3438c2ecf20Sopenharmony_ci		update_headroom(br, get_max_headroom(br));
3448c2ecf20Sopenharmony_ci	netdev_reset_rx_headroom(dev);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	nbp_vlan_flush(p);
3478c2ecf20Sopenharmony_ci	br_fdb_delete_by_port(br, p, 0, 1);
3488c2ecf20Sopenharmony_ci	switchdev_deferred_process();
3498c2ecf20Sopenharmony_ci	nbp_backup_clear(p);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	nbp_update_port_count(br);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	netdev_upper_dev_unlink(dev, br->dev);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	dev->priv_flags &= ~IFF_BRIDGE_PORT;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	netdev_rx_handler_unregister(dev);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	br_multicast_del_port(p);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	kobject_uevent(&p->kobj, KOBJ_REMOVE);
3628c2ecf20Sopenharmony_ci	kobject_del(&p->kobj);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	br_netpoll_disable(p);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	call_rcu(&p->rcu, destroy_nbp_rcu);
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci/* Delete bridge device */
3708c2ecf20Sopenharmony_civoid br_dev_delete(struct net_device *dev, struct list_head *head)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	struct net_bridge *br = netdev_priv(dev);
3738c2ecf20Sopenharmony_ci	struct net_bridge_port *p, *n;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	list_for_each_entry_safe(p, n, &br->port_list, list) {
3768c2ecf20Sopenharmony_ci		del_nbp(p);
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	br_recalculate_neigh_suppress_enabled(br);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	br_fdb_delete_by_port(br, NULL, 0, 1);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&br->gc_work);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	br_sysfs_delbr(br->dev);
3868c2ecf20Sopenharmony_ci	unregister_netdevice_queue(br->dev, head);
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci/* find an available port number */
3908c2ecf20Sopenharmony_cistatic int find_portno(struct net_bridge *br)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	int index;
3938c2ecf20Sopenharmony_ci	struct net_bridge_port *p;
3948c2ecf20Sopenharmony_ci	unsigned long *inuse;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	inuse = bitmap_zalloc(BR_MAX_PORTS, GFP_KERNEL);
3978c2ecf20Sopenharmony_ci	if (!inuse)
3988c2ecf20Sopenharmony_ci		return -ENOMEM;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	set_bit(0, inuse);	/* zero is reserved */
4018c2ecf20Sopenharmony_ci	list_for_each_entry(p, &br->port_list, list) {
4028c2ecf20Sopenharmony_ci		set_bit(p->port_no, inuse);
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci	index = find_first_zero_bit(inuse, BR_MAX_PORTS);
4058c2ecf20Sopenharmony_ci	bitmap_free(inuse);
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	return (index >= BR_MAX_PORTS) ? -EXFULL : index;
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci/* called with RTNL but without bridge lock */
4118c2ecf20Sopenharmony_cistatic struct net_bridge_port *new_nbp(struct net_bridge *br,
4128c2ecf20Sopenharmony_ci				       struct net_device *dev)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	struct net_bridge_port *p;
4158c2ecf20Sopenharmony_ci	int index, err;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	index = find_portno(br);
4188c2ecf20Sopenharmony_ci	if (index < 0)
4198c2ecf20Sopenharmony_ci		return ERR_PTR(index);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	p = kzalloc(sizeof(*p), GFP_KERNEL);
4228c2ecf20Sopenharmony_ci	if (p == NULL)
4238c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	p->br = br;
4268c2ecf20Sopenharmony_ci	dev_hold(dev);
4278c2ecf20Sopenharmony_ci	p->dev = dev;
4288c2ecf20Sopenharmony_ci	p->path_cost = port_cost(dev);
4298c2ecf20Sopenharmony_ci	p->priority = 0x8000 >> BR_PORT_BITS;
4308c2ecf20Sopenharmony_ci	p->port_no = index;
4318c2ecf20Sopenharmony_ci	p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
4328c2ecf20Sopenharmony_ci	br_init_port(p);
4338c2ecf20Sopenharmony_ci	br_set_state(p, BR_STATE_DISABLED);
4348c2ecf20Sopenharmony_ci	br_stp_port_timer_init(p);
4358c2ecf20Sopenharmony_ci	err = br_multicast_add_port(p);
4368c2ecf20Sopenharmony_ci	if (err) {
4378c2ecf20Sopenharmony_ci		dev_put(dev);
4388c2ecf20Sopenharmony_ci		kfree(p);
4398c2ecf20Sopenharmony_ci		p = ERR_PTR(err);
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	return p;
4438c2ecf20Sopenharmony_ci}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ciint br_add_bridge(struct net *net, const char *name)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	struct net_device *dev;
4488c2ecf20Sopenharmony_ci	int res;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	dev = alloc_netdev(sizeof(struct net_bridge), name, NET_NAME_UNKNOWN,
4518c2ecf20Sopenharmony_ci			   br_dev_setup);
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	if (!dev)
4548c2ecf20Sopenharmony_ci		return -ENOMEM;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	dev_net_set(dev, net);
4578c2ecf20Sopenharmony_ci	dev->rtnl_link_ops = &br_link_ops;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	res = register_netdev(dev);
4608c2ecf20Sopenharmony_ci	if (res)
4618c2ecf20Sopenharmony_ci		free_netdev(dev);
4628c2ecf20Sopenharmony_ci	return res;
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ciint br_del_bridge(struct net *net, const char *name)
4668c2ecf20Sopenharmony_ci{
4678c2ecf20Sopenharmony_ci	struct net_device *dev;
4688c2ecf20Sopenharmony_ci	int ret = 0;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	rtnl_lock();
4718c2ecf20Sopenharmony_ci	dev = __dev_get_by_name(net, name);
4728c2ecf20Sopenharmony_ci	if (dev == NULL)
4738c2ecf20Sopenharmony_ci		ret =  -ENXIO; 	/* Could not find device */
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	else if (!(dev->priv_flags & IFF_EBRIDGE)) {
4768c2ecf20Sopenharmony_ci		/* Attempt to delete non bridge device! */
4778c2ecf20Sopenharmony_ci		ret = -EPERM;
4788c2ecf20Sopenharmony_ci	}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	else if (dev->flags & IFF_UP) {
4818c2ecf20Sopenharmony_ci		/* Not shutdown yet. */
4828c2ecf20Sopenharmony_ci		ret = -EBUSY;
4838c2ecf20Sopenharmony_ci	}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	else
4868c2ecf20Sopenharmony_ci		br_dev_delete(dev, NULL);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	rtnl_unlock();
4898c2ecf20Sopenharmony_ci	return ret;
4908c2ecf20Sopenharmony_ci}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci/* MTU of the bridge pseudo-device: ETH_DATA_LEN or the minimum of the ports */
4938c2ecf20Sopenharmony_cistatic int br_mtu_min(const struct net_bridge *br)
4948c2ecf20Sopenharmony_ci{
4958c2ecf20Sopenharmony_ci	const struct net_bridge_port *p;
4968c2ecf20Sopenharmony_ci	int ret_mtu = 0;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	list_for_each_entry(p, &br->port_list, list)
4998c2ecf20Sopenharmony_ci		if (!ret_mtu || ret_mtu > p->dev->mtu)
5008c2ecf20Sopenharmony_ci			ret_mtu = p->dev->mtu;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	return ret_mtu ? ret_mtu : ETH_DATA_LEN;
5038c2ecf20Sopenharmony_ci}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_civoid br_mtu_auto_adjust(struct net_bridge *br)
5068c2ecf20Sopenharmony_ci{
5078c2ecf20Sopenharmony_ci	ASSERT_RTNL();
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	/* if the bridge MTU was manually configured don't mess with it */
5108c2ecf20Sopenharmony_ci	if (br_opt_get(br, BROPT_MTU_SET_BY_USER))
5118c2ecf20Sopenharmony_ci		return;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	/* change to the minimum MTU and clear the flag which was set by
5148c2ecf20Sopenharmony_ci	 * the bridge ndo_change_mtu callback
5158c2ecf20Sopenharmony_ci	 */
5168c2ecf20Sopenharmony_ci	dev_set_mtu(br->dev, br_mtu_min(br));
5178c2ecf20Sopenharmony_ci	br_opt_toggle(br, BROPT_MTU_SET_BY_USER, false);
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic void br_set_gso_limits(struct net_bridge *br)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	unsigned int gso_max_size = GSO_MAX_SIZE;
5238c2ecf20Sopenharmony_ci	u16 gso_max_segs = GSO_MAX_SEGS;
5248c2ecf20Sopenharmony_ci	const struct net_bridge_port *p;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	list_for_each_entry(p, &br->port_list, list) {
5278c2ecf20Sopenharmony_ci		gso_max_size = min(gso_max_size, p->dev->gso_max_size);
5288c2ecf20Sopenharmony_ci		gso_max_segs = min(gso_max_segs, p->dev->gso_max_segs);
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci	br->dev->gso_max_size = gso_max_size;
5318c2ecf20Sopenharmony_ci	br->dev->gso_max_segs = gso_max_segs;
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci/*
5358c2ecf20Sopenharmony_ci * Recomputes features using slave's features
5368c2ecf20Sopenharmony_ci */
5378c2ecf20Sopenharmony_cinetdev_features_t br_features_recompute(struct net_bridge *br,
5388c2ecf20Sopenharmony_ci	netdev_features_t features)
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	struct net_bridge_port *p;
5418c2ecf20Sopenharmony_ci	netdev_features_t mask;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	if (list_empty(&br->port_list))
5448c2ecf20Sopenharmony_ci		return features;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	mask = features;
5478c2ecf20Sopenharmony_ci	features &= ~NETIF_F_ONE_FOR_ALL;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	list_for_each_entry(p, &br->port_list, list) {
5508c2ecf20Sopenharmony_ci		features = netdev_increment_features(features,
5518c2ecf20Sopenharmony_ci						     p->dev->features, mask);
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci	features = netdev_add_tso_features(features, mask);
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	return features;
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci/* called with RTNL */
5598c2ecf20Sopenharmony_ciint br_add_if(struct net_bridge *br, struct net_device *dev,
5608c2ecf20Sopenharmony_ci	      struct netlink_ext_ack *extack)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	struct net_bridge_port *p;
5638c2ecf20Sopenharmony_ci	int err = 0;
5648c2ecf20Sopenharmony_ci	unsigned br_hr, dev_hr;
5658c2ecf20Sopenharmony_ci	bool changed_addr, fdb_synced = false;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	/* Don't allow bridging non-ethernet like devices. */
5688c2ecf20Sopenharmony_ci	if ((dev->flags & IFF_LOOPBACK) ||
5698c2ecf20Sopenharmony_ci	    dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN ||
5708c2ecf20Sopenharmony_ci	    !is_valid_ether_addr(dev->dev_addr))
5718c2ecf20Sopenharmony_ci		return -EINVAL;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	/* Also don't allow bridging of net devices that are DSA masters, since
5748c2ecf20Sopenharmony_ci	 * the bridge layer rx_handler prevents the DSA fake ethertype handler
5758c2ecf20Sopenharmony_ci	 * to be invoked, so we don't get the chance to strip off and parse the
5768c2ecf20Sopenharmony_ci	 * DSA switch tag protocol header (the bridge layer just returns
5778c2ecf20Sopenharmony_ci	 * RX_HANDLER_CONSUMED, stopping RX processing for these frames).
5788c2ecf20Sopenharmony_ci	 * The only case where that would not be an issue is when bridging can
5798c2ecf20Sopenharmony_ci	 * already be offloaded, such as when the DSA master is itself a DSA
5808c2ecf20Sopenharmony_ci	 * or plain switchdev port, and is bridged only with other ports from
5818c2ecf20Sopenharmony_ci	 * the same hardware device.
5828c2ecf20Sopenharmony_ci	 */
5838c2ecf20Sopenharmony_ci	if (netdev_uses_dsa(dev)) {
5848c2ecf20Sopenharmony_ci		list_for_each_entry(p, &br->port_list, list) {
5858c2ecf20Sopenharmony_ci			if (!netdev_port_same_parent_id(dev, p->dev)) {
5868c2ecf20Sopenharmony_ci				NL_SET_ERR_MSG(extack,
5878c2ecf20Sopenharmony_ci					       "Cannot do software bridging with a DSA master");
5888c2ecf20Sopenharmony_ci				return -EINVAL;
5898c2ecf20Sopenharmony_ci			}
5908c2ecf20Sopenharmony_ci		}
5918c2ecf20Sopenharmony_ci	}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	/* No bridging of bridges */
5948c2ecf20Sopenharmony_ci	if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit) {
5958c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG(extack,
5968c2ecf20Sopenharmony_ci			       "Can not enslave a bridge to a bridge");
5978c2ecf20Sopenharmony_ci		return -ELOOP;
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	/* Device has master upper dev */
6018c2ecf20Sopenharmony_ci	if (netdev_master_upper_dev_get(dev))
6028c2ecf20Sopenharmony_ci		return -EBUSY;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	/* No bridging devices that dislike that (e.g. wireless) */
6058c2ecf20Sopenharmony_ci	if (dev->priv_flags & IFF_DONT_BRIDGE) {
6068c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG(extack,
6078c2ecf20Sopenharmony_ci			       "Device does not allow enslaving to a bridge");
6088c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	p = new_nbp(br, dev);
6128c2ecf20Sopenharmony_ci	if (IS_ERR(p))
6138c2ecf20Sopenharmony_ci		return PTR_ERR(p);
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	call_netdevice_notifiers(NETDEV_JOIN, dev);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	err = dev_set_allmulti(dev, 1);
6188c2ecf20Sopenharmony_ci	if (err) {
6198c2ecf20Sopenharmony_ci		br_multicast_del_port(p);
6208c2ecf20Sopenharmony_ci		kfree(p);	/* kobject not yet init'd, manually free */
6218c2ecf20Sopenharmony_ci		goto err1;
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj),
6258c2ecf20Sopenharmony_ci				   SYSFS_BRIDGE_PORT_ATTR);
6268c2ecf20Sopenharmony_ci	if (err)
6278c2ecf20Sopenharmony_ci		goto err2;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	err = br_sysfs_addif(p);
6308c2ecf20Sopenharmony_ci	if (err)
6318c2ecf20Sopenharmony_ci		goto err2;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	err = br_netpoll_enable(p);
6348c2ecf20Sopenharmony_ci	if (err)
6358c2ecf20Sopenharmony_ci		goto err3;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	err = netdev_rx_handler_register(dev, br_get_rx_handler(dev), p);
6388c2ecf20Sopenharmony_ci	if (err)
6398c2ecf20Sopenharmony_ci		goto err4;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	dev->priv_flags |= IFF_BRIDGE_PORT;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	err = netdev_master_upper_dev_link(dev, br->dev, NULL, NULL, extack);
6448c2ecf20Sopenharmony_ci	if (err)
6458c2ecf20Sopenharmony_ci		goto err5;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	err = nbp_switchdev_mark_set(p);
6488c2ecf20Sopenharmony_ci	if (err)
6498c2ecf20Sopenharmony_ci		goto err6;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	dev_disable_lro(dev);
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	list_add_rcu(&p->list, &br->port_list);
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	nbp_update_port_count(br);
6568c2ecf20Sopenharmony_ci	if (!br_promisc_port(p) && (p->dev->priv_flags & IFF_UNICAST_FLT)) {
6578c2ecf20Sopenharmony_ci		/* When updating the port count we also update all ports'
6588c2ecf20Sopenharmony_ci		 * promiscuous mode.
6598c2ecf20Sopenharmony_ci		 * A port leaving promiscuous mode normally gets the bridge's
6608c2ecf20Sopenharmony_ci		 * fdb synced to the unicast filter (if supported), however,
6618c2ecf20Sopenharmony_ci		 * `br_port_clear_promisc` does not distinguish between
6628c2ecf20Sopenharmony_ci		 * non-promiscuous ports and *new* ports, so we need to
6638c2ecf20Sopenharmony_ci		 * sync explicitly here.
6648c2ecf20Sopenharmony_ci		 */
6658c2ecf20Sopenharmony_ci		fdb_synced = br_fdb_sync_static(br, p) == 0;
6668c2ecf20Sopenharmony_ci		if (!fdb_synced)
6678c2ecf20Sopenharmony_ci			netdev_err(dev, "failed to sync bridge static fdb addresses to this port\n");
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	netdev_update_features(br->dev);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	br_hr = br->dev->needed_headroom;
6738c2ecf20Sopenharmony_ci	dev_hr = netdev_get_fwd_headroom(dev);
6748c2ecf20Sopenharmony_ci	if (br_hr < dev_hr)
6758c2ecf20Sopenharmony_ci		update_headroom(br, dev_hr);
6768c2ecf20Sopenharmony_ci	else
6778c2ecf20Sopenharmony_ci		netdev_set_rx_headroom(dev, br_hr);
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	if (br_fdb_insert(br, p, dev->dev_addr, 0))
6808c2ecf20Sopenharmony_ci		netdev_err(dev, "failed insert local address bridge forwarding table\n");
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	if (br->dev->addr_assign_type != NET_ADDR_SET) {
6838c2ecf20Sopenharmony_ci		/* Ask for permission to use this MAC address now, even if we
6848c2ecf20Sopenharmony_ci		 * don't end up choosing it below.
6858c2ecf20Sopenharmony_ci		 */
6868c2ecf20Sopenharmony_ci		err = dev_pre_changeaddr_notify(br->dev, dev->dev_addr, extack);
6878c2ecf20Sopenharmony_ci		if (err)
6888c2ecf20Sopenharmony_ci			goto err7;
6898c2ecf20Sopenharmony_ci	}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	err = nbp_vlan_init(p, extack);
6928c2ecf20Sopenharmony_ci	if (err) {
6938c2ecf20Sopenharmony_ci		netdev_err(dev, "failed to initialize vlan filtering on this port\n");
6948c2ecf20Sopenharmony_ci		goto err7;
6958c2ecf20Sopenharmony_ci	}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	spin_lock_bh(&br->lock);
6988c2ecf20Sopenharmony_ci	changed_addr = br_stp_recalculate_bridge_id(br);
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	if (netif_running(dev) && netif_oper_up(dev) &&
7018c2ecf20Sopenharmony_ci	    (br->dev->flags & IFF_UP))
7028c2ecf20Sopenharmony_ci		br_stp_enable_port(p);
7038c2ecf20Sopenharmony_ci	spin_unlock_bh(&br->lock);
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	br_ifinfo_notify(RTM_NEWLINK, NULL, p);
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	if (changed_addr)
7088c2ecf20Sopenharmony_ci		call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	br_mtu_auto_adjust(br);
7118c2ecf20Sopenharmony_ci	br_set_gso_limits(br);
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	kobject_uevent(&p->kobj, KOBJ_ADD);
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	return 0;
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_cierr7:
7188c2ecf20Sopenharmony_ci	if (fdb_synced)
7198c2ecf20Sopenharmony_ci		br_fdb_unsync_static(br, p);
7208c2ecf20Sopenharmony_ci	list_del_rcu(&p->list);
7218c2ecf20Sopenharmony_ci	br_fdb_delete_by_port(br, p, 0, 1);
7228c2ecf20Sopenharmony_ci	nbp_update_port_count(br);
7238c2ecf20Sopenharmony_cierr6:
7248c2ecf20Sopenharmony_ci	netdev_upper_dev_unlink(dev, br->dev);
7258c2ecf20Sopenharmony_cierr5:
7268c2ecf20Sopenharmony_ci	dev->priv_flags &= ~IFF_BRIDGE_PORT;
7278c2ecf20Sopenharmony_ci	netdev_rx_handler_unregister(dev);
7288c2ecf20Sopenharmony_cierr4:
7298c2ecf20Sopenharmony_ci	br_netpoll_disable(p);
7308c2ecf20Sopenharmony_cierr3:
7318c2ecf20Sopenharmony_ci	sysfs_remove_link(br->ifobj, p->dev->name);
7328c2ecf20Sopenharmony_cierr2:
7338c2ecf20Sopenharmony_ci	br_multicast_del_port(p);
7348c2ecf20Sopenharmony_ci	kobject_put(&p->kobj);
7358c2ecf20Sopenharmony_ci	dev_set_allmulti(dev, -1);
7368c2ecf20Sopenharmony_cierr1:
7378c2ecf20Sopenharmony_ci	dev_put(dev);
7388c2ecf20Sopenharmony_ci	return err;
7398c2ecf20Sopenharmony_ci}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci/* called with RTNL */
7428c2ecf20Sopenharmony_ciint br_del_if(struct net_bridge *br, struct net_device *dev)
7438c2ecf20Sopenharmony_ci{
7448c2ecf20Sopenharmony_ci	struct net_bridge_port *p;
7458c2ecf20Sopenharmony_ci	bool changed_addr;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	p = br_port_get_rtnl(dev);
7488c2ecf20Sopenharmony_ci	if (!p || p->br != br)
7498c2ecf20Sopenharmony_ci		return -EINVAL;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	/* Since more than one interface can be attached to a bridge,
7528c2ecf20Sopenharmony_ci	 * there still maybe an alternate path for netconsole to use;
7538c2ecf20Sopenharmony_ci	 * therefore there is no reason for a NETDEV_RELEASE event.
7548c2ecf20Sopenharmony_ci	 */
7558c2ecf20Sopenharmony_ci	del_nbp(p);
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	br_mtu_auto_adjust(br);
7588c2ecf20Sopenharmony_ci	br_set_gso_limits(br);
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	spin_lock_bh(&br->lock);
7618c2ecf20Sopenharmony_ci	changed_addr = br_stp_recalculate_bridge_id(br);
7628c2ecf20Sopenharmony_ci	spin_unlock_bh(&br->lock);
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	if (changed_addr)
7658c2ecf20Sopenharmony_ci		call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	netdev_update_features(br->dev);
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	return 0;
7708c2ecf20Sopenharmony_ci}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_civoid br_port_flags_change(struct net_bridge_port *p, unsigned long mask)
7738c2ecf20Sopenharmony_ci{
7748c2ecf20Sopenharmony_ci	struct net_bridge *br = p->br;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	if (mask & BR_AUTO_MASK)
7778c2ecf20Sopenharmony_ci		nbp_update_port_count(br);
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	if (mask & BR_NEIGH_SUPPRESS)
7808c2ecf20Sopenharmony_ci		br_recalculate_neigh_suppress_enabled(br);
7818c2ecf20Sopenharmony_ci}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_cibool br_port_flag_is_set(const struct net_device *dev, unsigned long flag)
7848c2ecf20Sopenharmony_ci{
7858c2ecf20Sopenharmony_ci	struct net_bridge_port *p;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	p = br_port_get_rtnl_rcu(dev);
7888c2ecf20Sopenharmony_ci	if (!p)
7898c2ecf20Sopenharmony_ci		return false;
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	return p->flags & flag;
7928c2ecf20Sopenharmony_ci}
7938c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(br_port_flag_is_set);
794