www.usr.com/support/gpl/USR9107_release.1.4.tar.gz
[bcm963xx.git] / kernel / linux / net / bridge / br_forward.c
1 /*
2  *      Forwarding decision
3  *      Linux ethernet bridge
4  *
5  *      Authors:
6  *      Lennert Buytenhek               <buytenh@gnu.org>
7  *
8  *      $Id: br_forward.c,v 1.4 2001/08/14 22:05:57 davem Exp $
9  *
10  *      This program is free software; you can redistribute it and/or
11  *      modify it under the terms of the GNU General Public License
12  *      as published by the Free Software Foundation; either version
13  *      2 of the License, or (at your option) any later version.
14  */
15
16 #include <linux/kernel.h>
17 #include <linux/netdevice.h>
18 #include <linux/skbuff.h>
19 #include <linux/netfilter_bridge.h>
20 #include "br_private.h"
21
22 static inline int should_deliver(const struct net_bridge_port *p, 
23                                  const struct sk_buff *skb)
24 {
25         if (skb->dev == p->dev ||
26             p->state != BR_STATE_FORWARDING)
27                 return 0;
28
29 #if defined(CONFIG_MIPS_BRCM)
30         /*
31          * Do not forward  any packets received from
32          *  one WAN interface to other WAN interfaces in multiple PVC case
33          * In the following condition, if a new interface is added, please
34          * add the check to compare the first 3 chars from the name as
35          * shown below. Using strcmp will be expensive in this path.
36         */
37         if ((skb->nfmark & FROM_WAN)  &&
38             ((*(p->dev->name)    == 'n') &&
39             (*(p->dev->name + 1) == 'a') &&
40             (*(p->dev->name + 2) == 's')))
41                 return 0;
42 #endif
43
44         return 1;
45 }
46
47 int br_dev_queue_push_xmit(struct sk_buff *skb)
48 {
49 #if defined(CONFIG_MIPS_BRCM)
50         // Just to make it consistent with 2.4 so it will not surprise the customers.(Should be more intelligent.)
51 #ifdef CONFIG_BRIDGE_NETFILTER
52         /* ip_refrag calls ip_fragment, doesn't copy the MAC header. */
53         nf_bridge_maybe_copy_header(skb);
54 #endif
55         skb_push(skb, ETH_HLEN);
56
57         dev_queue_xmit(skb);
58 #else
59         if (skb->len > skb->dev->mtu) 
60                 kfree_skb(skb);
61         else {
62 #ifdef CONFIG_BRIDGE_NETFILTER
63                 /* ip_refrag calls ip_fragment, doesn't copy the MAC header. */
64                 nf_bridge_maybe_copy_header(skb);
65 #endif
66                 skb_push(skb, ETH_HLEN);
67
68                 dev_queue_xmit(skb);
69         }
70 #endif
71
72         return 0;
73 }
74
75 int br_forward_finish(struct sk_buff *skb)
76 {
77         NF_HOOK(PF_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev,
78                         br_dev_queue_push_xmit);
79
80         return 0;
81 }
82
83 static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
84 {
85         skb->dev = to->dev;
86 #ifdef CONFIG_NETFILTER_DEBUG
87         skb->nf_debug = 0;
88 #endif
89         NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
90                         br_forward_finish);
91 }
92
93 static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
94 {
95         struct net_device *indev;
96
97         indev = skb->dev;
98         skb->dev = to->dev;
99         skb->ip_summed = CHECKSUM_NONE;
100
101         NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev,
102                         br_forward_finish);
103 }
104
105 /* called with rcu_read_lock */
106 void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
107 {
108         if (should_deliver(to, skb)) {
109                 __br_deliver(to, skb);
110                 return;
111         }
112
113         kfree_skb(skb);
114 }
115
116 /* called with rcu_read_lock */
117 void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
118 {
119         if (should_deliver(to, skb)) {
120                 __br_forward(to, skb);
121                 return;
122         }
123
124         kfree_skb(skb);
125 }
126
127 /* called under bridge lock */
128 static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone,
129         void (*__packet_hook)(const struct net_bridge_port *p, 
130                               struct sk_buff *skb))
131 {
132         struct net_bridge_port *p;
133         struct net_bridge_port *prev;
134
135         if (clone) {
136                 struct sk_buff *skb2;
137
138                 if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
139                         br->statistics.tx_dropped++;
140                         return;
141                 }
142
143                 skb = skb2;
144         }
145
146         prev = NULL;
147
148         list_for_each_entry_rcu(p, &br->port_list, list) {
149                 if (should_deliver(p, skb)) {
150                         if (prev != NULL) {
151                                 struct sk_buff *skb2;
152
153                                 if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
154                                         br->statistics.tx_dropped++;
155                                         kfree_skb(skb);
156                                         return;
157                                 }
158
159                                 __packet_hook(prev, skb2);
160                         }
161
162                         prev = p;
163                 }
164         }
165
166         if (prev != NULL) {
167                 __packet_hook(prev, skb);
168                 return;
169         }
170
171         kfree_skb(skb);
172 }
173
174
175 /* called with rcu_read_lock */
176 void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, int clone)
177 {
178         br_flood(br, skb, clone, __br_deliver);
179 }
180
181 /* called under bridge lock */
182 void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, int clone)
183 {
184         br_flood(br, skb, clone, __br_forward);
185 }