Blame view

net/bridge/br_netfilter.c 26.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  /*
   *	Handle firewalling
   *	Linux ethernet bridge
   *
   *	Authors:
   *	Lennert Buytenhek               <buytenh@gnu.org>
   *	Bart De Schuymer (maintainer)	<bdschuym@pandora.be>
   *
   *	Changes:
   *	Apr 29 2003: physdev module support (bdschuym)
   *	Jun 19 2003: let arptables see bridged ARP traffic (bdschuym)
   *	Oct 06 2003: filter encapsulated IP/ARP VLAN traffic on untagged bridge
   *	             (bdschuym)
   *	Sep 01 2004: add IPv6 filtering (bdschuym)
   *
   *	This program is free software; you can redistribute it and/or
   *	modify it under the terms of the GNU General Public License
   *	as published by the Free Software Foundation; either version
   *	2 of the License, or (at your option) any later version.
   *
   *	Lennert dedicates this file to Kerstin Wurdinger.
   */
  
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/ip.h>
  #include <linux/netdevice.h>
  #include <linux/skbuff.h>
14c850212   Arnaldo Carvalho de Melo   [INET_SOCK]: Move...
29
  #include <linux/if_arp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
  #include <linux/if_ether.h>
  #include <linux/if_vlan.h>
516299d2f   Michael Milner   [NETFILTER]: brid...
32
33
  #include <linux/if_pppox.h>
  #include <linux/ppp_defs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
  #include <linux/netfilter_bridge.h>
  #include <linux/netfilter_ipv4.h>
  #include <linux/netfilter_ipv6.h>
  #include <linux/netfilter_arp.h>
  #include <linux/in_route.h>
f216f082b   Bart De Schuymer   [NETFILTER]: brid...
39
  #include <linux/inetdevice.h>
14c850212   Arnaldo Carvalho de Melo   [INET_SOCK]: Move...
40

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
  #include <net/ip.h>
  #include <net/ipv6.h>
14c850212   Arnaldo Carvalho de Melo   [INET_SOCK]: Move...
43
  #include <net/route.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  #include <asm/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
49
50
51
  #include "br_private.h"
  #ifdef CONFIG_SYSCTL
  #include <linux/sysctl.h>
  #endif
  
  #define skb_origaddr(skb)	 (((struct bridge_skb_cb *) \
  				 (skb->nf_bridge->data))->daddr.ipv4)
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
52
53
  #define store_orig_dstaddr(skb)	 (skb_origaddr(skb) = ip_hdr(skb)->daddr)
  #define dnat_took_place(skb)	 (skb_origaddr(skb) != ip_hdr(skb)->daddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
  #ifdef CONFIG_SYSCTL
  static struct ctl_table_header *brnf_sysctl_header;
9c1ea148a   Brian Haley   [BRIDGE]: Change ...
57
58
59
60
  static int brnf_call_iptables __read_mostly = 1;
  static int brnf_call_ip6tables __read_mostly = 1;
  static int brnf_call_arptables __read_mostly = 1;
  static int brnf_filter_vlan_tagged __read_mostly = 1;
516299d2f   Michael Milner   [NETFILTER]: brid...
61
  static int brnf_filter_pppoe_tagged __read_mostly = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
  #else
  #define brnf_filter_vlan_tagged 1
516299d2f   Michael Milner   [NETFILTER]: brid...
64
  #define brnf_filter_pppoe_tagged 1
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  #endif
b6f99a211   Dave Jones   [NET]: fix up mis...
66
  static inline __be16 vlan_proto(const struct sk_buff *skb)
8b42ec392   Stephen Hemminger   [BRIDGE]: netfilt...
67
68
69
70
71
72
  {
  	return vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
  }
  
  #define IS_VLAN_IP(skb) \
  	(skb->protocol == htons(ETH_P_8021Q) && \
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
73
  	 vlan_proto(skb) == htons(ETH_P_IP) && 	\
8b42ec392   Stephen Hemminger   [BRIDGE]: netfilt...
74
75
76
77
78
79
80
81
82
83
84
  	 brnf_filter_vlan_tagged)
  
  #define IS_VLAN_IPV6(skb) \
  	(skb->protocol == htons(ETH_P_8021Q) && \
  	 vlan_proto(skb) == htons(ETH_P_IPV6) &&\
  	 brnf_filter_vlan_tagged)
  
  #define IS_VLAN_ARP(skb) \
  	(skb->protocol == htons(ETH_P_8021Q) &&	\
  	 vlan_proto(skb) == htons(ETH_P_ARP) &&	\
  	 brnf_filter_vlan_tagged)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85

516299d2f   Michael Milner   [NETFILTER]: brid...
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  static inline __be16 pppoe_proto(const struct sk_buff *skb)
  {
  	return *((__be16 *)(skb_mac_header(skb) + ETH_HLEN +
  			    sizeof(struct pppoe_hdr)));
  }
  
  #define IS_PPPOE_IP(skb) \
  	(skb->protocol == htons(ETH_P_PPP_SES) && \
  	 pppoe_proto(skb) == htons(PPP_IP) && \
  	 brnf_filter_pppoe_tagged)
  
  #define IS_PPPOE_IPV6(skb) \
  	(skb->protocol == htons(ETH_P_PPP_SES) && \
  	 pppoe_proto(skb) == htons(PPP_IPV6) && \
  	 brnf_filter_pppoe_tagged)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  /* We need these fake structures to make netfilter happy --
   * lots of places assume that skb->dst != NULL, which isn't
   * all that unreasonable.
   *
   * Currently, we fill in the PMTU entry because netfilter
   * refragmentation needs it, and the rt_flags entry because
   * ipt_REJECT needs it.  Future netfilter modules might
   * require us to fill additional fields. */
  static struct net_device __fake_net_device = {
  	.hard_header_len	= ETH_HLEN
  };
  
  static struct rtable __fake_rtable = {
  	.u = {
  		.dst = {
  			.__refcnt		= ATOMIC_INIT(1),
  			.dev			= &__fake_net_device,
  			.path			= &__fake_rtable.u.dst,
  			.metrics		= {[RTAX_MTU - 1] = 1500},
42cf93cd4   Patrick McHardy   [NETFILTER]: Fix ...
120
  			.flags			= DST_NOXFRM,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
  		}
  	},
  	.rt_flags	= 0,
  };
