OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [net/] [bridge/] [br.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1629 jcastillo
/*
2
 *      Linux NET3 Bridge Support
3
 *
4
 *      Originally by John Hayes (Network Plumbing).
5
 *      Minor hacks to get it to run with 1.3.x by Alan Cox <Alan.Cox@linux.org>
6
 *
7
 *      This program is free software; you can redistribute it and/or
8
 *      modify it under the terms of the GNU General Public License
9
 *      as published by the Free Software Foundation; either version
10
 *      2 of the License, or (at your option) any later version.
11
 *
12
 *      Fixes:
13
 *
14
 *      Todo:
15
 *              Don't bring up devices automatically. Start ports disabled
16
 *      and use a netlink notifier so a daemon can maintain the bridge
17
 *      port group (could we also do multiple groups ????).
18
 *              A nice /proc file interface.
19
 *              Put the path costs in the port info and devices.
20
 *              Put the bridge port number in the device structure for speed.
21
 *              Bridge SNMP stats.
22
 *
23
 */
24
 
25
#include <linux/errno.h>
26
#include <linux/types.h>
27
#include <linux/socket.h>
28
#include <linux/in.h>
29
#include <linux/kernel.h>
30
#include <linux/sched.h>
31
#include <linux/timer.h>
32
#include <linux/string.h>
33
#include <linux/net.h>
34
#include <linux/inet.h>
35
#include <linux/netdevice.h>
36
#include <linux/string.h>
37
#include <linux/skbuff.h>
38
#include <linux/if_arp.h>
39
#include <asm/segment.h>
40
#include <asm/system.h>
41
#include <net/br.h>
42
 
43
static int br_device_event(struct notifier_block *dnot, unsigned long event, void *ptr);
44
static void br_tick(unsigned long arg);
45
int br_forward(struct sk_buff *skb, int port);  /* 3.7 */
46
int br_port_cost(struct device *dev);   /* 4.10.2 */
47
void br_bpdu(struct sk_buff *skb); /* consumes skb */
48
int br_tx_frame(struct sk_buff *skb);
49
int br_cmp(unsigned int *a, unsigned int *b);
50
 
51
unsigned char bridge_ula[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
52
 
53
Bridge_data     bridge_info;                      /* (4.5.3)     */
54
Port_data       port_info[All_ports];             /* (4.5.5)     */
55
Config_bpdu     config_bpdu[All_ports];
56
Tcn_bpdu        tcn_bpdu[All_ports];
57
Timer           hello_timer;                      /* (4.5.4.1)   */
58
Timer           tcn_timer;                        /* (4.5.4.2)   */
59
Timer           topology_change_timer;            /* (4.5.4.3)   */
60
Timer           message_age_timer[All_ports];     /* (4.5.6.1)   */
61
Timer           forward_delay_timer[All_ports];   /* (4.5.6.2)   */
62
Timer           hold_timer[All_ports];            /* (4.5.6.3)   */
63
 
64
/* entries timeout after this many seconds */
65
unsigned int fdb_aging_time = FDB_TIMEOUT;
66
 
67
struct br_stat br_stats;
68
 
69
static struct timer_list tl; /* for 1 second timer... */
70
 
71
/*
72
 * the following structure is required so that we receive
73
 * event notifications when network devices are enabled and
74
 * disabled (ifconfig up and down).
75
 */
76
static struct notifier_block br_dev_notifier={
77
        br_device_event,
78
        NULL,
79
 
80
};
81
 
82
/** Elements of Procedure (4.6) **/
83
 
84
/*
85
 * this section of code was graciously borrowed from the IEEE 802.1d
86
 * specification section 4.9.1 starting on pg 69.  It has been
87
 * modified somewhat to fit within out framework and structure.  It
88
 * implements the spanning tree algorithm that is the heart of the
89
 * 802.1d bridging protocol.
90
 */
91
 
92
void transmit_config(int port_no)                         /* (4.6.1)     */
93
{
94
        if(!(br_stats.flags & BR_UP))
95
                return; /* this should not happen but happens */
96
        if (hold_timer[port_no].active) {         /* (4.6.1.3.1)         */
97
                port_info[port_no].config_pending = TRUE;       /* (4.6.1.3.1)   */
98
        } else {                                  /* (4.6.1.3.2)         */
99
                config_bpdu[port_no].type = BPDU_TYPE_CONFIG;
100
                config_bpdu[port_no].root_id = bridge_info.designated_root;
101
                /* (4.6.1.3.2(1)) */
102
                config_bpdu[port_no].root_path_cost = bridge_info.root_path_cost;
103
                /* (4.6.1.3.2(2)) */
104
                config_bpdu[port_no].bridge_id = bridge_info.bridge_id;
105
                /* (4.6.1.3.2(3)) */
106
                config_bpdu[port_no].port_id = port_info[port_no].port_id;
107
                /*
108
                 * (4.6.1.3.2(4))
109
                 */
110
                if (root_bridge()) {
111
                        config_bpdu[port_no].message_age = Zero;        /* (4.6.1.3.2(5)) */
112
                } else {
113
                        config_bpdu[port_no].message_age
114
                                = message_age_timer[bridge_info.root_port].value
115
                                + Message_age_increment;        /* (4.6.1.3.2(6)) */
116
                }
117
 
118
                config_bpdu[port_no].max_age = bridge_info.max_age;     /* (4.6.1.3.2(7)) */
119
                config_bpdu[port_no].hello_time = bridge_info.hello_time;
120
                config_bpdu[port_no].forward_delay = bridge_info.forward_delay;
121
                config_bpdu[port_no].flags = 0;
122
                config_bpdu[port_no].flags |=
123
                        port_info[port_no].top_change_ack ? TOPOLOGY_CHANGE_ACK : 0;
124
                /* (4.6.1.3.2(8)) */
125
                port_info[port_no].top_change_ack = 0;
126
                /* (4.6.1.3.2(8)) */
127
                config_bpdu[port_no].flags |=
128
                        bridge_info.top_change ? TOPOLOGY_CHANGE : 0;
129
                /* (4.6.1.3.2(9)) */
130
 
131
                send_config_bpdu(port_no, &config_bpdu[port_no]);
132
                port_info[port_no].config_pending = FALSE;      /* (4.6.1.3.2(10)) */
133
                start_hold_timer(port_no);        /* (4.6.1.3.2(11)) */
134
        }
135
}
136
 
137
int root_bridge(void)
138
{
139
        return (br_cmp(bridge_info.designated_root.BRIDGE_ID,
140
                 bridge_info.bridge_id.BRIDGE_ID)?FALSE:TRUE);
141
}
142
 
143
int supersedes_port_info(int port_no, Config_bpdu *config)        /* (4.6.2.2)   */
144
{
145
        return (
146
                (br_cmp(config->root_id.BRIDGE_ID,
147
                 port_info[port_no].designated_root.BRIDGE_ID) < 0)      /* (4.6.2.2.1)   */
148
                ||
149
                ((br_cmp(config->root_id.BRIDGE_ID,
150
                  port_info[port_no].designated_root.BRIDGE_ID) == 0
151
                  )
152
                 &&
153
                 ((config->root_path_cost
154
                   < port_info[port_no].designated_cost /* (4.6.2.2.2)   */
155
                   )
156
                  ||
157
                  ((config->root_path_cost
158
                    == port_info[port_no].designated_cost
159
                    )
160
                   &&
161
                   ((br_cmp(config->bridge_id.BRIDGE_ID,
162
                     port_info[port_no].designated_bridge.BRIDGE_ID) < 0 /* (4.6.2.2.3)    */
163
                     )
164
                    ||
165
                    ((br_cmp(config->bridge_id.BRIDGE_ID,
166
                      port_info[port_no].designated_bridge.BRIDGE_ID) == 0
167
                      )                           /* (4.6.2.2.4)         */
168
                     &&
169
                     ((br_cmp(config->bridge_id.BRIDGE_ID,
170
                        bridge_info.bridge_id.BRIDGE_ID) != 0
171
                       )                          /* (4.6.2.2.4(1)) */
172
                      ||
173
                      (config->port_id <=
174
                       port_info[port_no].designated_port
175
                       )                          /* (4.6.2.2.4(2)) */
176
                      ))))))
177
                );
178
}
179
 
180
void record_config_information(int port_no, Config_bpdu *config)          /* (4.6.2)     */
181
{
182
        port_info[port_no].designated_root = config->root_id;   /* (4.6.2.3.1)   */
183
        port_info[port_no].designated_cost = config->root_path_cost;
184
        port_info[port_no].designated_bridge = config->bridge_id;
185
        port_info[port_no].designated_port = config->port_id;
186
        start_message_age_timer(port_no, config->message_age);  /* (4.6.2.3.2)   */
187
}
188
 
189
void record_config_timeout_values(Config_bpdu *config)            /* (4.6.3)     */
190
{
191
        bridge_info.max_age = config->max_age;    /* (4.6.3.3)   */
192
        bridge_info.hello_time = config->hello_time;
193
        bridge_info.forward_delay = config->forward_delay;
194
        if (config->flags & TOPOLOGY_CHANGE)
195
                bridge_info.top_change = 1;
196
}
197
 
198
void config_bpdu_generation(void)
199
{                                                 /* (4.6.4)     */
200
        int             port_no;
201
        for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.6.4.3) */
202
                if (designated_port(port_no)      /* (4.6.4.3)   */
203
                                &&
204
                                (port_info[port_no].state != Disabled)
205
                        ) {
206
                        transmit_config(port_no); /* (4.6.4.3)   */
207
                }                                 /* (4.6.1.2)   */
208
        }
209
}
210
 
