Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

br.c

Go to the documentation of this file.
00001 /*
00002  *      Linux NET3 Bridge Support
00003  *
00004  *      Originally by John Hayes (Network Plumbing).
00005  *      Minor hacks to get it to run with 1.3.x by Alan Cox <Alan.Cox@linux.org>
00006  *      More hacks to be able to switch protocols on and off by Christoph Lameter
00007  *      <clameter@debian.org>
00008  *      Software and more Documentation for the bridge is available from ftp.debian.org
00009  *      in the bridgex package
00010  *
00011  *      This program is free software; you can redistribute it and/or
00012  *      modify it under the terms of the GNU General Public License
00013  *      as published by the Free Software Foundation; either version
00014  *      2 of the License, or (at your option) any later version.
00015  *
00016  * Fixes:
00017  *      Yury Shevchuk   :       Bridge with non bridging ports
00018  *      Jean-Rene Peulve: jr.peulve@aix.pacwan.net              Jan/Feb 98
00019  *                      support Linux 2.0
00020  *                      Handle Receive config bpdu
00021  *                      kick mark_bh to send Spanning Tree pdus
00022  *                      bridgeId comparison using htonl()
00023  *                      make STP interoperable with other vendors
00024  *                      wrong test in root_selection()
00025  *                      add more STP debug info 
00026  *                      some performance improvments
00027  *                      do not clear bridgeId.mac  while setting priority
00028  *                      do not reset port priority when starting bridge
00029  *                      make port priority from user value and port number
00030  *                      maintains user port state out of device state
00031  *                      broacast/multicast storm limitation
00032  *                      forwarding statistics
00033  *                      stop br_tick when bridge is turn off
00034  *                      add local MACs in avl_tree to forward up stack
00035  *                      fake receive on right port for IP/ARP 
00036  *                      ages tree even if packet does not cross bridge
00037  *                      add BRCMD_DISPLAY_FDB (ioctl for now)
00038  *
00039  *      Alan Cox:       Merged Jean-Rene's stuff, reformatted stuff a bit
00040  *                      so blame me first if its broken ;)
00041  *
00042  *      Robert Pintarelli:      fixed bug in bpdu time values
00043  *
00044  *      Matthew Grant:  start ports disabled.  
00045  *                      auto-promiscuous mode on port enable/disable
00046  *                      fleshed out interface event handling, interfaces 
00047  *                        now register with bridge on module load as well as ifup
00048  *                      port control ioctls with ifindex support
00049  *                      brg0 logical ethernet interface
00050  *                      reworked brcfg to take interface arguments
00051  *                      added support for changing the hardware address
00052  *                      generally made bridge a lot more usable.
00053  *      
00054  *      Todo:
00055  *      Use a netlink notifier so a daemon can maintain the bridge
00056  *      port group (could we also do multiple groups ????).
00057  *              A nice /proc file interface.
00058  *              Put the path costs in the port info and devices.
00059  *              Put the bridge port number in the device structure for speed.
00060  *              Bridge SNMP stats.
00061  *      
00062  */
00063  
00064 #include <linux/config.h>
00065 #include <linux/module.h>
00066 #include <linux/errno.h>
00067 #include <linux/types.h>
00068 #include <linux/socket.h>
00069 #include <linux/in.h>
00070 
00071 #include <linux/kernel.h>
00072 #include <linux/sched.h>
00073 #include <linux/timer.h>
00074 #include <linux/malloc.h>
00075 #include <linux/string.h>
00076 #include <linux/net.h>
00077 #include <linux/inet.h>
00078 #include <linux/netdevice.h>
00079 #include <linux/inetdevice.h>
00080 #include <linux/etherdevice.h>
00081 #include <linux/skbuff.h>
00082 #include <linux/if_arp.h>
00083 #include <linux/ip.h>
00084 #include <linux/version.h>
00085 #include <linux/init.h>
00086 #include <asm/uaccess.h>
00087 #include <asm/system.h>
00088 #include <linux/rtnetlink.h>
00089 #include <net/br.h>
00090 #include <linux/proc_fs.h>
00091 #include <linux/delay.h>
00092 
00093 #ifndef min
00094 #define min(a, b) (((a) <= (b)) ? (a) : (b))
00095 #endif
00096 
00097 static void transmit_config(int port_no);
00098 static int root_bridge(void);
00099 static int supersedes_port_info(int port_no, Config_bpdu *config);
00100 static void record_config_information(int port_no, Config_bpdu *config);
00101 static void record_config_timeout_values(Config_bpdu *config);
00102 static void config_bpdu_generation(void);
00103 static int designated_port(int port_no);
00104 static void reply(int port_no);
00105 static void transmit_tcn(void);
00106 static void configuration_update(void);
00107 static void root_selection(void);
00108 static void designated_port_selection(void);
00109 static void become_designated_port(int port_no);
00110 static void port_state_selection(void);
00111 static void make_forwarding(int port_no);
00112 static void topology_change_detection(void);
00113 static void topology_change_acknowledged(void);
00114 static void acknowledge_topology_change(int port_no);
00115 static void make_blocking(int port_no);
00116 static void set_port_state(int port_no, int state);
00117 static void received_config_bpdu(int port_no, Config_bpdu *config);
00118 static void received_tcn_bpdu(int port_no, Tcn_bpdu *tcn);
00119 static void hello_timer_expiry(void);
00120 static void message_age_timer_expiry(int port_no);
00121 static void forward_delay_timer_expiry(int port_no);
00122 static int designated_for_some_port(void);
00123 static void tcn_timer_expiry(void);
00124 static void topology_change_timer_expiry(void);
00125 static void hold_timer_expiry(int port_no);
00126 static void br_init_port(int port_no);
00127 static void enable_port(int port_no);
00128 static void disable_port(int port_no);
00129 static void set_bridge_priority(bridge_id_t *new_bridge_id);
00130 static void set_port_priority(int port_no);
00131 static void set_path_cost(int port_no, unsigned short path_cost);
00132 static void start_hello_timer(void);
00133 static void stop_hello_timer(void);
00134 static int hello_timer_expired(void);
00135 static void start_tcn_timer(void);
00136 static void stop_tcn_timer(void);
00137 static int tcn_timer_expired(void);
00138 static void start_topology_change_timer(void);
00139 static void stop_topology_change_timer(void);
00140 static int topology_change_timer_expired(void);
00141 static void start_message_age_timer(int port_no, unsigned short message_age);
00142 static void stop_message_age_timer(int port_no);
00143 static int message_age_timer_expired(int port_no);
00144 static void start_forward_delay_timer(int port_no);
00145 static void stop_forward_delay_timer(int port_no);
00146 static int forward_delay_timer_expired(int port_no);
00147 static void start_hold_timer(int port_no);
00148 static void stop_hold_timer(int port_no);
00149 static int hold_timer_expired(int port_no);
00150 static int br_device_event(struct notifier_block *dnot, unsigned long event, void *ptr);
00151 static void br_tick(unsigned long arg);
00152 static int br_forward(struct sk_buff *skb, int port);   /* 3.7 */
00153 static int br_port_cost(struct device *dev);    /* 4.10.2 */
00154 static void br_bpdu(struct sk_buff *skb, int port); /* consumes skb */
00155 static int br_cmp(unsigned int *a, unsigned int *b);
00156 static int send_tcn_bpdu(int port_no, Tcn_bpdu *bpdu);
00157 static int send_config_bpdu(int port_no, Config_bpdu *config_bpdu);
00158 static int find_port(struct device *dev);
00159 static void br_add_local_mac(unsigned char *mac);
00160 static int br_flood(struct sk_buff *skb, int port);
00161 static int br_drop(struct sk_buff *skb);
00162 static int br_learn(struct sk_buff *skb, int port);     /* 3.8 */
00163 static int br_protocol_ok(unsigned short protocol);
00164 static int br_find_port(int ifindex);
00165 static void br_get_ifnames(void);
00166 static int brg_rx(struct sk_buff *skb, int port);
00167 
00168 static unsigned char bridge_ula[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
00169 static Bridge_data     bridge_info;                       /* (4.5.3)     */
00170 Port_data       port_info[All_ports];             /* (4.5.5)     */
00171 
00172 /* MAG: Maximum port registered - used to speed up flooding and to make
00173  * have a large ports array more efficient
00174  */
00175 static int max_port_used = 0; 
00176 
00177 /* JRP: fdb cache 1/port save kmalloc/kfree on every frame */
00178 struct fdb      *newfdb[All_ports];
00179 int allocated_fdb_cnt = 0;
00180 
00181 /* broacast/multicast storm limitation */
00182 int max_mcast_per_period = MAX_MCAST_PER_PERIOD;
00183 int mcast_hold_time      = MCAST_HOLD_TIME;
00184 
00185 /* JRP: next two bpdu are copied to skbuff so we need only 1 of each */
00186 static Config_bpdu      config_bpdu;
00187 static Tcn_bpdu         tcn_bpdu;
00188 static unsigned char    port_priority[All_ports];
00189 static unsigned char    user_port_state[All_ports];
00190 
00191 static Timer    hello_timer;                      /* (4.5.4.1)   */
00192 static Timer    tcn_timer;                        /* (4.5.4.2)   */
00193 static Timer    topology_change_timer;            /* (4.5.4.3)   */
00194 static Timer    message_age_timer[All_ports];     /* (4.5.6.1)   */
00195 static Timer    forward_delay_timer[All_ports];   /* (4.5.6.2)   */
00196 static Timer    hold_timer[All_ports];            /* (4.5.6.3)   */
00197 
00198 /* entries timeout after this many seconds */
00199 unsigned int fdb_aging_time = FDB_TIMEOUT; 
00200 
00201 struct br_stat br_stats;
00202 #define br_stats_cnt br_stats.packet_cnts
00203 
00204 static struct timer_list tl; /* for 1 second timer... */
00205 
00206 /*
00207  * the following structure is required so that we receive
00208  * event notifications when network devices are enabled and
00209  * disabled (ifconfig up and down).
00210  */
00211 static struct notifier_block br_dev_notifier={
00212         br_device_event,
00213         NULL,
00214         0
00215 };
00216 
00217 
00218 /* 
00219  * the following data is for the bridge network device
00220  */
00221 struct brg_if {
00222   struct device dev;
00223   char name[IFNAMSIZ];
00224 };
00225 static struct brg_if brg_if;
00226 
00227 /* 
00228  * Here to save linkage? problems
00229  */
00230 
00231 static inline int find_port(struct device *dev)
00232 {
00233         int i;
00234 
00235         for (i = One; i <= No_of_ports; i++)
00236                 if (port_info[i].dev == dev)
00237                         return(i);
00238         return(0);
00239 }
00240 
00241 /*
00242  * Implementation of Protocol specific bridging
00243  *
00244  * The protocols to be bridged or not to be bridged are stored in a hashed array. This is the old type
00245  * of unlinked hash array where one simply takes the next cell if the one the hash function points to
00246  * is occupied.
00247  */
00248 
00249 #define BR_PROTOCOL_HASH(x) (x % BR_MAX_PROTOCOLS)
00250 
00251 /* Checks if that protocol type is to be bridged */
00252 
00253 static int inline br_protocol_ok(unsigned short protocol)
00254 {
00255         unsigned x;
00256         
00257         /* See if protocol statistics are to be kept */
00258         if (br_stats.flags & BR_PROT_STATS)
00259         {
00260                 for(x=0;x<BR_MAX_PROT_STATS && br_stats.prot_id[x]!=protocol && br_stats.prot_id[x];x++);
00261                 if (x<BR_MAX_PROT_STATS)
00262                 {
00263                         br_stats.prot_id[x]=protocol;br_stats.prot_counter[x]++;
00264                 }
00265         }
00266 
00267         for (x=BR_PROTOCOL_HASH(protocol); br_stats.protocols[x]!=0;) 
00268         {
00269                 if (br_stats.protocols[x]==protocol)
00270                         return !br_stats.policy;
00271                 x++;
00272                 if (x==BR_MAX_PROTOCOLS)
00273                         x=0;
00274         }
00275         return br_stats.policy;
00276 }
00277 
00278 /* Add a protocol to be handled opposite to the standard policy of the bridge */
00279 
00280 static int br_add_exempt_protocol(unsigned short p)
00281 {
00282         unsigned x;
00283         if (p == 0) return -EINVAL;
00284         if (br_stats.exempt_protocols > BR_MAX_PROTOCOLS-2) return -EXFULL;
00285         for (x=BR_PROTOCOL_HASH(p);br_stats.protocols[x]!=0;) {
00286                 if (br_stats.protocols[x]==p) return 0; /* Attempt to add the protocol a second time */
00287                 x++;
00288                 if (x==BR_MAX_PROTOCOLS) x=0;
00289         }
00290         br_stats.protocols[x]=p;
00291         br_stats.exempt_protocols++;
00292         return 0;
00293 }
00294 
00295 /* Valid Policies are 0=No Protocols bridged 1=Bridge all protocols */
00296 static int br_set_policy(int policy)
00297 {
00298         if (policy>1) return -EINVAL;
00299         br_stats.policy=policy;
00300         /* Policy change means initializing the exempt table */
00301         memset(br_stats.protocols,0,sizeof(br_stats.protocols));
00302         br_stats.exempt_protocols = 0;
00303         return 0;
00304 }
00305 
00306 
00307 /** Elements of Procedure (4.6) **/
00308 
00309 /*
00310  * this section of code was graciously borrowed from the IEEE 802.1d
00311  * specification section 4.9.1 starting on pg 69.  It has been
00312  * modified somewhat to fit within our framework and structure.  It
00313  * implements the spanning tree algorithm that is the heart of the
00314  * 802.1d bridging protocol.
00315  */
00316 
00317 static void transmit_config(int port_no)          /* (4.6.1)     */
00318 {
00319         if (hold_timer[port_no].active) {         /* (4.6.1.3.1)         */
00320                 port_info[port_no].config_pending = TRUE;       /* (4.6.1.3.1)   */
00321         } else {                                  /* (4.6.1.3.2)         */
00322                 config_bpdu.type = BPDU_TYPE_CONFIG;
00323                 config_bpdu.root_id = bridge_info.designated_root;
00324                 /* (4.6.1.3.2(1)) */
00325                 config_bpdu.root_path_cost = bridge_info.root_path_cost;
00326                 /* (4.6.1.3.2(2)) */
00327                 config_bpdu.bridge_id = bridge_info.bridge_id;
00328                 /* (4.6.1.3.2(3)) */
00329                 config_bpdu.port_id = port_info[port_no].port_id;
00330                 /*
00331                  * (4.6.1.3.2(4))
00332                  */
00333                 if (root_bridge()) {
00334                         config_bpdu.message_age = Zero; /* (4.6.1.3.2(5)) */
00335                 } else {
00336                         config_bpdu.message_age
00337                                 = (message_age_timer[bridge_info.root_port].value
00338                                 + Message_age_increment) << 8;  /* (4.6.1.3.2(6)) */
00339                 }
00340 
00341                 config_bpdu.max_age = bridge_info.max_age << 8;/* (4.6.1.3.2(7)) */
00342                 config_bpdu.hello_time = bridge_info.hello_time << 8;
00343                 config_bpdu.forward_delay = bridge_info.forward_delay << 8;
00344                 config_bpdu.top_change_ack = 
00345                         port_info[port_no].top_change_ack;
00346                                                         /* (4.6.1.3.2(8)) */
00347                 port_info[port_no].top_change_ack = 0;
00348 
00349                 config_bpdu.top_change = 
00350                         bridge_info.top_change;         /* (4.6.1.3.2(9)) */
00351 
00352                 send_config_bpdu(port_no, &config_bpdu);
00353                 port_info[port_no].config_pending = FALSE;      /* (4.6.1.3.2(10)) */
00354                 start_hold_timer(port_no);        /* (4.6.1.3.2(11)) */
00355         }
00356 /* JRP: we want the frame to be xmitted even if no other traffic.
00357  *      net_bh() will do a dev_transmit() that kicks all devices
00358  */
00359         mark_bh(NET_BH);
00360 }
00361 
00362 static int root_bridge(void)
00363 {
00364         return (br_cmp(bridge_info.designated_root.BRIDGE_ID,
00365                  bridge_info.bridge_id.BRIDGE_ID)?FALSE:TRUE);
00366 }
00367 
00368 static int supersedes_port_info(int port_no, Config_bpdu *config)         /* (4.6.2.2)   */
00369 {
00370         return (
00371                 (br_cmp(config->root_id.BRIDGE_ID,
00372                  port_info[port_no].designated_root.BRIDGE_ID) < 0)     /* (4.6.2.2.1)   */ 
00373                 ||
00374                 ((br_cmp(config->root_id.BRIDGE_ID,
00375                   port_info[port_no].designated_root.BRIDGE_ID) == 0
00376                   )
00377                  &&
00378                  ((config->root_path_cost
00379                    < port_info[port_no].designated_cost /* (4.6.2.2.2)   */
00380                    )
00381                   ||
00382                   ((config->root_path_cost
00383                     == port_info[port_no].designated_cost
00384                     )
00385                    &&
00386                    ((br_cmp(config->bridge_id.BRIDGE_ID,
00387                      port_info[port_no].designated_bridge.BRIDGE_ID) < 0        /* (4.6.2.2.3)    */
00388                      )
00389                     ||
00390                     ((br_cmp(config->bridge_id.BRIDGE_ID,
00391                       port_info[port_no].designated_bridge.BRIDGE_ID) == 0
00392                       )                           /* (4.6.2.2.4)         */
00393                      &&
00394                      ((br_cmp(config->bridge_id.BRIDGE_ID,
00395                         bridge_info.bridge_id.BRIDGE_ID) != 0
00396                        )                          /* (4.6.2.2.4(1)) */
00397                       ||
00398                       (config->port_id <=
00399                        port_info[port_no].designated_port
00400                        )                          /* (4.6.2.2.4(2)) */
00401                       ))))))
00402                 );
00403 }
00404 
00405 static void record_config_information(int port_no, Config_bpdu *config)   /* (4.6.2)     */
00406 {
00407         port_info[port_no].designated_root = config->root_id;   /* (4.6.2.3.1)   */
00408         port_info[port_no].designated_cost = config->root_path_cost;
00409         port_info[port_no].designated_bridge = config->bridge_id;
00410         port_info[port_no].designated_port = config->port_id;
00411         start_message_age_timer(port_no, config->message_age);  /* (4.6.2.3.2)   */
00412 }
00413 
00414 static void record_config_timeout_values(Config_bpdu *config)             /* (4.6.3)     */
00415 {
00416         bridge_info.max_age = config->max_age >> 8;       /* (4.6.3.3)   */
00417         bridge_info.hello_time = config->hello_time >> 8;
00418         bridge_info.forward_delay = config->forward_delay >> 8;
00419         bridge_info.top_change = config->top_change >> 8;
00420 }
00421 
00422 static void config_bpdu_generation(void)
00423 {                                                 /* (4.6.4)     */
00424         int             port_no;
00425         for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.6.4.3) */
00426                 if (designated_port(port_no)      /* (4.6.4.3)   */
00427                                 &&
00428                                 (port_info[port_no].state != Disabled)
00429                         ) {
00430                         transmit_config(port_no); /* (4.6.4.3)   */
00431                 }                                 /* (4.6.1.2)   */
00432         }
00433 }
00434 
00435 static int designated_port(int port_no)
00436 {
00437         return ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
00438                  bridge_info.bridge_id.BRIDGE_ID) == 0
00439                  )
00440                 &&
00441                 (port_info[port_no].designated_port
00442                  == port_info[port_no].port_id
00443                  )
00444                 );
00445 }
00446 
00447 static void reply(int port_no)                                    /* (4.6.5)     */
00448 {
00449         transmit_config(port_no);                 /* (4.6.5.3)   */
00450 }
00451 
00452 static void transmit_tcn(void)
00453 {                                                 /* (4.6.6)     */
00454         int             port_no;
00455 
00456         port_no = bridge_info.root_port;
00457         tcn_bpdu.type = BPDU_TYPE_TOPO_CHANGE;
00458         send_tcn_bpdu(port_no, &tcn_bpdu);      /* (4.6.6.3)     */
00459 }
00460 
00461 static void configuration_update(void)  /* (4.6.7) */
00462 {
00463         root_selection();                         /* (4.6.7.3.1)         */
00464         /* (4.6.8.2)     */
00465         designated_port_selection();              /* (4.6.7.3.2)         */
00466         /* (4.6.9.2)     */
00467 }
00468 
00469 static void root_selection(void)
00470 {                                                 /* (4.6.8) */
00471         int             root_port;
00472         int             port_no;
00473         root_port = No_port;
00474         for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.6.8.3.1) */
00475                 if (((!designated_port(port_no))
00476                      &&
00477                      (port_info[port_no].state != Disabled)
00478                      &&
00479                 (br_cmp(port_info[port_no].designated_root.BRIDGE_ID,
00480                         bridge_info.bridge_id.BRIDGE_ID) < 0)
00481                         )
00482                                 &&
00483                                 ((root_port == No_port)
00484                                  ||
00485                                  (br_cmp(port_info[port_no].designated_root.BRIDGE_ID,
00486                                   port_info[root_port].designated_root.BRIDGE_ID) < 0
00487                                   )
00488                                  ||
00489                                  ((br_cmp(port_info[port_no].designated_root.BRIDGE_ID,
00490                                    port_info[root_port].designated_root.BRIDGE_ID) == 0
00491                                    )
00492                                   &&
00493                                   (((port_info[port_no].designated_cost
00494                                      + port_info[port_no].path_cost
00495                                      )
00496                                     <
00497                                     (port_info[root_port].designated_cost
00498                                      + port_info[root_port].path_cost
00499                                      )            /* (4.6.8.3.1(2)) */
00500                                     )
00501                                    ||
00502                                    (((port_info[port_no].designated_cost
00503                                       + port_info[port_no].path_cost
00504                                       )
00505                                      ==
00506                                      (port_info[root_port].designated_cost
00507                                       + port_info[root_port].path_cost
00508                                       )
00509                                      )
00510                                     &&
00511                                     ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
00512                                     port_info[root_port].designated_bridge.BRIDGE_ID) < 0
00513                                       )           /* (4.6.8.3.1(3)) */
00514                                      ||
00515                                      ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
00516                                    port_info[root_port].designated_bridge.BRIDGE_ID) == 0
00517                                        )
00518                                       &&
00519                                       ((port_info[port_no].designated_port
00520                                       < port_info[root_port].designated_port
00521                                         )         /* (4.6.8.3.1(4)) */
00522                                        ||
00523                                        ((port_info[port_no].designated_port
00524 /* JRP: was missing an "=" ! */       == port_info[root_port].designated_port
00525                                          )
00526                                         &&
00527                                         (port_info[port_no].port_id
00528                                          < port_info[root_port].port_id
00529                                          )        /* (4.6.8.3.1(5)) */
00530                                         ))))))))) {
00531                         root_port = port_no;
00532                 }
00533         }
00534         bridge_info.root_port = root_port;        /* (4.6.8.3.1)         */
00535 
00536         if (root_port == No_port) {               /* (4.6.8.3.2)         */
00537 #ifdef DEBUG_STP
00538                 if (br_stats.flags & BR_DEBUG)
00539                         printk(KERN_DEBUG "root_selection: becomes root\n");
00540 #endif
00541                 bridge_info.designated_root = bridge_info.bridge_id;
00542                 /* (4.6.8.3.2(1)) */
00543                 bridge_info.root_path_cost = Zero;/* (4.6.8.3.2(2)) */
00544         } else {                                  /* (4.6.8.3.3)         */
00545                 bridge_info.designated_root = port_info[root_port].designated_root;
00546                 /* (4.6.8.3.3(1)) */
00547                 bridge_info.root_path_cost = (port_info[root_port].designated_cost
00548                                             + port_info[root_port].path_cost
00549                         );                        /* (4.6.8.3.3(2)) */
00550         }
00551 }
00552 
00553 static void designated_port_selection(void)
00554 {                                                 /* (4.6.9)     */
00555         int             port_no;
00556 
00557         for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.6.9.3)     */
00558                 if(port_info[port_no].state == Disabled)
00559                         continue;
00560                 if (designated_port(port_no)      /* (4.6.9.3.1)         */
00561                                 ||
00562                                 (
00563                                  br_cmp(port_info[port_no].designated_root.BRIDGE_ID,
00564                                  bridge_info.designated_root.BRIDGE_ID) != 0
00565                                  )
00566                                 ||
00567                                 (bridge_info.root_path_cost
00568                                  < port_info[port_no].designated_cost
00569                                  )                /* (4.6.9.3.3)         */
00570                                 ||
00571                                 ((bridge_info.root_path_cost
00572                                   == port_info[port_no].designated_cost
00573                                   )
00574                                  &&
00575                                  ((br_cmp(bridge_info.bridge_id.BRIDGE_ID,
00576                                    port_info[port_no].designated_bridge.BRIDGE_ID) < 0
00577                                    )              /* (4.6.9.3.4)         */
00578                                   ||
00579                                   ((br_cmp(bridge_info.bridge_id.BRIDGE_ID,
00580                                     port_info[port_no].designated_bridge.BRIDGE_ID) == 0
00581                                     )
00582                                    &&
00583                                    (port_info[port_no].port_id
00584                                     <= port_info[port_no].designated_port
00585                                     )             /* (4.6.9.3.5)         */
00586                                    )))) {
00587                         become_designated_port(port_no);        /* (4.6.10.3.2.2) */
00588                 }
00589         }
00590 }
00591 
00592 static void become_designated_port(int port_no)
00593 {                                                 /* (4.6.10)    */
00594 
00595         /* (4.6.10.3.1) */
00596         port_info[port_no].designated_root = bridge_info.designated_root;
00597         /* (4.6.10.3.2) */
00598         port_info[port_no].designated_cost = bridge_info.root_path_cost;
00599         /* (4.6.10.3.3) */
00600         port_info[port_no].designated_bridge = bridge_info.bridge_id;
00601         /* (4.6.10.3.4) */
00602         port_info[port_no].designated_port = port_info[port_no].port_id;
00603 }
00604 
00605 static void port_state_selection(void)
00606 {                                                 /* (4.6.11) */
00607         int             port_no;
00608         char            *state_str;
00609         for (port_no = One; port_no <= No_of_ports; port_no++) {
00610 
00611                 if(port_info[port_no].state == Disabled)
00612                         continue;
00613                 if (port_no == bridge_info.root_port) { /* (4.6.11.3.1) */
00614                         state_str = "root";
00615                         port_info[port_no].config_pending = FALSE;      /* (4.6.11.3.1(1)) */
00616                         port_info[port_no].top_change_ack = 0;
00617                         make_forwarding(port_no); /* (4.6.11.3.1(2)) */
00618                 } else if (designated_port(port_no)) {  /* (4.6.11.3.2) */
00619                         state_str = "designated";
00620                         stop_message_age_timer(port_no);        /* (4.6.11.3.2(1)) */
00621                         make_forwarding(port_no); /* (4.6.11.3.2(2)) */
00622                 } else {                          /* (4.6.11.3.3) */
00623                         state_str = "blocking";
00624                         port_info[port_no].config_pending = FALSE;      /* (4.6.11.3.3(1)) */
00625                         port_info[port_no].top_change_ack = 0;
00626                         make_blocking(port_no);   /* (4.6.11.3.3(2)) */
00627                 }
00628 #ifdef DEBUG_STP
00629                 if (br_stats.flags & BR_DEBUG)
00630                         printk(KERN_DEBUG "port_state_selection: becomes %s port %d\n",
00631                                 state_str, port_no);
00632 #endif
00633                 
00634         }
00635 
00636 }
00637 
00638 static void make_forwarding(int port_no)
00639 {                                                 /* (4.6.12) */
00640         if (port_info[port_no].state == Blocking) {     /* (4.6.12.3) */
00641                 set_port_state(port_no, Listening);     /* (4.6.12.3.1) */
00642                 start_forward_delay_timer(port_no);     /* (4.6.12.3.2) */
00643         }
00644 }
00645 
00646 static void topology_change_detection(void)
00647 {                                                 /* (4.6.14)       */
00648 #ifdef DEBUG_STP
00649         if ((br_stats.flags & BR_DEBUG)
00650             && (bridge_info.top_change_detected == 0))
00651                 printk(KERN_DEBUG "topology_change_detected\n");
00652 #endif
00653         if (root_bridge()) {                      /* (4.6.14.3.1)   */
00654                 bridge_info.top_change = 1;
00655                 start_topology_change_timer();    /* (4.6.14.3.1(2)) */
00656         } else if (!(bridge_info.top_change_detected)) {
00657                 transmit_tcn();                   /* (4.6.14.3.2(1)) */
00658                 start_tcn_timer();                /* (4.6.14.3.2(2)) */
00659         }
00660         bridge_info.top_change_detected = 1;    /* (4.6.14.3.3) */
00661 }
00662 
00663 static void topology_change_acknowledged(void)
00664 {                                                 /* (4.6.15) */
00665 #ifdef DEBUG_STP
00666         if (br_stats.flags & BR_DEBUG)
00667                 printk(KERN_DEBUG "topology_change_acked\n");
00668 #endif
00669         bridge_info.top_change_detected = 0;    /* (4.6.15.3.1) */
00670         stop_tcn_timer();                         /* (4.6.15.3.2) */
00671 }
00672 
00673 static void acknowledge_topology_change(int port_no)
00674 {                                                 /* (4.6.16) */
00675         port_info[port_no].top_change_ack = 1;
00676         transmit_config(port_no);                 /* (4.6.16.3.2) */
00677 }
00678 
00679 static void make_blocking(int port_no)                            /* (4.6.13)    */
00680 {
00681 
00682         if ((port_info[port_no].state != Disabled)
00683                         &&
00684                         (port_info[port_no].state != Blocking)
00685         /* (4.6.13.3)    */
00686                 ) {
00687                 if ((port_info[port_no].state == Forwarding)
00688                                 ||
00689                                 (port_info[port_no].state == Learning)
00690                         ) {
00691                         topology_change_detection();    /* (4.6.13.3.1) */
00692                         /* (4.6.14.2.3)  */
00693                 }
00694                 set_port_state(port_no, Blocking);/* (4.6.13.3.2) */
00695                 stop_forward_delay_timer(port_no);/* (4.6.13.3.3) */
00696         }
00697 }
00698 
00699 static void set_port_state(int port_no, int state)
00700 {
00701         port_info[port_no].state = state;
00702 }
00703 
00704 static void received_config_bpdu(int port_no, Config_bpdu *config)                /* (4.7.1)     */
00705 {
00706         int root;
00707 
00708         root = root_bridge();
00709         if (port_info[port_no].state != Disabled) {
00710 
00711 #ifdef DEBUG_STP
00712                 if (br_stats.flags & BR_DEBUG)
00713                         printk(KERN_DEBUG "received_config_bpdu: port %d\n",
00714                                 port_no);
00715 #endif
00716                 if (supersedes_port_info(port_no, config)) {    /* (4.7.1.1)     *//* (4.
00717                                                                  * 6.2.2)        */
00718                         record_config_information(port_no, config);     /* (4.7.1.1.1)   */
00719                         /* (4.6.2.2)     */
00720                         configuration_update();   /* (4.7.1.1.2)         */
00721                         /* (4.6.7.2.1)   */
00722                         port_state_selection();   /* (4.7.1.1.3)         */
00723                         /* (4.6.11.2.1)  */
00724                         if ((!root_bridge()) && root) { /* (4.7.1.1.4)   */
00725                                 stop_hello_timer();
00726                                 if (bridge_info.top_change_detected) {  /* (4.7.1.1.5 */
00727                                         stop_topology_change_timer();
00728                                         transmit_tcn(); /* (4.6.6.1)     */
00729                                         start_tcn_timer();
00730                                 }
00731                         }
00732                         if (port_no == bridge_info.root_port) {
00733                                 record_config_timeout_values(config);   /* (4.7.1.1.6)   */
00734                                 /* (4.6.3.2)     */
00735                                 config_bpdu_generation();       /* (4.6.4.2.1)   */
00736                                 if (config->top_change_ack) {   /* (4.7.1.1.7)    */
00737                                         topology_change_acknowledged(); /* (4.6.15.2)    */
00738                                 }
00739                         }
00740                 } else if (designated_port(port_no)) {  /* (4.7.1.2)     */
00741                         reply(port_no);           /* (4.7.1.2.1)         */
00742                         /* (4.6.5.2)     */
00743                 }
00744         }
00745 }
00746 
00747 static void received_tcn_bpdu(int port_no, Tcn_bpdu *tcn)                         /* (4.7.2)     */
00748 {
00749         if (port_info[port_no].state != Disabled) {
00750 #ifdef DEBUG_STP
00751                 if (br_stats.flags & BR_DEBUG)
00752                         printk(KERN_DEBUG "received_tcn_bpdu: port %d\n",
00753                                 port_no);
00754 #endif
00755                 if (designated_port(port_no)) {
00756                         topology_change_detection();    /* (4.7.2.1)     */
00757                         /* (4.6.14.2.1)  */
00758                         acknowledge_topology_change(port_no);   /* (4.7.2.2)     */
00759                 }                                 /* (4.6.16.2)  */
00760         }
00761 }
00762 
00763 static void hello_timer_expiry(void)
00764 {                                                 /* (4.7.3)     */
00765         config_bpdu_generation();                 /* (4.6.4.2.2)         */
00766         start_hello_timer();
00767 }
00768 
00769 static void message_age_timer_expiry(int port_no) /* (4.7.4)     */
00770 {
00771         int root;
00772         root = root_bridge();
00773 
00774 #ifdef DEBUG_STP
00775         if (br_stats.flags & BR_DEBUG)
00776                 printk(KERN_DEBUG "message_age_timer_expiry: port %d\n",
00777                         port_no);
00778 #endif
00779         become_designated_port(port_no);          /* (4.7.4.1)   */
00780         /* (4.6.10.2.1)  */
00781         configuration_update();                   /* (4.7.4.2)   */
00782         /* (4.6.7.2.2)   */
00783         port_state_selection();                   /* (4.7.4.3)   */
00784         /* (4.6.11.2.2)  */
00785         if ((root_bridge()) && (!root)) {         /* (4.7.4.4)   */
00786 
00787                 bridge_info.max_age = bridge_info.bridge_max_age;       /* (4.7.4.4.1)    */
00788                 bridge_info.hello_time = bridge_info.bridge_hello_time;
00789                 bridge_info.forward_delay = bridge_info.bridge_forward_delay;
00790                 topology_change_detection();      /* (4.7.4.4.2)         */
00791                 /* (4.6.14.2.4)  */
00792                 stop_tcn_timer();                 /* (4.7.4.4.3)         */
00793                 config_bpdu_generation();         /* (4.7.4.4.4)         */
00794                 /* (4.6.4.4.3)   */
00795                 start_hello_timer();
00796         }
00797 }
00798 
00799 static void forward_delay_timer_expiry(int port_no)     /* (4.7.5)       */
00800 {
00801         if (port_info[port_no].state == Listening) 
00802         {                                               /* (4.7.5.1)     */
00803                 set_port_state(port_no, Learning);      /* (4.7.5.1.1)   */
00804                 start_forward_delay_timer(port_no);     /* (4.7.5.1.2)   */
00805         }
00806         else if (port_info[port_no].state == Learning) 
00807         {
00808                                                         /* (4.7.5.2) */
00809                 set_port_state(port_no, Forwarding);    /* (4.7.5.2.1) */
00810                 if (designated_for_some_port()) 
00811                 {                                       /* (4.7.5.2.2) */
00812                         topology_change_detection();    /* (4.6.14.2.2) */
00813 
00814                 }
00815         }
00816 }
00817 
00818 static int designated_for_some_port(void)
00819 {
00820         int port_no;
00821 
00822         for (port_no = One; port_no <= No_of_ports; port_no++) 
00823         {
00824                 if(port_info[port_no].state == Disabled)
00825                         continue;
00826                 if ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
00827                                 bridge_info.bridge_id.BRIDGE_ID) == 0)) 
00828                 {
00829                         return (TRUE);
00830                 }
00831         }
00832         return (FALSE);
00833 }
00834 
00835 static void tcn_timer_expiry(void)
00836 {                                                 /* (4.7.6)     */
00837         transmit_tcn();                           /* (4.7.6.1)   */
00838         start_tcn_timer();                        /* (4.7.6.2)   */
00839 }
00840 
00841 static void topology_change_timer_expiry(void)
00842 {                                                 /* (4.7.7)     */
00843         bridge_info.top_change_detected = 0;    /* (4.7.7.1) */
00844         bridge_info.top_change = 0;
00845           /* (4.7.7.2)   */
00846 }
00847 
00848 static void hold_timer_expiry(int port_no)        /* (4.7.8)     */
00849 {
00850         if (port_info[port_no].config_pending) 
00851         {
00852                 transmit_config(port_no);         /* (4.7.8.1)   */
00853         }                                         /* (4.6.1.2.3)         */
00854 }
00855 
00856 /* Vova Oksman: Write the buffer (contents of the Bridge table) */
00857 /* to a PROCfs file                                             */
00858 int br_tree_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
00859 {
00860         int size;
00861         int len=0;
00862         off_t pos=0;
00863         char* pbuffer;
00864 
00865         if(0==offset)
00866         {
00867                 /* first time write the header */
00868                 size = sprintf(buffer,"%s","MAC address           Device     Flags     Age (sec.)\n");
00869                 len=size;
00870         }
00871 
00872         pbuffer=&buffer[len];
00873         sprintf_avl(&pbuffer,NULL,&pos,&len,offset,length);
00874 
00875         *start = buffer+len-(pos-offset);       /* Start of wanted data */
00876         len = pos-offset;                       /* Start slop */
00877         if (len>length)
00878                 len = length;                   /* Ending slop */
00879 
00880         return len;
00881 }
00882 #ifdef CONFIG_PROC_FS
00883 struct proc_dir_entry proc_net_bridge= {
00884         PROC_NET_BRIDGE, 6, "bridge",
00885         S_IFREG | S_IRUGO, 1, 0, 0,
00886         0, &proc_net_inode_operations,
00887         br_tree_get_info
00888 };
00889 #endif
00890 __initfunc(void br_init(void))
00891 {                                                 /* (4.8.1)     */
00892         int port_no;
00893 
00894         printk(KERN_INFO "NET4: Ethernet Bridge 007 for NET4.0\n");
00895 
00896         /* Set up brg device information */
00897         bridge_info.instance = 0;
00898         brg_init();
00899 
00900         max_port_used = 0;
00901         
00902         /*
00903          * Form initial topology change time.
00904          * The topology change timer is only used if this is the root bridge.
00905          */
00906         
00907         bridge_info.topology_change_time = BRIDGE_MAX_AGE + BRIDGE_FORWARD_DELAY;       /* (4.5.3.13) */
00908 
00909         bridge_info.designated_root = bridge_info.bridge_id;    /* (4.8.1.1)     */
00910         bridge_info.root_path_cost = Zero;
00911         bridge_info.root_port = No_port;
00912 #ifdef DEBUG_STP
00913         printk(KERN_INFO "br_init: becomes root\n");
00914 #endif
00915 
00916         bridge_info.bridge_max_age = BRIDGE_MAX_AGE;
00917         bridge_info.bridge_hello_time = BRIDGE_HELLO_TIME;
00918         bridge_info.bridge_forward_delay = BRIDGE_FORWARD_DELAY;
00919         bridge_info.hold_time = HOLD_TIME;
00920 
00921         bridge_info.max_age = bridge_info.bridge_max_age;       /* (4.8.1.2)     */
00922         bridge_info.hello_time = bridge_info.bridge_hello_time;
00923         bridge_info.forward_delay = bridge_info.bridge_forward_delay;
00924 
00925         bridge_info.top_change_detected = 0;
00926         bridge_info.top_change = 0;
00927         stop_tcn_timer();
00928         stop_topology_change_timer();
00929         memset(newfdb, 0, sizeof(newfdb));
00930         for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.8.1.4) */
00931                 /* initial state = Disable */
00932                 user_port_state[port_no] = Disabled;
00933                 port_priority[port_no] = 128;
00934                 br_init_port(port_no);
00935                 disable_port(port_no);
00936         }
00937 #if 0 /* JRP: We are not UP ! Wait for the start command */
00938         port_state_selection();                   /* (4.8.1.5)   */
00939         config_bpdu_generation();                 /* (4.8.1.6)   */
00940         /* initialize system timer */
00941         tl.expires = jiffies+HZ;        /* 1 second */
00942         tl.function = br_tick;
00943         add_timer(&tl);
00944 #endif  
00945 
00946         register_netdevice_notifier(&br_dev_notifier);
00947         br_stats.flags = 0; /*BR_UP | BR_DEBUG*/;       /* enable bridge */
00948         br_stats.policy = BR_ACCEPT;                    /* Enable bridge to accpet all protocols */
00949         br_stats.exempt_protocols = 0;
00950         /*start_hello_timer();*/
00951         /* Vova Oksman: register the function for the PROCfs "bridge" file */
00952 #ifdef CONFIG_PROC_FS
00953         proc_net_register(&proc_net_bridge);
00954 #endif
00955 }
00956 
00957 static inline unsigned short make_port_id(int port_no)
00958 {
00959          return (port_priority[port_no] << 8) | port_no;
00960 }
00961 
00962 static void br_init_port(int port_no)
00963 {
00964         port_info[port_no].port_id = make_port_id(port_no);
00965         become_designated_port(port_no);          /* (4.8.1.4.1) */
00966         set_port_state(port_no, Blocking);        /* (4.8.1.4.2)    */
00967         port_info[port_no].top_change_ack = 0;
00968         port_info[port_no].config_pending = FALSE;/* (4.8.1.4.4)         */
00969         stop_message_age_timer(port_no);          /* (4.8.1.4.5)         */
00970         stop_forward_delay_timer(port_no);        /* (4.8.1.4.6)         */
00971         stop_hold_timer(port_no);                 /* (4.8.1.4.7)         */
00972 }
00973 
00974 static void enable_port(int port_no)                              /* (4.8.2)     */
00975 {
00976         br_init_port(port_no);
00977         port_state_selection();                   /* (4.8.2.7)   */
00978 }                                                 /* */
00979 
00980 static void disable_port(int port_no)                             /* (4.8.3)     */
00981 {
00982         int         root;
00983 
00984         root = root_bridge();
00985         become_designated_port(port_no);          /* (4.8.3.1)   */
00986         set_port_state(port_no, Disabled);        /* (4.8.3.2)   */
00987         port_info[port_no].top_change_ack = 0;
00988         port_info[port_no].config_pending = FALSE;/* (4.8.3.4)   */
00989         stop_message_age_timer(port_no);          /* (4.8.3.5)   */
00990         stop_forward_delay_timer(port_no);        /* (4.8.3.6)   */
00991         configuration_update();
00992         port_state_selection();                   /* (4.8.3.7)   */
00993         if ((root_bridge()) && (!root)) {         /* (4.8.3.8)   */
00994                 bridge_info.max_age = bridge_info.bridge_max_age;       /* (4.8.3.8.1)    */
00995                 bridge_info.hello_time = bridge_info.bridge_hello_time;
00996                 bridge_info.forward_delay = bridge_info.bridge_forward_delay;
00997                 topology_change_detection();      /* (4.8.3.8.2)    */
00998                 stop_tcn_timer();                 /* (4.8.3.8.3)    */
00999                 config_bpdu_generation();         /* (4.8.3.8.4)    */
01000                 start_hello_timer();
01001         }
01002 }
01003 
01004 
01005 static void set_bridge_priority(bridge_id_t *new_bridge_id)
01006                                                   /* (4.8.4)     */
01007 {
01008 
01009         int root;
01010         int port_no;
01011         root = root_bridge();
01012         for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.8.4.2) */
01013                 if(port_info[port_no].state == Disabled)
01014                         continue;
01015                 if (designated_port(port_no)) {
01016                         port_info[port_no].designated_bridge = *new_bridge_id;
01017                 }
01018         }
01019 
01020         bridge_info.bridge_id = *new_bridge_id;   /* (4.8.4.3)   */
01021         configuration_update();                   /* (4.8.4.4)   */
01022         port_state_selection();                   /* (4.8.4.5)   */
01023         if ((root_bridge()) && (!root)) {         /* (4.8.4.6)   */
01024                 bridge_info.max_age = bridge_info.bridge_max_age;       /* (4.8.4.6.1)    */
01025                 bridge_info.hello_time = bridge_info.bridge_hello_time;
01026                 bridge_info.forward_delay = bridge_info.bridge_forward_delay;
01027                 topology_change_detection();      /* (4.8.4.6.2)    */
01028                 stop_tcn_timer();                 /* (4.8.4.6.3)    */
01029                 config_bpdu_generation(),         /* (4.8.4.6.4)    */
01030                 start_hello_timer();
01031         }
01032 }
01033 
01034 static void set_port_priority(int port_no)
01035                                                   /* (4.8.5)     */
01036 {int new_port_id = make_port_id(port_no);
01037 
01038         if (designated_port(port_no)) {           /* (4.8.5.2)   */
01039                 port_info[port_no].designated_port = new_port_id;
01040         }
01041         port_info[port_no].port_id = new_port_id; /* (4.8.5.3)   */
01042         if ((br_cmp(bridge_info.bridge_id.BRIDGE_ID,
01043              port_info[port_no].designated_bridge.BRIDGE_ID) == 0
01044              )
01045                         &&
01046                         (port_info[port_no].port_id
01047                          < port_info[port_no].designated_port
01048 
01049                          )
01050                 ) 
01051         {
01052                 become_designated_port(port_no);  /* (4.8.5.4.1) */
01053                 port_state_selection();           /* (4.8.5.4.2) */
01054         }
01055 }
01056 
01057 static void set_path_cost(int port_no, unsigned short path_cost)
01058                                                   /* (4.8.6)     */
01059 {
01060         port_info[port_no].path_cost = path_cost; /* (4.8.6.1)   */
01061         configuration_update();                   /* (4.8.6.2)   */
01062         port_state_selection();                   /* (4.8.6.3)   */
01063 }
01064 
01065 static void br_tick(unsigned long arg)
01066 {
01067         int port_no;
01068 
01069         if(!(br_stats.flags & BR_UP))
01070                 return;                  /* JRP: we have been shot down */
01071 
01072         if (hello_timer_expired())
01073                 hello_timer_expiry();
01074 
01075         if (tcn_timer_expired())
01076                 tcn_timer_expiry();
01077 
01078         if (topology_change_timer_expired())
01079                 topology_change_timer_expiry();
01080 
01081         for (port_no = One; port_no <= No_of_ports; port_no++) 
01082         {
01083                 if(port_info[port_no].state == Disabled)
01084                         continue;
01085 
01086                 if (forward_delay_timer_expired(port_no)) 
01087                         forward_delay_timer_expiry(port_no);
01088 
01089                 if (message_age_timer_expired(port_no))
01090                         message_age_timer_expiry(port_no);
01091 
01092                 if (hold_timer_expired(port_no))
01093                         hold_timer_expiry(port_no);
01094         }
01095         /* call me again sometime... */
01096         tl.expires = jiffies+HZ;        /* 1 second */
01097         tl.function = br_tick;
01098         add_timer(&tl);
01099 }
01100 
01101 static void start_hello_timer(void)
01102 {
01103         hello_timer.value = 0;
01104         hello_timer.active = TRUE;
01105 }
01106 
01107 static void stop_hello_timer(void)
01108 {
01109         hello_timer.active = FALSE;
01110 }
01111 
01112 static int hello_timer_expired(void)
01113 {
01114         if (hello_timer.active && (++hello_timer.value >= bridge_info.hello_time)) 
01115         {
01116                 hello_timer.active = FALSE;
01117                 return (TRUE);
01118         }
01119         return (FALSE);
01120 }
01121 
01122 static void start_tcn_timer(void)
01123 {
01124         tcn_timer.value = 0;
01125         tcn_timer.active = TRUE;
01126 }
01127 
01128 static void stop_tcn_timer(void)
01129 {
01130         tcn_timer.active = FALSE;
01131 }
01132 
01133 static int tcn_timer_expired(void)
01134 {
01135         if (tcn_timer.active && (++tcn_timer.value >= bridge_info.bridge_hello_time)) 
01136         {
01137                 tcn_timer.active = FALSE;
01138                 return (TRUE);
01139         }
01140         return (FALSE);
01141 
01142 }
01143 
01144 static void start_topology_change_timer(void)
01145 {
01146         topology_change_timer.value = 0;
01147         topology_change_timer.active = TRUE;
01148 }
01149 
01150 static void stop_topology_change_timer(void)
01151 {
01152         topology_change_timer.