xref: /openbmc/linux/net/bridge/br_forward.c (revision 1ce60741)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *	Forwarding decision
41da177e4SLinus Torvalds  *	Linux ethernet bridge
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  *	Authors:
71da177e4SLinus Torvalds  *	Lennert Buytenhek		<buytenh@gnu.org>
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
10025d89c2SHerbert Xu #include <linux/err.h>
115a0e3ad6STejun Heo #include <linux/slab.h>
121da177e4SLinus Torvalds #include <linux/kernel.h>
131da177e4SLinus Torvalds #include <linux/netdevice.h>
14c06ee961SWANG Cong #include <linux/netpoll.h>
151da177e4SLinus Torvalds #include <linux/skbuff.h>
1685ca719eSStephen Hemminger #include <linux/if_vlan.h>
171da177e4SLinus Torvalds #include <linux/netfilter_bridge.h>
181da177e4SLinus Torvalds #include "br_private.h"
191da177e4SLinus Torvalds 
201a81a2e0Stanxiaojun /* Don't forward packets to originating port or forwarding disabled */
should_deliver(const struct net_bridge_port * p,const struct sk_buff * skb)211da177e4SLinus Torvalds static inline int should_deliver(const struct net_bridge_port *p,
221da177e4SLinus Torvalds 				 const struct sk_buff *skb)
231da177e4SLinus Torvalds {
242594e906SNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
252594e906SNikolay Aleksandrov 
26907b1e6eSNikolay Aleksandrov 	vg = nbp_vlan_group_rcu(p);
27a97bfc1dStanxiaojun 	return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
28ac0e932dSNikolay Aleksandrov 		p->state == BR_STATE_FORWARDING && br_allowed_egress(vg, skb) &&
297d850abdSNikolay Aleksandrov 		nbp_switchdev_allowed_egress(p, skb) &&
307d850abdSNikolay Aleksandrov 		!br_skb_isolated(p, skb);
311da177e4SLinus Torvalds }
321da177e4SLinus Torvalds 
br_dev_queue_push_xmit(struct net * net,struct sock * sk,struct sk_buff * skb)330c4b51f0SEric W. Biederman int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
341da177e4SLinus Torvalds {
3528c1382fSYunjian Wang 	skb_push(skb, ETH_HLEN);
36df356d5eSToshiaki Makita 	if (!is_skb_forwardable(skb->dev, skb))
37df356d5eSToshiaki Makita 		goto drop;
38df356d5eSToshiaki Makita 
39a881e963SPeter Huang (Peng) 	br_drop_fake_rtable(skb);
40df356d5eSToshiaki Makita 
41df356d5eSToshiaki Makita 	if (skb->ip_summed == CHECKSUM_PARTIAL &&
42a98c0c47SMenglong Dong 	    eth_type_vlan(skb->protocol)) {
43df356d5eSToshiaki Makita 		int depth;
44df356d5eSToshiaki Makita 
454063384eSEric Dumazet 		if (!vlan_get_protocol_and_depth(skb, skb->protocol, &depth))
46df356d5eSToshiaki Makita 			goto drop;
47df356d5eSToshiaki Makita 
48df356d5eSToshiaki Makita 		skb_set_network_header(skb, depth);
491da177e4SLinus Torvalds 	}
501da177e4SLinus Torvalds 
51c5381154SVladimir Oltean 	br_switchdev_frame_set_offload_fwd_mark(skb);
5247211192STobias Waldekranz 
53df356d5eSToshiaki Makita 	dev_queue_xmit(skb);
54df356d5eSToshiaki Makita 
55df356d5eSToshiaki Makita 	return 0;
56df356d5eSToshiaki Makita 
57df356d5eSToshiaki Makita drop:
58df356d5eSToshiaki Makita 	kfree_skb(skb);
591da177e4SLinus Torvalds 	return 0;
601da177e4SLinus Torvalds }
6134666d46SPablo Neira Ayuso EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit);
621da177e4SLinus Torvalds 
br_forward_finish(struct net * net,struct sock * sk,struct sk_buff * skb)630c4b51f0SEric W. Biederman int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
641da177e4SLinus Torvalds {
65de799101SMartin KaFai Lau 	skb_clear_tstamp(skb);
6629a26a56SEric W. Biederman 	return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING,
6729a26a56SEric W. Biederman 		       net, sk, skb, NULL, skb->dev,
681da177e4SLinus Torvalds 		       br_dev_queue_push_xmit);
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds }
7134666d46SPablo Neira Ayuso EXPORT_SYMBOL_GPL(br_forward_finish);
721da177e4SLinus Torvalds 
__br_forward(const struct net_bridge_port * to,struct sk_buff * skb,bool local_orig)7337b090e6SNikolay Aleksandrov static void __br_forward(const struct net_bridge_port *to,
7437b090e6SNikolay Aleksandrov 			 struct sk_buff *skb, bool local_orig)
751da177e4SLinus Torvalds {
762594e906SNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
771da177e4SLinus Torvalds 	struct net_device *indev;
7837b090e6SNikolay Aleksandrov 	struct net *net;
7937b090e6SNikolay Aleksandrov 	int br_hook;
804906f998SHerbert Xu 
8147211192STobias Waldekranz 	/* Mark the skb for forwarding offload early so that br_handle_vlan()
8247211192STobias Waldekranz 	 * can know whether to pop the VLAN header on egress or keep it.
8347211192STobias Waldekranz 	 */
8447211192STobias Waldekranz 	nbp_switchdev_frame_mark_tx_fwd_offload(to, skb);
8547211192STobias Waldekranz 
86907b1e6eSNikolay Aleksandrov 	vg = nbp_vlan_group_rcu(to);
8711538d03SRoopa Prabhu 	skb = br_handle_vlan(to->br, to, vg, skb);
8878851988SVlad Yasevich 	if (!skb)
8978851988SVlad Yasevich 		return;
9078851988SVlad Yasevich 
911da177e4SLinus Torvalds 	indev = skb->dev;
921da177e4SLinus Torvalds 	skb->dev = to->dev;
9337b090e6SNikolay Aleksandrov 	if (!local_orig) {
9437b090e6SNikolay Aleksandrov 		if (skb_warn_if_lro(skb)) {
9537b090e6SNikolay Aleksandrov 			kfree_skb(skb);
9637b090e6SNikolay Aleksandrov 			return;
9737b090e6SNikolay Aleksandrov 		}
9837b090e6SNikolay Aleksandrov 		br_hook = NF_BR_FORWARD;
9935fc92a9SHerbert Xu 		skb_forward_csum(skb);
10037b090e6SNikolay Aleksandrov 		net = dev_net(indev);
10137b090e6SNikolay Aleksandrov 	} else {
10237b090e6SNikolay Aleksandrov 		if (unlikely(netpoll_tx_running(to->br->dev))) {
10337b090e6SNikolay Aleksandrov 			skb_push(skb, ETH_HLEN);
10428c1382fSYunjian Wang 			if (!is_skb_forwardable(skb->dev, skb))
10528c1382fSYunjian Wang 				kfree_skb(skb);
10628c1382fSYunjian Wang 			else
10737b090e6SNikolay Aleksandrov 				br_netpoll_send_skb(to, skb);
10837b090e6SNikolay Aleksandrov 			return;
10937b090e6SNikolay Aleksandrov 		}
11037b090e6SNikolay Aleksandrov 		br_hook = NF_BR_LOCAL_OUT;
11137b090e6SNikolay Aleksandrov 		net = dev_net(skb->dev);
11237b090e6SNikolay Aleksandrov 		indev = NULL;
11337b090e6SNikolay Aleksandrov 	}
1141da177e4SLinus Torvalds 
11537b090e6SNikolay Aleksandrov 	NF_HOOK(NFPROTO_BRIDGE, br_hook,
11637b090e6SNikolay Aleksandrov 		net, NULL, skb, indev, skb->dev,
1171da177e4SLinus Torvalds 		br_forward_finish);
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds 
deliver_clone(const struct net_bridge_port * prev,struct sk_buff * skb,bool local_orig)12087faf3ccSDavid S. Miller static int deliver_clone(const struct net_bridge_port *prev,
12137b090e6SNikolay Aleksandrov 			 struct sk_buff *skb, bool local_orig)
122025d89c2SHerbert Xu {
123025d89c2SHerbert Xu 	struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
124025d89c2SHerbert Xu 
125fed396a5SHerbert Xu 	skb = skb_clone(skb, GFP_ATOMIC);
126fed396a5SHerbert Xu 	if (!skb) {
12744bdb313SEric Dumazet 		DEV_STATS_INC(dev, tx_dropped);
128025d89c2SHerbert Xu 		return -ENOMEM;
129025d89c2SHerbert Xu 	}
130025d89c2SHerbert Xu 
13137b090e6SNikolay Aleksandrov 	__br_forward(prev, skb, local_orig);
132025d89c2SHerbert Xu 	return 0;
133025d89c2SHerbert Xu }
134025d89c2SHerbert Xu 
13537b090e6SNikolay Aleksandrov /**
13637b090e6SNikolay Aleksandrov  * br_forward - forward a packet to a specific port
13737b090e6SNikolay Aleksandrov  * @to: destination port
13837b090e6SNikolay Aleksandrov  * @skb: packet being forwarded
13937b090e6SNikolay Aleksandrov  * @local_rcv: packet will be received locally after forwarding
14037b090e6SNikolay Aleksandrov  * @local_orig: packet is locally originated
14137b090e6SNikolay Aleksandrov  *
14237b090e6SNikolay Aleksandrov  * Should be called with rcu_read_lock.
14337b090e6SNikolay Aleksandrov  */
br_forward(const struct net_bridge_port * to,struct sk_buff * skb,bool local_rcv,bool local_orig)14437b090e6SNikolay Aleksandrov void br_forward(const struct net_bridge_port *to,
14537b090e6SNikolay Aleksandrov 		struct sk_buff *skb, bool local_rcv, bool local_orig)
14637b090e6SNikolay Aleksandrov {
1472756f68cSNikolay Aleksandrov 	if (unlikely(!to))
1482756f68cSNikolay Aleksandrov 		goto out;
1492756f68cSNikolay Aleksandrov 
1502756f68cSNikolay Aleksandrov 	/* redirect to backup link if the destination port is down */
1512756f68cSNikolay Aleksandrov 	if (rcu_access_pointer(to->backup_port) && !netif_carrier_ok(to->dev)) {
1522756f68cSNikolay Aleksandrov 		struct net_bridge_port *backup_port;
1532756f68cSNikolay Aleksandrov 
1542756f68cSNikolay Aleksandrov 		backup_port = rcu_dereference(to->backup_port);
1552756f68cSNikolay Aleksandrov 		if (unlikely(!backup_port))
1562756f68cSNikolay Aleksandrov 			goto out;
15729cfb2aaSIdo Schimmel 		BR_INPUT_SKB_CB(skb)->backup_nhid = READ_ONCE(to->backup_nhid);
1582756f68cSNikolay Aleksandrov 		to = backup_port;
1592756f68cSNikolay Aleksandrov 	}
1602756f68cSNikolay Aleksandrov 
1612756f68cSNikolay Aleksandrov 	if (should_deliver(to, skb)) {
16237b090e6SNikolay Aleksandrov 		if (local_rcv)
16337b090e6SNikolay Aleksandrov 			deliver_clone(to, skb, local_orig);
16437b090e6SNikolay Aleksandrov 		else
16537b090e6SNikolay Aleksandrov 			__br_forward(to, skb, local_orig);
16637b090e6SNikolay Aleksandrov 		return;
16737b090e6SNikolay Aleksandrov 	}
16837b090e6SNikolay Aleksandrov 
1692756f68cSNikolay Aleksandrov out:
17037b090e6SNikolay Aleksandrov 	if (!local_rcv)
17137b090e6SNikolay Aleksandrov 		kfree_skb(skb);
17237b090e6SNikolay Aleksandrov }
17337b090e6SNikolay Aleksandrov EXPORT_SYMBOL_GPL(br_forward);
17437b090e6SNikolay Aleksandrov 
maybe_deliver(struct net_bridge_port * prev,struct net_bridge_port * p,struct sk_buff * skb,bool local_orig)175025d89c2SHerbert Xu static struct net_bridge_port *maybe_deliver(
176025d89c2SHerbert Xu 	struct net_bridge_port *prev, struct net_bridge_port *p,
17737b090e6SNikolay Aleksandrov 	struct sk_buff *skb, bool local_orig)
178025d89c2SHerbert Xu {
179847d44efSPablo Neira Ayuso 	u8 igmp_type = br_multicast_igmp_type(skb);
180025d89c2SHerbert Xu 	int err;
181025d89c2SHerbert Xu 
182025d89c2SHerbert Xu 	if (!should_deliver(p, skb))
183025d89c2SHerbert Xu 		return prev;
184025d89c2SHerbert Xu 
18547211192STobias Waldekranz 	nbp_switchdev_frame_mark_tx_fwd_to_hwdom(p, skb);
18647211192STobias Waldekranz 
187025d89c2SHerbert Xu 	if (!prev)
188025d89c2SHerbert Xu 		goto out;
189025d89c2SHerbert Xu 
19037b090e6SNikolay Aleksandrov 	err = deliver_clone(prev, skb, local_orig);
191025d89c2SHerbert Xu 	if (err)
192025d89c2SHerbert Xu 		return ERR_PTR(err);
193025d89c2SHerbert Xu out:
194847d44efSPablo Neira Ayuso 	br_multicast_count(p->br, p, skb, igmp_type, BR_MCAST_DIR_TX);
195847d44efSPablo Neira Ayuso 
196025d89c2SHerbert Xu 	return p;
197025d89c2SHerbert Xu }
198025d89c2SHerbert Xu 
19937b090e6SNikolay Aleksandrov /* called under rcu_read_lock */
br_flood(struct net_bridge * br,struct sk_buff * skb,enum br_pkt_type pkt_type,bool local_rcv,bool local_orig,u16 vid)20037b090e6SNikolay Aleksandrov void br_flood(struct net_bridge *br, struct sk_buff *skb,
201e408336aSIdo Schimmel 	      enum br_pkt_type pkt_type, bool local_rcv, bool local_orig,
202e408336aSIdo Schimmel 	      u16 vid)
2031da177e4SLinus Torvalds {
20437b090e6SNikolay Aleksandrov 	struct net_bridge_port *prev = NULL;
2051080ab95SNikolay Aleksandrov 	struct net_bridge_port *p;
2061da177e4SLinus Torvalds 
2077b4858dfSIdo Schimmel 	br_tc_skb_miss_set(skb, pkt_type != BR_PKT_BROADCAST);
2087b4858dfSIdo Schimmel 
2091da177e4SLinus Torvalds 	list_for_each_entry_rcu(p, &br->port_list, list) {
21099f906e9SMike Manning 		/* Do not flood unicast traffic to ports that turn it off, nor
21199f906e9SMike Manning 		 * other traffic if flood off, except for traffic we originate
21299f906e9SMike Manning 		 */
21399f906e9SMike Manning 		switch (pkt_type) {
21499f906e9SMike Manning 		case BR_PKT_UNICAST:
21599f906e9SMike Manning 			if (!(p->flags & BR_FLOOD))
216867a5943SVlad Yasevich 				continue;
21799f906e9SMike Manning 			break;
21899f906e9SMike Manning 		case BR_PKT_MULTICAST:
21999f906e9SMike Manning 			if (!(p->flags & BR_MCAST_FLOOD) && skb->dev != br->dev)
220b6cb5ac8SNikolay Aleksandrov 				continue;
22199f906e9SMike Manning 			break;
22299f906e9SMike Manning 		case BR_PKT_BROADCAST:
22399f906e9SMike Manning 			if (!(p->flags & BR_BCAST_FLOOD) && skb->dev != br->dev)
22499f906e9SMike Manning 				continue;
22599f906e9SMike Manning 			break;
22699f906e9SMike Manning 		}
22795850116SKyeyoon Park 
22895850116SKyeyoon Park 		/* Do not flood to ports that enable proxy ARP */
22995850116SKyeyoon Park 		if (p->flags & BR_PROXYARP)
23095850116SKyeyoon Park 			continue;
231013a7ce8SIdo Schimmel 		if (BR_INPUT_SKB_CB(skb)->proxyarp_replied &&
2323aca683eSIdo Schimmel 		    ((p->flags & BR_PROXYARP_WIFI) ||
2333aca683eSIdo Schimmel 		     br_is_neigh_suppress_enabled(p, vid)))
234842a9ae0SJouni Malinen 			continue;
23595850116SKyeyoon Park 
23637b090e6SNikolay Aleksandrov 		prev = maybe_deliver(prev, p, skb, local_orig);
237025d89c2SHerbert Xu 		if (IS_ERR(prev))
238b33084beSHerbert Xu 			goto out;
2391da177e4SLinus Torvalds 	}
2401da177e4SLinus Torvalds 
241b33084beSHerbert Xu 	if (!prev)
242b33084beSHerbert Xu 		goto out;
243b33084beSHerbert Xu 
244b35c5f63SNikolay Aleksandrov 	if (local_rcv)
24537b090e6SNikolay Aleksandrov 		deliver_clone(prev, skb, local_orig);
246025d89c2SHerbert Xu 	else
24737b090e6SNikolay Aleksandrov 		__br_forward(prev, skb, local_orig);
2481da177e4SLinus Torvalds 	return;
2491da177e4SLinus Torvalds 
250b33084beSHerbert Xu out:
251b35c5f63SNikolay Aleksandrov 	if (!local_rcv)
2521da177e4SLinus Torvalds 		kfree_skb(skb);
2531da177e4SLinus Torvalds }
2541da177e4SLinus Torvalds 
2555cb5e947SHerbert Xu #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
maybe_deliver_addr(struct net_bridge_port * p,struct sk_buff * skb,const unsigned char * addr,bool local_orig)2565b9d6b15SArnd Bergmann static void maybe_deliver_addr(struct net_bridge_port *p, struct sk_buff *skb,
2575b9d6b15SArnd Bergmann 			       const unsigned char *addr, bool local_orig)
2585b9d6b15SArnd Bergmann {
2595b9d6b15SArnd Bergmann 	struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
2605b9d6b15SArnd Bergmann 	const unsigned char *src = eth_hdr(skb)->h_source;
2611ce60741SFelix Fietkau 	struct sk_buff *nskb;
2625b9d6b15SArnd Bergmann 
2635b9d6b15SArnd Bergmann 	if (!should_deliver(p, skb))
2645b9d6b15SArnd Bergmann 		return;
2655b9d6b15SArnd Bergmann 
2665b9d6b15SArnd Bergmann 	/* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */
2675b9d6b15SArnd Bergmann 	if (skb->dev == p->dev && ether_addr_equal(src, addr))
2685b9d6b15SArnd Bergmann 		return;
2695b9d6b15SArnd Bergmann 
2701ce60741SFelix Fietkau 	__skb_push(skb, ETH_HLEN);
2711ce60741SFelix Fietkau 	nskb = pskb_copy(skb, GFP_ATOMIC);
2721ce60741SFelix Fietkau 	__skb_pull(skb, ETH_HLEN);
2731ce60741SFelix Fietkau 	if (!nskb) {
27444bdb313SEric Dumazet 		DEV_STATS_INC(dev, tx_dropped);
2755b9d6b15SArnd Bergmann 		return;
2765b9d6b15SArnd Bergmann 	}
2775b9d6b15SArnd Bergmann 
2781ce60741SFelix Fietkau 	skb = nskb;
2791ce60741SFelix Fietkau 	__skb_pull(skb, ETH_HLEN);
2805b9d6b15SArnd Bergmann 	if (!is_broadcast_ether_addr(addr))
2815b9d6b15SArnd Bergmann 		memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN);
2825b9d6b15SArnd Bergmann 
2835b9d6b15SArnd Bergmann 	__br_forward(p, skb, local_orig);
2845b9d6b15SArnd Bergmann }
2855b9d6b15SArnd Bergmann 
2865cb5e947SHerbert Xu /* called with rcu_read_lock */
br_multicast_flood(struct net_bridge_mdb_entry * mdst,struct sk_buff * skb,struct net_bridge_mcast * brmctx,bool local_rcv,bool local_orig)28737b090e6SNikolay Aleksandrov void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
288b35c5f63SNikolay Aleksandrov 			struct sk_buff *skb,
289adc47037SNikolay Aleksandrov 			struct net_bridge_mcast *brmctx,
29037b090e6SNikolay Aleksandrov 			bool local_rcv, bool local_orig)
2915cb5e947SHerbert Xu {
292afe0159dSstephen hemminger 	struct net_bridge_port *prev = NULL;
2935cb5e947SHerbert Xu 	struct net_bridge_port_group *p;
29436cfec73SNikolay Aleksandrov 	bool allow_mode_include = true;
2955cb5e947SHerbert Xu 	struct hlist_node *rp;
2965cb5e947SHerbert Xu 
297adc47037SNikolay Aleksandrov 	rp = br_multicast_get_first_rport_node(brmctx, skb);
29844ebb081SLinus Lüssing 
29936cfec73SNikolay Aleksandrov 	if (mdst) {
30036cfec73SNikolay Aleksandrov 		p = rcu_dereference(mdst->ports);
301adc47037SNikolay Aleksandrov 		if (br_multicast_should_handle_mode(brmctx, mdst->addr.proto) &&
30236cfec73SNikolay Aleksandrov 		    br_multicast_is_star_g(&mdst->addr))
30336cfec73SNikolay Aleksandrov 			allow_mode_include = false;
30436cfec73SNikolay Aleksandrov 	} else {
30536cfec73SNikolay Aleksandrov 		p = NULL;
3067b4858dfSIdo Schimmel 		br_tc_skb_miss_set(skb, true);
30736cfec73SNikolay Aleksandrov 	}
30836cfec73SNikolay Aleksandrov 
3095cb5e947SHerbert Xu 	while (p || rp) {
310afe0159dSstephen hemminger 		struct net_bridge_port *port, *lport, *rport;
311afe0159dSstephen hemminger 
312085b53c8SNikolay Aleksandrov 		lport = p ? p->key.port : NULL;
31344ebb081SLinus Lüssing 		rport = br_multicast_rport_from_node_skb(rp, skb);
3145cb5e947SHerbert Xu 
3156db6f0eaSFelix Fietkau 		if ((unsigned long)lport > (unsigned long)rport) {
3166db6f0eaSFelix Fietkau 			port = lport;
3176db6f0eaSFelix Fietkau 
3186db6f0eaSFelix Fietkau 			if (port->flags & BR_MULTICAST_TO_UNICAST) {
3196db6f0eaSFelix Fietkau 				maybe_deliver_addr(lport, skb, p->eth_addr,
3206db6f0eaSFelix Fietkau 						   local_orig);
3216db6f0eaSFelix Fietkau 				goto delivered;
3226db6f0eaSFelix Fietkau 			}
32336cfec73SNikolay Aleksandrov 			if ((!allow_mode_include &&
32436cfec73SNikolay Aleksandrov 			     p->filter_mode == MCAST_INCLUDE) ||
32536cfec73SNikolay Aleksandrov 			    (p->flags & MDB_PG_FLAGS_BLOCKED))
32636cfec73SNikolay Aleksandrov 				goto delivered;
3276db6f0eaSFelix Fietkau 		} else {
3286db6f0eaSFelix Fietkau 			port = rport;
3296db6f0eaSFelix Fietkau 		}
3305cb5e947SHerbert Xu 
33137b090e6SNikolay Aleksandrov 		prev = maybe_deliver(prev, port, skb, local_orig);
3325cb5e947SHerbert Xu 		if (IS_ERR(prev))
3335cb5e947SHerbert Xu 			goto out;
334847d44efSPablo Neira Ayuso delivered:
3355cb5e947SHerbert Xu 		if ((unsigned long)lport >= (unsigned long)port)
33683f6a740Sstephen hemminger 			p = rcu_dereference(p->next);
3375cb5e947SHerbert Xu 		if ((unsigned long)rport >= (unsigned long)port)
338e8051688SEric Dumazet 			rp = rcu_dereference(hlist_next_rcu(rp));
3395cb5e947SHerbert Xu 	}
3405cb5e947SHerbert Xu 
3415cb5e947SHerbert Xu 	if (!prev)
3425cb5e947SHerbert Xu 		goto out;
3435cb5e947SHerbert Xu 
344b35c5f63SNikolay Aleksandrov 	if (local_rcv)
34537b090e6SNikolay Aleksandrov 		deliver_clone(prev, skb, local_orig);
3465cb5e947SHerbert Xu 	else
34737b090e6SNikolay Aleksandrov 		__br_forward(prev, skb, local_orig);
3485cb5e947SHerbert Xu 	return;
3495cb5e947SHerbert Xu 
3505cb5e947SHerbert Xu out:
351b35c5f63SNikolay Aleksandrov 	if (!local_rcv)
3525cb5e947SHerbert Xu 		kfree_skb(skb);
3535cb5e947SHerbert Xu }
3545cb5e947SHerbert Xu #endif
355