211
int designated_port(int port_no)
212
{
213
        return ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
214
                 bridge_info.bridge_id.BRIDGE_ID) == 0
215
                 )
216
                &&
217
                (port_info[port_no].designated_port
218
                 == port_info[port_no].port_id
219
                 )
220
                );
221
}
222
 
223
void reply(int port_no)                                   /* (4.6.5)     */
224
{
225
        transmit_config(port_no);                 /* (4.6.5.3)   */
226
}
227
 
228
void transmit_tcn(void)
229
{                                                 /* (4.6.6)     */
230
        int             port_no;
231
 
232
        port_no = bridge_info.root_port;
233
        tcn_bpdu[port_no].type = BPDU_TYPE_TOPO_CHANGE;
234
        send_tcn_bpdu(port_no, &tcn_bpdu[bridge_info.root_port]);       /* (4.6.6.3)     */
235
}
236
 
237
void configuration_update(void) /* (4.6.7) */
238
{
239
        root_selection();                         /* (4.6.7.3.1)         */
240
        /* (4.6.8.2)     */
241
        designated_port_selection();              /* (4.6.7.3.2)         */
242
        /* (4.6.9.2)     */
243
}
244
 
245
void root_selection(void)
246
{                                                 /* (4.6.8) */
247
        int             root_port;
248
        int             port_no;
249
        root_port = No_port;
250
        for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.6.8.3.1) */
251
                if (((!designated_port(port_no))
252
                     &&
253
                     (port_info[port_no].state != Disabled)
254
                     &&
255
                (br_cmp(port_info[port_no].designated_root.BRIDGE_ID,
256
                        bridge_info.bridge_id.BRIDGE_ID) < 0)
257
                        )
258
                                &&
259
                                ((root_port == No_port)
260
                                 ||
261
                                 (br_cmp(port_info[port_no].designated_root.BRIDGE_ID,
262
                                  port_info[root_port].designated_root.BRIDGE_ID) < 0
263
                                  )
264
                                 ||
265
                                 ((br_cmp(port_info[port_no].designated_root.BRIDGE_ID,
266
                                   port_info[root_port].designated_root.BRIDGE_ID) == 0
267
                                   )
268
                                  &&
269
                                  (((port_info[port_no].designated_cost
270
                                     + port_info[port_no].path_cost
271
                                     )
272
                                    <
273
                                    (port_info[root_port].designated_cost
274
                                     + port_info[root_port].path_cost
275
                                     )            /* (4.6.8.3.1(2)) */
276
                                    )
277
                                   ||
278
                                   (((port_info[port_no].designated_cost
279
                                      + port_info[port_no].path_cost
280
                                      )
281
                                     ==
282
                                     (port_info[root_port].designated_cost
283
                                      + port_info[root_port].path_cost
284
                                      )
285
                                     )
286
                                    &&
287
                                    ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
288
                                    port_info[root_port].designated_bridge.BRIDGE_ID) < 0
289
                                      )           /* (4.6.8.3.1(3)) */
290
                                     ||
291
                                     ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
292
                                   port_info[root_port].designated_bridge.BRIDGE_ID) == 0
293
                                       )
294
                                      &&
295
                                      ((port_info[port_no].designated_port
296
                                      < port_info[root_port].designated_port
297
                                        )         /* (4.6.8.3.1(4)) */
298
                                       ||
299
                                       ((port_info[port_no].designated_port
300
                                      = port_info[root_port].designated_port
301
                                         )
302
                                        &&
303
                                        (port_info[port_no].port_id
304
                                         < port_info[root_port].port_id
305
                                         )        /* (4.6.8.3.1(5)) */
306
                                        ))))))))) {
307
                        root_port = port_no;
308
                }
309
        }
310
        bridge_info.root_port = root_port;        /* (4.6.8.3.1)         */
311
 
312
        if (root_port == No_port) {               /* (4.6.8.3.2)         */
313
                bridge_info.designated_root = bridge_info.bridge_id;
314
                /* (4.6.8.3.2(1)) */
315
                bridge_info.root_path_cost = Zero;/* (4.6.8.3.2(2)) */
316
        } else {                                  /* (4.6.8.3.3)         */
317
                bridge_info.designated_root = port_info[root_port].designated_root;
318
                /* (4.6.8.3.3(1)) */
319
                bridge_info.root_path_cost = (port_info[root_port].designated_cost
320
                                            + port_info[root_port].path_cost
321
                        );                        /* (4.6.8.3.3(2)) */
322
        }
323
}
324
 
325
void designated_port_selection(void)
326
{                                                 /* (4.6.9)     */
327
        int             port_no;
328
 
329
        for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.6.9.3)     */
330
                if (designated_port(port_no)      /* (4.6.9.3.1)         */
331
                                ||
332
                                (
333
                                 br_cmp(port_info[port_no].designated_root.BRIDGE_ID,
334
                                 bridge_info.designated_root.BRIDGE_ID) != 0
335
                                 )
336
                                ||
337
                                (bridge_info.root_path_cost
338
                                 < port_info[port_no].designated_cost
339
                                 )                /* (4.6.9.3.3)         */
340
                                ||
341
                                ((bridge_info.root_path_cost
342
                                  == port_info[port_no].designated_cost
343
                                  )
344
                                 &&
345
                                 ((br_cmp(bridge_info.bridge_id.BRIDGE_ID,
346
                                   port_info[port_no].designated_bridge.BRIDGE_ID) < 0
347
                                   )              /* (4.6.9.3.4)         */
348
                                  ||
349
                                  ((br_cmp(bridge_info.bridge_id.BRIDGE_ID,
350
                                    port_info[port_no].designated_bridge.BRIDGE_ID) == 0
351
                                    )
352
                                   &&
353
                                   (port_info[port_no].port_id
354
                                    <= port_info[port_no].designated_port
355
                                    )             /* (4.6.9.3.5)         */
356
                                   )))) {
357
                        become_designated_port(port_no);        /* (4.6.10.3.2.2) */
358
                }
359
        }
360
}
361
 
362
void become_designated_port(int port_no)
363
{                                                 /* (4.6.10)    */
364
 
365
        /* (4.6.10.3.1) */
366
        port_info[port_no].designated_root = bridge_info.designated_root;
367
        /* (4.6.10.3.2) */
368
        port_info[port_no].designated_cost = bridge_info.root_path_cost;
369
        /* (4.6.10.3.3) */
370
        port_info[port_no].designated_bridge = bridge_info.bridge_id;
371
        /* (4.6.10.3.4) */
372
        port_info[port_no].designated_port = port_info[port_no].port_id;
373
}
374
 
