162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Handle incoming frames 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/slab.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/netdevice.h> 1362306a36Sopenharmony_ci#include <linux/etherdevice.h> 1462306a36Sopenharmony_ci#include <linux/netfilter_bridge.h> 1562306a36Sopenharmony_ci#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE 1662306a36Sopenharmony_ci#include <net/netfilter/nf_queue.h> 1762306a36Sopenharmony_ci#endif 1862306a36Sopenharmony_ci#include <linux/neighbour.h> 1962306a36Sopenharmony_ci#include <net/arp.h> 2062306a36Sopenharmony_ci#include <net/dsa.h> 2162306a36Sopenharmony_ci#include <linux/export.h> 2262306a36Sopenharmony_ci#include <linux/rculist.h> 2362306a36Sopenharmony_ci#include "br_private.h" 2462306a36Sopenharmony_ci#include "br_private_tunnel.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic int 2762306a36Sopenharmony_cibr_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci br_drop_fake_rtable(skb); 3062306a36Sopenharmony_ci return netif_receive_skb(skb); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic int br_pass_frame_up(struct sk_buff *skb) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev; 3662306a36Sopenharmony_ci struct net_bridge *br = netdev_priv(brdev); 3762306a36Sopenharmony_ci struct net_bridge_vlan_group *vg; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci dev_sw_netstats_rx_add(brdev, skb->len); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci vg = br_vlan_group_rcu(br); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* Reset the offload_fwd_mark because there could be a stacked 4462306a36Sopenharmony_ci * bridge above, and it should not think this bridge it doing 4562306a36Sopenharmony_ci * that bridge's work forwarding out its ports. 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci br_switchdev_frame_unmark(skb); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci /* Bridge is just like any other port. Make sure the 5062306a36Sopenharmony_ci * packet is allowed except in promisc mode when someone 5162306a36Sopenharmony_ci * may be running packet capture. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci if (!(brdev->flags & IFF_PROMISC) && 5462306a36Sopenharmony_ci !br_allowed_egress(vg, skb)) { 5562306a36Sopenharmony_ci kfree_skb(skb); 5662306a36Sopenharmony_ci return NET_RX_DROP; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci indev = skb->dev; 6062306a36Sopenharmony_ci skb->dev = brdev; 6162306a36Sopenharmony_ci skb = br_handle_vlan(br, NULL, vg, skb); 6262306a36Sopenharmony_ci if (!skb) 6362306a36Sopenharmony_ci return NET_RX_DROP; 6462306a36Sopenharmony_ci /* update the multicast stats if the packet is IGMP/MLD */ 6562306a36Sopenharmony_ci br_multicast_count(br, NULL, skb, br_multicast_igmp_type(skb), 6662306a36Sopenharmony_ci BR_MCAST_DIR_TX); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, 6962306a36Sopenharmony_ci dev_net(indev), NULL, skb, indev, NULL, 7062306a36Sopenharmony_ci br_netif_receive_skb); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* note: already called with rcu_read_lock */ 7462306a36Sopenharmony_ciint br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct net_bridge_port *p = br_port_get_rcu(skb->dev); 7762306a36Sopenharmony_ci enum br_pkt_type pkt_type = BR_PKT_UNICAST; 7862306a36Sopenharmony_ci struct net_bridge_fdb_entry *dst = NULL; 7962306a36Sopenharmony_ci struct net_bridge_mcast_port *pmctx; 8062306a36Sopenharmony_ci struct net_bridge_mdb_entry *mdst; 8162306a36Sopenharmony_ci bool local_rcv, mcast_hit = false; 8262306a36Sopenharmony_ci struct net_bridge_mcast *brmctx; 8362306a36Sopenharmony_ci struct net_bridge_vlan *vlan; 8462306a36Sopenharmony_ci struct net_bridge *br; 8562306a36Sopenharmony_ci u16 vid = 0; 8662306a36Sopenharmony_ci u8 state; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (!p) 8962306a36Sopenharmony_ci goto drop; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci br = p->br; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (br_mst_is_enabled(br)) { 9462306a36Sopenharmony_ci state = BR_STATE_FORWARDING; 9562306a36Sopenharmony_ci } else { 9662306a36Sopenharmony_ci if (p->state == BR_STATE_DISABLED) 9762306a36Sopenharmony_ci goto drop; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci state = p->state; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci brmctx = &p->br->multicast_ctx; 10362306a36Sopenharmony_ci pmctx = &p->multicast_ctx; 10462306a36Sopenharmony_ci if (!br_allowed_ingress(p->br, nbp_vlan_group_rcu(p), skb, &vid, 10562306a36Sopenharmony_ci &state, &vlan)) 10662306a36Sopenharmony_ci goto out; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (p->flags & BR_PORT_LOCKED) { 10962306a36Sopenharmony_ci struct net_bridge_fdb_entry *fdb_src = 11062306a36Sopenharmony_ci br_fdb_find_rcu(br, eth_hdr(skb)->h_source, vid); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (!fdb_src) { 11362306a36Sopenharmony_ci /* FDB miss. Create locked FDB entry if MAB is enabled 11462306a36Sopenharmony_ci * and drop the packet. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ci if (p->flags & BR_PORT_MAB) 11762306a36Sopenharmony_ci br_fdb_update(br, p, eth_hdr(skb)->h_source, 11862306a36Sopenharmony_ci vid, BIT(BR_FDB_LOCKED)); 11962306a36Sopenharmony_ci goto drop; 12062306a36Sopenharmony_ci } else if (READ_ONCE(fdb_src->dst) != p || 12162306a36Sopenharmony_ci test_bit(BR_FDB_LOCAL, &fdb_src->flags)) { 12262306a36Sopenharmony_ci /* FDB mismatch. Drop the packet without roaming. */ 12362306a36Sopenharmony_ci goto drop; 12462306a36Sopenharmony_ci } else if (test_bit(BR_FDB_LOCKED, &fdb_src->flags)) { 12562306a36Sopenharmony_ci /* FDB match, but entry is locked. Refresh it and drop 12662306a36Sopenharmony_ci * the packet. 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, 12962306a36Sopenharmony_ci BIT(BR_FDB_LOCKED)); 13062306a36Sopenharmony_ci goto drop; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci nbp_switchdev_frame_mark(p, skb); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* insert into forwarding database after filtering to avoid spoofing */ 13762306a36Sopenharmony_ci if (p->flags & BR_LEARNING) 13862306a36Sopenharmony_ci br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, 0); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci local_rcv = !!(br->dev->flags & IFF_PROMISC); 14162306a36Sopenharmony_ci if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) { 14262306a36Sopenharmony_ci /* by definition the broadcast is also a multicast address */ 14362306a36Sopenharmony_ci if (is_broadcast_ether_addr(eth_hdr(skb)->h_dest)) { 14462306a36Sopenharmony_ci pkt_type = BR_PKT_BROADCAST; 14562306a36Sopenharmony_ci local_rcv = true; 14662306a36Sopenharmony_ci } else { 14762306a36Sopenharmony_ci pkt_type = BR_PKT_MULTICAST; 14862306a36Sopenharmony_ci if (br_multicast_rcv(&brmctx, &pmctx, vlan, skb, vid)) 14962306a36Sopenharmony_ci goto drop; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (state == BR_STATE_LEARNING) 15462306a36Sopenharmony_ci goto drop; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci BR_INPUT_SKB_CB(skb)->brdev = br->dev; 15762306a36Sopenharmony_ci BR_INPUT_SKB_CB(skb)->src_port_isolated = !!(p->flags & BR_ISOLATED); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_INET) && 16062306a36Sopenharmony_ci (skb->protocol == htons(ETH_P_ARP) || 16162306a36Sopenharmony_ci skb->protocol == htons(ETH_P_RARP))) { 16262306a36Sopenharmony_ci br_do_proxy_suppress_arp(skb, br, vid, p); 16362306a36Sopenharmony_ci } else if (IS_ENABLED(CONFIG_IPV6) && 16462306a36Sopenharmony_ci skb->protocol == htons(ETH_P_IPV6) && 16562306a36Sopenharmony_ci br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) && 16662306a36Sopenharmony_ci pskb_may_pull(skb, sizeof(struct ipv6hdr) + 16762306a36Sopenharmony_ci sizeof(struct nd_msg)) && 16862306a36Sopenharmony_ci ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) { 16962306a36Sopenharmony_ci struct nd_msg *msg, _msg; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci msg = br_is_nd_neigh_msg(skb, &_msg); 17262306a36Sopenharmony_ci if (msg) 17362306a36Sopenharmony_ci br_do_suppress_nd(skb, br, vid, p, msg); 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci switch (pkt_type) { 17762306a36Sopenharmony_ci case BR_PKT_MULTICAST: 17862306a36Sopenharmony_ci mdst = br_mdb_get(brmctx, skb, vid); 17962306a36Sopenharmony_ci if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && 18062306a36Sopenharmony_ci br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst)) { 18162306a36Sopenharmony_ci if ((mdst && mdst->host_joined) || 18262306a36Sopenharmony_ci br_multicast_is_router(brmctx, skb)) { 18362306a36Sopenharmony_ci local_rcv = true; 18462306a36Sopenharmony_ci DEV_STATS_INC(br->dev, multicast); 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci mcast_hit = true; 18762306a36Sopenharmony_ci } else { 18862306a36Sopenharmony_ci local_rcv = true; 18962306a36Sopenharmony_ci DEV_STATS_INC(br->dev, multicast); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci break; 19262306a36Sopenharmony_ci case BR_PKT_UNICAST: 19362306a36Sopenharmony_ci dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid); 19462306a36Sopenharmony_ci break; 19562306a36Sopenharmony_ci default: 19662306a36Sopenharmony_ci break; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (dst) { 20062306a36Sopenharmony_ci unsigned long now = jiffies; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (test_bit(BR_FDB_LOCAL, &dst->flags)) 20362306a36Sopenharmony_ci return br_pass_frame_up(skb); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (now != dst->used) 20662306a36Sopenharmony_ci dst->used = now; 20762306a36Sopenharmony_ci br_forward(dst->dst, skb, local_rcv, false); 20862306a36Sopenharmony_ci } else { 20962306a36Sopenharmony_ci if (!mcast_hit) 21062306a36Sopenharmony_ci br_flood(br, skb, pkt_type, local_rcv, false, vid); 21162306a36Sopenharmony_ci else 21262306a36Sopenharmony_ci br_multicast_flood(mdst, skb, brmctx, local_rcv, false); 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (local_rcv) 21662306a36Sopenharmony_ci return br_pass_frame_up(skb); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ciout: 21962306a36Sopenharmony_ci return 0; 22062306a36Sopenharmony_cidrop: 22162306a36Sopenharmony_ci kfree_skb(skb); 22262306a36Sopenharmony_ci goto out; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(br_handle_frame_finish); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic void __br_handle_local_finish(struct sk_buff *skb) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci struct net_bridge_port *p = br_port_get_rcu(skb->dev); 22962306a36Sopenharmony_ci u16 vid = 0; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci /* check if vlan is allowed, to avoid spoofing */ 23262306a36Sopenharmony_ci if ((p->flags & BR_LEARNING) && 23362306a36Sopenharmony_ci nbp_state_should_learn(p) && 23462306a36Sopenharmony_ci !br_opt_get(p->br, BROPT_NO_LL_LEARN) && 23562306a36Sopenharmony_ci br_should_learn(p, skb, &vid)) 23662306a36Sopenharmony_ci br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, 0); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci/* note: already called with rcu_read_lock */ 24062306a36Sopenharmony_cistatic int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci __br_handle_local_finish(skb); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* return 1 to signal the okfn() was called so it's ok to use the skb */ 24562306a36Sopenharmony_ci return 1; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int nf_hook_bridge_pre(struct sk_buff *skb, struct sk_buff **pskb) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE 25162306a36Sopenharmony_ci struct nf_hook_entries *e = NULL; 25262306a36Sopenharmony_ci struct nf_hook_state state; 25362306a36Sopenharmony_ci unsigned int verdict, i; 25462306a36Sopenharmony_ci struct net *net; 25562306a36Sopenharmony_ci int ret; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci net = dev_net(skb->dev); 25862306a36Sopenharmony_ci#ifdef HAVE_JUMP_LABEL 25962306a36Sopenharmony_ci if (!static_key_false(&nf_hooks_needed[NFPROTO_BRIDGE][NF_BR_PRE_ROUTING])) 26062306a36Sopenharmony_ci goto frame_finish; 26162306a36Sopenharmony_ci#endif 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci e = rcu_dereference(net->nf.hooks_bridge[NF_BR_PRE_ROUTING]); 26462306a36Sopenharmony_ci if (!e) 26562306a36Sopenharmony_ci goto frame_finish; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci nf_hook_state_init(&state, NF_BR_PRE_ROUTING, 26862306a36Sopenharmony_ci NFPROTO_BRIDGE, skb->dev, NULL, NULL, 26962306a36Sopenharmony_ci net, br_handle_frame_finish); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci for (i = 0; i < e->num_hook_entries; i++) { 27262306a36Sopenharmony_ci verdict = nf_hook_entry_hookfn(&e->hooks[i], skb, &state); 27362306a36Sopenharmony_ci switch (verdict & NF_VERDICT_MASK) { 27462306a36Sopenharmony_ci case NF_ACCEPT: 27562306a36Sopenharmony_ci if (BR_INPUT_SKB_CB(skb)->br_netfilter_broute) { 27662306a36Sopenharmony_ci *pskb = skb; 27762306a36Sopenharmony_ci return RX_HANDLER_PASS; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci break; 28062306a36Sopenharmony_ci case NF_DROP: 28162306a36Sopenharmony_ci kfree_skb(skb); 28262306a36Sopenharmony_ci return RX_HANDLER_CONSUMED; 28362306a36Sopenharmony_ci case NF_QUEUE: 28462306a36Sopenharmony_ci ret = nf_queue(skb, &state, i, verdict); 28562306a36Sopenharmony_ci if (ret == 1) 28662306a36Sopenharmony_ci continue; 28762306a36Sopenharmony_ci return RX_HANDLER_CONSUMED; 28862306a36Sopenharmony_ci default: /* STOLEN */ 28962306a36Sopenharmony_ci return RX_HANDLER_CONSUMED; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ciframe_finish: 29362306a36Sopenharmony_ci net = dev_net(skb->dev); 29462306a36Sopenharmony_ci br_handle_frame_finish(net, NULL, skb); 29562306a36Sopenharmony_ci#else 29662306a36Sopenharmony_ci br_handle_frame_finish(dev_net(skb->dev), NULL, skb); 29762306a36Sopenharmony_ci#endif 29862306a36Sopenharmony_ci return RX_HANDLER_CONSUMED; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/* Return 0 if the frame was not processed otherwise 1 30262306a36Sopenharmony_ci * note: already called with rcu_read_lock 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_cistatic int br_process_frame_type(struct net_bridge_port *p, 30562306a36Sopenharmony_ci struct sk_buff *skb) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct br_frame_type *tmp; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci hlist_for_each_entry_rcu(tmp, &p->br->frame_type_list, list) 31062306a36Sopenharmony_ci if (unlikely(tmp->type == skb->protocol)) 31162306a36Sopenharmony_ci return tmp->frame_handler(p, skb); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci return 0; 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci/* 31762306a36Sopenharmony_ci * Return NULL if skb is handled 31862306a36Sopenharmony_ci * note: already called with rcu_read_lock 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_cistatic rx_handler_result_t br_handle_frame(struct sk_buff **pskb) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci struct net_bridge_port *p; 32362306a36Sopenharmony_ci struct sk_buff *skb = *pskb; 32462306a36Sopenharmony_ci const unsigned char *dest = eth_hdr(skb)->h_dest; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (unlikely(skb->pkt_type == PACKET_LOOPBACK)) 32762306a36Sopenharmony_ci return RX_HANDLER_PASS; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) 33062306a36Sopenharmony_ci goto drop; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci skb = skb_share_check(skb, GFP_ATOMIC); 33362306a36Sopenharmony_ci if (!skb) 33462306a36Sopenharmony_ci return RX_HANDLER_CONSUMED; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci memset(skb->cb, 0, sizeof(struct br_input_skb_cb)); 33762306a36Sopenharmony_ci br_tc_skb_miss_set(skb, false); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci p = br_port_get_rcu(skb->dev); 34062306a36Sopenharmony_ci if (p->flags & BR_VLAN_TUNNEL) 34162306a36Sopenharmony_ci br_handle_ingress_vlan_tunnel(skb, p, nbp_vlan_group_rcu(p)); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (unlikely(is_link_local_ether_addr(dest))) { 34462306a36Sopenharmony_ci u16 fwd_mask = p->br->group_fwd_mask_required; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci /* 34762306a36Sopenharmony_ci * See IEEE 802.1D Table 7-10 Reserved addresses 34862306a36Sopenharmony_ci * 34962306a36Sopenharmony_ci * Assignment Value 35062306a36Sopenharmony_ci * Bridge Group Address 01-80-C2-00-00-00 35162306a36Sopenharmony_ci * (MAC Control) 802.3 01-80-C2-00-00-01 35262306a36Sopenharmony_ci * (Link Aggregation) 802.3 01-80-C2-00-00-02 35362306a36Sopenharmony_ci * 802.1X PAE address 01-80-C2-00-00-03 35462306a36Sopenharmony_ci * 35562306a36Sopenharmony_ci * 802.1AB LLDP 01-80-C2-00-00-0E 35662306a36Sopenharmony_ci * 35762306a36Sopenharmony_ci * Others reserved for future standardization 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_ci fwd_mask |= p->group_fwd_mask; 36062306a36Sopenharmony_ci switch (dest[5]) { 36162306a36Sopenharmony_ci case 0x00: /* Bridge Group Address */ 36262306a36Sopenharmony_ci /* If STP is turned off, 36362306a36Sopenharmony_ci then must forward to keep loop detection */ 36462306a36Sopenharmony_ci if (p->br->stp_enabled == BR_NO_STP || 36562306a36Sopenharmony_ci fwd_mask & (1u << dest[5])) 36662306a36Sopenharmony_ci goto forward; 36762306a36Sopenharmony_ci *pskb = skb; 36862306a36Sopenharmony_ci __br_handle_local_finish(skb); 36962306a36Sopenharmony_ci return RX_HANDLER_PASS; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci case 0x01: /* IEEE MAC (Pause) */ 37262306a36Sopenharmony_ci goto drop; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci case 0x0E: /* 802.1AB LLDP */ 37562306a36Sopenharmony_ci fwd_mask |= p->br->group_fwd_mask; 37662306a36Sopenharmony_ci if (fwd_mask & (1u << dest[5])) 37762306a36Sopenharmony_ci goto forward; 37862306a36Sopenharmony_ci *pskb = skb; 37962306a36Sopenharmony_ci __br_handle_local_finish(skb); 38062306a36Sopenharmony_ci return RX_HANDLER_PASS; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci default: 38362306a36Sopenharmony_ci /* Allow selective forwarding for most other protocols */ 38462306a36Sopenharmony_ci fwd_mask |= p->br->group_fwd_mask; 38562306a36Sopenharmony_ci if (fwd_mask & (1u << dest[5])) 38662306a36Sopenharmony_ci goto forward; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* The else clause should be hit when nf_hook(): 39062306a36Sopenharmony_ci * - returns < 0 (drop/error) 39162306a36Sopenharmony_ci * - returns = 0 (stolen/nf_queue) 39262306a36Sopenharmony_ci * Thus return 1 from the okfn() to signal the skb is ok to pass 39362306a36Sopenharmony_ci */ 39462306a36Sopenharmony_ci if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, 39562306a36Sopenharmony_ci dev_net(skb->dev), NULL, skb, skb->dev, NULL, 39662306a36Sopenharmony_ci br_handle_local_finish) == 1) { 39762306a36Sopenharmony_ci return RX_HANDLER_PASS; 39862306a36Sopenharmony_ci } else { 39962306a36Sopenharmony_ci return RX_HANDLER_CONSUMED; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (unlikely(br_process_frame_type(p, skb))) 40462306a36Sopenharmony_ci return RX_HANDLER_PASS; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ciforward: 40762306a36Sopenharmony_ci if (br_mst_is_enabled(p->br)) 40862306a36Sopenharmony_ci goto defer_stp_filtering; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci switch (p->state) { 41162306a36Sopenharmony_ci case BR_STATE_FORWARDING: 41262306a36Sopenharmony_ci case BR_STATE_LEARNING: 41362306a36Sopenharmony_cidefer_stp_filtering: 41462306a36Sopenharmony_ci if (ether_addr_equal(p->br->dev->dev_addr, dest)) 41562306a36Sopenharmony_ci skb->pkt_type = PACKET_HOST; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci return nf_hook_bridge_pre(skb, pskb); 41862306a36Sopenharmony_ci default: 41962306a36Sopenharmony_cidrop: 42062306a36Sopenharmony_ci kfree_skb(skb); 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci return RX_HANDLER_CONSUMED; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci/* This function has no purpose other than to appease the br_port_get_rcu/rtnl 42662306a36Sopenharmony_ci * helpers which identify bridged ports according to the rx_handler installed 42762306a36Sopenharmony_ci * on them (so there _needs_ to be a bridge rx_handler even if we don't need it 42862306a36Sopenharmony_ci * to do anything useful). This bridge won't support traffic to/from the stack, 42962306a36Sopenharmony_ci * but only hardware bridging. So return RX_HANDLER_PASS so we don't steal 43062306a36Sopenharmony_ci * frames from the ETH_P_XDSA packet_type handler. 43162306a36Sopenharmony_ci */ 43262306a36Sopenharmony_cistatic rx_handler_result_t br_handle_frame_dummy(struct sk_buff **pskb) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci return RX_HANDLER_PASS; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cirx_handler_func_t *br_get_rx_handler(const struct net_device *dev) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci if (netdev_uses_dsa(dev)) 44062306a36Sopenharmony_ci return br_handle_frame_dummy; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return br_handle_frame; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_civoid br_add_frame(struct net_bridge *br, struct br_frame_type *ft) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci hlist_add_head_rcu(&ft->list, &br->frame_type_list); 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_civoid br_del_frame(struct net_bridge *br, struct br_frame_type *ft) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct br_frame_type *tmp; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci hlist_for_each_entry(tmp, &br->frame_type_list, list) 45562306a36Sopenharmony_ci if (ft == tmp) { 45662306a36Sopenharmony_ci hlist_del_rcu(&ft->list); 45762306a36Sopenharmony_ci return; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci} 460