]> bbs.cooldavid.org Git - net-next-2.6.git/blame - net/bridge/br_forward.c
bridge br_multicast: Don't refer to BR_INPUT_SKB_CB(skb)->mrouters_only without IGMP...
[net-next-2.6.git] / net / bridge / br_forward.c
CommitLineData
1da177e4
LT
1/*
2 * Forwarding decision
3 * Linux ethernet bridge
4 *
5 * Authors:
6 * Lennert Buytenhek <buytenh@gnu.org>
7 *
1da177e4
LT
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13
025d89c2 14#include <linux/err.h>
1da177e4
LT
15#include <linux/kernel.h>
16#include <linux/netdevice.h>
17#include <linux/skbuff.h>
85ca719e 18#include <linux/if_vlan.h>
1da177e4
LT
19#include <linux/netfilter_bridge.h>
20#include "br_private.h"
21
7f7708f0
MB
22static int deliver_clone(struct net_bridge_port *prev, struct sk_buff *skb,
23 void (*__packet_hook)(const struct net_bridge_port *p,
24 struct sk_buff *skb));
25
9ef513be 26/* Don't forward packets to originating port or forwarding diasabled */
9d6f229f 27static inline int should_deliver(const struct net_bridge_port *p,
1da177e4
LT
28 const struct sk_buff *skb)
29{
3982d3d2
FA
30 return (((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
31 p->state == BR_STATE_FORWARDING);
1da177e4
LT
32}
33
85ca719e
SH
34static inline unsigned packet_length(const struct sk_buff *skb)
35{
36 return skb->len - (skb->protocol == htons(ETH_P_8021Q) ? VLAN_HLEN : 0);
37}
38
1da177e4
LT
39int br_dev_queue_push_xmit(struct sk_buff *skb)
40{
7967168c 41 /* drop mtu oversized packets except gso */
89114afd 42 if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))
1da177e4
LT
43 kfree_skb(skb);
44 else {
1da177e4 45 /* ip_refrag calls ip_fragment, doesn't copy the MAC header. */
3a13813e
SH
46 if (nf_bridge_maybe_copy_header(skb))
47 kfree_skb(skb);
07317621 48 else {
3a13813e 49 skb_push(skb, ETH_HLEN);
1da177e4 50
3a13813e
SH
51 dev_queue_xmit(skb);
52 }
1da177e4
LT
53 }
54
55 return 0;
56}
57
58int br_forward_finish(struct sk_buff *skb)
59{
9ef513be
SH
60 return NF_HOOK(PF_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev,
61 br_dev_queue_push_xmit);
1da177e4 62
1da177e4
LT
63}
64
65static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
66{
67 skb->dev = to->dev;
1da177e4
LT
68 NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
69 br_forward_finish);
70}
71
72static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
73{
74 struct net_device *indev;
75
4906f998
HX
76 if (skb_warn_if_lro(skb)) {
77 kfree_skb(skb);
78 return;
79 }
80
1da177e4
LT
81 indev = skb->dev;
82 skb->dev = to->dev;
35fc92a9 83 skb_forward_csum(skb);
1da177e4
LT
84
85 NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev,
86 br_forward_finish);
87}
88
89/* called with rcu_read_lock */
90void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
91{
92 if (should_deliver(to, skb)) {
93 __br_deliver(to, skb);
94 return;
95 }
96
97 kfree_skb(skb);
98}
99
100/* called with rcu_read_lock */
7f7708f0 101void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0)
1da177e4 102{
4906f998 103 if (should_deliver(to, skb)) {
7f7708f0
MB
104 if (skb0)
105 deliver_clone(to, skb, __br_forward);
106 else
107 __br_forward(to, skb);
1da177e4
LT
108 return;
109 }
110
7f7708f0
MB
111 if (!skb0)
112 kfree_skb(skb);
1da177e4
LT
113}
114
025d89c2
HX
115static int deliver_clone(struct net_bridge_port *prev, struct sk_buff *skb,
116 void (*__packet_hook)(const struct net_bridge_port *p,
117 struct sk_buff *skb))
118{
119 skb = skb_clone(skb, GFP_ATOMIC);
120 if (!skb) {
121 struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
122
123 dev->stats.tx_dropped++;
124 return -ENOMEM;
125 }
126
127 __packet_hook(prev, skb);
128 return 0;
129}
130
131static struct net_bridge_port *maybe_deliver(
132 struct net_bridge_port *prev, struct net_bridge_port *p,
133 struct sk_buff *skb,
134 void (*__packet_hook)(const struct net_bridge_port *p,
135 struct sk_buff *skb))
136{
137 int err;
138
139 if (!should_deliver(p, skb))
140 return prev;
141
142 if (!prev)
143 goto out;
144
145 err = deliver_clone(prev, skb, __packet_hook);
146 if (err)
147 return ERR_PTR(err);
148
149out:
150 return p;
151}
152
1da177e4 153/* called under bridge lock */
e081e1e3 154static void br_flood(struct net_bridge *br, struct sk_buff *skb,
b33084be
HX
155 struct sk_buff *skb0,
156 void (*__packet_hook)(const struct net_bridge_port *p,
157 struct sk_buff *skb))
1da177e4
LT
158{
159 struct net_bridge_port *p;
160 struct net_bridge_port *prev;
161
1da177e4
LT
162 prev = NULL;
163
164 list_for_each_entry_rcu(p, &br->port_list, list) {
025d89c2
HX
165 prev = maybe_deliver(prev, p, skb, __packet_hook);
166 if (IS_ERR(prev))
167 goto out;
1da177e4
LT
168 }
169
b33084be
HX
170 if (!prev)
171 goto out;
172
025d89c2
HX
173 if (skb0)
174 deliver_clone(prev, skb, __packet_hook);
175 else
176 __packet_hook(prev, skb);
b33084be 177 return;
1da177e4 178
b33084be
HX
179out:
180 if (!skb0)
181 kfree_skb(skb);
1da177e4
LT
182}
183
184
185/* called with rcu_read_lock */
e081e1e3 186void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb)
1da177e4 187{
b33084be 188 br_flood(br, skb, NULL, __br_deliver);
1da177e4
LT
189}
190
191/* called under bridge lock */
b33084be
HX
192void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
193 struct sk_buff *skb2)
1da177e4 194{
b33084be 195 br_flood(br, skb, skb2, __br_forward);
1da177e4 196}
5cb5e947
HX
197
198#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
199/* called with rcu_read_lock */
200static void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
201 struct sk_buff *skb, struct sk_buff *skb0,
202 void (*__packet_hook)(
203 const struct net_bridge_port *p,
204 struct sk_buff *skb))
205{
206 struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
207 struct net_bridge *br = netdev_priv(dev);
208 struct net_bridge_port *port;
209 struct net_bridge_port *lport, *rport;
210 struct net_bridge_port *prev;
211 struct net_bridge_port_group *p;
212 struct hlist_node *rp;
213
214 prev = NULL;
215
216 rp = br->router_list.first;
217 p = mdst ? mdst->ports : NULL;
218 while (p || rp) {
219 lport = p ? p->port : NULL;
220 rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
221 NULL;
222
223 port = (unsigned long)lport > (unsigned long)rport ?
224 lport : rport;
225
226 prev = maybe_deliver(prev, port, skb, __packet_hook);
227 if (IS_ERR(prev))
228 goto out;
229
230 if ((unsigned long)lport >= (unsigned long)port)
231 p = p->next;
232 if ((unsigned long)rport >= (unsigned long)port)
233 rp = rp->next;
234 }
235
236 if (!prev)
237 goto out;
238
239 if (skb0)
240 deliver_clone(prev, skb, __packet_hook);
241 else
242 __packet_hook(prev, skb);
243 return;
244
245out:
246 if (!skb0)
247 kfree_skb(skb);
248}
249
250/* called with rcu_read_lock */
251void br_multicast_deliver(struct net_bridge_mdb_entry *mdst,
252 struct sk_buff *skb)
253{
254 br_multicast_flood(mdst, skb, NULL, __br_deliver);
255}
256
257/* called with rcu_read_lock */
258void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
259 struct sk_buff *skb, struct sk_buff *skb2)
260{
261 br_multicast_flood(mdst, skb, skb2, __br_forward);
262}
263#endif