375
void port_state_selection(void)
376
{                                                 /* (4.6.11) */
377
        int             port_no;
378
        for (port_no = One; port_no <= No_of_ports; port_no++) {
379
                if (port_no == bridge_info.root_port) { /* (4.6.11.3.1) */
380
                        port_info[port_no].config_pending = FALSE;      /* (4.6.11.3~1(1)) */
381
                        port_info[port_no].top_change_ack = 0;
382
                        make_forwarding(port_no); /* (4.6.11.3.1(2)) */
383
                } else if (designated_port(port_no)) {  /* (4.6.11.3.2) */
384
                        stop_message_age_timer(port_no);        /* (4.6.11.3.2(1)) */
385
                        make_forwarding(port_no); /* (4.6.11.3.2(2)) */
386
                } else {                          /* (4.6.11.3.3) */
387
                        port_info[port_no].config_pending = FALSE;      /* (4.6.11.3.3(1)) */
388
                        port_info[port_no].top_change_ack = 0;
389
                        make_blocking(port_no);   /* (4.6.11.3.3(2)) */
390
                }
391
        }
392
 
393
}
394
 
395
void make_forwarding(int port_no)
396
{                                                 /* (4.6.12) */
397
        if (port_info[port_no].state == Blocking) {     /* (4.6.12.3) */
398
                set_port_state(port_no, Listening);     /* (4.6.12.3.1) */
399
                start_forward_delay_timer(port_no);     /* (4.6.12.3.2) */
400
        }
401
}
402
 
403
void topology_change_detection(void)
404
{                                                 /* (4.6.14)       */
405
        if (root_bridge()) {                      /* (4.6.14.3.1)   */
406
                bridge_info.top_change = 1;
407
                start_topology_change_timer();    /* (4.6.14.3.1(2)) */
408
        } else if (!(bridge_info.top_change_detected)) {
409
                transmit_tcn();                   /* (4.6.14.3.2(1)) */
410
                start_tcn_timer();                /* (4.6.14.3.2(2)) */
411
        }
412
        bridge_info.top_change = 1;
413
}
414
 
415
void topology_change_acknowledged(void)
416
{                                                 /* (4.6.15) */
417
        bridge_info.top_change_detected = 0;
418
        stop_tcn_timer();                         /* (4.6.15.3.2) */
419
}
420
 
421
void acknowledge_topology_change(int port_no)
422
{                                                 /* (4.6.16) */
423
        port_info[port_no].top_change_ack = 1;
424
        transmit_config(port_no);                 /* (4.6.16.3.2) */
425
}
426
 
427
void make_blocking(int port_no)                           /* (4.6.13)    */
428
{
429
 
430
        if ((port_info[port_no].state != Disabled)
431
                        &&
432
                        (port_info[port_no].state != Blocking)
433
        /* (4.6.13.3)    */
434
                ) {
435
                if ((port_info[port_no].state == Forwarding)
436
                                ||
437
                                (port_info[port_no].state == Learning)
438
                        ) {
439
                        topology_change_detection();    /* (4.6.13.3.1) */
440
                        /* (4.6.14.2.3)  */
441
                }
442
                set_port_state(port_no, Blocking);/* (4.6.13.3.2) */
443
                stop_forward_delay_timer(port_no);/* (4.6.13.3.3) */
444
        }
445
}
446
 
447
void set_port_state(int port_no, int state)
448
{
449
        port_info[port_no].state = state;
450
}
451
 
452
void received_config_bpdu(int port_no, Config_bpdu *config)               /* (4.7.1)     */
453
{
454
        int         root;
455
 
456
        root = root_bridge();
457
        if (port_info[port_no].state != Disabled) {
458
                if (supersedes_port_info(port_no, config)) {    /* (4.7.1.1)     *//* (4.
459
                                                                 * 6.2.2)        */
460
                        record_config_information(port_no, config);     /* (4.7.1.1.1)   */
461
                        /* (4.6.2.2)     */
462
                        configuration_update();   /* (4.7.1.1.2)         */
463
                        /* (4.6.7.2.1)   */
464
                        port_state_selection();   /* (4.7.1.1.3)         */
465
                        /* (4.6.11.2.1)  */
466
                        if ((!root_bridge()) && root) { /* (4.7.1.1.4)   */
467
                                stop_hello_timer();
468
                                if (bridge_info.top_change_detected) {  /* (4.7.1.1.5~ */
469
                                        stop_topology_change_timer();
470
                                        transmit_tcn(); /* (4.6.6.1)     */
471
                                        start_tcn_timer();
472
                                }
473
                        }
474
                        if (port_no == bridge_info.root_port) {
475
                                record_config_timeout_values(config);   /* (4.7.1.1.6)   */
476
                                /* (4.6.3.2)     */
477
                                config_bpdu_generation();       /* (4.6.4.2.1)   */
478
                                if (config->flags & TOPOLOGY_CHANGE_ACK) {      /* (4.7.1.1.7)    */
479
                                        topology_change_acknowledged(); /* (4.6.15.2)    */
480
                                }
481
                        }
482
                } else if (designated_port(port_no)) {  /* (4.7.1.2)     */
483
                        reply(port_no);           /* (4.7.1.2.1)         */
484
                        /* (4.6.5.2)     */
485
                }
486
        }
487
}
488
 
489
void received_tcn_bpdu(int port_no, Tcn_bpdu *tcn)                        /* (4.7.2)     */
490
{
491
        if (port_info[port_no].state != Disabled) {
492
                if (designated_port(port_no)) {
493
                        topology_change_detection();    /* (4.7.2.1)     */
494
                        /* (4.6.14.2.1)  */
495
                        acknowledge_topology_change(port_no);   /* (4.7.2.2)     */
496
                }                                 /* (4.6.16.2)  */
497
        }
498
}
499
 
500
void hello_timer_expiry(void)
501
{                                                 /* (4.7.3)     */
502
        config_bpdu_generation();                 /* (4.6.4.2.2)         */
503
        start_hello_timer();
504
}
505
 
506
void message_age_timer_expiry(int port_no)                /* (4.7.4)     */
507
{
508
        int         root;
509
        root = root_bridge();
510
 
511
        become_designated_port(port_no);          /* (4.7.4.1)   */
512
        /* (4.6.10.2.1)  */
513
        configuration_update();                   /* (4.7.4.2)   */
514
        /* (4.6.7.2.2)   */
515
        port_state_selection();                   /* (4.7.4.3)   */
516
        /* (4.6.11.2.2)  */
517
        if ((root_bridge()) && (!root)) {         /* (4.7.4.4)   */
518
 
519
                bridge_info.max_age = bridge_info.bridge_max_age;       /* (4.7.4.4.1)    */
520
                bridge_info.hello_time = bridge_info.bridge_hello_time;
521
                bridge_info.forward_delay = bridge_info.bridge_forward_delay;
522
                topology_change_detection();      /* (4.7.4.4.2)         */
523
                /* (4.6.14.2.4)  */
524
                stop_tcn_timer();                 /* (4.7.4.4.3)         */
525
                config_bpdu_generation();         /* (4.7.4.4.4)         */
526
                /* (4.6.4.4.3)   */
527
                start_hello_timer();
528
        }
529
}
530
 
531
void forward_delay_timer_expiry(int port_no)              /* (4.7.5)     */
532
{
533
        if (port_info[port_no].state == Listening) {    /* (4.7.5.1)     */
534
                set_port_state(port_no, Learning);      /* (4.7.5.1.1)   */
535
                start_forward_delay_timer(port_no);     /* (4.7.5.1.2)   */
536
        } else if (port_info[port_no].state == Learning) {      /* (4.7.5.2) */
537
                set_port_state(port_no, Forwarding);    /* (4.7.5.2.1) */
538
                if (designated_for_some_port()) { /* (4.7.5.2.2) */
539
                        topology_change_detection();    /* (4.6.14.2.2) */
540
 
541
                }
542
        }
543
}
544
 
