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