root/net/bridge/br.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. transmit_config
  2. root_bridge
  3. supersedes_port_info
  4. record_config_information
  5. record_config_timeout_values
  6. config_bpdu_generation
  7. designated_port
  8. reply
  9. transmit_tcn
  10. configuration_update
  11. root_selection
  12. designated_port_selection
  13. become_designated_port
  14. port_state_selection
  15. make_forwarding
  16. topology_change_detection
  17. topology_change_acknowledged
  18. acknowledge_topology_change
  19. make_blocking
  20. set_port_state
  21. received_config_bpdu
  22. received_tcn_bpdu
  23. hello_timer_expiry
  24. message_age_timer_expiry
  25. forward_delay_timer_expiry
  26. designated_for_some_port
  27. tcn_timer_expiry
  28. topology_change_timer_expiry
  29. hold_timer_expiry
  30. br_init
  31. br_init_port
  32. enable_port
  33. disable_port
  34. set_bridge_priority
  35. set_port_priority
  36. set_path_cost
  37. br_tick
  38. start_hello_timer
  39. stop_hello_timer
  40. hello_timer_expired
  41. start_tcn_timer
  42. stop_tcn_timer
  43. tcn_timer_expired
  44. start_topology_change_timer
  45. stop_topology_change_timer
  46. topology_change_timer_expired
  47. start_message_age_timer
  48. stop_message_age_timer
  49. message_age_timer_expired
  50. start_forward_delay_timer
  51. stop_forward_delay_timer
  52. forward_delay_timer_expired
  53. start_hold_timer
  54. stop_hold_timer
  55. hold_timer_expired
  56. send_config_bpdu
  57. send_tcn_bpdu
  58. br_device_event
  59. br_receive_frame
  60. br_tx_frame
  61. br_learn
  62. br_drop
  63. br_dev_drop
  64. br_forward
  65. br_flood
  66. find_port
  67. br_port_cost
  68. br_bpdu
  69. br_ioctl
  70. br_cmp

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

/* [previous][next][first][last][top][bottom][index][help] */