545
int designated_for_some_port(void)
546
{
547
        int             port_no;
548
 
549
 
550
        for (port_no = One; port_no <= No_of_ports; port_no++) {
551
                if ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
552
                                bridge_info.bridge_id.BRIDGE_ID) == 0)
553
                        ) {
554
                        return (TRUE);
555
                }
556
        }
557
        return (FALSE);
558
}
559
 
560
void tcn_timer_expiry(void)
561
{                                                 /* (4.7.6)     */
562
        transmit_tcn();                           /* (4.7.6.1)   */
563
        start_tcn_timer();                        /* (4.7.6.2)   */
564
}
565
 
566
void topology_change_timer_expiry(void)
567
{                                                 /* (4.7.7)     */
568
        bridge_info.top_change_detected = 0;
569
        bridge_info.top_change = 0;
570
          /* (4.7.7.2)   */
571
}
572
 
573
void hold_timer_expiry(int port_no)                       /* (4.7.8)     */
574
{
575
        if (port_info[port_no].config_pending) {
576
                transmit_config(port_no);         /* (4.7.8.1)   */
577
        }                                         /* (4.6.1.2.3)         */
578
}
579
 
580
void br_init(void)
581
{                                                 /* (4.8.1)     */
582
        int             port_no;
583
 
584
        printk(KERN_INFO "Ethernet Bridge 002 for NET3.035 (Linux 2.0)\n");
585
        bridge_info.designated_root = bridge_info.bridge_id;    /* (4.8.1.1)     */
586
        bridge_info.root_path_cost = Zero;
587
        bridge_info.root_port = No_port;
588
 
589
        bridge_info.bridge_max_age = BRIDGE_MAX_AGE;
590
        bridge_info.bridge_hello_time = BRIDGE_HELLO_TIME;
591
        bridge_info.bridge_forward_delay = BRIDGE_FORWARD_DELAY;
592
        bridge_info.hold_time = HOLD_TIME;
593
 
594
        bridge_info.max_age = bridge_info.bridge_max_age;       /* (4.8.1.2)     */
595
        bridge_info.hello_time = bridge_info.bridge_hello_time;
596
        bridge_info.forward_delay = bridge_info.bridge_forward_delay;
597
 
598
        bridge_info.top_change_detected = 0;
599
        bridge_info.top_change = 0;
600
        stop_tcn_timer();
601
        stop_topology_change_timer();
602
        for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.8.1.4) */
603
                br_init_port(port_no);
604
                disable_port(port_no);
605
        }
606
        port_state_selection();                   /* (4.8.1.5)   */
607
        config_bpdu_generation();                 /* (4.8.1.6)   */
608
 
609
        /* initialize system timer */
610
        tl.expires = jiffies+HZ;        /* 1 second */
611
        tl.function = br_tick;
612
        add_timer(&tl);
613
 
614
        register_netdevice_notifier(&br_dev_notifier);
615
        br_stats.flags = 0; /*BR_UP | BR_DEBUG*/;        /* enable bridge */
616
        /*start_hello_timer();*/
617
}
618
 
619
void br_init_port(int port_no)
620
{
621
        become_designated_port(port_no);          /* (4.8.1.4.1) */
622
        set_port_state(port_no, Blocking);        /* (4.8.1.4.2)    */
623
        port_info[port_no].top_change_ack = 0;
624
        port_info[port_no].config_pending = FALSE;/* (4.8.1.4.4)         */
625
        stop_message_age_timer(port_no);          /* (4.8.1.4.5)         */
626
        stop_forward_delay_timer(port_no);        /* (4.8.1.4.6)         */
627
        stop_hold_timer(port_no);                 /* (4.8.1.4.7)         */
628
}
629
 
630
void enable_port(int port_no)                             /* (4.8.2)     */
631
{
632
        br_init_port(port_no);
633
        port_state_selection();                   /* (4.8.2.7)   */
634
}                                                 /* */
635
 
636
void disable_port(int port_no)                            /* (4.8.3)     */
637
{
638
        int         root;
639
 
640
        root = root_bridge();
641
        become_designated_port(port_no);          /* (4.8.3.1)   */
642
        set_port_state(port_no, Disabled);        /* (4.8.3.2)   */
643
        port_info[port_no].top_change_ack = 0;
644
        port_info[port_no].config_pending = FALSE;/* (4.8.3.4)   */
645
        stop_message_age_timer(port_no);          /* (4.8.3.5)   */
646
        stop_forward_delay_timer(port_no);        /* (4.8.3.6)   */
647
        configuration_update();
648
        port_state_selection();                   /* (4.8.3.7)   */
649
        if ((root_bridge()) && (!root)) {         /* (4.8.3.8)   */
650
                bridge_info.max_age = bridge_info.bridge_max_age;       /* (4.8.3.8.1)    */
651
                bridge_info.hello_time = bridge_info.bridge_hello_time;
652
                bridge_info.forward_delay = bridge_info.bridge_forward_delay;
653
                topology_change_detection();      /* (4.8.3.8.2)    */
654
                stop_tcn_timer();                 /* (4.8.3.8.3)    */
655
                config_bpdu_generation();         /* (4.8.3.8.4)    */
656
                start_hello_timer();
657
        }
658
}
659
 
660
 
661
void set_bridge_priority(bridge_id_t *new_bridge_id)              /* (4.8.4)     */
662
{
663
 
664
        int         root;
665
        int             port_no;
666
        root = root_bridge();
667
        for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.8.4.2) */
668
                if (designated_port(port_no)) {
669
                        port_info[port_no].designated_bridge = *new_bridge_id;
670
                }
671
        }
672
 
673
        bridge_info.bridge_id = *new_bridge_id;   /* (4.8.4.3)   */
674
        configuration_update();                   /* (4.8.4.4)   */
675
        port_state_selection();                   /* (4.8.4.5)   */
676
        if ((root_bridge()) && (!root)) {         /* (4.8.4.6)   */
677
                bridge_info.max_age = bridge_info.bridge_max_age;       /* (4.8.4.6.1)    */
678
                bridge_info.hello_time = bridge_info.bridge_hello_time;
679
                bridge_info.forward_delay = bridge_info.bridge_forward_delay;
680
                topology_change_detection();      /* (4.8.4.6.2)    */
681
                stop_tcn_timer();                 /* (4.8.4.6.3)    */
682
                config_bpdu_generation(),         /* (4.8.4.6.4)    */
683
                start_hello_timer();
684
        }
685
}
686
 
687
void set_port_priority(int port_no, unsigned short new_port_id)           /* (4.8.5)     */
688
{
689
        if (designated_port(port_no)) {           /* (4.8.5.2)   */
690
                port_info[port_no].designated_port = new_port_id;
691
        }
692
        port_info[port_no].port_id = new_port_id; /* (4.8.5.3)   */
693
        if ((br_cmp(bridge_info.bridge_id.BRIDGE_ID,
694
             port_info[port_no].designated_bridge.BRIDGE_ID) == 0
695
             )
696
                        &&
697
                        (port_info[port_no].port_id
698
                         < port_info[port_no].designated_port
699
 
700
                         )
701
                ) {
702
                become_designated_port(port_no);  /* (4.8.5.4.1) */
703
                port_state_selection();           /* (4.8.5.4.2) */
704
        }
705
}
706
 
707
void set_path_cost(int port_no, unsigned short path_cost)                 /* (4.8.6)     */
708
{
709
        port_info[port_no].path_cost = path_cost; /* (4.8.6.1)   */
710
        configuration_update();                   /* (4.8.6.2)   */
711
        port_state_selection();                   /* (4.8.6.3)   */
712
}
713
 
