Blame view

net/bridge/br_forward.c 3.42 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
  /*
   *	Forwarding decision
   *	Linux ethernet bridge
   *
   *	Authors:
   *	Lennert Buytenhek		<buytenh@gnu.org>
   *
   *	$Id: br_forward.c,v 1.4 2001/08/14 22:05:57 davem Exp $
   *
   *	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.
   */
  
  #include <linux/kernel.h>
  #include <linux/netdevice.h>
  #include <linux/skbuff.h>
85ca719e5   Stephen Hemminger   [BRIDGE]: allow f...
19
  #include <linux/if_vlan.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
  #include <linux/netfilter_bridge.h>
  #include "br_private.h"
9ef513bed   Stephen Hemminger   [BRIDGE]: optimiz...
22
  /* Don't forward packets to originating port or forwarding diasabled */
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
23
  static inline int should_deliver(const struct net_bridge_port *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
  				 const struct sk_buff *skb)
  {
9ef513bed   Stephen Hemminger   [BRIDGE]: optimiz...
26
  	return (skb->dev != p->dev && p->state == BR_STATE_FORWARDING);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
  }
85ca719e5   Stephen Hemminger   [BRIDGE]: allow f...
28
29
30
31
  static inline unsigned packet_length(const struct sk_buff *skb)
  {
  	return skb->len - (skb->protocol == htons(ETH_P_8021Q) ? VLAN_HLEN : 0);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
  int br_dev_queue_push_xmit(struct sk_buff *skb)
  {
7967168ce   Herbert Xu   [NET]: Merge TSO/...
34
  	/* drop mtu oversized packets except gso */
89114afd4   Herbert Xu   [NET] gso: Add sk...
35
  	if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
  		kfree_skb(skb);
  	else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  		/* ip_refrag calls ip_fragment, doesn't copy the MAC header. */
3a13813e6   Stephen Hemminger   [BRIDGE] netfilte...
39
40
  		if (nf_bridge_maybe_copy_header(skb))
  			kfree_skb(skb);
07317621d   Stephen Hemminger   [NETFILTER] bridg...
41
  		else {
3a13813e6   Stephen Hemminger   [BRIDGE] netfilte...
42
  			skb_push(skb, ETH_HLEN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43

3a13813e6   Stephen Hemminger   [BRIDGE] netfilte...
44
45
  			dev_queue_xmit(skb);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
50
51
52
  	}
  
  	return 0;
  }
  
  int br_forward_finish(struct sk_buff *skb)
  {
9ef513bed   Stephen Hemminger   [BRIDGE]: optimiz...
53
54
  	return NF_HOOK(PF_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev,
  		       br_dev_queue_push_xmit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
59
60
  }
  
  static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
  {
  	skb->dev = to->dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
63
64
65
66
67
68
69
70
  	NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
  			br_forward_finish);
  }
  
  static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
  {
  	struct net_device *indev;
  
  	indev = skb->dev;
  	skb->dev = to->dev;
35fc92a9d   Herbert Xu   [NET]: Allow forw...
71
  	skb_forward_csum(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  
  	NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev,
  			br_forward_finish);
  }
  
  /* called with rcu_read_lock */
  void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
  {
  	if (should_deliver(to, skb)) {
  		__br_deliver(to, skb);
  		return;
  	}
  
  	kfree_skb(skb);
  }
  
  /* called with rcu_read_lock */
  void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
  {
  	if (should_deliver(to, skb)) {
  		__br_forward(to, skb);
  		return;
  	}
  
  	kfree_skb(skb);
  }
  
  /* called under bridge lock */
  static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone,
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
101
  	void (*__packet_hook)(const struct net_bridge_port *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  			      struct sk_buff *skb))
  {
  	struct net_bridge_port *p;
  	struct net_bridge_port *prev;
  
  	if (clone) {
  		struct sk_buff *skb2;
  
  		if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
  			br->statistics.tx_dropped++;
  			return;
  		}
  
  		skb = skb2;
  	}
  
  	prev = NULL;
  
  	list_for_each_entry_rcu(p, &br->port_list, list) {
  		if (should_deliver(p, skb)) {
  			if (prev != NULL) {
  				struct sk_buff *skb2;
  
  				if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
  					br->statistics.tx_dropped++;
  					kfree_skb(skb);
  					return;
  				}
  
  				__packet_hook(prev, skb2);
  			}
  
  			prev = p;
  		}
  	}
  
  	if (prev != NULL) {
  		__packet_hook(prev, skb);
  		return;
  	}
  
  	kfree_skb(skb);
  }
  
  
  /* called with rcu_read_lock */
  void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, int clone)
  {
  	br_flood(br, skb, clone, __br_deliver);
  }
  
  /* called under bridge lock */
  void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, int clone)
  {
  	br_flood(br, skb, clone, __br_forward);
  }