aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/bridge/br_forward.c67
-rw-r--r--net/bridge/br_private.h15
2 files changed, 82 insertions, 0 deletions
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 86cd0712d63e..d61e6f741125 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -186,3 +186,70 @@ void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
186{ 186{
187 br_flood(br, skb, skb2, __br_forward); 187 br_flood(br, skb, skb2, __br_forward);
188} 188}
189
190#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
191/* called with rcu_read_lock */
192static void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
193 struct sk_buff *skb, struct sk_buff *skb0,
194 void (*__packet_hook)(
195 const struct net_bridge_port *p,
196 struct sk_buff *skb))
197{
198 struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
199 struct net_bridge *br = netdev_priv(dev);
200 struct net_bridge_port *port;
201 struct net_bridge_port *lport, *rport;
202 struct net_bridge_port *prev;
203 struct net_bridge_port_group *p;
204 struct hlist_node *rp;
205
206 prev = NULL;
207
208 rp = br->router_list.first;
209 p = mdst ? mdst->ports : NULL;
210 while (p || rp) {
211 lport = p ? p->port : NULL;
212 rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
213 NULL;
214
215 port = (unsigned long)lport > (unsigned long)rport ?
216 lport : rport;
217
218 prev = maybe_deliver(prev, port, skb, __packet_hook);
219 if (IS_ERR(prev))
220 goto out;
221
222 if ((unsigned long)lport >= (unsigned long)port)
223 p = p->next;
224 if ((unsigned long)rport >= (unsigned long)port)
225 rp = rp->next;
226 }
227
228 if (!prev)
229 goto out;
230
231 if (skb0)
232 deliver_clone(prev, skb, __packet_hook);
233 else
234 __packet_hook(prev, skb);
235 return;
236
237out:
238 if (!skb0)
239 kfree_skb(skb);
240}
241
242/* called with rcu_read_lock */
243void br_multicast_deliver(struct net_bridge_mdb_entry *mdst,
244 struct sk_buff *skb)
245{
246 br_multicast_flood(mdst, skb, NULL, __br_deliver);
247}
248
249/* called with rcu_read_lock */
250void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
251 struct sk_buff *skb, struct sk_buff *skb2)
252{
253 br_multicast_flood(mdst, skb, skb2, __br_forward);
254}
255#endif
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 44345c9afdd3..c85943c2b23f 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -293,6 +293,10 @@ extern void br_multicast_disable_port(struct net_bridge_port *port);
293extern void br_multicast_init(struct net_bridge *br); 293extern void br_multicast_init(struct net_bridge *br);
294extern void br_multicast_open(struct net_bridge *br); 294extern void br_multicast_open(struct net_bridge *br);
295extern void br_multicast_stop(struct net_bridge *br); 295extern void br_multicast_stop(struct net_bridge *br);
296extern void br_multicast_deliver(struct net_bridge_mdb_entry *mdst,
297 struct sk_buff *skb);
298extern void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
299 struct sk_buff *skb, struct sk_buff *skb2);
296#else 300#else
297static inline int br_multicast_rcv(struct net_bridge *br, 301static inline int br_multicast_rcv(struct net_bridge *br,
298 struct net_bridge_port *port, 302 struct net_bridge_port *port,
@@ -334,6 +338,17 @@ static inline void br_multicast_open(struct net_bridge *br)
334static inline void br_multicast_stop(struct net_bridge *br) 338static inline void br_multicast_stop(struct net_bridge *br)
335{ 339{
336} 340}
341
342static inline void br_multicast_deliver(struct net_bridge_mdb_entry *mdst,
343 struct sk_buff *skb)
344{
345}
346
347static inline void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
348 struct sk_buff *skb,
349 struct sk_buff *skb2)
350{
351}
337#endif 352#endif
338 353
339static inline bool br_multicast_is_router(struct net_bridge *br) 354static inline bool br_multicast_is_router(struct net_bridge *br)