5dce971ac   Stephen Hemminger   [BRIDGE]: netfilt...
125
126
127
128
129
130
  static inline struct net_device *bridge_parent(const struct net_device *dev)
  {
  	struct net_bridge_port *port = rcu_dereference(dev->br_port);
  
  	return port ? port->br->dev : NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131

fdeabdefb   Stephen Hemminger   [BRIDGE]: netfilt...
132
133
134
135
136
137
138
139
  static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)
  {
  	skb->nf_bridge = kzalloc(sizeof(struct nf_bridge_info), GFP_ATOMIC);
  	if (likely(skb->nf_bridge))
  		atomic_set(&(skb->nf_bridge->use), 1);
  
  	return skb->nf_bridge;
  }
fc38582db   Patrick McHardy   [NETFILTER]: brid...
140
141
142
143
144
145
146
147
148
  static inline void nf_bridge_push_encap_header(struct sk_buff *skb)
  {
  	unsigned int len = nf_bridge_encap_header_len(skb);
  
  	skb_push(skb, len);
  	skb->network_header -= len;
  }
  
  static inline void nf_bridge_pull_encap_header(struct sk_buff *skb)
fdeabdefb   Stephen Hemminger   [BRIDGE]: netfilt...
149
  {
fc38582db   Patrick McHardy   [NETFILTER]: brid...
150
151
152
153
154
  	unsigned int len = nf_bridge_encap_header_len(skb);
  
  	skb_pull(skb, len);
  	skb->network_header += len;
  }
fdeabdefb   Stephen Hemminger   [BRIDGE]: netfilt...
155

fc38582db   Patrick McHardy   [NETFILTER]: brid...
156
157
158
159
160
161
162
163
164
165
166
  static inline void nf_bridge_pull_encap_header_rcsum(struct sk_buff *skb)
  {
  	unsigned int len = nf_bridge_encap_header_len(skb);
  
  	skb_pull_rcsum(skb, len);
  	skb->network_header += len;
  }
  
  static inline void nf_bridge_save_header(struct sk_buff *skb)
  {
  	int header_size = ETH_HLEN + nf_bridge_encap_header_len(skb);
fdeabdefb   Stephen Hemminger   [BRIDGE]: netfilt...
167

d626f62b1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
168
169
  	skb_copy_from_linear_data_offset(skb, -header_size,
  					 skb->nf_bridge->data, header_size);
fdeabdefb   Stephen Hemminger   [BRIDGE]: netfilt...
170
  }