714
static void br_tick(unsigned long arg)
715
{
716
        int             port_no;
717
 
718
        if (hello_timer_expired()) {
719
                hello_timer_expiry();
720
        }
721
        if (tcn_timer_expired()) {
722
                tcn_timer_expiry();
723
        }
724
        if (topology_change_timer_expired()) {
725
                topology_change_timer_expiry();
726
        }
727
        for (port_no = One; port_no <= No_of_ports; port_no++) {
728
                if (forward_delay_timer_expired(port_no)) {
729
                        forward_delay_timer_expiry(port_no);
730
                }
731
                if (message_age_timer_expired(port_no)) {
732
                        message_age_timer_expiry(port_no);
733
                }
734
                if (hold_timer_expired(port_no)) {
735
                        hold_timer_expiry(port_no);
736
                }
737
        }
738
        /* call me again sometime... */
739
        tl.expires = jiffies+HZ;        /* 1 second */
740
        tl.function = br_tick;
741
        add_timer(&tl);
742
}
743
 
744
void start_hello_timer(void)
745
{
746
        hello_timer.value = 0;
747
        hello_timer.active = TRUE;
748
}
749
 
750
void stop_hello_timer(void)
751
{
752
        hello_timer.active = FALSE;
753
}
754
 
755
int hello_timer_expired(void)
756
{
757
        if (hello_timer.active && (++hello_timer.value >= bridge_info.hello_time)) {
758
                hello_timer.active = FALSE;
759
                return (TRUE);
760
        }
761
        return (FALSE);
762
}
763
 
764
void start_tcn_timer(void)
765
{
766
        tcn_timer.value = 0;
767
        tcn_timer.active = TRUE;
768
}
769
 
770
void stop_tcn_timer(void)
771
{
772
        tcn_timer.active = FALSE;
773
}
774
 
775
int tcn_timer_expired(void)
776
{
777
        if (tcn_timer.active && (++tcn_timer.value >=
778
                                 bridge_info.bridge_hello_time)) {
779
                tcn_timer.active = FALSE;
780
                return (TRUE);
781
        }
782
        return (FALSE);
783
 
784
}
785
 
786
void start_topology_change_timer(void)
787
{
788
        topology_change_timer.value = 0;
789
        topology_change_timer.active = TRUE;
790
}
791
 
792
void stop_topology_change_timer(void)
793
{
794
        topology_change_timer.active = FALSE;
795
}
796
 
797
int topology_change_timer_expired(void)
798
{
799
        if (topology_change_timer.active
800
                        && (++topology_change_timer.value
801
                            >= bridge_info.topology_change_time
802
                            )) {
803
                topology_change_timer.active = FALSE;
804
                return (TRUE);
805
        }
806
        return (FALSE);
807
}
808
 
809
void start_message_age_timer(int port_no, unsigned short message_age)
810
{
811
        message_age_timer[port_no].value = message_age;
812
        message_age_timer[port_no].active = TRUE;
813
}
814
 
815
void stop_message_age_timer(int port_no)
816
{
817
        message_age_timer[port_no].active = FALSE;
818
}
819
 
820
int message_age_timer_expired(int port_no)
821
{
822
        if (message_age_timer[port_no].active &&
823
              (++message_age_timer[port_no].value >= bridge_info.max_age)) {
824
                message_age_timer[port_no].active = FALSE;
825
                return (TRUE);
826
        }
827
        return (FALSE);
828
}
829
 
830
void start_forward_delay_timer(int port_no)
831
{
832
        forward_delay_timer[port_no].value = 0;
833
        forward_delay_timer[port_no].active = TRUE;
834
}
835
 
836
void stop_forward_delay_timer(int port_no)
837
{
838
        forward_delay_timer[port_no].active = FALSE;
839
}
840
 
841
int forward_delay_timer_expired(int port_no)
842
{
843
                if (forward_delay_timer[port_no].active &&
844
                                (++forward_delay_timer[port_no].value >= bridge_info.forward_delay)) {
845
                        forward_delay_timer[port_no].active = FALSE;
846
                        return (TRUE);
847
                }
848
                return (FALSE);
849
}
850
 
851
void start_hold_timer(int port_no)
852
{
853
        hold_timer[port_no].value = 0;
854
        hold_timer[port_no].active = TRUE;
855
}
856
 
857
void stop_hold_timer(int port_no)
858
{
859
        hold_timer[port_no].active = FALSE;
860
}
861
 
862
 
863
int hold_timer_expired(int port_no)
864
{
865
        if (hold_timer[port_no].active &&
866
                   (++hold_timer[port_no].value >= bridge_info.hold_time)) {
867
                hold_timer[port_no].active = FALSE;
868
                return (TRUE);
869
        }
870
        return (FALSE);
871
 
872
}
873
 
874
int send_config_bpdu(int port_no, Config_bpdu *config_bpdu)
875
{
876
        struct sk_buff *skb;
877
        struct device *dev = port_info[port_no].dev;
878
        int size;
879
 
880
        if(!(br_stats.flags & BR_UP))
881
                return(-1); /* this should not happen but happens */
882
        if (port_info[port_no].state == Disabled) {
883
                printk(KERN_DEBUG "send_config_bpdu: port %i not valid\n",port_no);
884
                return(-1);
885
                }
886
        if (br_stats.flags & BR_DEBUG)
887
                printk("send_config_bpdu: ");
888
        /*
889
         * create and send the message
890
         */
891
        size = sizeof(Config_bpdu) + dev->hard_header_len;
892
        skb = alloc_skb(size, GFP_ATOMIC);
893
        if (skb == NULL) {
894
                printk(KERN_DEBUG "send_config_bpdu: no skb available\n");
895
                return(-1);
896
                }
897
        skb->dev = dev;
898
        skb->free = 1;
899
        skb->h.eth = (struct ethhdr *)skb_put(skb, size);
900
        memcpy(skb->h.eth->h_dest, bridge_ula, ETH_ALEN);
901
        memcpy(skb->h.eth->h_source, dev->dev_addr, ETH_ALEN);
902
        if (br_stats.flags & BR_DEBUG)
903
                printk("port %i src %02x:%02x:%02x:%02x:%02x:%02x\
904
                        dest %02x:%02x:%02x:%02x:%02x:%02x\n",
905
                        port_no,
906
                        skb->h.eth->h_source[0],
907
                        skb->h.eth->h_source[1],
908
                        skb->h.eth->h_source[2],
909
                        skb->h.eth->h_source[3],
910
                        skb->h.eth->h_source[4],
911
                        skb->h.eth->h_source[5],
912
                        skb->h.eth->h_dest[0],
913
                        skb->h.eth->h_dest[1],
914
                        skb->h.eth->h_dest[2],
915
                        skb->h.eth->h_dest[3],
916
                        skb->h.eth->h_dest[4],
917
                        skb->h.eth->h_dest[5]);
918
        skb->h.eth->h_proto = htonl(0x8038);    /* XXX verify */
919
 
920
        skb->h.raw += skb->dev->hard_header_len;
921
        memcpy(skb->h.raw, config_bpdu, sizeof(Config_bpdu));
922
 
923
        /* won't get bridged again... */
924
        skb->pkt_bridged = IS_BRIDGED;
925
        skb->arp = 1;   /* do not resolve... */
926
        skb->h.raw = skb->data + ETH_HLEN;
927
        dev_queue_xmit(skb, dev, SOPRI_INTERACTIVE);
928
        return(0);
929
}
930
 
