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

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