18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *	Handle incoming frames
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/slab.h>
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
138c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
148c2ecf20Sopenharmony_ci#include <linux/netfilter_bridge.h>
158c2ecf20Sopenharmony_ci#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
168c2ecf20Sopenharmony_ci#include <net/netfilter/nf_queue.h>
178c2ecf20Sopenharmony_ci#endif
188c2ecf20Sopenharmony_ci#include <linux/neighbour.h>
198c2ecf20Sopenharmony_ci#include <net/arp.h>
208c2ecf20Sopenharmony_ci#include <net/dsa.h>
218c2ecf20Sopenharmony_ci#include <linux/export.h>
228c2ecf20Sopenharmony_ci#include <linux/rculist.h>
238c2ecf20Sopenharmony_ci#include "br_private.h"
248c2ecf20Sopenharmony_ci#include "br_private_tunnel.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic int
278c2ecf20Sopenharmony_cibr_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	br_drop_fake_rtable(skb);
308c2ecf20Sopenharmony_ci	return netif_receive_skb(skb);
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic int br_pass_frame_up(struct sk_buff *skb)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
368c2ecf20Sopenharmony_ci	struct net_bridge *br = netdev_priv(brdev);
378c2ecf20Sopenharmony_ci	struct net_bridge_vlan_group *vg;
388c2ecf20Sopenharmony_ci	struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	u64_stats_update_begin(&brstats->syncp);
418c2ecf20Sopenharmony_ci	brstats->rx_packets++;
428c2ecf20Sopenharmony_ci	brstats->rx_bytes += skb->len;
438c2ecf20Sopenharmony_ci	u64_stats_update_end(&brstats->syncp);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	vg = br_vlan_group_rcu(br);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	/* Reset the offload_fwd_mark because there could be a stacked
488c2ecf20Sopenharmony_ci	 * bridge above, and it should not think this bridge it doing
498c2ecf20Sopenharmony_ci	 * that bridge's work forwarding out its ports.
508c2ecf20Sopenharmony_ci	 */
518c2ecf20Sopenharmony_ci	br_switchdev_frame_unmark(skb);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	/* Bridge is just like any other port.  Make sure the
548c2ecf20Sopenharmony_ci	 * packet is allowed except in promisc modue when someone
558c2ecf20Sopenharmony_ci	 * may be running packet capture.
568c2ecf20Sopenharmony_ci	 */
578c2ecf20Sopenharmony_ci	if (!(brdev->flags & IFF_PROMISC) &&
588c2ecf20Sopenharmony_ci	    !br_allowed_egress(vg, skb)) {
598c2ecf20Sopenharmony_ci		kfree_skb(skb);
608c2ecf20Sopenharmony_ci		return NET_RX_DROP;
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	indev = skb->dev;
648c2ecf20Sopenharmony_ci	skb->dev = brdev;
658c2ecf20Sopenharmony_ci	skb = br_handle_vlan(br, NULL, vg, skb);
668c2ecf20Sopenharmony_ci	if (!skb)
678c2ecf20Sopenharmony_ci		return NET_RX_DROP;
688c2ecf20Sopenharmony_ci	/* update the multicast stats if the packet is IGMP/MLD */
698c2ecf20Sopenharmony_ci	br_multicast_count(br, NULL, skb, br_multicast_igmp_type(skb),
708c2ecf20Sopenharmony_ci			   BR_MCAST_DIR_TX);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN,
738c2ecf20Sopenharmony_ci		       dev_net(indev), NULL, skb, indev, NULL,
748c2ecf20Sopenharmony_ci		       br_netif_receive_skb);
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/* note: already called with rcu_read_lock */
788c2ecf20Sopenharmony_ciint br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	struct net_bridge_port *p = br_port_get_rcu(skb->dev);
818c2ecf20Sopenharmony_ci	enum br_pkt_type pkt_type = BR_PKT_UNICAST;
828c2ecf20Sopenharmony_ci	struct net_bridge_fdb_entry *dst = NULL;
838c2ecf20Sopenharmony_ci	struct net_bridge_mdb_entry *mdst;
848c2ecf20Sopenharmony_ci	bool local_rcv, mcast_hit = false;
858c2ecf20Sopenharmony_ci	struct net_bridge *br;
868c2ecf20Sopenharmony_ci	u16 vid = 0;
878c2ecf20Sopenharmony_ci	u8 state;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	if (!p || p->state == BR_STATE_DISABLED)
908c2ecf20Sopenharmony_ci		goto drop;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	state = p->state;
938c2ecf20Sopenharmony_ci	if (!br_allowed_ingress(p->br, nbp_vlan_group_rcu(p), skb, &vid,
948c2ecf20Sopenharmony_ci				&state))
958c2ecf20Sopenharmony_ci		goto out;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	nbp_switchdev_frame_mark(p, skb);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	/* insert into forwarding database after filtering to avoid spoofing */
1008c2ecf20Sopenharmony_ci	br = p->br;
1018c2ecf20Sopenharmony_ci	if (p->flags & BR_LEARNING)
1028c2ecf20Sopenharmony_ci		br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, 0);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	local_rcv = !!(br->dev->flags & IFF_PROMISC);
1058c2ecf20Sopenharmony_ci	if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) {
1068c2ecf20Sopenharmony_ci		/* by definition the broadcast is also a multicast address */
1078c2ecf20Sopenharmony_ci		if (is_broadcast_ether_addr(eth_hdr(skb)->h_dest)) {
1088c2ecf20Sopenharmony_ci			pkt_type = BR_PKT_BROADCAST;
1098c2ecf20Sopenharmony_ci			local_rcv = true;
1108c2ecf20Sopenharmony_ci		} else {
1118c2ecf20Sopenharmony_ci			pkt_type = BR_PKT_MULTICAST;
1128c2ecf20Sopenharmony_ci			if (br_multicast_rcv(br, p, skb, vid))
1138c2ecf20Sopenharmony_ci				goto drop;
1148c2ecf20Sopenharmony_ci		}
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	if (state == BR_STATE_LEARNING)
1188c2ecf20Sopenharmony_ci		goto drop;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	BR_INPUT_SKB_CB(skb)->brdev = br->dev;
1218c2ecf20Sopenharmony_ci	BR_INPUT_SKB_CB(skb)->src_port_isolated = !!(p->flags & BR_ISOLATED);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_INET) &&
1248c2ecf20Sopenharmony_ci	    (skb->protocol == htons(ETH_P_ARP) ||
1258c2ecf20Sopenharmony_ci	     skb->protocol == htons(ETH_P_RARP))) {
1268c2ecf20Sopenharmony_ci		br_do_proxy_suppress_arp(skb, br, vid, p);
1278c2ecf20Sopenharmony_ci	} else if (IS_ENABLED(CONFIG_IPV6) &&
1288c2ecf20Sopenharmony_ci		   skb->protocol == htons(ETH_P_IPV6) &&
1298c2ecf20Sopenharmony_ci		   br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) &&
1308c2ecf20Sopenharmony_ci		   pskb_may_pull(skb, sizeof(struct ipv6hdr) +
1318c2ecf20Sopenharmony_ci				 sizeof(struct nd_msg)) &&
1328c2ecf20Sopenharmony_ci		   ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) {
1338c2ecf20Sopenharmony_ci			struct nd_msg *msg, _msg;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci			msg = br_is_nd_neigh_msg(skb, &_msg);
1368c2ecf20Sopenharmony_ci			if (msg)
1378c2ecf20Sopenharmony_ci				br_do_suppress_nd(skb, br, vid, p, msg);
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	switch (pkt_type) {
1418c2ecf20Sopenharmony_ci	case BR_PKT_MULTICAST:
1428c2ecf20Sopenharmony_ci		mdst = br_mdb_get(br, skb, vid);
1438c2ecf20Sopenharmony_ci		if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
1448c2ecf20Sopenharmony_ci		    br_multicast_querier_exists(br, eth_hdr(skb))) {
1458c2ecf20Sopenharmony_ci			if ((mdst && mdst->host_joined) ||
1468c2ecf20Sopenharmony_ci			    br_multicast_is_router(br)) {
1478c2ecf20Sopenharmony_ci				local_rcv = true;
1488c2ecf20Sopenharmony_ci				DEV_STATS_INC(br->dev, multicast);
1498c2ecf20Sopenharmony_ci			}
1508c2ecf20Sopenharmony_ci			mcast_hit = true;
1518c2ecf20Sopenharmony_ci		} else {
1528c2ecf20Sopenharmony_ci			local_rcv = true;
1538c2ecf20Sopenharmony_ci			DEV_STATS_INC(br->dev, multicast);
1548c2ecf20Sopenharmony_ci		}
1558c2ecf20Sopenharmony_ci		break;
1568c2ecf20Sopenharmony_ci	case BR_PKT_UNICAST:
1578c2ecf20Sopenharmony_ci		dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid);
1588c2ecf20Sopenharmony_ci	default:
1598c2ecf20Sopenharmony_ci		break;
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	if (dst) {
1638c2ecf20Sopenharmony_ci		unsigned long now = jiffies;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci		if (test_bit(BR_FDB_LOCAL, &dst->flags))
1668c2ecf20Sopenharmony_ci			return br_pass_frame_up(skb);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci		if (now != dst->used)
1698c2ecf20Sopenharmony_ci			dst->used = now;
1708c2ecf20Sopenharmony_ci		br_forward(dst->dst, skb, local_rcv, false);
1718c2ecf20Sopenharmony_ci	} else {
1728c2ecf20Sopenharmony_ci		if (!mcast_hit)
1738c2ecf20Sopenharmony_ci			br_flood(br, skb, pkt_type, local_rcv, false);
1748c2ecf20Sopenharmony_ci		else
1758c2ecf20Sopenharmony_ci			br_multicast_flood(mdst, skb, local_rcv, false);
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	if (local_rcv)
1798c2ecf20Sopenharmony_ci		return br_pass_frame_up(skb);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ciout:
1828c2ecf20Sopenharmony_ci	return 0;
1838c2ecf20Sopenharmony_cidrop:
1848c2ecf20Sopenharmony_ci	kfree_skb(skb);
1858c2ecf20Sopenharmony_ci	goto out;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(br_handle_frame_finish);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic void __br_handle_local_finish(struct sk_buff *skb)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	struct net_bridge_port *p = br_port_get_rcu(skb->dev);
1928c2ecf20Sopenharmony_ci	u16 vid = 0;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	/* check if vlan is allowed, to avoid spoofing */
1958c2ecf20Sopenharmony_ci	if ((p->flags & BR_LEARNING) &&
1968c2ecf20Sopenharmony_ci	    nbp_state_should_learn(p) &&
1978c2ecf20Sopenharmony_ci	    !br_opt_get(p->br, BROPT_NO_LL_LEARN) &&
1988c2ecf20Sopenharmony_ci	    br_should_learn(p, skb, &vid))
1998c2ecf20Sopenharmony_ci		br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, 0);
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci/* note: already called with rcu_read_lock */
2038c2ecf20Sopenharmony_cistatic int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	__br_handle_local_finish(skb);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	/* return 1 to signal the okfn() was called so it's ok to use the skb */
2088c2ecf20Sopenharmony_ci	return 1;
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic int nf_hook_bridge_pre(struct sk_buff *skb, struct sk_buff **pskb)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
2148c2ecf20Sopenharmony_ci	struct nf_hook_entries *e = NULL;
2158c2ecf20Sopenharmony_ci	struct nf_hook_state state;
2168c2ecf20Sopenharmony_ci	unsigned int verdict, i;
2178c2ecf20Sopenharmony_ci	struct net *net;
2188c2ecf20Sopenharmony_ci	int ret;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	net = dev_net(skb->dev);
2218c2ecf20Sopenharmony_ci#ifdef HAVE_JUMP_LABEL
2228c2ecf20Sopenharmony_ci	if (!static_key_false(&nf_hooks_needed[NFPROTO_BRIDGE][NF_BR_PRE_ROUTING]))
2238c2ecf20Sopenharmony_ci		goto frame_finish;
2248c2ecf20Sopenharmony_ci#endif
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	e = rcu_dereference(net->nf.hooks_bridge[NF_BR_PRE_ROUTING]);
2278c2ecf20Sopenharmony_ci	if (!e)
2288c2ecf20Sopenharmony_ci		goto frame_finish;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	nf_hook_state_init(&state, NF_BR_PRE_ROUTING,
2318c2ecf20Sopenharmony_ci			   NFPROTO_BRIDGE, skb->dev, NULL, NULL,
2328c2ecf20Sopenharmony_ci			   net, br_handle_frame_finish);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	for (i = 0; i < e->num_hook_entries; i++) {
2358c2ecf20Sopenharmony_ci		verdict = nf_hook_entry_hookfn(&e->hooks[i], skb, &state);
2368c2ecf20Sopenharmony_ci		switch (verdict & NF_VERDICT_MASK) {
2378c2ecf20Sopenharmony_ci		case NF_ACCEPT:
2388c2ecf20Sopenharmony_ci			if (BR_INPUT_SKB_CB(skb)->br_netfilter_broute) {
2398c2ecf20Sopenharmony_ci				*pskb = skb;
2408c2ecf20Sopenharmony_ci				return RX_HANDLER_PASS;
2418c2ecf20Sopenharmony_ci			}
2428c2ecf20Sopenharmony_ci			break;
2438c2ecf20Sopenharmony_ci		case NF_DROP:
2448c2ecf20Sopenharmony_ci			kfree_skb(skb);
2458c2ecf20Sopenharmony_ci			return RX_HANDLER_CONSUMED;
2468c2ecf20Sopenharmony_ci		case NF_QUEUE:
2478c2ecf20Sopenharmony_ci			ret = nf_queue(skb, &state, i, verdict);
2488c2ecf20Sopenharmony_ci			if (ret == 1)
2498c2ecf20Sopenharmony_ci				continue;
2508c2ecf20Sopenharmony_ci			return RX_HANDLER_CONSUMED;
2518c2ecf20Sopenharmony_ci		default: /* STOLEN */
2528c2ecf20Sopenharmony_ci			return RX_HANDLER_CONSUMED;
2538c2ecf20Sopenharmony_ci		}
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ciframe_finish:
2568c2ecf20Sopenharmony_ci	net = dev_net(skb->dev);
2578c2ecf20Sopenharmony_ci	br_handle_frame_finish(net, NULL, skb);
2588c2ecf20Sopenharmony_ci#else
2598c2ecf20Sopenharmony_ci	br_handle_frame_finish(dev_net(skb->dev), NULL, skb);
2608c2ecf20Sopenharmony_ci#endif
2618c2ecf20Sopenharmony_ci	return RX_HANDLER_CONSUMED;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci/*
2658c2ecf20Sopenharmony_ci * Return NULL if skb is handled
2668c2ecf20Sopenharmony_ci * note: already called with rcu_read_lock
2678c2ecf20Sopenharmony_ci */
2688c2ecf20Sopenharmony_cistatic rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	struct net_bridge_port *p;
2718c2ecf20Sopenharmony_ci	struct sk_buff *skb = *pskb;
2728c2ecf20Sopenharmony_ci	const unsigned char *dest = eth_hdr(skb)->h_dest;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
2758c2ecf20Sopenharmony_ci		return RX_HANDLER_PASS;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
2788c2ecf20Sopenharmony_ci		goto drop;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	skb = skb_share_check(skb, GFP_ATOMIC);
2818c2ecf20Sopenharmony_ci	if (!skb)
2828c2ecf20Sopenharmony_ci		return RX_HANDLER_CONSUMED;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	memset(skb->cb, 0, sizeof(struct br_input_skb_cb));
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	p = br_port_get_rcu(skb->dev);
2878c2ecf20Sopenharmony_ci	if (p->flags & BR_VLAN_TUNNEL) {
2888c2ecf20Sopenharmony_ci		if (br_handle_ingress_vlan_tunnel(skb, p,
2898c2ecf20Sopenharmony_ci						  nbp_vlan_group_rcu(p)))
2908c2ecf20Sopenharmony_ci			goto drop;
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (unlikely(is_link_local_ether_addr(dest))) {
2948c2ecf20Sopenharmony_ci		u16 fwd_mask = p->br->group_fwd_mask_required;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci		/*
2978c2ecf20Sopenharmony_ci		 * See IEEE 802.1D Table 7-10 Reserved addresses
2988c2ecf20Sopenharmony_ci		 *
2998c2ecf20Sopenharmony_ci		 * Assignment		 		Value
3008c2ecf20Sopenharmony_ci		 * Bridge Group Address		01-80-C2-00-00-00
3018c2ecf20Sopenharmony_ci		 * (MAC Control) 802.3		01-80-C2-00-00-01
3028c2ecf20Sopenharmony_ci		 * (Link Aggregation) 802.3	01-80-C2-00-00-02
3038c2ecf20Sopenharmony_ci		 * 802.1X PAE address		01-80-C2-00-00-03
3048c2ecf20Sopenharmony_ci		 *
3058c2ecf20Sopenharmony_ci		 * 802.1AB LLDP 		01-80-C2-00-00-0E
3068c2ecf20Sopenharmony_ci		 *
3078c2ecf20Sopenharmony_ci		 * Others reserved for future standardization
3088c2ecf20Sopenharmony_ci		 */
3098c2ecf20Sopenharmony_ci		fwd_mask |= p->group_fwd_mask;
3108c2ecf20Sopenharmony_ci		switch (dest[5]) {
3118c2ecf20Sopenharmony_ci		case 0x00:	/* Bridge Group Address */
3128c2ecf20Sopenharmony_ci			/* If STP is turned off,
3138c2ecf20Sopenharmony_ci			   then must forward to keep loop detection */
3148c2ecf20Sopenharmony_ci			if (p->br->stp_enabled == BR_NO_STP ||
3158c2ecf20Sopenharmony_ci			    fwd_mask & (1u << dest[5]))
3168c2ecf20Sopenharmony_ci				goto forward;
3178c2ecf20Sopenharmony_ci			*pskb = skb;
3188c2ecf20Sopenharmony_ci			__br_handle_local_finish(skb);
3198c2ecf20Sopenharmony_ci			return RX_HANDLER_PASS;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci		case 0x01:	/* IEEE MAC (Pause) */
3228c2ecf20Sopenharmony_ci			goto drop;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci		case 0x0E:	/* 802.1AB LLDP */
3258c2ecf20Sopenharmony_ci			fwd_mask |= p->br->group_fwd_mask;
3268c2ecf20Sopenharmony_ci			if (fwd_mask & (1u << dest[5]))
3278c2ecf20Sopenharmony_ci				goto forward;
3288c2ecf20Sopenharmony_ci			*pskb = skb;
3298c2ecf20Sopenharmony_ci			__br_handle_local_finish(skb);
3308c2ecf20Sopenharmony_ci			return RX_HANDLER_PASS;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci		default:
3338c2ecf20Sopenharmony_ci			/* Allow selective forwarding for most other protocols */
3348c2ecf20Sopenharmony_ci			fwd_mask |= p->br->group_fwd_mask;
3358c2ecf20Sopenharmony_ci			if (fwd_mask & (1u << dest[5]))
3368c2ecf20Sopenharmony_ci				goto forward;
3378c2ecf20Sopenharmony_ci		}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci		/* The else clause should be hit when nf_hook():
3408c2ecf20Sopenharmony_ci		 *   - returns < 0 (drop/error)
3418c2ecf20Sopenharmony_ci		 *   - returns = 0 (stolen/nf_queue)
3428c2ecf20Sopenharmony_ci		 * Thus return 1 from the okfn() to signal the skb is ok to pass
3438c2ecf20Sopenharmony_ci		 */
3448c2ecf20Sopenharmony_ci		if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN,
3458c2ecf20Sopenharmony_ci			    dev_net(skb->dev), NULL, skb, skb->dev, NULL,
3468c2ecf20Sopenharmony_ci			    br_handle_local_finish) == 1) {
3478c2ecf20Sopenharmony_ci			return RX_HANDLER_PASS;
3488c2ecf20Sopenharmony_ci		} else {
3498c2ecf20Sopenharmony_ci			return RX_HANDLER_CONSUMED;
3508c2ecf20Sopenharmony_ci		}
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	if (unlikely(br_mrp_process(p, skb)))
3548c2ecf20Sopenharmony_ci		return RX_HANDLER_PASS;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ciforward:
3578c2ecf20Sopenharmony_ci	switch (p->state) {
3588c2ecf20Sopenharmony_ci	case BR_STATE_FORWARDING:
3598c2ecf20Sopenharmony_ci	case BR_STATE_LEARNING:
3608c2ecf20Sopenharmony_ci		if (ether_addr_equal(p->br->dev->dev_addr, dest))
3618c2ecf20Sopenharmony_ci			skb->pkt_type = PACKET_HOST;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci		return nf_hook_bridge_pre(skb, pskb);
3648c2ecf20Sopenharmony_ci	default:
3658c2ecf20Sopenharmony_cidrop:
3668c2ecf20Sopenharmony_ci		kfree_skb(skb);
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci	return RX_HANDLER_CONSUMED;
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci/* This function has no purpose other than to appease the br_port_get_rcu/rtnl
3728c2ecf20Sopenharmony_ci * helpers which identify bridged ports according to the rx_handler installed
3738c2ecf20Sopenharmony_ci * on them (so there _needs_ to be a bridge rx_handler even if we don't need it
3748c2ecf20Sopenharmony_ci * to do anything useful). This bridge won't support traffic to/from the stack,
3758c2ecf20Sopenharmony_ci * but only hardware bridging. So return RX_HANDLER_PASS so we don't steal
3768c2ecf20Sopenharmony_ci * frames from the ETH_P_XDSA packet_type handler.
3778c2ecf20Sopenharmony_ci */
3788c2ecf20Sopenharmony_cistatic rx_handler_result_t br_handle_frame_dummy(struct sk_buff **pskb)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	return RX_HANDLER_PASS;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cirx_handler_func_t *br_get_rx_handler(const struct net_device *dev)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	if (netdev_uses_dsa(dev))
3868c2ecf20Sopenharmony_ci		return br_handle_frame_dummy;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	return br_handle_frame;
3898c2ecf20Sopenharmony_ci}
390