07317621d   Stephen Hemminger   [NETFILTER] bridg...
171
172
173
174
175
176
177
  /*
   * When forwarding bridge frames, we save a copy of the original
   * header before processing.
   */
  int nf_bridge_copy_header(struct sk_buff *skb)
  {
  	int err;
fc38582db   Patrick McHardy   [NETFILTER]: brid...
178
  	int header_size = ETH_HLEN + nf_bridge_encap_header_len(skb);
07317621d   Stephen Hemminger   [NETFILTER] bridg...
179
180
181
182
  
  	err = skb_cow(skb, header_size);
  	if (err)
  		return err;
27d7ff46a   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
183
184
  	skb_copy_to_linear_data_offset(skb, -header_size,
  				       skb->nf_bridge->data, header_size);
fc38582db   Patrick McHardy   [NETFILTER]: brid...
185
  	__skb_push(skb, nf_bridge_encap_header_len(skb));
07317621d   Stephen Hemminger   [NETFILTER] bridg...
186
187
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
191
192
193
  /* PF_BRIDGE/PRE_ROUTING *********************************************/
  /* Undo the changes made for ip6tables PREROUTING and continue the
   * bridge PRE_ROUTING hook. */
  static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
  {
  	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
197
198
199
200
201
202
203
  	if (nf_bridge->mask & BRNF_PKT_TYPE) {
  		skb->pkt_type = PACKET_OTHERHOST;
  		nf_bridge->mask ^= BRNF_PKT_TYPE;
  	}
  	nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
  
  	skb->dst = (struct dst_entry *)&__fake_rtable;
  	dst_hold(skb->dst);
  
  	skb->dev = nf_bridge->physindev;
fc38582db   Patrick McHardy   [NETFILTER]: brid...
204
  	nf_bridge_push_encap_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
207
208
209
210
211
212
213
214
215
216
  	NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
  		       br_handle_frame_finish, 1);
  
  	return 0;
  }
  
  static void __br_dnat_complain(void)
  {
  	static unsigned long last_complaint;
  
  	if (jiffies - last_complaint >= 5 * HZ) {
  		printk(KERN_WARNING "Performing cross-bridge DNAT requires IP "
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
217
218
  		       "forwarding to be enabled
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  		last_complaint = jiffies;
  	}
  }
  
  /* This requires some explaining. If DNAT has taken place,
   * we will need to fix up the destination Ethernet address,
   * and this is a tricky process.
   *
   * There are two cases to consider:
   * 1. The packet was DNAT'ed to a device in the same bridge
   *    port group as it was received on. We can still bridge
   *    the packet.
   * 2. The packet was DNAT'ed to a different device, either
   *    a non-bridged device or another bridge port group.
   *    The packet will need to be routed.
   *
   * The correct way of distinguishing between these two cases is to
   * call ip_route_input() and to look at skb->dst->dev, which is
   * changed to the destination device if ip_route_input() succeeds.
   *
   * Let us first consider the case that ip_route_input() succeeds:
   *
   * If skb->dst->dev equals the logical bridge device the packet
   * came in on, we can consider this bridging. We then call
   * skb->dst->output() which will make the packet enter br_nf_local_out()
   * not much later. In that function it is assured that the iptables
   * FORWARD chain is traversed for the packet.
   *
   * Otherwise, the packet is considered to be routed and we just
   * change the destination MAC address so that the packet will
f216f082b   Bart De Schuymer   [NETFILTER]: brid...
249
250
251
   * later be passed up to the IP stack to be routed. For a redirected
   * packet, ip_route_input() will give back the localhost as output device,
   * which differs from the bridge device.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
254
   *
   * Let us now consider the case that ip_route_input() fails:
   *
f216f082b   Bart De Schuymer   [NETFILTER]: brid...
255
256
   * This can be because the destination address is martian, in which case
   * the packet will be dropped.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
259
260
261
262
263
264
265
266
267
268
   * After a "echo '0' > /proc/sys/net/ipv4/ip_forward" ip_route_input()
   * will fail, while __ip_route_output_key() will return success. The source
   * address for __ip_route_output_key() is set to zero, so __ip_route_output_key
   * thinks we're handling a locally generated packet and won't care
   * if IP forwarding is allowed. We send a warning message to the users's
   * log telling her to put IP forwarding on.
   *
   * ip_route_input() will also fail if there is no route available.
   * In that case we just drop the packet.
   *
   * --Lennert, 20020411
   * --Bart, 20020416 (updated)
f216f082b   Bart De Schuymer   [NETFILTER]: brid...
269
270
   * --Bart, 20021007 (updated)
   * --Bart, 20062711 (updated) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
  static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
275
276
277
278
279
  	if (skb->pkt_type == PACKET_OTHERHOST) {
  		skb->pkt_type = PACKET_HOST;
  		skb->nf_bridge->mask |= BRNF_PKT_TYPE;
  	}
  	skb->nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
  
  	skb->dev = bridge_parent(skb->dev);
5dce971ac   Stephen Hemminger   [BRIDGE]: netfilt...
280
281
282
  	if (!skb->dev)
  		kfree_skb(skb);
  	else {
fc38582db   Patrick McHardy   [NETFILTER]: brid...
283
  		nf_bridge_pull_encap_header(skb);
5dce971ac   Stephen Hemminger   [BRIDGE]: netfilt...
284
  		skb->dst->output(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
289
290
291
  	return 0;
  }
  
  static int br_nf_pre_routing_finish(struct sk_buff *skb)
  {
  	struct net_device *dev = skb->dev;
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
292
  	struct iphdr *iph = ip_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
f216f082b   Bart De Schuymer   [NETFILTER]: brid...
294
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
299
300
  	if (nf_bridge->mask & BRNF_PKT_TYPE) {
  		skb->pkt_type = PACKET_OTHERHOST;
  		nf_bridge->mask ^= BRNF_PKT_TYPE;
  	}
  	nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
  	if (dnat_took_place(skb)) {
f216f082b   Bart De Schuymer   [NETFILTER]: brid...
302
  		if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
  			struct rtable *rt;
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
304
305
306
307
308
309
310
311
312
  			struct flowi fl = {
  				.nl_u = {
  					.ip4_u = {
  						 .daddr = iph->daddr,
  						 .saddr = 0,
  						 .tos = RT_TOS(iph->tos) },
  				},
  				.proto = 0,
  			};
f216f082b   Bart De Schuymer   [NETFILTER]: brid...
313
314
315
316
317
318
319
320
321
322
323
  			struct in_device *in_dev = in_dev_get(dev);
  
  			/* If err equals -EHOSTUNREACH the error is due to a
  			 * martian destination or due to the fact that
  			 * forwarding is disabled. For most martian packets,
  			 * ip_route_output_key() will fail. It won't fail for 2 types of
  			 * martian destinations: loopback destinations and destination
  			 * 0.0.0.0. In both cases the packet will be dropped because the
  			 * destination is the loopback device and not the bridge. */
  			if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev))
  				goto free_skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
  
  			if (!ip_route_output_key(&rt, &fl)) {
1c011bed5   Bart De Schuymer   [BRIDGE-NF]: Fix ...
326
  				/* - Bridged-and-DNAT'ed traffic doesn't
f216f082b   Bart De Schuymer   [NETFILTER]: brid...
327
328
  				 *   require ip_forwarding. */
  				if (((struct dst_entry *)rt)->dev == dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
331
  					skb->dst = (struct dst_entry *)rt;
  					goto bridged_dnat;
  				}
f216f082b   Bart De Schuymer   [NETFILTER]: brid...
332
333
334
335
  				/* we are sure that forwarding is disabled, so printing
  				 * this message is no problem. Note that the packet could
  				 * still have a martian destination address, in which case
  				 * the packet could be dropped even if forwarding were enabled */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
338
  				__br_dnat_complain();
  				dst_release((struct dst_entry *)rt);
  			}
f216f082b   Bart De Schuymer   [NETFILTER]: brid...
339
  free_skb:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