931
int send_tcn_bpdu(int port_no, Tcn_bpdu *bpdu)
932
{
933
        struct sk_buff *skb;
934
        struct device *dev = port_info[port_no].dev;
935
        int size;
936
 
937
        if(!(br_stats.flags & BR_UP))
938
                return(-1); /* this should not happen but happens */
939
        if (port_info[port_no].state == Disabled) {
940
                printk(KERN_DEBUG "send_tcn_bpdu: port %i not valid\n",port_no);
941
                return(-1);
942
                }
943
        if (br_stats.flags & BR_DEBUG)
944
                printk("send_tcn_bpdu: ");
945
        size = sizeof(Tcn_bpdu) + dev->hard_header_len;
946
        skb = alloc_skb(size, GFP_ATOMIC);
947
        if (skb == NULL) {
948
                printk(KERN_DEBUG "send_tcn_bpdu: no skb available\n");
949
                return(-1);
950
                }
951
        skb->dev = dev;
952
        skb->free = 1;
953
        skb->h.eth = (struct ethhdr *)skb_put(skb,size);
954
        memcpy(skb->h.eth->h_dest, bridge_ula, ETH_ALEN);
955
        memcpy(skb->h.eth->h_source, dev->dev_addr, ETH_ALEN);
956
        if (br_stats.flags & BR_DEBUG)
957
                printk("port %i src %02x:%02x:%02x:%02x:%02x:%02x\
958
                        dest %02x:%02x:%02x:%02x:%02x:%02x\n",
959
                        port_no,
960
                        skb->h.eth->h_source[0],
961
                        skb->h.eth->h_source[1],
962
                        skb->h.eth->h_source[2],
963
                        skb->h.eth->h_source[3],
964
                        skb->h.eth->h_source[4],
965
                        skb->h.eth->h_source[5],
966
                        skb->h.eth->h_dest[0],
967
                        skb->h.eth->h_dest[1],
968
                        skb->h.eth->h_dest[2],
969
                        skb->h.eth->h_dest[3],
970
                        skb->h.eth->h_dest[4],
971
                        skb->h.eth->h_dest[5]);
972
        skb->h.eth->h_proto = 0x8038;   /* XXX verify */
973
 
974
        skb->h.raw += skb->dev->hard_header_len;
975
        memcpy(skb->h.raw, bpdu, sizeof(Tcn_bpdu));
976
 
977
        /* mark that's we've been here... */
978
        skb->pkt_bridged = IS_BRIDGED;
979
        skb->arp = 1;   /* do not resolve... */
980
        skb->h.raw = skb->data + ETH_HLEN;
981
 
982
        dev_queue_xmit(skb, dev, SOPRI_INTERACTIVE);
983
        return(0);
984
}
985
 
986
static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
987
{
988
        struct device *dev = ptr;
989
        int i;
990
 
991
        /* check for loopback devices */
992
        if (dev->flags & IFF_LOOPBACK)
993
                return(NOTIFY_DONE);
994
 
995
        switch (event) {
996
        case NETDEV_DOWN:
997
                if (br_stats.flags & BR_DEBUG)
998
                        printk("br_device_event: NETDEV_DOWN...\n");
999
                /* find our device and mark it down */
1000
                for (i = One; i <= No_of_ports; i++) {
1001
                        if (port_info[i].dev == dev) {
1002
                                disable_port(i);
1003
                                return NOTIFY_DONE;
1004
                                break;
1005
                        }
1006
                }
1007
                break;
1008
        case NETDEV_UP:
1009
                if (br_stats.flags & BR_DEBUG)
1010
                        printk("br_device_event: NETDEV_UP...\n");
1011
                /* Only handle ethernet ports */
1012
                if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_LOOPBACK)
1013
                        return NOTIFY_DONE;
1014
                /* look up an unused device and enable it */
1015
                for (i = One; i <= No_of_ports; i++) {
1016
                        if ((port_info[i].dev == (struct device *)0) ||
1017
                                (port_info[i].dev == dev)) {
1018
                                port_info[i].dev = dev;
1019
                                enable_port(i);
1020
                                set_path_cost(i, br_port_cost(dev));
1021
                                set_port_priority(i, 128);
1022
                                port_info[i].port_id = i;
1023
                                /* set bridge addr from 1st device addr */
1024
                                if ((bridge_info.bridge_id.BRIDGE_ID[0] == 0) &&
1025
                                                (bridge_info.bridge_id.BRIDGE_ID[1] == 0)) {
1026
                                        memcpy(bridge_info.bridge_id.BRIDGE_ID_ULA, dev->dev_addr, 6);
1027
                                        bridge_info.bridge_id.BRIDGE_PRIORITY = port_info[i].port_id;
1028
                                        set_bridge_priority(&bridge_info.bridge_id);
1029
                                }
1030
                                make_forwarding(i);
1031
                                return NOTIFY_DONE;
1032
                                break;
1033
                        }
1034
                }
1035
                break;
1036
#if 0
1037
        default:
1038
                printk("br_device_event: unknown event [%x]\n",
1039
                        (unsigned int)event);
1040
#endif                  
1041
        }
1042
        return NOTIFY_DONE;
1043
}
1044
 
1045
/*
1046
 * following routine is called when a frame is received
1047
 * from an interface, it returns 1 when it consumes the
1048
 * frame, 0 when it does not
1049
 */
1050
 
1051
int br_receive_frame(struct sk_buff *skb)       /* 3.5 */
1052
{
1053
        int port;
1054
 
1055
        if (br_stats.flags & BR_DEBUG)
1056
                printk("br_receive_frame: ");
1057
        /* sanity */
1058
        if (!skb) {
1059
                printk(KERN_CRIT "br_receive_frame: no skb!\n");
1060
                return(1);
1061
        }
1062
 
1063
        skb->pkt_bridged = IS_BRIDGED;
1064
 
1065
        /* check for loopback */
1066
        if (skb->dev->flags & IFF_LOOPBACK)
1067
                return(0);
1068
 
1069
        port = find_port(skb->dev);
1070
 
1071
        skb->arp = 1;           /* Received frame so it is resolved */
1072
        skb->h.raw = skb->mac.raw;
1073
        if (br_stats.flags & BR_DEBUG)
1074
                printk("port %i src %02x:%02x:%02x:%02x:%02x:%02x\
1075
                        dest %02x:%02x:%02x:%02x:%02x:%02x\n",
1076
                        port,
1077
                        skb->h.eth->h_source[0],
1078
                        skb->h.eth->h_source[1],
1079
                        skb->h.eth->h_source[2],
1080
                        skb->h.eth->h_source[3],
1081
                        skb->h.eth->h_source[4],
1082
                        skb->h.eth->h_source[5],
1083
                        skb->h.eth->h_dest[0],
1084
                        skb->h.eth->h_dest[1],
1085
                        skb->h.eth->h_dest[2],
1086
                        skb->h.eth->h_dest[3],
1087
                        skb->h.eth->h_dest[4],
1088
                        skb->h.eth->h_dest[5]);
1089
 
1090
        if (!port) {
1091
                if(br_stats.flags&BR_DEBUG)
1092
                        printk("\nbr_receive_frame: no port!\n");
1093
                return(0);
1094
        }
1095
 
1096
        switch (port_info[port].state)
1097
        {
1098
                case Learning:
1099
                        (void) br_learn(skb, port);     /* 3.8 */
1100
                        /* fall through */
1101
                case Listening:
1102
                        /* process BPDUs */
1103
                        if (memcmp(skb->h.eth->h_dest, bridge_ula, 6) == 0) {
1104
                                br_bpdu(skb);
1105
                                return(1); /* br_bpdu consumes skb */
1106
                        }
1107
                        /* fall through */
1108
                case Blocking:
1109
                        /* fall through */
1110
                case Disabled:
1111
                        /* should drop frames, but for now, we let
1112
                         * them get passed up to the next higher layer
1113
                        return(br_drop(skb));
1114
                         */
1115
                        return(0);       /* pass frame up stack */
1116
                        break;
1117
                case Forwarding:
1118
                        (void) br_learn(skb, port);     /* 3.8 */
1119
                        /* process BPDUs */
1120
                        if (memcmp(skb->h.eth->h_dest, bridge_ula,
1121
                                        ETH_ALEN) == 0)
1122
                        {
1123
                                /*printk("frame bpdu processor for me!!!\n");*/
1124
                                br_bpdu(skb);
1125
                                return(1); /* br_bpdu consumes skb */
1126
                        }
1127
                        /* is frame for me? */
1128
                        if (memcmp(skb->h.eth->h_dest,
1129
                                        port_info[port].dev->dev_addr,
1130
                                        ETH_ALEN) == 0)
1131
                        {
1132
                                /* Packet is for us */
1133
                                skb->pkt_type = PACKET_HOST;
1134
                                return(0);       /* pass frame up our stack (this will */
1135
                                                /* happen in net_bh() in dev.c) */
1136
                        }
1137
                        /* ok, forward this frame... */
1138
                        return(br_forward(skb, port));
1139
                default:
1140
                        printk(KERN_DEBUG "br_receive_frame: port [%i] unknown state [%i]\n",
1141
                                port, port_info[port].state);
1142
                        return(0);       /* pass frame up stack? */
1143
        }
1144
}
1145
 
