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         
1069         skb->arp = 1;           /* Received frame so it is resolved */
1070         skb->h.raw = skb->mac.raw;
1071         if (br_stats.flags & BR_DEBUG)
1072                 printk("port %i src %02x:%02x:%02x:%02x:%02x:%02x\
1073                         dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
1074                         port,
1075                         skb->h.eth->h_source[0],
1076                         skb->h.eth->h_source[1],
1077                         skb->h.eth->h_source[2],
1078                         skb->h.eth->h_source[3],
1079                         skb->h.eth->h_source[4],
1080                         skb->h.eth->h_source[5],
1081                         skb->h.eth->h_dest[0],
1082                         skb->h.eth->h_dest[1],
1083                         skb->h.eth->h_dest[2],
1084                         skb->h.eth->h_dest[3],
1085                         skb->h.eth->h_dest[4],
1086                         skb->h.eth->h_dest[5]);
1087 
1088         if (!port) {
1089                 if(br_stats.flags&BR_DEBUG)
1090                         printk("\nbr_receive_frame: no port!\n");
1091                 return(0);
1092         }
1093 
1094         switch (port_info[port].state) 
1095         {
1096                 case Learning:
1097                         (void) br_learn(skb, port);     /* 3.8 */
1098                         /* fall through */
1099                 case Listening:
1100                         /* process BPDUs */
1101                         if (memcmp(skb->h.eth->h_dest, bridge_ula, 6) == 0) {
1102                                 br_bpdu(skb);
1103                                 return(1); /* br_bpdu consumes skb */
1104                         }
1105                         /* fall through */
1106                 case Blocking:
1107                         /* fall through */
1108                 case Disabled:
1109                         /* should drop frames, but for now, we let
1110                          * them get passed up to the next higher layer
1111                         return(br_drop(skb));   
1112                          */
1113                         return(0);      /* pass frame up stack */
1114                         break;
1115                 case Forwarding:
1116                         (void) br_learn(skb, port);     /* 3.8 */
1117                         /* process BPDUs */
1118                         if (memcmp(skb->h.eth->h_dest, bridge_ula, 
1119                                         ETH_ALEN) == 0) 
1120                         {
1121                                 /*printk("frame bpdu processor for me!!!\n");*/
1122                                 br_bpdu(skb);
1123                                 return(1); /* br_bpdu consumes skb */
1124                         }
1125                         /* is frame for me? */  
1126                         if (memcmp(skb->h.eth->h_dest, 
1127                                         port_info[port].dev->dev_addr, 
1128                                         ETH_ALEN) == 0) 
1129                         {
1130                                 return(0);      /* pass frame up our stack (this will */
1131                                                 /* happen in net_bh() in dev.c) */
1132                         }
1133                         /* ok, forward this frame... */
1134                         skb_device_lock(skb);
1135                         return(br_forward(skb, port));
1136                 default:
1137                         printk("br_receive_frame: port [%i] unknown state [%i]\n",
1138                                 port, port_info[port].state);
1139                         return(0);      /* pass frame up stack? */
1140         }
1141 }
1142 
1143 /*
1144  * the following routine is called to transmit frames from the host
1145  * stack.  it returns 1 when it consumes the frame and
1146  * 0 when it does not.
1147  */
1148 
1149 int br_tx_frame(struct sk_buff *skb)    /* 3.5 */
     /* [previous][next][first][last][top][bottom][index][help] */
1150 {
1151         int port;
1152         
1153         /* sanity */
1154         if (!skb) 
1155         {
1156                 printk("br_tx_frame: no skb!\n");
1157                 return(0);
1158         }
1159         /* check for loopback */
1160         if (skb->dev->flags & IFF_LOOPBACK)
1161                 return(0);
1162 
1163         skb->h.raw = skb->data;
1164         port = 0;       /* an impossible port */        
1165         if (br_stats.flags & BR_DEBUG)
1166                 printk("br_tx_fr : port %i src %02x:%02x:%02x:%02x:%02x:%02x\
1167                         dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
1168                         port,
1169                         skb->h.eth->h_source[0],
1170                         skb->h.eth->h_source[1],
1171                         skb->h.eth->h_source[2],
1172                         skb->h.eth->h_source[3],
1173                         skb->h.eth->h_source[4],
1174                         skb->h.eth->h_source[5],
1175                         skb->h.eth->h_dest[0],
1176                         skb->h.eth->h_dest[1],
1177                         skb->h.eth->h_dest[2],
1178                         skb->h.eth->h_dest[3],
1179                         skb->h.eth->h_dest[4],
1180                         skb->h.eth->h_dest[5]);
1181         return(br_forward(skb, port));
1182 }
1183 
1184 /*
1185  * this routine returns 0 when it learns (or updates) from the
1186  * frame, and -1 if the frame is simply discarded due to port
1187  * state or lack of resources...
1188  */
1189 
1190 int br_learn(struct sk_buff *skb, int port)     /* 3.8 */
     /* [previous][next][first][last][top][bottom][index][help] */