341
342
343
344
345
346
347
348
  			kfree_skb(skb);
  			return 0;
  		} else {
  			if (skb->dst->dev == dev) {
  bridged_dnat:
  				/* Tell br_nf_local_out this is a
  				 * bridged frame */
  				nf_bridge->mask |= BRNF_BRIDGED_DNAT;
  				skb->dev = nf_bridge->physindev;
fc38582db   Patrick McHardy   [NETFILTER]: brid...
349
  				nf_bridge_push_encap_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
353
354
355
  				NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING,
  					       skb, skb->dev, NULL,
  					       br_nf_pre_routing_finish_bridge,
  					       1);
  				return 0;
  			}
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
356
  			memcpy(eth_hdr(skb)->h_dest, dev->dev_addr, ETH_ALEN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
359
360
361
362
363
364
  			skb->pkt_type = PACKET_HOST;
  		}
  	} else {
  		skb->dst = (struct dst_entry *)&__fake_rtable;
  		dst_hold(skb->dst);
  	}
  
  	skb->dev = nf_bridge->physindev;
fc38582db   Patrick McHardy   [NETFILTER]: brid...
365
  	nf_bridge_push_encap_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
368
369
370
371
372
  	NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
  		       br_handle_frame_finish, 1);
  
  	return 0;
  }
  
  /* Some common code for IPv4/IPv6 */