1146
/*
1147
 * the following routine is called to transmit frames from the host
1148
 * stack.  it returns 1 when it consumes the frame and
1149
 * 0 when it does not.
1150
 */
1151
 
1152
int br_tx_frame(struct sk_buff *skb)    /* 3.5 */
1153
{
1154
        int port;
1155
 
1156
        /* sanity */
1157
        if (!skb)
1158
        {
1159
                printk(KERN_CRIT "br_tx_frame: no skb!\n");
1160
                return(0);
1161
        }
1162
 
1163
        if (!skb->dev)
1164
        {
1165
                printk(KERN_CRIT "br_tx_frame: no dev!\n");
1166
                return(0);
1167
        }
1168
 
1169
        /* check for loopback */
1170
        if (skb->dev->flags & IFF_LOOPBACK)
1171
                return(0);
1172
 
1173
        skb->h.raw = skb->data;
1174
        port = 0;        /* an impossible port */
1175
        if (br_stats.flags & BR_DEBUG)
1176
                printk("br_tx_fr : port %i src %02x:%02x:%02x:%02x:%02x:%02x\
1177
                        dest %02x:%02x:%02x:%02x:%02x:%02x\n",
1178
                        port,
1179
                        skb->h.eth->h_source[0],
1180
                        skb->h.eth->h_source[1],
1181
                        skb->h.eth->h_source[2],
1182
                        skb->h.eth->h_source[3],
1183
                        skb->h.eth->h_source[4],
1184
                        skb->h.eth->h_source[5],
1185
                        skb->h.eth->h_dest[0],
1186
                        skb->h.eth->h_dest[1],
1187
                        skb->h.eth->h_dest[2],
1188
                        skb->h.eth->h_dest[3],
1189
                        skb->h.eth->h_dest[4],
1190
                        skb->h.eth->h_dest[5]);
1191
        return(br_forward(skb, port));
1192
}
1193
 
1194
/*
1195
 * this routine returns 0 when it learns (or updates) from the
1196
 * frame, and -1 if the frame is simply discarded due to port
1197
 * state or lack of resources...
1198
 */
1199
 
1200
int br_learn(struct sk_buff *skb, int port)     /* 3.8 */
1201
{
1202
        struct fdb *f;
1203
 
1204
        switch (port_info[port].state) {
1205
                case Listening:
1206
                case Blocking:
1207
                case Disabled:
1208
                default:
1209
                        return(-1);
1210
                        /* break; */
1211
                case Learning:
1212
                case Forwarding:
1213
                        /* don't keep group addresses in the tree */
1214
                        if (skb->h.eth->h_source[0] & 0x01)
1215
                                return(-1);
1216
 
1217
                        f = (struct fdb *)kmalloc(sizeof(struct fdb),
1218
                                GFP_ATOMIC);
1219
 
1220
                        if (!f) {
1221
                                printk(KERN_DEBUG "br_learn: unable to malloc fdb\n");
1222
                                return(-1);
1223
                        }
1224
                        f->port = port; /* source port */
1225
                        memcpy(f->ula, skb->h.eth->h_source, 6);
1226
                        f->timer = CURRENT_TIME;
1227
                        f->flags = FDB_ENT_VALID;
1228
                        /*
1229
                         * add entity to AVL tree.  If entity already
1230
                         * exists in the tree, update the fields with
1231
                         * what we have here.
1232
                         */
1233
                        if (br_avl_insert(f) == 0) { /* update */
1234
                                kfree(f);
1235
                                return(0);
1236
                        }
1237
                        /* add to head of port chain */
1238
                        f->fdb_next = port_info[port].fdb;
1239
                        port_info[port].fdb = f;
1240
                        return(0);
1241
                        /* break */
1242
        }
1243
}
1244
 
1245
/*
1246
 * this routine always consumes the frame
1247
 */
1248
 
1249
int br_drop(struct sk_buff *skb)
1250
{
1251
        kfree_skb(skb, 0);
1252
        return(1);
1253
}
1254
 
1255
/*
1256
 * this routine always consumes the frame
1257
 */
1258
 
1259
int br_dev_drop(struct sk_buff *skb)
1260
{
1261
        dev_kfree_skb(skb, 0);
1262
        return(1);
1263
}
1264
 
1265
/*
1266
 * this routine returns 1 if it consumes the frame, 0
1267
 * if not...
1268
 */
1269
 
1270
int br_forward(struct sk_buff *skb, int port)   /* 3.7 */
1271
{
1272
        struct fdb *f;
1273
 
1274
        /*
1275
         * flood all ports with frames destined for a group
1276
         * address.  If frame came from above, drop it,
1277
         * otherwise it will be handled in br_receive_frame()
1278
         * Multicast frames will also need to be seen
1279
         * by our upper layers.
1280
         */
1281
        if (skb->h.eth->h_dest[0] & 0x01)
1282
        {
1283
                /* group address */
1284
                br_flood(skb, port);
1285
                /*
1286
                 *      External groups are fed out via the normal source
1287
                 *      This probably should be dropped since the flood will
1288
                 *      have sent it anyway.
1289
                 */
1290
                if (port == 0)                   /* locally generated */
1291
                        return(br_dev_drop(skb));
1292
                return(0);
1293
        } else {
1294
                /* locate port to forward to */
1295
                f = br_avl_find_addr(skb->h.eth->h_dest);
1296
                /*
1297
                 *      Send flood and drop.
1298
                 */
1299
                if (!f || !(f->flags & FDB_ENT_VALID)) {
1300
                        /* not found; flood all ports */
1301
                        br_flood(skb, port);
1302
                        return(br_dev_drop(skb));
1303
                }
1304
                /*
1305
                 *      Sending
1306
                 */
1307
 
1308
                /*
1309
                 * Vova Oksman: There was the BUG, we must to check timer
1310
                 * before comparing source and destination ports, becouse
1311
                 * case that destination was switched from same port with
1312
                 * source to other port.
1313
                 */
1314
                        /* has entry expired? */
1315
                if (port_info[f->port].state == Forwarding &&
1316
                    f->timer + fdb_aging_time < CURRENT_TIME) {
1317
                                /* timer expired, invalidate entry */
1318
                                f->flags &= ~FDB_ENT_VALID;
1319
                                if (br_stats.flags & BR_DEBUG)
1320
                                        printk("fdb entry expired...\n");
1321
                                /*
1322
                                 *      Send flood and drop original
1323
                                 */
1324
                                br_flood(skb, port);
1325
                                return(br_dev_drop(skb));
1326
                        }
1327
                if (f->port!=port && port_info[f->port].state == Forwarding) {
1328
                        /* mark that's we've been here... */
1329
                        skb->pkt_bridged = IS_BRIDGED;
1330
 
1331
                        /* reset the skb->ip pointer */
1332
                        skb->h.raw = skb->data + ETH_HLEN;
1333
 
1334
                        /*
1335
                         *      Send the buffer out.
1336
                         */
1337
 
1338
                        skb->dev=port_info[f->port].dev;
1339
 
1340
                        /*
1341
                         *      We send this still locked
1342
                         */
1343
                        dev_queue_xmit(skb, skb->dev,1);
1344
                        return(1);      /* skb has been consumed */
1345
                } else {
1346
                        /*
1347
                         *      Arrived on the right port, we discard
1348
                         */
1349
                        return(br_dev_drop(skb));
1350
                }
1351
        }
1352
}
1353
 
