162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *	Device handling code
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/netpoll.h>
1362306a36Sopenharmony_ci#include <linux/etherdevice.h>
1462306a36Sopenharmony_ci#include <linux/ethtool.h>
1562306a36Sopenharmony_ci#include <linux/list.h>
1662306a36Sopenharmony_ci#include <linux/netfilter_bridge.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/uaccess.h>
1962306a36Sopenharmony_ci#include "br_private.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define COMMON_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | \
2262306a36Sopenharmony_ci			 NETIF_F_GSO_MASK | NETIF_F_HW_CSUM)
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ciconst struct nf_br_ops __rcu *nf_br_ops __read_mostly;
2562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nf_br_ops);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/* net device transmit always called with BH disabled */
2862306a36Sopenharmony_cinetdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	struct net_bridge_mcast_port *pmctx_null = NULL;
3162306a36Sopenharmony_ci	struct net_bridge *br = netdev_priv(dev);
3262306a36Sopenharmony_ci	struct net_bridge_mcast *brmctx = &br->multicast_ctx;
3362306a36Sopenharmony_ci	struct net_bridge_fdb_entry *dst;
3462306a36Sopenharmony_ci	struct net_bridge_mdb_entry *mdst;
3562306a36Sopenharmony_ci	const struct nf_br_ops *nf_ops;
3662306a36Sopenharmony_ci	u8 state = BR_STATE_FORWARDING;
3762306a36Sopenharmony_ci	struct net_bridge_vlan *vlan;
3862306a36Sopenharmony_ci	const unsigned char *dest;
3962306a36Sopenharmony_ci	u16 vid = 0;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	memset(skb->cb, 0, sizeof(struct br_input_skb_cb));
4262306a36Sopenharmony_ci	br_tc_skb_miss_set(skb, false);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	rcu_read_lock();
4562306a36Sopenharmony_ci	nf_ops = rcu_dereference(nf_br_ops);
4662306a36Sopenharmony_ci	if (nf_ops && nf_ops->br_dev_xmit_hook(skb)) {
4762306a36Sopenharmony_ci		rcu_read_unlock();
4862306a36Sopenharmony_ci		return NETDEV_TX_OK;
4962306a36Sopenharmony_ci	}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	dev_sw_netstats_tx_add(dev, 1, skb->len);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	br_switchdev_frame_unmark(skb);
5462306a36Sopenharmony_ci	BR_INPUT_SKB_CB(skb)->brdev = dev;
5562306a36Sopenharmony_ci	BR_INPUT_SKB_CB(skb)->frag_max_size = 0;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	skb_reset_mac_header(skb);
5862306a36Sopenharmony_ci	skb_pull(skb, ETH_HLEN);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &vid,
6162306a36Sopenharmony_ci				&state, &vlan))
6262306a36Sopenharmony_ci		goto out;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_INET) &&
6562306a36Sopenharmony_ci	    (eth_hdr(skb)->h_proto == htons(ETH_P_ARP) ||
6662306a36Sopenharmony_ci	     eth_hdr(skb)->h_proto == htons(ETH_P_RARP)) &&
6762306a36Sopenharmony_ci	    br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) {
6862306a36Sopenharmony_ci		br_do_proxy_suppress_arp(skb, br, vid, NULL);
6962306a36Sopenharmony_ci	} else if (IS_ENABLED(CONFIG_IPV6) &&
7062306a36Sopenharmony_ci		   skb->protocol == htons(ETH_P_IPV6) &&
7162306a36Sopenharmony_ci		   br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) &&
7262306a36Sopenharmony_ci		   pskb_may_pull(skb, sizeof(struct ipv6hdr) +
7362306a36Sopenharmony_ci				 sizeof(struct nd_msg)) &&
7462306a36Sopenharmony_ci		   ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) {
7562306a36Sopenharmony_ci			struct nd_msg *msg, _msg;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci			msg = br_is_nd_neigh_msg(skb, &_msg);
7862306a36Sopenharmony_ci			if (msg)
7962306a36Sopenharmony_ci				br_do_suppress_nd(skb, br, vid, NULL, msg);
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	dest = eth_hdr(skb)->h_dest;
8362306a36Sopenharmony_ci	if (is_broadcast_ether_addr(dest)) {
8462306a36Sopenharmony_ci		br_flood(br, skb, BR_PKT_BROADCAST, false, true, vid);
8562306a36Sopenharmony_ci	} else if (is_multicast_ether_addr(dest)) {
8662306a36Sopenharmony_ci		if (unlikely(netpoll_tx_running(dev))) {
8762306a36Sopenharmony_ci			br_flood(br, skb, BR_PKT_MULTICAST, false, true, vid);
8862306a36Sopenharmony_ci			goto out;
8962306a36Sopenharmony_ci		}
9062306a36Sopenharmony_ci		if (br_multicast_rcv(&brmctx, &pmctx_null, vlan, skb, vid)) {
9162306a36Sopenharmony_ci			kfree_skb(skb);
9262306a36Sopenharmony_ci			goto out;
9362306a36Sopenharmony_ci		}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci		mdst = br_mdb_get(brmctx, skb, vid);
9662306a36Sopenharmony_ci		if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
9762306a36Sopenharmony_ci		    br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst))
9862306a36Sopenharmony_ci			br_multicast_flood(mdst, skb, brmctx, false, true);
9962306a36Sopenharmony_ci		else
10062306a36Sopenharmony_ci			br_flood(br, skb, BR_PKT_MULTICAST, false, true, vid);
10162306a36Sopenharmony_ci	} else if ((dst = br_fdb_find_rcu(br, dest, vid)) != NULL) {
10262306a36Sopenharmony_ci		br_forward(dst->dst, skb, false, true);
10362306a36Sopenharmony_ci	} else {
10462306a36Sopenharmony_ci		br_flood(br, skb, BR_PKT_UNICAST, false, true, vid);
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ciout:
10762306a36Sopenharmony_ci	rcu_read_unlock();
10862306a36Sopenharmony_ci	return NETDEV_TX_OK;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic struct lock_class_key bridge_netdev_addr_lock_key;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic void br_set_lockdep_class(struct net_device *dev)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	lockdep_set_class(&dev->addr_list_lock, &bridge_netdev_addr_lock_key);
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic int br_dev_init(struct net_device *dev)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	struct net_bridge *br = netdev_priv(dev);
12162306a36Sopenharmony_ci	int err;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
12462306a36Sopenharmony_ci	if (!dev->tstats)
12562306a36Sopenharmony_ci		return -ENOMEM;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	err = br_fdb_hash_init(br);
12862306a36Sopenharmony_ci	if (err) {
12962306a36Sopenharmony_ci		free_percpu(dev->tstats);
13062306a36Sopenharmony_ci		return err;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	err = br_mdb_hash_init(br);
13462306a36Sopenharmony_ci	if (err) {
13562306a36Sopenharmony_ci		free_percpu(dev->tstats);
13662306a36Sopenharmony_ci		br_fdb_hash_fini(br);
13762306a36Sopenharmony_ci		return err;
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	err = br_vlan_init(br);
14162306a36Sopenharmony_ci	if (err) {
14262306a36Sopenharmony_ci		free_percpu(dev->tstats);
14362306a36Sopenharmony_ci		br_mdb_hash_fini(br);
14462306a36Sopenharmony_ci		br_fdb_hash_fini(br);
14562306a36Sopenharmony_ci		return err;
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	err = br_multicast_init_stats(br);
14962306a36Sopenharmony_ci	if (err) {
15062306a36Sopenharmony_ci		free_percpu(dev->tstats);
15162306a36Sopenharmony_ci		br_vlan_flush(br);
15262306a36Sopenharmony_ci		br_mdb_hash_fini(br);
15362306a36Sopenharmony_ci		br_fdb_hash_fini(br);
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	br_set_lockdep_class(dev);
15762306a36Sopenharmony_ci	return err;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic void br_dev_uninit(struct net_device *dev)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct net_bridge *br = netdev_priv(dev);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	br_multicast_dev_del(br);
16562306a36Sopenharmony_ci	br_multicast_uninit_stats(br);
16662306a36Sopenharmony_ci	br_vlan_flush(br);
16762306a36Sopenharmony_ci	br_mdb_hash_fini(br);
16862306a36Sopenharmony_ci	br_fdb_hash_fini(br);
16962306a36Sopenharmony_ci	free_percpu(dev->tstats);
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic int br_dev_open(struct net_device *dev)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	struct net_bridge *br = netdev_priv(dev);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	netdev_update_features(dev);
17762306a36Sopenharmony_ci	netif_start_queue(dev);
17862306a36Sopenharmony_ci	br_stp_enable_bridge(br);
17962306a36Sopenharmony_ci	br_multicast_open(br);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (br_opt_get(br, BROPT_MULTICAST_ENABLED))
18262306a36Sopenharmony_ci		br_multicast_join_snoopers(br);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	return 0;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic void br_dev_set_multicast_list(struct net_device *dev)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic void br_dev_change_rx_flags(struct net_device *dev, int change)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	if (change & IFF_PROMISC)
19462306a36Sopenharmony_ci		br_manage_promisc(netdev_priv(dev));
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic int br_dev_stop(struct net_device *dev)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	struct net_bridge *br = netdev_priv(dev);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	br_stp_disable_bridge(br);
20262306a36Sopenharmony_ci	br_multicast_stop(br);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (br_opt_get(br, BROPT_MULTICAST_ENABLED))
20562306a36Sopenharmony_ci		br_multicast_leave_snoopers(br);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	netif_stop_queue(dev);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	return 0;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic int br_change_mtu(struct net_device *dev, int new_mtu)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	struct net_bridge *br = netdev_priv(dev);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	dev->mtu = new_mtu;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	/* this flag will be cleared if the MTU was automatically adjusted */
21962306a36Sopenharmony_ci	br_opt_toggle(br, BROPT_MTU_SET_BY_USER, true);
22062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
22162306a36Sopenharmony_ci	/* remember the MTU in the rtable for PMTU */
22262306a36Sopenharmony_ci	dst_metric_set(&br->fake_rtable.dst, RTAX_MTU, new_mtu);
22362306a36Sopenharmony_ci#endif
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	return 0;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci/* Allow setting mac address to any valid ethernet address. */
22962306a36Sopenharmony_cistatic int br_set_mac_address(struct net_device *dev, void *p)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	struct net_bridge *br = netdev_priv(dev);
23262306a36Sopenharmony_ci	struct sockaddr *addr = p;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (!is_valid_ether_addr(addr->sa_data))
23562306a36Sopenharmony_ci		return -EADDRNOTAVAIL;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/* dev_set_mac_addr() can be called by a master device on bridge's
23862306a36Sopenharmony_ci	 * NETDEV_UNREGISTER, but since it's being destroyed do nothing
23962306a36Sopenharmony_ci	 */
24062306a36Sopenharmony_ci	if (dev->reg_state != NETREG_REGISTERED)
24162306a36Sopenharmony_ci		return -EBUSY;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	spin_lock_bh(&br->lock);
24462306a36Sopenharmony_ci	if (!ether_addr_equal(dev->dev_addr, addr->sa_data)) {
24562306a36Sopenharmony_ci		/* Mac address will be changed in br_stp_change_bridge_id(). */
24662306a36Sopenharmony_ci		br_stp_change_bridge_id(br, addr->sa_data);
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci	spin_unlock_bh(&br->lock);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	return 0;
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	strscpy(info->driver, "bridge", sizeof(info->driver));
25662306a36Sopenharmony_ci	strscpy(info->version, BR_VERSION, sizeof(info->version));
25762306a36Sopenharmony_ci	strscpy(info->fw_version, "N/A", sizeof(info->fw_version));
25862306a36Sopenharmony_ci	strscpy(info->bus_info, "N/A", sizeof(info->bus_info));
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic int br_get_link_ksettings(struct net_device *dev,
26262306a36Sopenharmony_ci				 struct ethtool_link_ksettings *cmd)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	struct net_bridge *br = netdev_priv(dev);
26562306a36Sopenharmony_ci	struct net_bridge_port *p;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	cmd->base.duplex = DUPLEX_UNKNOWN;
26862306a36Sopenharmony_ci	cmd->base.port = PORT_OTHER;
26962306a36Sopenharmony_ci	cmd->base.speed = SPEED_UNKNOWN;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	list_for_each_entry(p, &br->port_list, list) {
27262306a36Sopenharmony_ci		struct ethtool_link_ksettings ecmd;
27362306a36Sopenharmony_ci		struct net_device *pdev = p->dev;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci		if (!netif_running(pdev) || !netif_oper_up(pdev))
27662306a36Sopenharmony_ci			continue;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci		if (__ethtool_get_link_ksettings(pdev, &ecmd))
27962306a36Sopenharmony_ci			continue;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci		if (ecmd.base.speed == (__u32)SPEED_UNKNOWN)
28262306a36Sopenharmony_ci			continue;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		if (cmd->base.speed == (__u32)SPEED_UNKNOWN ||
28562306a36Sopenharmony_ci		    cmd->base.speed < ecmd.base.speed)
28662306a36Sopenharmony_ci			cmd->base.speed = ecmd.base.speed;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	return 0;
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistatic netdev_features_t br_fix_features(struct net_device *dev,
29362306a36Sopenharmony_ci	netdev_features_t features)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	struct net_bridge *br = netdev_priv(dev);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	return br_features_recompute(br, features);
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
30162306a36Sopenharmony_cistatic void br_poll_controller(struct net_device *br_dev)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic void br_netpoll_cleanup(struct net_device *dev)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	struct net_bridge *br = netdev_priv(dev);
30862306a36Sopenharmony_ci	struct net_bridge_port *p;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	list_for_each_entry(p, &br->port_list, list)
31162306a36Sopenharmony_ci		br_netpoll_disable(p);
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic int __br_netpoll_enable(struct net_bridge_port *p)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	struct netpoll *np;
31762306a36Sopenharmony_ci	int err;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	np = kzalloc(sizeof(*p->np), GFP_KERNEL);
32062306a36Sopenharmony_ci	if (!np)
32162306a36Sopenharmony_ci		return -ENOMEM;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	err = __netpoll_setup(np, p->dev);
32462306a36Sopenharmony_ci	if (err) {
32562306a36Sopenharmony_ci		kfree(np);
32662306a36Sopenharmony_ci		return err;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	p->np = np;
33062306a36Sopenharmony_ci	return err;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ciint br_netpoll_enable(struct net_bridge_port *p)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	if (!p->br->dev->npinfo)
33662306a36Sopenharmony_ci		return 0;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	return __br_netpoll_enable(p);
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct net_bridge *br = netdev_priv(dev);
34462306a36Sopenharmony_ci	struct net_bridge_port *p;
34562306a36Sopenharmony_ci	int err = 0;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	list_for_each_entry(p, &br->port_list, list) {
34862306a36Sopenharmony_ci		if (!p->dev)
34962306a36Sopenharmony_ci			continue;
35062306a36Sopenharmony_ci		err = __br_netpoll_enable(p);
35162306a36Sopenharmony_ci		if (err)
35262306a36Sopenharmony_ci			goto fail;
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ciout:
35662306a36Sopenharmony_ci	return err;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cifail:
35962306a36Sopenharmony_ci	br_netpoll_cleanup(dev);
36062306a36Sopenharmony_ci	goto out;
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_civoid br_netpoll_disable(struct net_bridge_port *p)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	struct netpoll *np = p->np;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	if (!np)
36862306a36Sopenharmony_ci		return;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	p->np = NULL;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	__netpoll_free(np);
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci#endif
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic int br_add_slave(struct net_device *dev, struct net_device *slave_dev,
37862306a36Sopenharmony_ci			struct netlink_ext_ack *extack)
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	struct net_bridge *br = netdev_priv(dev);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	return br_add_if(br, slave_dev, extack);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic int br_del_slave(struct net_device *dev, struct net_device *slave_dev)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	struct net_bridge *br = netdev_priv(dev);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	return br_del_if(br, slave_dev);
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic int br_fill_forward_path(struct net_device_path_ctx *ctx,
39462306a36Sopenharmony_ci				struct net_device_path *path)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	struct net_bridge_fdb_entry *f;
39762306a36Sopenharmony_ci	struct net_bridge_port *dst;
39862306a36Sopenharmony_ci	struct net_bridge *br;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	if (netif_is_bridge_port(ctx->dev))
40162306a36Sopenharmony_ci		return -1;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	br = netdev_priv(ctx->dev);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	br_vlan_fill_forward_path_pvid(br, ctx, path);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	f = br_fdb_find_rcu(br, ctx->daddr, path->bridge.vlan_id);
40862306a36Sopenharmony_ci	if (!f || !f->dst)
40962306a36Sopenharmony_ci		return -1;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	dst = READ_ONCE(f->dst);
41262306a36Sopenharmony_ci	if (!dst)
41362306a36Sopenharmony_ci		return -1;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	if (br_vlan_fill_forward_path_mode(br, dst, path))
41662306a36Sopenharmony_ci		return -1;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	path->type = DEV_PATH_BRIDGE;
41962306a36Sopenharmony_ci	path->dev = dst->br->dev;
42062306a36Sopenharmony_ci	ctx->dev = dst->dev;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	switch (path->bridge.vlan_mode) {
42362306a36Sopenharmony_ci	case DEV_PATH_BR_VLAN_TAG:
42462306a36Sopenharmony_ci		if (ctx->num_vlans >= ARRAY_SIZE(ctx->vlan))
42562306a36Sopenharmony_ci			return -ENOSPC;
42662306a36Sopenharmony_ci		ctx->vlan[ctx->num_vlans].id = path->bridge.vlan_id;
42762306a36Sopenharmony_ci		ctx->vlan[ctx->num_vlans].proto = path->bridge.vlan_proto;
42862306a36Sopenharmony_ci		ctx->num_vlans++;
42962306a36Sopenharmony_ci		break;
43062306a36Sopenharmony_ci	case DEV_PATH_BR_VLAN_UNTAG_HW:
43162306a36Sopenharmony_ci	case DEV_PATH_BR_VLAN_UNTAG:
43262306a36Sopenharmony_ci		ctx->num_vlans--;
43362306a36Sopenharmony_ci		break;
43462306a36Sopenharmony_ci	case DEV_PATH_BR_VLAN_KEEP:
43562306a36Sopenharmony_ci		break;
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	return 0;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic const struct ethtool_ops br_ethtool_ops = {
44262306a36Sopenharmony_ci	.get_drvinfo		 = br_getinfo,
44362306a36Sopenharmony_ci	.get_link		 = ethtool_op_get_link,
44462306a36Sopenharmony_ci	.get_link_ksettings	 = br_get_link_ksettings,
44562306a36Sopenharmony_ci};
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic const struct net_device_ops br_netdev_ops = {
44862306a36Sopenharmony_ci	.ndo_open		 = br_dev_open,
44962306a36Sopenharmony_ci	.ndo_stop		 = br_dev_stop,
45062306a36Sopenharmony_ci	.ndo_init		 = br_dev_init,
45162306a36Sopenharmony_ci	.ndo_uninit		 = br_dev_uninit,
45262306a36Sopenharmony_ci	.ndo_start_xmit		 = br_dev_xmit,
45362306a36Sopenharmony_ci	.ndo_get_stats64	 = dev_get_tstats64,
45462306a36Sopenharmony_ci	.ndo_set_mac_address	 = br_set_mac_address,
45562306a36Sopenharmony_ci	.ndo_set_rx_mode	 = br_dev_set_multicast_list,
45662306a36Sopenharmony_ci	.ndo_change_rx_flags	 = br_dev_change_rx_flags,
45762306a36Sopenharmony_ci	.ndo_change_mtu		 = br_change_mtu,
45862306a36Sopenharmony_ci	.ndo_siocdevprivate	 = br_dev_siocdevprivate,
45962306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
46062306a36Sopenharmony_ci	.ndo_netpoll_setup	 = br_netpoll_setup,
46162306a36Sopenharmony_ci	.ndo_netpoll_cleanup	 = br_netpoll_cleanup,
46262306a36Sopenharmony_ci	.ndo_poll_controller	 = br_poll_controller,
46362306a36Sopenharmony_ci#endif
46462306a36Sopenharmony_ci	.ndo_add_slave		 = br_add_slave,
46562306a36Sopenharmony_ci	.ndo_del_slave		 = br_del_slave,
46662306a36Sopenharmony_ci	.ndo_fix_features        = br_fix_features,
46762306a36Sopenharmony_ci	.ndo_fdb_add		 = br_fdb_add,
46862306a36Sopenharmony_ci	.ndo_fdb_del		 = br_fdb_delete,
46962306a36Sopenharmony_ci	.ndo_fdb_del_bulk	 = br_fdb_delete_bulk,
47062306a36Sopenharmony_ci	.ndo_fdb_dump		 = br_fdb_dump,
47162306a36Sopenharmony_ci	.ndo_fdb_get		 = br_fdb_get,
47262306a36Sopenharmony_ci	.ndo_mdb_add		 = br_mdb_add,
47362306a36Sopenharmony_ci	.ndo_mdb_del		 = br_mdb_del,
47462306a36Sopenharmony_ci	.ndo_mdb_dump		 = br_mdb_dump,
47562306a36Sopenharmony_ci	.ndo_bridge_getlink	 = br_getlink,
47662306a36Sopenharmony_ci	.ndo_bridge_setlink	 = br_setlink,
47762306a36Sopenharmony_ci	.ndo_bridge_dellink	 = br_dellink,
47862306a36Sopenharmony_ci	.ndo_features_check	 = passthru_features_check,
47962306a36Sopenharmony_ci	.ndo_fill_forward_path	 = br_fill_forward_path,
48062306a36Sopenharmony_ci};
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic struct device_type br_type = {
48362306a36Sopenharmony_ci	.name	= "bridge",
48462306a36Sopenharmony_ci};
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_civoid br_dev_setup(struct net_device *dev)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	struct net_bridge *br = netdev_priv(dev);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	eth_hw_addr_random(dev);
49162306a36Sopenharmony_ci	ether_setup(dev);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	dev->netdev_ops = &br_netdev_ops;
49462306a36Sopenharmony_ci	dev->needs_free_netdev = true;
49562306a36Sopenharmony_ci	dev->ethtool_ops = &br_ethtool_ops;
49662306a36Sopenharmony_ci	SET_NETDEV_DEVTYPE(dev, &br_type);
49762306a36Sopenharmony_ci	dev->priv_flags = IFF_EBRIDGE | IFF_NO_QUEUE;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	dev->features = COMMON_FEATURES | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL |
50062306a36Sopenharmony_ci			NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
50162306a36Sopenharmony_ci	dev->hw_features = COMMON_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
50262306a36Sopenharmony_ci			   NETIF_F_HW_VLAN_STAG_TX;
50362306a36Sopenharmony_ci	dev->vlan_features = COMMON_FEATURES;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	br->dev = dev;
50662306a36Sopenharmony_ci	spin_lock_init(&br->lock);
50762306a36Sopenharmony_ci	INIT_LIST_HEAD(&br->port_list);
50862306a36Sopenharmony_ci	INIT_HLIST_HEAD(&br->fdb_list);
50962306a36Sopenharmony_ci	INIT_HLIST_HEAD(&br->frame_type_list);
51062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_BRIDGE_MRP)
51162306a36Sopenharmony_ci	INIT_HLIST_HEAD(&br->mrp_list);
51262306a36Sopenharmony_ci#endif
51362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_BRIDGE_CFM)
51462306a36Sopenharmony_ci	INIT_HLIST_HEAD(&br->mep_list);
51562306a36Sopenharmony_ci#endif
51662306a36Sopenharmony_ci	spin_lock_init(&br->hash_lock);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	br->bridge_id.prio[0] = 0x80;
51962306a36Sopenharmony_ci	br->bridge_id.prio[1] = 0x00;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	ether_addr_copy(br->group_addr, eth_stp_addr);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	br->stp_enabled = BR_NO_STP;
52462306a36Sopenharmony_ci	br->group_fwd_mask = BR_GROUPFWD_DEFAULT;
52562306a36Sopenharmony_ci	br->group_fwd_mask_required = BR_GROUPFWD_DEFAULT;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	br->designated_root = br->bridge_id;
52862306a36Sopenharmony_ci	br->bridge_max_age = br->max_age = 20 * HZ;
52962306a36Sopenharmony_ci	br->bridge_hello_time = br->hello_time = 2 * HZ;
53062306a36Sopenharmony_ci	br->bridge_forward_delay = br->forward_delay = 15 * HZ;
53162306a36Sopenharmony_ci	br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME;
53262306a36Sopenharmony_ci	dev->max_mtu = ETH_MAX_MTU;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	br_netfilter_rtable_init(br);
53562306a36Sopenharmony_ci	br_stp_timer_init(br);
53662306a36Sopenharmony_ci	br_multicast_init(br);
53762306a36Sopenharmony_ci	INIT_DELAYED_WORK(&br->gc_work, br_fdb_cleanup);
53862306a36Sopenharmony_ci}
539