1191 {
1192         struct fdb *f;
1193 
1194         switch (port_info[port].state) {
1195                 case Listening:
1196                 case Blocking:
1197                 case Disabled:
1198                 default:
1199                         return(-1);
1200                         /* break; */
1201                 case Learning:
1202                 case Forwarding:
1203                         /* don't keep group addresses in the tree */
1204                         if (skb->h.eth->h_source[0] & 0x01)
1205                                 return(-1);
1206                         
1207                         f = (struct fdb *)kmalloc(sizeof(struct fdb), 
1208                                 GFP_ATOMIC);
1209 
1210                         if (!f) {
1211                                 printk("br_learn: unable to malloc fdb\n");
1212                                 return(-1);
1213                         }
1214                         f->port = port; /* source port */
1215                         memcpy(f->ula, skb->h.eth->h_source, 6);
1216                         f->timer = CURRENT_TIME;
1217                         f->flags = FDB_ENT_VALID;
1218                         /*
1219                          * add entity to AVL tree.  If entity already
1220                          * exists in the tree, update the fields with
1221                          * what we have here.
1222                          */
1223                         if (br_avl_insert(f) == 0) { /* update */
1224                                 kfree(f);
1225                                 return(0);
1226                         }
1227                         /* add to head of port chain */
1228                         f->fdb_next = port_info[port].fdb;
1229                         port_info[port].fdb = f;
1230                         return(0);
1231                         /* break */
1232         }
1233 }
1234 
1235 /*
1236  * this routine always consumes the frame
1237  */
1238 
1239 int br_drop(struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
1240 {
1241         kfree_skb(skb, 0);
1242         return(1);
1243 }
1244 
1245 /*
1246  * this routine always consumes the frame
1247  */
1248 
1249 int br_dev_drop(struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
1250 {
1251         dev_kfree_skb(skb, 0);
1252         return(1);
1253 }
1254 
1255 /*
1256  * this routine returns 1 if it consumes the frame, 0
1257  * if not...
1258  */
1259 
1260 int br_forward(struct sk_buff *skb, int port)   /* 3.7 */
     /* [previous][next][first][last][top][bottom][index][help] */
1261 {
1262         struct fdb *f;
1263         unsigned long flags;
1264         
1265         /*
1266          * flood all ports with frames destined for a group
1267          * address.  If frame came from above, drop it,
1268          * otherwise it will be handled in br_receive_frame()
1269          * Multicast frames will also need to be seen
1270          * by our upper layers.
1271          */     
1272         if (skb->h.eth->h_dest[0] & 0x01) 
1273         {
1274                 /* group address */
1275                 br_flood(skb, port);
1276                 /*
1277                  *      External groups are fed out via the normal source
1278                  *      This probably should be dropped since the flood will
1279                  *      have sent it anyway.
1280                  */
1281                 if (port == 0)                  /* locally generated */
1282                         return(br_dev_drop(skb));
1283                 return(0);
1284         } else {
1285                 /* locate port to forward to */
1286                 f = br_avl_find_addr(skb->h.eth->h_dest);
1287                 /*
1288                  *      Send flood and drop.
1289                  */
1290                 if (!f | !(f->flags & FDB_ENT_VALID)) {
1291                         /* not found; flood all ports */
1292                         br_flood(skb, port);
1293                         return(br_dev_drop(skb));
1294                 }
1295                 /*
1296                  *      Sending
1297                  */
1298                 if (port_info[f->port].state == Forwarding) {
1299                         /* has entry expired? */
1300                         if (f->timer + fdb_aging_time < CURRENT_TIME) {
1301                                 /* timer expired, invalidate entry */
1302                                 f->flags &= ~FDB_ENT_VALID;
1303                                 if (br_stats.flags & BR_DEBUG)
1304                                         printk("fdb entry expired...\n");
1305                                 /*
1306                                  *      Send flood and drop original
1307                                  */
1308                                 br_flood(skb, port);
1309                                 return(br_dev_drop(skb));
1310                         }
1311                         /* mark that's we've been here... */
1312                         skb->pkt_bridged = IS_BRIDGED;
1313                         
1314                         /* reset the skb->ip pointer */ 
1315                         skb->h.raw = skb->data + ETH_HLEN;
1316 
1317                         /*
1318                          *      Send the buffer out.
1319                          */
1320                          
1321                         skb->dev=port_info[f->port].dev;
1322                          
1323                         /*
1324                          *      We send this still locked
1325                          */
1326                         dev_queue_xmit(skb, skb->dev,1);
1327                         return(1);      /* skb has been consumed */
1328                 } else {
1329                         /*
1330                          *      Arrived on the right port, we discard
1331                          */
1332                         return(br_dev_drop(skb));
1333                 }
1334         }
1335 }
1336 
1337 /*
1338  * this routine sends a copy of the frame to all forwarding ports
1339  * with the exception of the port given.  This routine never
1340  * consumes the original frame.
1341  */
1342         
1343 int br_flood(struct sk_buff *skb, int port)
     /* [previous][next][first][last][top][bottom][index][help] */
1344 {
1345         int i;
1346         struct sk_buff *nskb;
1347         unsigned long flags;
1348 
1349         for (i = One; i <= No_of_ports; i++) 
1350         {
1351                 if (i == port)
1352                         continue;
1353                 if (port_info[i].state == Forwarding) 
1354                 {
1355                         nskb = skb_clone(skb, GFP_ATOMIC);
1356                         /* mark that's we've been here... */
1357                         nskb->pkt_bridged = IS_BRIDGED;
1358                         nskb->arp = skb->arp;
1359                         
1360 /*                      printk("Flood to port %d\n",i);*/
1361                         nskb->h.raw = nskb->data + ETH_HLEN;
1362                         dev_queue_xmit(nskb,nskb->dev,1);
1363                 }
1364         }
1365         return(0);
1366 }
1367 
1368 int find_port(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
1369 {
1370         int i;
1371 
1372         for (i = One; i <= No_of_ports; i++)
1373                 if ((port_info[i].dev == dev) && 
1374                         (port_info[i].state != Disabled))
1375                         return(i);
1376         return(0);
1377 }
1378 
1379 int br_port_cost(struct device *dev)    /* 4.10.2 */
     /* [previous][next][first][last][top][bottom][index][help] */
1380 {
1381         if (strncmp(dev->name, "eth", 3) == 0)  /* ethernet */
1382                 return(100);
1383         if (strncmp(dev->name, "wic", 3) == 0)  /* wic */
1384                 return(1600);
1385         if (strncmp(dev->name, "plip",4) == 0) /* plip */
1386                 return (1600);
1387         return(100);    /* default */
1388 }
1389 
1390 /*
1391  * this routine always consumes the skb 
1392  */
1393 
1394 void br_bpdu(struct sk_buff *skb) /* consumes skb */
     /* [previous][next][first][last][top][bottom][index][help] */
1395 {
1396         Tcn_bpdu *bpdu;
1397         int port;
1398 
1399         port = find_port(skb->dev);
1400         if (port == 0) {        /* unknown port */
1401                 br_drop(skb);
1402                 return;
1403         }
1404                 
1405         bpdu = (Tcn_bpdu *)skb->data + ETH_HLEN;
1406         switch (bpdu->type) {
1407                 case BPDU_TYPE_CONFIG:
1408                         received_config_bpdu(port, (Config_bpdu *)bpdu);
1409                         break;
1410                 case BPDU_TYPE_TOPO_CHANGE:
1411                         received_tcn_bpdu(port, bpdu);
1412                         break;
1413                 default:
1414                         printk("br_bpdu: received unknown bpdu, type = %i\n",
1415                                 bpdu->type);
1416                         /* break; */
1417         }
1418         br_drop(skb);
1419 }
1420 
1421 int br_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1422 {
1423         int err;
1424         struct br_cf bcf;
1425         int i;
1426 
1427         switch(cmd)
1428         {
1429                 case SIOCGIFBR: /* get bridging control blocks */
1430                         err = verify_area(VERIFY_WRITE, arg, 
1431                                 sizeof(struct br_stat));
1432                         if(err)
1433                                 return err;
1434                         memcpy(&br_stats.bridge_data, &bridge_info, sizeof(Bridge_data));
1435                         memcpy(&br_stats.port_data, &port_info, sizeof(Port_data)*No_of_ports);
1436                         memcpy_tofs(arg, &br_stats, sizeof(struct br_stat));
1437                         return(0);
1438                 case SIOCSIFBR:
1439                         if (!suser())
1440                                 return -EPERM;
1441                         err = verify_area(VERIFY_READ, arg, 
1442                                 sizeof(struct br_cf));
1443                         if(err)
1444                                 return err;
1445                         memcpy_fromfs(&bcf, arg, sizeof(struct br_cf));
1446                         switch (bcf.cmd) {
1447                                 case BRCMD_BRIDGE_ENABLE:
1448                                         if (br_stats.flags & BR_UP)
1449                                                 return(-EALREADY);      
1450                                         printk("br: enabling bridging function\n");
1451                                         br_stats.flags |= BR_UP;        /* enable bridge */
1452                                         start_hello_timer();
1453                                         break;
1454                                 case BRCMD_BRIDGE_DISABLE:
1455                                         if (!(br_stats.flags & BR_UP))
1456                                                 return(-EALREADY);      
1457                                         printk("br: disabling bridging function\n");
1458                                         br_stats.flags &= ~BR_UP;       /* disable bridge */
1459                                         stop_hello_timer();
1460 #if 0                                   
1461                                         for (i = One; i <= No_of_ports; i++)
1462                                                 if (port_info[i].state != Disabled)
1463                                                         disable_port(i);
1464 #endif                                                  
1465                                         break;
1466                                 case BRCMD_PORT_ENABLE:
1467                                         if (port_info[bcf.arg1].dev == 0)
1468                                                 return(-EINVAL);
1469                                         if (port_info[bcf.arg1].state != Disabled)
1470                                                 return(-EALREADY);
1471                                         printk("br: enabling port %i\n",bcf.arg1);
1472                                         enable_port(bcf.arg1);
1473                                         break;
1474                                 case BRCMD_PORT_DISABLE:
1475                                         if (port_info[bcf.arg1].dev == 0)
1476                                                 return(-EINVAL);
1477                                         if (port_info[bcf.arg1].state == Disabled)
1478                                                 return(-EALREADY);
1479                                         printk("br: disabling port %i\n",bcf.arg1);
1480                                         disable_port(bcf.arg1);
1481                                         break;
1482                                 case BRCMD_SET_BRIDGE_PRIORITY:
1483                                         set_bridge_priority((bridge_id_t *)&bcf.arg1);
1484                                         break;
1485                                 case BRCMD_SET_PORT_PRIORITY:
1486                                         if (port_info[bcf.arg1].dev == 0)
1487                                                 return(-EINVAL);
1488                                         set_port_priority(bcf.arg1, bcf.arg2);
1489                                         break;
1490                                 case BRCMD_SET_PATH_COST:
1491                                         if (port_info[bcf.arg1].dev == 0)
1492                                                 return(-EINVAL);
1493                                         set_path_cost(bcf.arg1, bcf.arg2);
1494                                         break;
1495                                 case BRCMD_ENABLE_DEBUG:
1496                                         br_stats.flags |= BR_DEBUG;
1497                                         break;
1498                                 case BRCMD_DISABLE_DEBUG:
1499                                         br_stats.flags &= ~BR_DEBUG;
1500                                         break;
1501                                 default:
1502                                         return -EINVAL;
1503                         }
1504                         return(0);
1505                 default:
1506                         return -EINVAL;
1507         }
1508         /*NOTREACHED*/
1509         return 0;
1510 }
1511 
1512 int br_cmp(unsigned int *a, unsigned int *b)
     /* [previous][next][first][last][top][bottom][index][help] */
1513 {
1514         int i;  
1515         for (i=0; i<2; i++) 
1516         {
1517                 if (a[i] == b[i])
1518                         continue;
1519                 if (a[i] < b[i])
1520                         return(1);
1521                 if (a[i] > b[i])
1522                         return(-1);
1523         }
1524         return(0);
1525 }
1526                 

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