1 /*
2 * Userspace interface
3 * Linux ethernet bridge
4 *
5 * Authors:
6 * Lennert Buytenhek <buytenh@gnu.org>
7 *
8 * $Id: br_if.c,v 1.5 2000/11/08 05:16:40 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/if_arp.h>
18 #include <linux/if_bridge.h>
19 #include <linux/inetdevice.h>
20 #include <linux/rtnetlink.h>
21 #include <asm/uaccess.h>
22 #include "br_private.h"
23
24 static struct net_bridge *bridge_list;
25
26 static int br_initial_port_cost(struct net_device *dev)
27 {
28 if (!strncmp(dev->name, "lec", 3))
29 return 7;
30
31 if (!strncmp(dev->name, "eth", 3))
32 return 100; /* FIXME handle 100Mbps */
33
34 if (!strncmp(dev->name, "plip", 4))
35 return 2500;
36
37 return 100;
38 }
39
40 /* called under bridge lock */
41 static int __br_del_if(struct net_bridge *br, struct net_device *dev)
42 {
43 struct net_bridge_port *p;
44 struct net_bridge_port **pptr;
45
46 if ((p = dev->br_port) == NULL)
47 return -EINVAL;
48
49 br_stp_disable_port(p);
50
51 dev_set_promiscuity(dev, -1);
52 dev->br_port = NULL;
53
54 pptr = &br->port_list;
55 while (*pptr != NULL) {
56 if (*pptr == p) {
57 *pptr = p->next;
58 break;
59 }
60
61 pptr = &((*pptr)->next);
62 }
63
64 br_fdb_delete_by_port(br, p);
65 kfree(p);
66 dev_put(dev);
67
68 return 0;
69 }
70
71 static struct net_bridge **__find_br(char *name)
72 {
73 struct net_bridge **b;
74 struct net_bridge *br;
75
76 b = &bridge_list;
77 while ((br = *b) != NULL) {
78 if (!strncmp(br->dev.name, name, IFNAMSIZ))
79 return b;
80
81 b = &(br->next);
82 }
83
84 return NULL;
85 }
86
87 static void del_ifs(struct net_bridge *br)
88 {
89 write_lock_bh(&br->lock);
90 while (br->port_list != NULL)
91 __br_del_if(br, br->port_list->dev);
92 write_unlock_bh(&br->lock);
93 }
94
95 static struct net_bridge *new_nb(char *name)
96 {
97 struct net_bridge *br;
98 struct net_device *dev;
99
100 if ((br = kmalloc(sizeof(*br), GFP_KERNEL)) == NULL)
101 return NULL;
102
103 memset(br, 0, sizeof(*br));
104 dev = &br->dev;
105
106 strncpy(dev->name, name, IFNAMSIZ);
107 dev->priv = br;
108 ether_setup(dev);
109 br_dev_setup(dev);
110
111 br->lock = RW_LOCK_UNLOCKED;
112 br->hash_lock = RW_LOCK_UNLOCKED;
113
114 br->bridge_id.prio[0] = 0x80;
115 br->bridge_id.prio[1] = 0x00;
116 memset(br->bridge_id.addr, 0, ETH_ALEN);
117
118 br->stp_enabled = 1;
119 br->designated_root = br->bridge_id;
120 br->root_path_cost = 0;
121 br->root_port = 0;
122 br->bridge_max_age = br->max_age = 20 * HZ;
123 br->bridge_hello_time = br->hello_time = 2 * HZ;
124 br->bridge_forward_delay = br->forward_delay = 15 * HZ;
125 br->topology_change = 0;
126 br->topology_change_detected = 0;
127 br_timer_clear(&br->hello_timer);
128 br_timer_clear(&br->tcn_timer);
129 br_timer_clear(&br->topology_change_timer);
130
131 br->ageing_time = 300 * HZ;
132 br->gc_interval = 4 * HZ;
133
134 return br;
135 }
136
137 /* called under bridge lock */
138 static struct net_bridge_port *new_nbp(struct net_bridge *br, struct net_device *dev)
139 {
140 int i;
141 struct net_bridge_port *p;
142
143 p = kmalloc(sizeof(*p), GFP_KERNEL);
144 if (p == NULL)
145 return p;
146
147 memset(p, 0, sizeof(*p));
148 p->br = br;
149 p->dev = dev;
150 p->path_cost = br_initial_port_cost(dev);
151 p->priority = 0x80;
152
153 dev->br_port = p;
154
155 for (i=1;i<255;i++)
156 if (br_get_port(br, i) == NULL)
157 break;
158
159 if (i == 255) {
160 kfree(p);
161 return NULL;
162 }
163
164 p->port_no = i;
165 br_init_port(p);
166 p->state = BR_STATE_DISABLED;
167
168 p->next = br->port_list;
169 br->port_list = p;
170
171 return p;
172 }
173
174 int br_add_bridge(char *name)
175 {
176 struct net_bridge *br;
177
178 if ((br = new_nb(name)) == NULL)
179 return -ENOMEM;
180
181 if (__dev_get_by_name(name) != NULL) {
182 kfree(br);
183 return -EEXIST;
184 }
185
186 br->next = bridge_list;
187 bridge_list = br;
188
189 br_inc_use_count();
190 register_netdev(&br->dev);
191
192 return 0;
193 }
194
195 int br_del_bridge(char *name)
196 {
197 struct net_bridge **b;
198 struct net_bridge *br;
199
200 if ((b = __find_br(name)) == NULL)
201 return -ENXIO;
202
203 br = *b;
204
205 if (br->dev.flags & IFF_UP)
206 return -EBUSY;
207
208 del_ifs(br);
209
210 *b = br->next;
211
212 unregister_netdev(&br->dev);
213 kfree(br);
214 br_dec_use_count();
215
216 return 0;
217 }
218
219 int br_add_if(struct net_bridge *br, struct net_device *dev)
220 {
221 struct net_bridge_port *p;
222
223 if (dev->br_port != NULL)
224 return -EBUSY;
225
226 if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER)
227 return -EINVAL;
228
229 dev_hold(dev);
230 write_lock_bh(&br->lock);
231 if ((p = new_nbp(br, dev)) == NULL) {
232 write_unlock_bh(&br->lock);
233 dev_put(dev);
234 return -EXFULL;
235 }
236
237 dev_set_promiscuity(dev, 1);
238
239 br_stp_recalculate_bridge_id(br);
240 br_fdb_insert(br, p, dev->dev_addr, 1);
241 if ((br->dev.flags & IFF_UP) && (dev->flags & IFF_UP))
242 br_stp_enable_port(p);
243 write_unlock_bh(&br->lock);
244
245 return 0;
246 }
247
248 int br_del_if(struct net_bridge *br, struct net_device *dev)
249 {
250 int retval;
251
252 write_lock_bh(&br->lock);
253 retval = __br_del_if(br, dev);
254 br_stp_recalculate_bridge_id(br);
255 write_unlock_bh(&br->lock);
256
257 return retval;
258 }
259
260 int br_get_bridge_ifindices(int *indices, int num)
261 {
262 struct net_bridge *br;
263 int i;
264
265 i = 0;
266
267 br = bridge_list;
268 for (i=0;i<num;i++) {
269 if (br == NULL)
270 break;
271
272 indices[i] = br->dev.ifindex;
273 br = br->next;
274 }
275
276 return i;
277 }
278
279 /* called under ioctl_lock */
280 void br_get_port_ifindices(struct net_bridge *br, int *ifindices)
281 {
282 struct net_bridge_port *p;
283
284 p = br->port_list;
285 while (p != NULL) {
286 ifindices[p->port_no] = p->dev->ifindex;
287 p = p->next;
288 }
289 }
290
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.