5dce971ac   Stephen Hemminger   [BRIDGE]: netfilt...
373
  static struct net_device *setup_pre_routing(struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
376
377
378
379
380
381
382
383
384
  {
  	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
  
  	if (skb->pkt_type == PACKET_OTHERHOST) {
  		skb->pkt_type = PACKET_HOST;
  		nf_bridge->mask |= BRNF_PKT_TYPE;
  	}
  
  	nf_bridge->mask |= BRNF_NF_BRIDGE_PREROUTING;
  	nf_bridge->physindev = skb->dev;
  	skb->dev = bridge_parent(skb->dev);
5dce971ac   Stephen Hemminger   [BRIDGE]: netfilt...
385
386
  
  	return skb->dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
389
390
391
  }
  
  /* We only check the length. A bridge shouldn't do any hop-by-hop stuff anyway */
  static int check_hbh_len(struct sk_buff *skb)
  {
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
392
  	unsigned char *raw = (u8 *)(ipv6_hdr(skb) + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
  	u32 pkt_len;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
394
395
  	const unsigned char *nh = skb_network_header(skb);
  	int off = raw - nh;
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
396
  	int len = (raw[1] + 1) << 3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
399
400
401
402
403
404
  
  	if ((raw + len) - skb->data > skb_headlen(skb))
  		goto bad;
  
  	off += 2;
  	len -= 2;
  
  	while (len > 0) {
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
405
  		int optlen = nh[off + 1] + 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406

d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
407
  		switch (nh[off]) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
410
411
412
413
414
415
  		case IPV6_TLV_PAD0:
  			optlen = 1;
  			break;
  
  		case IPV6_TLV_PADN:
  			break;
  
  		case IPV6_TLV_JUMBO:
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
416
  			if (nh[off + 1] != 4 || (off & 3) != 2)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
  				goto bad;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
418
  			pkt_len = ntohl(*(__be32 *) (nh + off + 2));
b03664869   Bart De Schuymer   [BRIDGE-NF]: Fix ...
419
  			if (pkt_len <= IPV6_MAXPLEN ||
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
420
  			    ipv6_hdr(skb)->payload_len)
b03664869   Bart De Schuymer   [BRIDGE-NF]: Fix ...
421
  				goto bad;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
  			if (pkt_len > skb->len - sizeof(struct ipv6hdr))
  				goto bad;
b03664869   Bart De Schuymer   [BRIDGE-NF]: Fix ...
424
  			if (pskb_trim_rcsum(skb,
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
425
  					    pkt_len + sizeof(struct ipv6hdr)))
b03664869   Bart De Schuymer   [BRIDGE-NF]: Fix ...
426
  				goto bad;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
427
  			nh = skb_network_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
  			break;
  		default:
  			if (optlen > len)
  				goto bad;
  			break;
  		}
  		off += optlen;
  		len -= optlen;
  	}
  	if (len == 0)
  		return 0;
  bad:
  	return -1;
  
  }
  
  /* Replicate the checks that IPv6 does on packet reception and pass the packet
   * to ip6tables, which doesn't support NAT, so things are fairly simple. */
  static unsigned int br_nf_pre_routing_ipv6(unsigned int hook,
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
447
448
449
450
  					   struct sk_buff *skb,
  					   const struct net_device *in,
  					   const struct net_device *out,
  					   int (*okfn)(struct sk_buff *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
452
453
  {
  	struct ipv6hdr *hdr;
  	u32 pkt_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
456
457
458
459
  
  	if (skb->len < sizeof(struct ipv6hdr))
  		goto inhdr_error;
  
  	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
  		goto inhdr_error;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
460
  	hdr = ipv6_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
464
465
466
467
468
469
  
  	if (hdr->version != 6)
  		goto inhdr_error;
  
  	pkt_len = ntohs(hdr->payload_len);
  
  	if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
  		if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
  			goto inhdr_error;
b38dfee3d   Herbert Xu   [NET]: skb_trim a...
470
471
  		if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
  			goto inhdr_error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
  	}
  	if (hdr->nexthdr == NEXTHDR_HOP && check_hbh_len(skb))
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
474
  		goto inhdr_error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475

789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
476
  	nf_bridge_put(skb->nf_bridge);
fdeabdefb   Stephen Hemminger   [BRIDGE]: netfilt...
477
  	if (!nf_bridge_alloc(skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
  		return NF_DROP;
5dce971ac   Stephen Hemminger   [BRIDGE]: netfilt...
479
480
  	if (!setup_pre_routing(skb))
  		return NF_DROP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
  
  	NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL,
  		br_nf_pre_routing_finish_ipv6);
  
  	return NF_STOLEN;
  
  inhdr_error:
  	return NF_DROP;
  }
  
  /* Direct IPv6 traffic to br_nf_pre_routing_ipv6.
   * Replicate the checks that IPv4 does on packet reception.
   * Set skb->dev to the bridge device (i.e. parent of the
   * receiving device) to make netfilter happy, the REDIRECT
   * target in particular.  Save the original destination IP
   * address to be able to detect DNAT afterwards. */
  static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb,
ee02b3a61   Stephen Hemminger   [BRIDGE] netfilte...
498
499
500
  				      const struct net_device *in,
  				      const struct net_device *out,
  				      int (*okfn)(struct sk_buff *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
503
504
  {
  	struct iphdr *iph;
  	__u32 len;
  	struct sk_buff *skb = *pskb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505

516299d2f   Michael Milner   [NETFILTER]: brid...
506
507
  	if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) ||
  	    IS_PPPOE_IPV6(skb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
511
512
513
  #ifdef CONFIG_SYSCTL
  		if (!brnf_call_ip6tables)
  			return NF_ACCEPT;
  #endif
  		if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
  			goto out;
fc38582db   Patrick McHardy   [NETFILTER]: brid...
514
  		nf_bridge_pull_encap_header_rcsum(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
517
518
519
520
  		return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn);
  	}
  #ifdef CONFIG_SYSCTL
  	if (!brnf_call_iptables)
  		return NF_ACCEPT;
  #endif
516299d2f   Michael Milner   [NETFILTER]: brid...
521
522
  	if (skb->protocol != htons(ETH_P_IP) && !IS_VLAN_IP(skb) &&
  	    !IS_PPPOE_IP(skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
526
  		return NF_ACCEPT;
  
  	if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
  		goto out;
fc38582db   Patrick McHardy   [NETFILTER]: brid...
527
  	nf_bridge_pull_encap_header_rcsum(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
529
530
  
  	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
  		goto inhdr_error;
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
531
  	iph = ip_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
  	if (iph->ihl < 5 || iph->version != 4)
  		goto inhdr_error;
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
534
  	if (!pskb_may_pull(skb, 4 * iph->ihl))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
  		goto inhdr_error;
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
536
  	iph = ip_hdr(skb);
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
537
  	if (ip_fast_csum((__u8 *) iph, iph->ihl) != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
539
540
  		goto inhdr_error;
  
  	len = ntohs(iph->tot_len);
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
541
  	if (skb->len < len || len < 4 * iph->ihl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
  		goto inhdr_error;
b38dfee3d   Herbert Xu   [NET]: skb_trim a...
543
  	pskb_trim_rcsum(skb, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544

789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
545
  	nf_bridge_put(skb->nf_bridge);
fdeabdefb   Stephen Hemminger   [BRIDGE]: netfilt...
546
  	if (!nf_bridge_alloc(skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
  		return NF_DROP;
5dce971ac   Stephen Hemminger   [BRIDGE]: netfilt...
548
549
  	if (!setup_pre_routing(skb))
  		return NF_DROP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
552
553
554
555
556
557
  	store_orig_dstaddr(skb);
  
  	NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL,
  		br_nf_pre_routing_finish);
  
  	return NF_STOLEN;
  
  inhdr_error:
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
558
  //      IP_INC_STATS_BH(IpInHdrErrors);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
562
563
564
565
566
567
568
569
570
571
  out:
  	return NF_DROP;
  }
  
  
  /* PF_BRIDGE/LOCAL_IN ************************************************/
  /* The packet is locally destined, which requires a real
   * dst_entry, so detach the fake one.  On the way up, the
   * packet would pass through PRE_ROUTING again (which already
   * took place when the packet entered the bridge), but we
   * register an IPv4 PRE_ROUTING 'sabotage' hook that will
   * prevent this from happening. */
  static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff **pskb,
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
572
573
574
  				   const struct net_device *in,
  				   const struct net_device *out,
  				   int (*okfn)(struct sk_buff *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
577
578
579
580
581
582
583
584
  {
  	struct sk_buff *skb = *pskb;
  
  	if (skb->dst == (struct dst_entry *)&__fake_rtable) {
  		dst_release(skb->dst);
  		skb->dst = NULL;
  	}
  
  	return NF_ACCEPT;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
588
589
  /* PF_BRIDGE/FORWARD *************************************************/
  static int br_nf_forward_finish(struct sk_buff *skb)
  {
  	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
  	struct net_device *in;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590

8b42ec392   Stephen Hemminger   [BRIDGE]: netfilt...
591
  	if (skb->protocol != htons(ETH_P_ARP) && !IS_VLAN_ARP(skb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
594
595
596
597
598
599
  		in = nf_bridge->physindev;
  		if (nf_bridge->mask & BRNF_PKT_TYPE) {
  			skb->pkt_type = PACKET_OTHERHOST;
  			nf_bridge->mask ^= BRNF_PKT_TYPE;
  		}
  	} else {
  		in = *((struct net_device **)(skb->cb));
  	}
fc38582db   Patrick McHardy   [NETFILTER]: brid...
600
  	nf_bridge_push_encap_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
  	NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in,
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
602
  		       skb->dev, br_forward_finish, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
605
606
607
608
609
610
611
  	return 0;
  }
  
  /* This is the 'purely bridged' case.  For IP, we pass the packet to
   * netfilter with indev and outdev set to the bridge device,
   * but we are still able to filter on the 'real' indev/outdev
   * because of the physdev module. For ARP, indev and outdev are the
   * bridge ports. */
  static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb,
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
612
613
614
  				     const struct net_device *in,
  				     const struct net_device *out,
  				     int (*okfn)(struct sk_buff *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
616
617
  {
  	struct sk_buff *skb = *pskb;
  	struct nf_bridge_info *nf_bridge;
5dce971ac   Stephen Hemminger   [BRIDGE]: netfilt...
618
  	struct net_device *parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619
620
621
622
  	int pf;
  
  	if (!skb->nf_bridge)
  		return NF_ACCEPT;
5dce971ac   Stephen Hemminger   [BRIDGE]: netfilt...
623
624
625
  	parent = bridge_parent(out);
  	if (!parent)
  		return NF_DROP;
516299d2f   Michael Milner   [NETFILTER]: brid...
626
627
  	if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb) ||
  	    IS_PPPOE_IP(skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
630
  		pf = PF_INET;
  	else
  		pf = PF_INET6;
fc38582db   Patrick McHardy   [NETFILTER]: brid...
631
  	nf_bridge_pull_encap_header(*pskb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
634
635
636
637
638
639
640
641
  	nf_bridge = skb->nf_bridge;
  	if (skb->pkt_type == PACKET_OTHERHOST) {
  		skb->pkt_type = PACKET_HOST;
  		nf_bridge->mask |= BRNF_PKT_TYPE;
  	}
  
  	/* The physdev module checks on this */
  	nf_bridge->mask |= BRNF_BRIDGED;
  	nf_bridge->physoutdev = skb->dev;
5dce971ac   Stephen Hemminger   [BRIDGE]: netfilt...
642
643
  	NF_HOOK(pf, NF_IP_FORWARD, skb, bridge_parent(in), parent,
  		br_nf_forward_finish);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
646
647
648
  
  	return NF_STOLEN;
  }
  
  static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb,
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
649
650
651
  				      const struct net_device *in,
  				      const struct net_device *out,
  				      int (*okfn)(struct sk_buff *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
653
  {
  	struct sk_buff *skb = *pskb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
655
656
657
658
659
  	struct net_device **d = (struct net_device **)(skb->cb);
  
  #ifdef CONFIG_SYSCTL
  	if (!brnf_call_arptables)
  		return NF_ACCEPT;
  #endif
f8a260286   Stephen Hemminger   [BRIDGE]: netfilt...
660
  	if (skb->protocol != htons(ETH_P_ARP)) {
8b42ec392   Stephen Hemminger   [BRIDGE]: netfilt...
661
  		if (!IS_VLAN_ARP(skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
  			return NF_ACCEPT;
fc38582db   Patrick McHardy   [NETFILTER]: brid...
663
  		nf_bridge_pull_encap_header(*pskb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
  	}
d0a92be05   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
665
  	if (arp_hdr(skb)->ar_pln != 4) {
fc38582db   Patrick McHardy   [NETFILTER]: brid...
666
667
  		if (IS_VLAN_ARP(skb))
  			nf_bridge_push_encap_header(*pskb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
670
671
672
673
674
675
  		return NF_ACCEPT;
  	}
  	*d = (struct net_device *)in;
  	NF_HOOK(NF_ARP, NF_ARP_FORWARD, skb, (struct net_device *)in,
  		(struct net_device *)out, br_nf_forward_finish);
  
  	return NF_STOLEN;
  }
2bf540b73   Patrick McHardy   [NETFILTER]: brid...
676
677
678
  /* PF_BRIDGE/LOCAL_OUT ***********************************************
   *
   * This function sees both locally originated IP packets and forwarded
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
680
   * IP packets (in both cases the destination device is a bridge
   * device). It also sees bridged-and-DNAT'ed packets.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
683
684
685
686
   *
   * If (nf_bridge->mask & BRNF_BRIDGED_DNAT) then the packet is bridged
   * and we fake the PF_BRIDGE/FORWARD hook. The function br_nf_forward()
   * will then fake the PF_INET/FORWARD hook. br_nf_local_out() has priority
   * NF_BR_PRI_FIRST, so no relevant PF_BRIDGE/INPUT functions have been nor
   * will be executed.
2bf540b73   Patrick McHardy   [NETFILTER]: brid...
687
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688
  static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb,
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
689
690
691
  				    const struct net_device *in,
  				    const struct net_device *out,
  				    int (*okfn)(struct sk_buff *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
  {
2bf540b73   Patrick McHardy   [NETFILTER]: brid...
693
  	struct net_device *realindev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
695
  	struct sk_buff *skb = *pskb;
  	struct nf_bridge_info *nf_bridge;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
697
698
  
  	if (!skb->nf_bridge)
  		return NF_ACCEPT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
  	nf_bridge = skb->nf_bridge;
2bf540b73   Patrick McHardy   [NETFILTER]: brid...
700
701
  	if (!(nf_bridge->mask & BRNF_BRIDGED_DNAT))
  		return NF_ACCEPT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
704
  
  	/* Bridged, take PF_BRIDGE/FORWARD.
  	 * (see big note in front of br_nf_pre_routing_finish) */
2bf540b73   Patrick McHardy   [NETFILTER]: brid...
705
706
  	nf_bridge->physoutdev = skb->dev;
  	realindev = nf_bridge->physindev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707

2bf540b73   Patrick McHardy   [NETFILTER]: brid...
708
709
710
  	if (nf_bridge->mask & BRNF_PKT_TYPE) {
  		skb->pkt_type = PACKET_OTHERHOST;
  		nf_bridge->mask ^= BRNF_PKT_TYPE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
  	}
fc38582db   Patrick McHardy   [NETFILTER]: brid...
712
  	nf_bridge_push_encap_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713

2bf540b73   Patrick McHardy   [NETFILTER]: brid...
714
715
  	NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, realindev, skb->dev,
  		br_forward_finish);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
717
  	return NF_STOLEN;
  }
2e2f7aefa   Patrick McHardy   [NETFILTER]: Fix ...
718
719
720
721
  static int br_nf_dev_queue_xmit(struct sk_buff *skb)
  {
  	if (skb->protocol == htons(ETH_P_IP) &&
  	    skb->len > skb->dev->mtu &&
89114afd4   Herbert Xu   [NET] gso: Add sk...
722
  	    !skb_is_gso(skb))
2e2f7aefa   Patrick McHardy   [NETFILTER]: Fix ...
723
724
725
726
  		return ip_fragment(skb, br_dev_queue_push_xmit);
  	else
  		return br_dev_queue_push_xmit(skb);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
729
  
  /* PF_BRIDGE/POST_ROUTING ********************************************/
  static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
730
731
732
  				       const struct net_device *in,
  				       const struct net_device *out,
  				       int (*okfn)(struct sk_buff *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
734
735
  {
  	struct sk_buff *skb = *pskb;
  	struct nf_bridge_info *nf_bridge = (*pskb)->nf_bridge;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
738
739
740
741
  	struct net_device *realoutdev = bridge_parent(skb->dev);
  	int pf;
  
  #ifdef CONFIG_NETFILTER_DEBUG
  	/* Be very paranoid. This probably won't happen anymore, but let's
  	 * keep the check just to be sure... */
98e399f82   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
742
743
  	if (skb_mac_header(skb) < skb->head ||
  	    skb_mac_header(skb) + ETH_HLEN > skb->data) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
  		printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: "
8394e9b2f   Stephen Hemminger   [NETFILTER] bridg...
745
746
  		       "bad mac.raw pointer.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
749
750
751
752
  		goto print_error;
  	}
  #endif
  
  	if (!nf_bridge)
  		return NF_ACCEPT;
5dce971ac   Stephen Hemminger   [BRIDGE]: netfilt...
753
754
  	if (!realoutdev)
  		return NF_DROP;
516299d2f   Michael Milner   [NETFILTER]: brid...
755
756
  	if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb) ||
  	    IS_PPPOE_IP(skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
759
760
761
762
  		pf = PF_INET;
  	else
  		pf = PF_INET6;
  
  #ifdef CONFIG_NETFILTER_DEBUG
  	if (skb->dst == NULL) {
8394e9b2f   Stephen Hemminger   [NETFILTER] bridg...
763
764
  		printk(KERN_INFO "br_netfilter post_routing: skb->dst == NULL
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
766
  		goto print_error;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
769
770
771
772
773
774
  #endif
  
  	/* We assume any code from br_dev_queue_push_xmit onwards doesn't care
  	 * about the value of skb->pkt_type. */
  	if (skb->pkt_type == PACKET_OTHERHOST) {
  		skb->pkt_type = PACKET_HOST;
  		nf_bridge->mask |= BRNF_PKT_TYPE;
  	}
fc38582db   Patrick McHardy   [NETFILTER]: brid...
775
  	nf_bridge_pull_encap_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
777
778
779
780
781
782
  	nf_bridge_save_header(skb);
  
  #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
  	if (nf_bridge->netoutdev)
  		realoutdev = nf_bridge->netoutdev;
  #endif
  	NF_HOOK(pf, NF_IP_POST_ROUTING, skb, NULL, realoutdev,
2e2f7aefa   Patrick McHardy   [NETFILTER]: Fix ...
783
  		br_nf_dev_queue_xmit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
785
786
787
788
789
790
  
  	return NF_STOLEN;
  
  #ifdef CONFIG_NETFILTER_DEBUG
  print_error:
  	if (skb->dev != NULL) {
  		printk("[%s]", skb->dev->name);
178a3259f   Stephen Hemminger   [BRIDGE]: Better ...
791
792
  		if (realoutdev)
  			printk("[%s]", realoutdev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793
  	}
98e399f82   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
794
795
  	printk(" head:%p, raw:%p, data:%p
  ", skb->head, skb_mac_header(skb),
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
796
  	       skb->data);
8394e9b2f   Stephen Hemminger   [NETFILTER] bridg...
797
  	dump_stack();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
799
800
  	return NF_ACCEPT;
  #endif
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
802
803
804
  /* IP/SABOTAGE *****************************************************/
  /* Don't hand locally destined packets to PF_INET(6)/PRE_ROUTING
   * for the second time. */
  static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff **pskb,
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
805
806
807
  				   const struct net_device *in,
  				   const struct net_device *out,
  				   int (*okfn)(struct sk_buff *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
810
811
812
813
814
815
  {
  	if ((*pskb)->nf_bridge &&
  	    !((*pskb)->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)) {
  		return NF_STOP;
  	}
  
  	return NF_ACCEPT;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
817
818
819
820
  /* For br_nf_local_out we need (prio = NF_BR_PRI_FIRST), to insure that innocent
   * PF_BRIDGE/NF_BR_LOCAL_OUT functions don't get bridged traffic as input.
   * For br_nf_post_routing, we need (prio = NF_BR_PRI_LAST), because
   * ip_refrag() can return NF_STOLEN. */
  static struct nf_hook_ops br_nf_ops[] = {
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
821
822
823
824
  	{ .hook = br_nf_pre_routing,
  	  .owner = THIS_MODULE,
  	  .pf = PF_BRIDGE,
  	  .hooknum = NF_BR_PRE_ROUTING,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
  	  .priority = NF_BR_PRI_BRNF, },
  	{ .hook = br_nf_local_in,
  	  .owner = THIS_MODULE,
  	  .pf = PF_BRIDGE,
  	  .hooknum = NF_BR_LOCAL_IN,
  	  .priority = NF_BR_PRI_BRNF, },
  	{ .hook = br_nf_forward_ip,
  	  .owner = THIS_MODULE,
  	  .pf = PF_BRIDGE,
  	  .hooknum = NF_BR_FORWARD,
  	  .priority = NF_BR_PRI_BRNF - 1, },
  	{ .hook = br_nf_forward_arp,
  	  .owner = THIS_MODULE,
  	  .pf = PF_BRIDGE,
  	  .hooknum = NF_BR_FORWARD,
  	  .priority = NF_BR_PRI_BRNF, },
  	{ .hook = br_nf_local_out,
  	  .owner = THIS_MODULE,
  	  .pf = PF_BRIDGE,
  	  .hooknum = NF_BR_LOCAL_OUT,
  	  .priority = NF_BR_PRI_FIRST, },
  	{ .hook = br_nf_post_routing,
  	  .owner = THIS_MODULE,
  	  .pf = PF_BRIDGE,
  	  .hooknum = NF_BR_POST_ROUTING,
  	  .priority = NF_BR_PRI_LAST, },
  	{ .hook = ip_sabotage_in,
  	  .owner = THIS_MODULE,
  	  .pf = PF_INET,
  	  .hooknum = NF_IP_PRE_ROUTING,
  	  .priority = NF_IP_PRI_FIRST, },
  	{ .hook = ip_sabotage_in,
  	  .owner = THIS_MODULE,
  	  .pf = PF_INET6,
  	  .hooknum = NF_IP6_PRE_ROUTING,
  	  .priority = NF_IP6_PRI_FIRST, },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
862
863
864
  };
  
  #ifdef CONFIG_SYSCTL
  static
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
865
866
  int brnf_sysctl_call_tables(ctl_table * ctl, int write, struct file *filp,
  			    void __user * buffer, size_t * lenp, loff_t * ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
  {
  	int ret;
  
  	ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
  
  	if (write && *(int *)(ctl->data))
  		*(int *)(ctl->data) = 1;
  	return ret;
  }
  
  static ctl_table brnf_table[] = {
  	{
  		.ctl_name	= NET_BRIDGE_NF_CALL_ARPTABLES,
  		.procname	= "bridge-nf-call-arptables",
  		.data		= &brnf_call_arptables,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
  		.proc_handler	= &brnf_sysctl_call_tables,
  	},
  	{
  		.ctl_name	= NET_BRIDGE_NF_CALL_IPTABLES,
  		.procname	= "bridge-nf-call-iptables",
  		.data		= &brnf_call_iptables,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
  		.proc_handler	= &brnf_sysctl_call_tables,
  	},
  	{
  		.ctl_name	= NET_BRIDGE_NF_CALL_IP6TABLES,
  		.procname	= "bridge-nf-call-ip6tables",
  		.data		= &brnf_call_ip6tables,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
  		.proc_handler	= &brnf_sysctl_call_tables,
  	},
  	{
  		.ctl_name	= NET_BRIDGE_NF_FILTER_VLAN_TAGGED,
  		.procname	= "bridge-nf-filter-vlan-tagged",
  		.data		= &brnf_filter_vlan_tagged,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
  		.proc_handler	= &brnf_sysctl_call_tables,
516299d2f   Michael Milner   [NETFILTER]: brid...
909
910
911
912
913
914
915
916
  	},
  	{
  		.ctl_name	= NET_BRIDGE_NF_FILTER_PPPOE_TAGGED,
  		.procname	= "bridge-nf-filter-pppoe-tagged",
  		.data		= &brnf_filter_pppoe_tagged,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
  		.proc_handler	= &brnf_sysctl_call_tables,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
  	},
  	{ .ctl_name = 0 }
  };
  
  static ctl_table brnf_bridge_table[] = {
  	{
  		.ctl_name	= NET_BRIDGE,
  		.procname	= "bridge",
  		.mode		= 0555,
  		.child		= brnf_table,
  	},
  	{ .ctl_name = 0 }
  };
  
  static ctl_table brnf_net_table[] = {
  	{
  		.ctl_name	= CTL_NET,
  		.procname	= "net",
  		.mode		= 0555,
  		.child		= brnf_bridge_table,
  	},
  	{ .ctl_name = 0 }
  };
  #endif
5eb87f456   Patrick McHardy   [NETFILTER]: brid...
941
  int __init br_netfilter_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942
  {
5eb87f456   Patrick McHardy   [NETFILTER]: brid...
943
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944

5eb87f456   Patrick McHardy   [NETFILTER]: brid...
945
946
  	ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
  	if (ret < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948
  #ifdef CONFIG_SYSCTL
0b4d41471   Eric W. Biederman   [PATCH] sysctl: r...
949
  	brnf_sysctl_header = register_sysctl_table(brnf_net_table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
  	if (brnf_sysctl_header == NULL) {
789bc3e5b   Stephen Hemminger   [BRIDGE]: netfilt...
951
952
953
  		printk(KERN_WARNING
  		       "br_netfilter: can't register to sysctl.
  ");
5eb87f456   Patrick McHardy   [NETFILTER]: brid...
954
955
  		nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956
957
  	}
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
958
959
  	printk(KERN_NOTICE "Bridge firewalling registered
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
962
963
964
  	return 0;
  }
  
  void br_netfilter_fini(void)
  {
5eb87f456   Patrick McHardy   [NETFILTER]: brid...
965
  	nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966
967
968
969
  #ifdef CONFIG_SYSCTL
  	unregister_sysctl_table(brnf_sysctl_header);
  #endif
  }