1354
/*
1355
 * this routine sends a copy of the frame to all forwarding ports
1356
 * with the exception of the port given.  This routine never
1357
 * consumes the original frame.
1358
 */
1359
 
1360
int br_flood(struct sk_buff *skb, int port)
1361
{
1362
        int i;
1363
        struct sk_buff *nskb;
1364
 
1365
        for (i = One; i <= No_of_ports; i++)
1366
        {
1367
                if (i == port)
1368
                        continue;
1369
                if (port_info[i].state == Forwarding)
1370
                {
1371
                        nskb = skb_clone(skb, GFP_ATOMIC);
1372
                        if(nskb==NULL)
1373
                                continue;
1374
                        /* mark that's we've been here... */
1375
                        nskb->pkt_bridged = IS_BRIDGED;
1376
                        /* Send to each port in turn */
1377
                        nskb->dev= port_info[i].dev;
1378
                        /* To get here we must have done ARP already,
1379
                           or have a received valid MAC header */
1380
                        nskb->arp = 1;
1381
 
1382
/*                      printk("Flood to port %d\n",i);*/
1383
                        nskb->h.raw = nskb->data + ETH_HLEN;
1384
                        dev_queue_xmit(nskb,nskb->dev,1);
1385
                }
1386
        }
1387
        return(0);
1388
}
1389
 
1390
int find_port(struct device *dev)
1391
{
1392
        int i;
1393
 
1394
        for (i = One; i <= No_of_ports; i++)
1395
                if ((port_info[i].dev == dev) &&
1396
                        (port_info[i].state != Disabled))
1397
                        return(i);
1398
        return(0);
1399
}
1400
 
1401
int br_port_cost(struct device *dev)    /* 4.10.2 */
1402
{
1403
        if (strncmp(dev->name, "eth", 3) == 0)   /* ethernet */
1404
                return(100);
1405
        if (strncmp(dev->name, "wic", 3) == 0)   /* wic */
1406
                return(1600);
1407
        if (strncmp(dev->name, "plip",4) == 0) /* plip */
1408
                return (1600);
1409
        return(100);    /* default */
1410
}
1411
 
1412
/*
1413
 * this routine always consumes the skb
1414
 */
1415
 
1416
void br_bpdu(struct sk_buff *skb) /* consumes skb */
1417
{
1418
        Tcn_bpdu *bpdu;
1419
        int port;
1420
 
1421
        port = find_port(skb->dev);
1422
        if (port == 0) { /* unknown port */
1423
                br_drop(skb);
1424
                return;
1425
        }
1426
 
1427
        bpdu = (Tcn_bpdu *) (skb->data + ETH_HLEN);
1428
        switch (bpdu->type) {
1429
                case BPDU_TYPE_CONFIG:
1430
                        received_config_bpdu(port, (Config_bpdu *)bpdu);
1431
                        break;
1432
                case BPDU_TYPE_TOPO_CHANGE:
1433
                        received_tcn_bpdu(port, bpdu);
1434
                        break;
1435
                default:
1436
                        printk(KERN_DEBUG "br_bpdu: received unknown bpdu, type = %i\n",
1437
                                bpdu->type);
1438
                        /* break; */
1439
        }
1440
        br_drop(skb);
1441
}
1442
 
1443
int br_ioctl(unsigned int cmd, void *arg)
1444
{
1445
        int err;
1446
        struct br_cf bcf;
1447
 
1448
        switch(cmd)
1449
        {
1450
                case SIOCGIFBR: /* get bridging control blocks */
1451
                        err = verify_area(VERIFY_WRITE, arg,
1452
                                sizeof(struct br_stat));
1453
                        if(err)
1454
                                return err;
1455
                        memcpy(&br_stats.bridge_data, &bridge_info, sizeof(Bridge_data));
1456
                        memcpy(&br_stats.port_data, &port_info, sizeof(Port_data)*No_of_ports);
1457
                        memcpy_tofs(arg, &br_stats, sizeof(struct br_stat));
1458
                        return(0);
1459
                case SIOCSIFBR:
1460
                        if (!suser())
1461
                                return -EPERM;
1462
                        err = verify_area(VERIFY_READ, arg,
1463
                                sizeof(struct br_cf));
1464
                        if(err)
1465
                                return err;
1466
                        memcpy_fromfs(&bcf, arg, sizeof(struct br_cf));
1467
                        switch (bcf.cmd) {
1468
                                case BRCMD_BRIDGE_ENABLE:
1469
                                        if (br_stats.flags & BR_UP)
1470
                                                return(-EALREADY);
1471
                                        printk(KERN_DEBUG "br: enabling bridging function\n");
1472
                                        br_stats.flags |= BR_UP;        /* enable bridge */
1473
                                        start_hello_timer();
1474
                                        break;
1475
                                case BRCMD_BRIDGE_DISABLE:
1476
                                        if (!(br_stats.flags & BR_UP))
1477
                                                return(-EALREADY);
1478
                                        printk(KERN_DEBUG "br: disabling bridging function\n");
1479
                                        br_stats.flags &= ~BR_UP;       /* disable bridge */
1480
                                        stop_hello_timer();
1481
#if 0                                   
1482
                                        for (i = One; i <= No_of_ports; i++)
1483
                                                if (port_info[i].state != Disabled)
1484
                                                        disable_port(i);
1485
#endif                                                  
1486
                                        break;
1487
                                case BRCMD_PORT_ENABLE:
1488
                                        if (port_info[bcf.arg1].dev == 0)
1489
                                                return(-EINVAL);
1490
                                        if (port_info[bcf.arg1].state != Disabled)
1491
                                                return(-EALREADY);
1492
                                        printk(KERN_DEBUG "br: enabling port %i\n",bcf.arg1);
1493
                                        enable_port(bcf.arg1);
1494
                                        break;
1495
                                case BRCMD_PORT_DISABLE:
1496
                                        if (port_info[bcf.arg1].dev == 0)
1497
                                                return(-EINVAL);
1498
                                        if (port_info[bcf.arg1].state == Disabled)
1499
                                                return(-EALREADY);
1500
                                        printk(KERN_DEBUG "br: disabling port %i\n",bcf.arg1);
1501
                                        disable_port(bcf.arg1);
1502
                                        break;
1503
                                case BRCMD_SET_BRIDGE_PRIORITY:
1504
                                        set_bridge_priority((bridge_id_t *)&bcf.arg1);
1505
                                        break;
1506
                                case BRCMD_SET_PORT_PRIORITY:
1507
                                        if (port_info[bcf.arg1].dev == 0)
1508
                                                return(-EINVAL);
1509
                                        set_port_priority(bcf.arg1, bcf.arg2);
1510
                                        break;
1511
                                case BRCMD_SET_PATH_COST:
1512
                                        if (port_info[bcf.arg1].dev == 0)
1513
                                                return(-EINVAL);
1514
                                        set_path_cost(bcf.arg1, bcf.arg2);
1515
                                        break;
1516
                                case BRCMD_ENABLE_DEBUG:
1517
                                        br_stats.flags |= BR_DEBUG;
1518
                                        break;
1519
                                case BRCMD_DISABLE_DEBUG:
1520
                                        br_stats.flags &= ~BR_DEBUG;
1521
                                        break;
1522
                                default:
1523
                                        return -EINVAL;
1524
                        }
1525
                        return(0);
1526
                default:
1527
                        return -EINVAL;
1528
        }
1529
        /*NOTREACHED*/
1530
        return 0;
1531
}
1532
 
1533
int br_cmp(unsigned int *a, unsigned int *b)
1534
{
1535
        int i;
1536
        for (i=0; i<2; i++)
1537
        {
1538
                if (a[i] == b[i])
1539
                        continue;
1540
                if (a[i] < b[i])
1541
                        return(1);
1542
                if (a[i] > b[i])
1543
                        return(-1);
1544
        }
1545
        return(0);
1546
}
1547
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.