1 /* $NetBSD: bridgestp.c,v 1.5 2003/11/28 08:56:48 keihan Exp $ */ 2 3 /* 4 * Copyright (c) 2000 Jason L. Wright (jason@thought.net) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 * 28 * OpenBSD: bridgestp.c,v 1.5 2001/03/22 03:48:29 jason Exp 29 */ 30 31 /* 32 * Implementation of the spanning tree protocol as defined in 33 * ISO/IEC Final DIS 15802-3 (IEEE P802.1D/D17), May 25, 1998. 34 * (In English: IEEE 802.1D, Draft 17, 1998) 35 */ 36 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/mbuf.h> 43 #include <sys/socket.h> 44 #include <sys/sockio.h> 45 #include <sys/kernel.h> 46 #include <sys/callout.h> 47 #include <sys/module.h> 48 #include <sys/proc.h> 49 #include <sys/lock.h> 50 #include <sys/mutex.h> 51 #include <sys/taskqueue.h> 52 53 #include <net/if.h> 54 #include <net/if_dl.h> 55 #include <net/if_types.h> 56 #include <net/if_llc.h> 57 #include <net/if_media.h> 58 59 #include <netinet/in.h> 60 #include <netinet/in_systm.h> 61 #include <netinet/in_var.h> 62 #include <netinet/if_ether.h> 63 #include <net/bridgestp.h> 64 65 const uint8_t bstp_etheraddr[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; 66 67 LIST_HEAD(, bstp_state) bstp_list; 68 static struct mtx bstp_list_mtx; 69 70 static void bstp_initialize_port(struct bstp_state *, 71 struct bstp_port *); 72 static void bstp_ifupdstatus(struct bstp_state *, struct bstp_port *); 73 static void bstp_enable_port(struct bstp_state *, struct bstp_port *); 74 static void bstp_disable_port(struct bstp_state *, 75 struct bstp_port *); 76 #ifdef notused 77 static void bstp_enable_change_detection(struct bstp_port *); 78 static void bstp_disable_change_detection(struct bstp_port *); 79 #endif /* notused */ 80 static int bstp_root_bridge(struct bstp_state *bs); 81 static int bstp_supersedes_port_info(struct bstp_state *, 82 struct bstp_port *, struct bstp_config_unit *); 83 static int bstp_designated_port(struct bstp_state *, 84 struct bstp_port *); 85 static int bstp_designated_for_some_port(struct bstp_state *); 86 static void bstp_transmit_config(struct bstp_state *, 87 struct bstp_port *); 88 static void bstp_transmit_tcn(struct bstp_state *); 89 static void bstp_received_config_bpdu(struct bstp_state *, 90 struct bstp_port *, struct bstp_config_unit *); 91 static void bstp_received_tcn_bpdu(struct bstp_state *, 92 struct bstp_port *, struct bstp_tcn_unit *); 93 static void bstp_record_config_information(struct bstp_state *, 94 struct bstp_port *, struct bstp_config_unit *); 95 static void bstp_record_config_timeout_values(struct bstp_state *, 96 struct bstp_config_unit *); 97 static void bstp_config_bpdu_generation(struct bstp_state *); 98 static void bstp_send_config_bpdu(struct bstp_state *, 99 struct bstp_port *, struct bstp_config_unit *); 100 static void bstp_configuration_update(struct bstp_state *); 101 static void bstp_root_selection(struct bstp_state *); 102 static void bstp_designated_port_selection(struct bstp_state *); 103 static void bstp_become_designated_port(struct bstp_state *, 104 struct bstp_port *); 105 static void bstp_port_state_selection(struct bstp_state *); 106 static void bstp_make_forwarding(struct bstp_state *, 107 struct bstp_port *); 108 static void bstp_make_blocking(struct bstp_state *, 109 struct bstp_port *); 110 static void bstp_set_port_state(struct bstp_port *, uint8_t); 111 static void bstp_state_change(void *, int); 112 static void bstp_update_forward_transitions(struct bstp_port *); 113 #ifdef notused 114 static void bstp_set_bridge_priority(struct bstp_state *, uint64_t); 115 static void bstp_set_port_priority(struct bstp_state *, 116 struct bstp_port *, uint16_t); 117 static void bstp_set_path_cost(struct bstp_state *, 118 struct bstp_port *, uint32_t); 119 #endif /* notused */ 120 static void bstp_topology_change_detection(struct bstp_state *); 121 static void bstp_topology_change_acknowledged(struct bstp_state *); 122 static void bstp_acknowledge_topology_change(struct bstp_state *, 123 struct bstp_port *); 124 125 static void bstp_enqueue(struct ifnet *, struct mbuf *); 126 static void bstp_tick(void *); 127 static void bstp_timer_start(struct bstp_timer *, uint16_t); 128 static void bstp_timer_stop(struct bstp_timer *); 129 static int bstp_timer_expired(struct bstp_timer *, uint16_t); 130 131 static void bstp_hold_timer_expiry(struct bstp_state *, 132 struct bstp_port *); 133 static void bstp_message_age_timer_expiry(struct bstp_state *, 134 struct bstp_port *); 135 static void bstp_forward_delay_timer_expiry(struct bstp_state *, 136 struct bstp_port *); 137 static void bstp_topology_change_timer_expiry(struct bstp_state *); 138 static void bstp_tcn_timer_expiry(struct bstp_state *); 139 static void bstp_hello_timer_expiry(struct bstp_state *); 140 static int bstp_addr_cmp(const uint8_t *, const uint8_t *); 141 142 static void 143 bstp_transmit_config(struct bstp_state *bs, struct bstp_port *bp) 144 { 145 BSTP_LOCK_ASSERT(bs); 146 147 if (bp->bp_hold_timer.active) { 148 bp->bp_config_pending = 1; 149 return; 150 } 151 152 bp->bp_config_bpdu.cu_message_type = BSTP_MSGTYPE_CFG; 153 bp->bp_config_bpdu.cu_rootid = bs->bs_designated_root; 154 bp->bp_config_bpdu.cu_root_path_cost = bs->bs_root_path_cost; 155 bp->bp_config_bpdu.cu_bridge_id = bs->bs_bridge_id; 156 bp->bp_config_bpdu.cu_port_id = bp->bp_port_id; 157 158 if (bstp_root_bridge(bs)) 159 bp->bp_config_bpdu.cu_message_age = 0; 160 else 161 bp->bp_config_bpdu.cu_message_age = 162 bs->bs_root_port->bp_message_age_timer.value + 163 BSTP_MESSAGE_AGE_INCR; 164 165 bp->bp_config_bpdu.cu_max_age = bs->bs_max_age; 166 bp->bp_config_bpdu.cu_hello_time = bs->bs_hello_time; 167 bp->bp_config_bpdu.cu_forward_delay = bs->bs_forward_delay; 168 bp->bp_config_bpdu.cu_topology_change_acknowledgment 169 = bp->bp_topology_change_acknowledge; 170 bp->bp_config_bpdu.cu_topology_change = bs->bs_topology_change; 171 172 if (bp->bp_config_bpdu.cu_message_age < bs->bs_max_age) { 173 bp->bp_topology_change_acknowledge = 0; 174 bp->bp_config_pending = 0; 175 bstp_send_config_bpdu(bs, bp, &bp->bp_config_bpdu); 176 bstp_timer_start(&bp->bp_hold_timer, 0); 177 } 178 } 179 180 static void 181 bstp_send_config_bpdu(struct bstp_state *bs, struct bstp_port *bp, 182 struct bstp_config_unit *cu) 183 { 184 struct ifnet *ifp; 185 struct mbuf *m; 186 struct ether_header *eh; 187 struct bstp_cbpdu bpdu; 188 189 BSTP_LOCK_ASSERT(bs); 190 191 ifp = bp->bp_ifp; 192 193 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 194 return; 195 196 MGETHDR(m, M_DONTWAIT, MT_DATA); 197 if (m == NULL) 198 return; 199 200 eh = mtod(m, struct ether_header *); 201 202 m->m_pkthdr.rcvif = ifp; 203 m->m_pkthdr.len = sizeof(*eh) + sizeof(bpdu); 204 m->m_len = m->m_pkthdr.len; 205 206 bpdu.cbu_ssap = bpdu.cbu_dsap = LLC_8021D_LSAP; 207 bpdu.cbu_ctl = LLC_UI; 208 bpdu.cbu_protoid = htons(0); 209 bpdu.cbu_protover = 0; 210 bpdu.cbu_bpdutype = cu->cu_message_type; 211 bpdu.cbu_flags = (cu->cu_topology_change ? BSTP_FLAG_TC : 0) | 212 (cu->cu_topology_change_acknowledgment ? BSTP_FLAG_TCA : 0); 213 214 bpdu.cbu_rootpri = htons(cu->cu_rootid >> 48); 215 bpdu.cbu_rootaddr[0] = cu->cu_rootid >> 40; 216 bpdu.cbu_rootaddr[1] = cu->cu_rootid >> 32; 217 bpdu.cbu_rootaddr[2] = cu->cu_rootid >> 24; 218 bpdu.cbu_rootaddr[3] = cu->cu_rootid >> 16; 219 bpdu.cbu_rootaddr[4] = cu->cu_rootid >> 8; 220 bpdu.cbu_rootaddr[5] = cu->cu_rootid >> 0; 221 222 bpdu.cbu_rootpathcost = htonl(cu->cu_root_path_cost); 223 224 bpdu.cbu_bridgepri = htons(cu->cu_bridge_id >> 48); 225 bpdu.cbu_bridgeaddr[0] = cu->cu_bridge_id >> 40; 226 bpdu.cbu_bridgeaddr[1] = cu->cu_bridge_id >> 32; 227 bpdu.cbu_bridgeaddr[2] = cu->cu_bridge_id >> 24; 228 bpdu.cbu_bridgeaddr[3] = cu->cu_bridge_id >> 16; 229 bpdu.cbu_bridgeaddr[4] = cu->cu_bridge_id >> 8; 230 bpdu.cbu_bridgeaddr[5] = cu->cu_bridge_id >> 0; 231 232 bpdu.cbu_portid = htons(cu->cu_port_id); 233 bpdu.cbu_messageage = htons(cu->cu_message_age); 234 bpdu.cbu_maxage = htons(cu->cu_max_age); 235 bpdu.cbu_hellotime = htons(cu->cu_hello_time); 236 bpdu.cbu_forwarddelay = htons(cu->cu_forward_delay); 237 238 memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN); 239 memcpy(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN); 240 eh->ether_type = htons(sizeof(bpdu)); 241 242 memcpy(mtod(m, caddr_t) + sizeof(*eh), &bpdu, sizeof(bpdu)); 243 244 bstp_enqueue(ifp, m); 245 } 246 247 static int 248 bstp_root_bridge(struct bstp_state *bs) 249 { 250 return (bs->bs_designated_root == bs->bs_bridge_id); 251 } 252 253 static int 254 bstp_supersedes_port_info(struct bstp_state *bs, struct bstp_port *bp, 255 struct bstp_config_unit *cu) 256 { 257 if (cu->cu_rootid < bp->bp_designated_root) 258 return (1); 259 if (cu->cu_rootid > bp->bp_designated_root) 260 return (0); 261 262 if (cu->cu_root_path_cost < bp->bp_designated_cost) 263 return (1); 264 if (cu->cu_root_path_cost > bp->bp_designated_cost) 265 return (0); 266 267 if (cu->cu_bridge_id < bp->bp_designated_bridge) 268 return (1); 269 if (cu->cu_bridge_id > bp->bp_designated_bridge) 270 return (0); 271 272 if (bs->bs_bridge_id != cu->cu_bridge_id) 273 return (1); 274 if (cu->cu_port_id <= bp->bp_designated_port) 275 return (1); 276 return (0); 277 } 278 279 static void 280 bstp_record_config_information(struct bstp_state *bs, 281 struct bstp_port *bp, struct bstp_config_unit *cu) 282 { 283 BSTP_LOCK_ASSERT(bs); 284 285 bp->bp_designated_root = cu->cu_rootid; 286 bp->bp_designated_cost = cu->cu_root_path_cost; 287 bp->bp_designated_bridge = cu->cu_bridge_id; 288 bp->bp_designated_port = cu->cu_port_id; 289 bstp_timer_start(&bp->bp_message_age_timer, cu->cu_message_age); 290 } 291 292 static void 293 bstp_record_config_timeout_values(struct bstp_state *bs, 294 struct bstp_config_unit *config) 295 { 296 BSTP_LOCK_ASSERT(bs); 297 298 bs->bs_max_age = config->cu_max_age; 299 bs->bs_hello_time = config->cu_hello_time; 300 bs->bs_forward_delay = config->cu_forward_delay; 301 bs->bs_topology_change = config->cu_topology_change; 302 } 303 304 static void 305 bstp_config_bpdu_generation(struct bstp_state *bs) 306 { 307 struct bstp_port *bp; 308 309 BSTP_LOCK_ASSERT(bs); 310 311 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { 312 if (bstp_designated_port(bs, bp) && 313 (bp->bp_state != BSTP_IFSTATE_DISABLED)) 314 bstp_transmit_config(bs, bp); 315 } 316 } 317 318 static int 319 bstp_designated_port(struct bstp_state *bs, struct bstp_port *bp) 320 { 321 return ((bp->bp_designated_bridge == bs->bs_bridge_id) 322 && (bp->bp_designated_port == bp->bp_port_id)); 323 } 324 325 static void 326 bstp_transmit_tcn(struct bstp_state *bs) 327 { 328 struct bstp_tbpdu bpdu; 329 struct bstp_port *bp = bs->bs_root_port; 330 struct ifnet *ifp = bp->bp_ifp; 331 struct ether_header *eh; 332 struct mbuf *m; 333 334 BSTP_LOCK_ASSERT(bs); 335 336 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 337 return; 338 339 MGETHDR(m, M_DONTWAIT, MT_DATA); 340 if (m == NULL) 341 return; 342 343 m->m_pkthdr.rcvif = ifp; 344 m->m_pkthdr.len = sizeof(*eh) + sizeof(bpdu); 345 m->m_len = m->m_pkthdr.len; 346 347 eh = mtod(m, struct ether_header *); 348 349 memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN); 350 memcpy(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN); 351 eh->ether_type = htons(sizeof(bpdu)); 352 353 bpdu.tbu_ssap = bpdu.tbu_dsap = LLC_8021D_LSAP; 354 bpdu.tbu_ctl = LLC_UI; 355 bpdu.tbu_protoid = 0; 356 bpdu.tbu_protover = 0; 357 bpdu.tbu_bpdutype = BSTP_MSGTYPE_TCN; 358 359 memcpy(mtod(m, caddr_t) + sizeof(*eh), &bpdu, sizeof(bpdu)); 360 361 bstp_enqueue(ifp, m); 362 } 363 364 static void 365 bstp_configuration_update(struct bstp_state *bs) 366 { 367 BSTP_LOCK_ASSERT(bs); 368 369 bstp_root_selection(bs); 370 bstp_designated_port_selection(bs); 371 } 372 373 static void 374 bstp_root_selection(struct bstp_state *bs) 375 { 376 struct bstp_port *root_port = NULL, *bp; 377 378 BSTP_LOCK_ASSERT(bs); 379 380 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { 381 if (bstp_designated_port(bs, bp)) 382 continue; 383 if (bp->bp_state == BSTP_IFSTATE_DISABLED) 384 continue; 385 if (bp->bp_designated_root >= bs->bs_bridge_id) 386 continue; 387 if (root_port == NULL) 388 goto set_port; 389 390 if (bp->bp_designated_root < root_port->bp_designated_root) 391 goto set_port; 392 if (bp->bp_designated_root > root_port->bp_designated_root) 393 continue; 394 395 if ((bp->bp_designated_cost + bp->bp_path_cost) < 396 (root_port->bp_designated_cost + root_port->bp_path_cost)) 397 goto set_port; 398 if ((bp->bp_designated_cost + bp->bp_path_cost) > 399 (root_port->bp_designated_cost + root_port->bp_path_cost)) 400 continue; 401 402 if (bp->bp_designated_bridge < 403 root_port->bp_designated_bridge) 404 goto set_port; 405 if (bp->bp_designated_bridge > 406 root_port->bp_designated_bridge) 407 continue; 408 409 if (bp->bp_designated_port < root_port->bp_designated_port) 410 goto set_port; 411 if (bp->bp_designated_port > root_port->bp_designated_port) 412 continue; 413 414 if (bp->bp_port_id >= root_port->bp_port_id) 415 continue; 416 set_port: 417 root_port = bp; 418 } 419 420 bs->bs_root_port = root_port; 421 if (root_port == NULL) { 422 bs->bs_designated_root = bs->bs_bridge_id; 423 bs->bs_root_path_cost = 0; 424 } else { 425 bs->bs_designated_root = root_port->bp_designated_root; 426 bs->bs_root_path_cost = root_port->bp_designated_cost + 427 root_port->bp_path_cost; 428 } 429 } 430 431 static void 432 bstp_designated_port_selection(struct bstp_state *bs) 433 { 434 struct bstp_port *bp; 435 436 BSTP_LOCK_ASSERT(bs); 437 438 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { 439 if (bstp_designated_port(bs, bp)) 440 goto designated; 441 if (bp->bp_designated_root != bs->bs_designated_root) 442 goto designated; 443 444 if (bs->bs_root_path_cost < bp->bp_designated_cost) 445 goto designated; 446 if (bs->bs_root_path_cost > bp->bp_designated_cost) 447 continue; 448 449 if (bs->bs_bridge_id < bp->bp_designated_bridge) 450 goto designated; 451 if (bs->bs_bridge_id > bp->bp_designated_bridge) 452 continue; 453 454 if (bp->bp_port_id > bp->bp_designated_port) 455 continue; 456 designated: 457 bstp_become_designated_port(bs, bp); 458 } 459 } 460 461 static void 462 bstp_become_designated_port(struct bstp_state *bs, struct bstp_port *bp) 463 { 464 BSTP_LOCK_ASSERT(bs); 465 466 bp->bp_designated_root = bs->bs_designated_root; 467 bp->bp_designated_cost = bs->bs_root_path_cost; 468 bp->bp_designated_bridge = bs->bs_bridge_id; 469 bp->bp_designated_port = bp->bp_port_id; 470 } 471 472 static void 473 bstp_port_state_selection(struct bstp_state *bs) 474 { 475 struct bstp_port *bp; 476 477 BSTP_LOCK_ASSERT(bs); 478 479 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { 480 if (bp == bs->bs_root_port) { 481 bp->bp_config_pending = 0; 482 bp->bp_topology_change_acknowledge = 0; 483 bstp_make_forwarding(bs, bp); 484 } else if (bstp_designated_port(bs, bp)) { 485 bstp_timer_stop(&bp->bp_message_age_timer); 486 bstp_make_forwarding(bs, bp); 487 } else { 488 bp->bp_config_pending = 0; 489 bp->bp_topology_change_acknowledge = 0; 490 bstp_make_blocking(bs, bp); 491 } 492 } 493 } 494 495 static void 496 bstp_make_forwarding(struct bstp_state *bs, struct bstp_port *bp) 497 { 498 BSTP_LOCK_ASSERT(bs); 499 500 if (bp->bp_state == BSTP_IFSTATE_BLOCKING) { 501 bstp_set_port_state(bp, BSTP_IFSTATE_LISTENING); 502 bstp_timer_start(&bp->bp_forward_delay_timer, 0); 503 } 504 } 505 506 static void 507 bstp_make_blocking(struct bstp_state *bs, struct bstp_port *bp) 508 { 509 BSTP_LOCK_ASSERT(bs); 510 511 if ((bp->bp_state != BSTP_IFSTATE_DISABLED) && 512 (bp->bp_state != BSTP_IFSTATE_BLOCKING)) { 513 if ((bp->bp_state == BSTP_IFSTATE_FORWARDING) || 514 (bp->bp_state == BSTP_IFSTATE_LEARNING)) { 515 if (bp->bp_change_detection_enabled) { 516 bstp_topology_change_detection(bs); 517 } 518 } 519 bstp_set_port_state(bp, BSTP_IFSTATE_BLOCKING); 520 bstp_timer_stop(&bp->bp_forward_delay_timer); 521 } 522 } 523 524 static void 525 bstp_set_port_state(struct bstp_port *bp, uint8_t state) 526 { 527 struct bstp_state *bs = bp->bp_bs; 528 529 bp->bp_state = state; 530 531 /* notify the parent bridge */ 532 if (bs->bs_state_cb != NULL) 533 taskqueue_enqueue(taskqueue_swi, &bp->bp_statetask); 534 } 535 536 /* 537 * Notify the bridge that a port state has changed, we need to do this from a 538 * taskqueue to avoid a LOR. 539 */ 540 static void 541 bstp_state_change(void *arg, int pending) 542 { 543 struct bstp_port *bp = (struct bstp_port *)arg; 544 struct bstp_state *bs = bp->bp_bs; 545 546 if (bp->bp_active == 1) 547 (*bs->bs_state_cb)(bp->bp_ifp, bp->bp_state); 548 } 549 550 static void 551 bstp_update_forward_transitions(struct bstp_port *bp) 552 { 553 bp->bp_forward_transitions++; 554 } 555 556 static void 557 bstp_topology_change_detection(struct bstp_state *bs) 558 { 559 BSTP_LOCK_ASSERT(bs); 560 561 if (bstp_root_bridge(bs)) { 562 bs->bs_topology_change = 1; 563 bstp_timer_start(&bs->bs_topology_change_timer, 0); 564 } else if (!bs->bs_topology_change_detected) { 565 bstp_transmit_tcn(bs); 566 bstp_timer_start(&bs->bs_tcn_timer, 0); 567 } 568 bs->bs_topology_change_detected = 1; 569 getmicrotime(&bs->bs_last_tc_time); 570 } 571 572 static void 573 bstp_topology_change_acknowledged(struct bstp_state *bs) 574 { 575 BSTP_LOCK_ASSERT(bs); 576 577 bs->bs_topology_change_detected = 0; 578 bstp_timer_stop(&bs->bs_tcn_timer); 579 } 580 581 static void 582 bstp_acknowledge_topology_change(struct bstp_state *bs, 583 struct bstp_port *bp) 584 { 585 BSTP_LOCK_ASSERT(bs); 586 587 bp->bp_topology_change_acknowledge = 1; 588 bstp_transmit_config(bs, bp); 589 } 590 591 struct mbuf * 592 bstp_input(struct bstp_port *bp, struct ifnet *ifp, struct mbuf *m) 593 { 594 struct bstp_state *bs = bp->bp_bs; 595 struct ether_header *eh; 596 struct bstp_tbpdu tpdu; 597 struct bstp_cbpdu cpdu; 598 struct bstp_config_unit cu; 599 struct bstp_tcn_unit tu; 600 uint16_t len; 601 602 if (bp->bp_active == 0) { 603 m_freem(m); 604 return (NULL); 605 } 606 607 BSTP_LOCK(bs); 608 609 eh = mtod(m, struct ether_header *); 610 611 len = ntohs(eh->ether_type); 612 if (len < sizeof(tpdu)) 613 goto out; 614 615 m_adj(m, ETHER_HDR_LEN); 616 617 if (m->m_pkthdr.len > len) 618 m_adj(m, len - m->m_pkthdr.len); 619 if (m->m_len < sizeof(tpdu) && 620 (m = m_pullup(m, sizeof(tpdu))) == NULL) 621 goto out; 622 623 memcpy(&tpdu, mtod(m, caddr_t), sizeof(tpdu)); 624 625 if (tpdu.tbu_dsap != LLC_8021D_LSAP || 626 tpdu.tbu_ssap != LLC_8021D_LSAP || 627 tpdu.tbu_ctl != LLC_UI) 628 goto out; 629 if (tpdu.tbu_protoid != 0 || tpdu.tbu_protover != 0) 630 goto out; 631 632 switch (tpdu.tbu_bpdutype) { 633 case BSTP_MSGTYPE_TCN: 634 tu.tu_message_type = tpdu.tbu_bpdutype; 635 bstp_received_tcn_bpdu(bs, bp, &tu); 636 break; 637 case BSTP_MSGTYPE_CFG: 638 if (m->m_len < sizeof(cpdu) && 639 (m = m_pullup(m, sizeof(cpdu))) == NULL) 640 goto out; 641 memcpy(&cpdu, mtod(m, caddr_t), sizeof(cpdu)); 642 643 cu.cu_rootid = 644 (((uint64_t)ntohs(cpdu.cbu_rootpri)) << 48) | 645 (((uint64_t)cpdu.cbu_rootaddr[0]) << 40) | 646 (((uint64_t)cpdu.cbu_rootaddr[1]) << 32) | 647 (((uint64_t)cpdu.cbu_rootaddr[2]) << 24) | 648 (((uint64_t)cpdu.cbu_rootaddr[3]) << 16) | 649 (((uint64_t)cpdu.cbu_rootaddr[4]) << 8) | 650 (((uint64_t)cpdu.cbu_rootaddr[5]) << 0); 651 652 cu.cu_bridge_id = 653 (((uint64_t)ntohs(cpdu.cbu_bridgepri)) << 48) | 654 (((uint64_t)cpdu.cbu_bridgeaddr[0]) << 40) | 655 (((uint64_t)cpdu.cbu_bridgeaddr[1]) << 32) | 656 (((uint64_t)cpdu.cbu_bridgeaddr[2]) << 24) | 657 (((uint64_t)cpdu.cbu_bridgeaddr[3]) << 16) | 658 (((uint64_t)cpdu.cbu_bridgeaddr[4]) << 8) | 659 (((uint64_t)cpdu.cbu_bridgeaddr[5]) << 0); 660 661 cu.cu_root_path_cost = ntohl(cpdu.cbu_rootpathcost); 662 cu.cu_message_age = ntohs(cpdu.cbu_messageage); 663 cu.cu_max_age = ntohs(cpdu.cbu_maxage); 664 cu.cu_hello_time = ntohs(cpdu.cbu_hellotime); 665 cu.cu_forward_delay = ntohs(cpdu.cbu_forwarddelay); 666 cu.cu_port_id = ntohs(cpdu.cbu_portid); 667 cu.cu_message_type = cpdu.cbu_bpdutype; 668 cu.cu_topology_change_acknowledgment = 669 (cpdu.cbu_flags & BSTP_FLAG_TCA) ? 1 : 0; 670 cu.cu_topology_change = 671 (cpdu.cbu_flags & BSTP_FLAG_TC) ? 1 : 0; 672 bstp_received_config_bpdu(bs, bp, &cu); 673 break; 674 default: 675 goto out; 676 } 677 678 out: 679 BSTP_UNLOCK(bs); 680 if (m) 681 m_freem(m); 682 return (NULL); 683 } 684 685 static void 686 bstp_received_config_bpdu(struct bstp_state *bs, struct bstp_port *bp, 687 struct bstp_config_unit *cu) 688 { 689 int root; 690 691 BSTP_LOCK_ASSERT(bs); 692 693 root = bstp_root_bridge(bs); 694 695 if (bp->bp_state != BSTP_IFSTATE_DISABLED) { 696 if (bstp_supersedes_port_info(bs, bp, cu)) { 697 bstp_record_config_information(bs, bp, cu); 698 bstp_configuration_update(bs); 699 bstp_port_state_selection(bs); 700 701 if ((bstp_root_bridge(bs) == 0) && root) { 702 bstp_timer_stop(&bs->bs_hello_timer); 703 704 if (bs->bs_topology_change_detected) { 705 bstp_timer_stop( 706 &bs->bs_topology_change_timer); 707 bstp_transmit_tcn(bs); 708 bstp_timer_start(&bs->bs_tcn_timer, 0); 709 } 710 } 711 712 if (bp == bs->bs_root_port) { 713 bstp_record_config_timeout_values(bs, cu); 714 bstp_config_bpdu_generation(bs); 715 716 if (cu->cu_topology_change_acknowledgment) 717 bstp_topology_change_acknowledged(bs); 718 } 719 } else if (bstp_designated_port(bs, bp)) 720 bstp_transmit_config(bs, bp); 721 } 722 } 723 724 static void 725 bstp_received_tcn_bpdu(struct bstp_state *bs, struct bstp_port *bp, 726 struct bstp_tcn_unit *tcn) 727 { 728 if (bp->bp_state != BSTP_IFSTATE_DISABLED && 729 bstp_designated_port(bs, bp)) { 730 bstp_topology_change_detection(bs); 731 bstp_acknowledge_topology_change(bs, bp); 732 } 733 } 734 735 static void 736 bstp_hello_timer_expiry(struct bstp_state *bs) 737 { 738 bstp_config_bpdu_generation(bs); 739 bstp_timer_start(&bs->bs_hello_timer, 0); 740 } 741 742 static void 743 bstp_message_age_timer_expiry(struct bstp_state *bs, 744 struct bstp_port *bp) 745 { 746 int root; 747 748 BSTP_LOCK_ASSERT(bs); 749 750 root = bstp_root_bridge(bs); 751 bstp_become_designated_port(bs, bp); 752 bstp_configuration_update(bs); 753 bstp_port_state_selection(bs); 754 755 if ((bstp_root_bridge(bs)) && (root == 0)) { 756 bs->bs_max_age = bs->bs_bridge_max_age; 757 bs->bs_hello_time = bs->bs_bridge_hello_time; 758 bs->bs_forward_delay = bs->bs_bridge_forward_delay; 759 760 bstp_topology_change_detection(bs); 761 bstp_timer_stop(&bs->bs_tcn_timer); 762 bstp_config_bpdu_generation(bs); 763 bstp_timer_start(&bs->bs_hello_timer, 0); 764 } 765 } 766 767 static void 768 bstp_forward_delay_timer_expiry(struct bstp_state *bs, 769 struct bstp_port *bp) 770 { 771 if (bp->bp_state == BSTP_IFSTATE_LISTENING) { 772 bstp_set_port_state(bp, BSTP_IFSTATE_LEARNING); 773 bstp_timer_start(&bp->bp_forward_delay_timer, 0); 774 } else if (bp->bp_state == BSTP_IFSTATE_LEARNING) { 775 bstp_set_port_state(bp, BSTP_IFSTATE_FORWARDING); 776 bstp_update_forward_transitions(bp); 777 if (bstp_designated_for_some_port(bs) && 778 bp->bp_change_detection_enabled) 779 bstp_topology_change_detection(bs); 780 } 781 } 782 783 static int 784 bstp_designated_for_some_port(struct bstp_state *bs) 785 { 786 787 struct bstp_port *bp; 788 789 BSTP_LOCK_ASSERT(bs); 790 791 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { 792 if (bp->bp_designated_bridge == bs->bs_bridge_id) 793 return (1); 794 } 795 return (0); 796 } 797 798 static void 799 bstp_tcn_timer_expiry(struct bstp_state *bs) 800 { 801 BSTP_LOCK_ASSERT(bs); 802 803 bstp_transmit_tcn(bs); 804 bstp_timer_start(&bs->bs_tcn_timer, 0); 805 } 806 807 static void 808 bstp_topology_change_timer_expiry(struct bstp_state *bs) 809 { 810 BSTP_LOCK_ASSERT(bs); 811 812 bs->bs_topology_change_detected = 0; 813 bs->bs_topology_change = 0; 814 } 815 816 static void 817 bstp_hold_timer_expiry(struct bstp_state *bs, struct bstp_port *bp) 818 { 819 if (bp->bp_config_pending) 820 bstp_transmit_config(bs, bp); 821 } 822 823 static int 824 bstp_addr_cmp(const uint8_t *a, const uint8_t *b) 825 { 826 int i, d; 827 828 for (i = 0, d = 0; i < ETHER_ADDR_LEN && d == 0; i++) { 829 d = ((int)a[i]) - ((int)b[i]); 830 } 831 832 return (d); 833 } 834 835 void 836 bstp_reinit(struct bstp_state *bs) 837 { 838 struct bstp_port *bp, *mbp; 839 u_char *e_addr; 840 841 BSTP_LOCK(bs); 842 843 mbp = NULL; 844 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { 845 bp->bp_port_id = (bp->bp_priority << 8) | 846 (bp->bp_ifp->if_index & 0xff); 847 848 if (mbp == NULL) { 849 mbp = bp; 850 continue; 851 } 852 if (bstp_addr_cmp(IF_LLADDR(bp->bp_ifp), 853 IF_LLADDR(mbp->bp_ifp)) < 0) { 854 mbp = bp; 855 continue; 856 } 857 } 858 if (mbp == NULL) { 859 BSTP_UNLOCK(bs); 860 bstp_stop(bs); 861 return; 862 } 863 864 e_addr = IF_LLADDR(mbp->bp_ifp); 865 bs->bs_bridge_id = 866 (((uint64_t)bs->bs_bridge_priority) << 48) | 867 (((uint64_t)e_addr[0]) << 40) | 868 (((uint64_t)e_addr[1]) << 32) | 869 (((uint64_t)e_addr[2]) << 24) | 870 (((uint64_t)e_addr[3]) << 16) | 871 (((uint64_t)e_addr[4]) << 8) | 872 (((uint64_t)e_addr[5])); 873 874 bs->bs_designated_root = bs->bs_bridge_id; 875 bs->bs_root_path_cost = 0; 876 bs->bs_root_port = NULL; 877 878 bs->bs_max_age = bs->bs_bridge_max_age; 879 bs->bs_hello_time = bs->bs_bridge_hello_time; 880 bs->bs_forward_delay = bs->bs_bridge_forward_delay; 881 bs->bs_topology_change_detected = 0; 882 bs->bs_topology_change = 0; 883 bstp_timer_stop(&bs->bs_tcn_timer); 884 bstp_timer_stop(&bs->bs_topology_change_timer); 885 886 if (callout_pending(&bs->bs_bstpcallout) == 0) 887 callout_reset(&bs->bs_bstpcallout, hz, 888 bstp_tick, bs); 889 890 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) 891 bstp_ifupdstatus(bs, bp); 892 893 getmicrotime(&bs->bs_last_tc_time); 894 bstp_port_state_selection(bs); 895 bstp_config_bpdu_generation(bs); 896 bstp_timer_start(&bs->bs_hello_timer, 0); 897 bstp_timer_start(&bs->bs_link_timer, 0); 898 BSTP_UNLOCK(bs); 899 } 900 901 static int 902 bstp_modevent(module_t mod, int type, void *data) 903 { 904 905 switch (type) { 906 case MOD_LOAD: 907 mtx_init(&bstp_list_mtx, "bridgestp list", NULL, MTX_DEF); 908 LIST_INIT(&bstp_list); 909 bstp_linkstate_p = bstp_linkstate; 910 break; 911 case MOD_UNLOAD: 912 mtx_destroy(&bstp_list_mtx); 913 break; 914 default: 915 return (EOPNOTSUPP); 916 } 917 return (0); 918 } 919 920 static moduledata_t bstp_mod = { 921 "bridgestp", 922 bstp_modevent, 923 0 924 }; 925 926 DECLARE_MODULE(bridgestp, bstp_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 927 MODULE_VERSION(bridgestp, 1); 928 929 void 930 bstp_attach(struct bstp_state *bs, bstp_state_cb_t state_callback) 931 { 932 BSTP_LOCK_INIT(bs); 933 callout_init_mtx(&bs->bs_bstpcallout, &bs->bs_mtx, 0); 934 LIST_INIT(&bs->bs_bplist); 935 936 bs->bs_bridge_max_age = BSTP_DEFAULT_MAX_AGE; 937 bs->bs_bridge_hello_time = BSTP_DEFAULT_HELLO_TIME; 938 bs->bs_bridge_forward_delay = BSTP_DEFAULT_FORWARD_DELAY; 939 bs->bs_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY; 940 bs->bs_hold_time = BSTP_DEFAULT_HOLD_TIME; 941 bs->bs_state_cb = state_callback; 942 943 mtx_lock(&bstp_list_mtx); 944 LIST_INSERT_HEAD(&bstp_list, bs, bs_list); 945 mtx_unlock(&bstp_list_mtx); 946 } 947 948 void 949 bstp_detach(struct bstp_state *bs) 950 { 951 KASSERT(LIST_EMPTY(&bs->bs_bplist), ("bstp still active")); 952 953 mtx_lock(&bstp_list_mtx); 954 LIST_REMOVE(bs, bs_list); 955 mtx_unlock(&bstp_list_mtx); 956 BSTP_LOCK_DESTROY(bs); 957 } 958 959 void 960 bstp_init(struct bstp_state *bs) 961 { 962 callout_reset(&bs->bs_bstpcallout, hz, bstp_tick, bs); 963 bstp_reinit(bs); 964 } 965 966 void 967 bstp_stop(struct bstp_state *bs) 968 { 969 struct bstp_port *bp; 970 971 BSTP_LOCK(bs); 972 973 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { 974 bstp_set_port_state(bp, BSTP_IFSTATE_DISABLED); 975 bstp_timer_stop(&bp->bp_hold_timer); 976 bstp_timer_stop(&bp->bp_message_age_timer); 977 bstp_timer_stop(&bp->bp_forward_delay_timer); 978 } 979 980 callout_drain(&bs->bs_bstpcallout); 981 callout_stop(&bs->bs_bstpcallout); 982 983 bstp_timer_stop(&bs->bs_topology_change_timer); 984 bstp_timer_stop(&bs->bs_tcn_timer); 985 bstp_timer_stop(&bs->bs_hello_timer); 986 987 BSTP_UNLOCK(bs); 988 } 989 990 static void 991 bstp_initialize_port(struct bstp_state *bs, struct bstp_port *bp) 992 { 993 BSTP_LOCK_ASSERT(bs); 994 995 bstp_become_designated_port(bs, bp); 996 bstp_set_port_state(bp, BSTP_IFSTATE_BLOCKING); 997 bp->bp_topology_change_acknowledge = 0; 998 bp->bp_config_pending = 0; 999 bp->bp_change_detection_enabled = 1; 1000 bstp_timer_stop(&bp->bp_message_age_timer); 1001 bstp_timer_stop(&bp->bp_forward_delay_timer); 1002 bstp_timer_stop(&bp->bp_hold_timer); 1003 } 1004 1005 static void 1006 bstp_enable_port(struct bstp_state *bs, struct bstp_port *bp) 1007 { 1008 bstp_initialize_port(bs, bp); 1009 bstp_port_state_selection(bs); 1010 } 1011 1012 static void 1013 bstp_disable_port(struct bstp_state *bs, struct bstp_port *bp) 1014 { 1015 int root; 1016 1017 BSTP_LOCK_ASSERT(bs); 1018 1019 root = bstp_root_bridge(bs); 1020 bstp_become_designated_port(bs, bp); 1021 bstp_set_port_state(bp, BSTP_IFSTATE_DISABLED); 1022 bp->bp_topology_change_acknowledge = 0; 1023 bp->bp_config_pending = 0; 1024 bstp_timer_stop(&bp->bp_message_age_timer); 1025 bstp_timer_stop(&bp->bp_forward_delay_timer); 1026 bstp_configuration_update(bs); 1027 bstp_port_state_selection(bs); 1028 1029 if (bstp_root_bridge(bs) && (root == 0)) { 1030 bs->bs_max_age = bs->bs_bridge_max_age; 1031 bs->bs_hello_time = bs->bs_bridge_hello_time; 1032 bs->bs_forward_delay = bs->bs_bridge_forward_delay; 1033 1034 bstp_topology_change_detection(bs); 1035 bstp_timer_stop(&bs->bs_tcn_timer); 1036 bstp_config_bpdu_generation(bs); 1037 bstp_timer_start(&bs->bs_hello_timer, 0); 1038 } 1039 } 1040 1041 #ifdef notused 1042 static void 1043 bstp_set_bridge_priority(struct bstp_state *bs, uint64_t new_bridge_id) 1044 { 1045 struct bstp_port *bp; 1046 int root; 1047 1048 BSTP_LOCK_ASSERT(bs); 1049 1050 root = bstp_root_bridge(bs); 1051 1052 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { 1053 if (bstp_designated_port(bs, bp)) 1054 bp->bp_designated_bridge = new_bridge_id; 1055 } 1056 1057 bs->bs_bridge_id = new_bridge_id; 1058 1059 bstp_configuration_update(bs); 1060 bstp_port_state_selection(bs); 1061 1062 if (bstp_root_bridge(bs) && (root == 0)) { 1063 bs->bs_max_age = bs->bs_bridge_max_age; 1064 bs->bs_hello_time = bs->bs_bridge_hello_time; 1065 bs->bs_forward_delay = bs->bs_bridge_forward_delay; 1066 1067 bstp_topology_change_detection(bs); 1068 bstp_timer_stop(&bs->bs_tcn_timer); 1069 bstp_config_bpdu_generation(bs); 1070 bstp_timer_start(&bs->bs_hello_timer, 0); 1071 } 1072 } 1073 1074 static void 1075 bstp_set_port_priority(struct bstp_state *bs, struct bstp_port *bp, 1076 uint16_t new_port_id) 1077 { 1078 if (bstp_designated_port(bs, bp)) 1079 bp->bp_designated_port = new_port_id; 1080 1081 bp->bp_port_id = new_port_id; 1082 1083 if ((bs->bs_bridge_id == bp->bp_designated_bridge) && 1084 (bp->bp_port_id < bp->bp_designated_port)) { 1085 bstp_become_designated_port(bs, bp); 1086 bstp_port_state_selection(bs); 1087 } 1088 } 1089 1090 static void 1091 bstp_set_path_cost(struct bstp_state *bs, struct bstp_port *bp, 1092 uint32_t path_cost) 1093 { 1094 bp->bp_path_cost = path_cost; 1095 bstp_configuration_update(bs); 1096 bstp_port_state_selection(bs); 1097 } 1098 1099 static void 1100 bstp_enable_change_detection(struct bstp_port *bp) 1101 { 1102 bp->bp_change_detection_enabled = 1; 1103 } 1104 1105 static void 1106 bstp_disable_change_detection(struct bstp_port *bp) 1107 { 1108 bp->bp_change_detection_enabled = 0; 1109 } 1110 #endif /* notused */ 1111 1112 static void 1113 bstp_enqueue(struct ifnet *dst_ifp, struct mbuf *m) 1114 { 1115 int err = 0; 1116 1117 IFQ_ENQUEUE(&dst_ifp->if_snd, m, err); 1118 1119 if ((dst_ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) 1120 (*dst_ifp->if_start)(dst_ifp); 1121 } 1122 1123 void 1124 bstp_linkstate(struct ifnet *ifp, int state) 1125 { 1126 struct bstp_state *bs; 1127 struct bstp_port *bp; 1128 1129 /* 1130 * It would be nice if the ifnet had a pointer to the bstp_port so we 1131 * didnt need to search for it, but that may be an overkill. In reality 1132 * this is fast and doesnt get called often. 1133 */ 1134 mtx_lock(&bstp_list_mtx); 1135 LIST_FOREACH(bs, &bstp_list, bs_list) { 1136 BSTP_LOCK(bs); 1137 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { 1138 if (bp->bp_ifp == ifp) { 1139 bstp_ifupdstatus(bs, bp); 1140 /* it only exists once so return */ 1141 BSTP_UNLOCK(bs); 1142 mtx_unlock(&bstp_list_mtx); 1143 return; 1144 } 1145 } 1146 BSTP_UNLOCK(bs); 1147 } 1148 mtx_unlock(&bstp_list_mtx); 1149 } 1150 1151 static void 1152 bstp_ifupdstatus(struct bstp_state *bs, struct bstp_port *bp) 1153 { 1154 struct ifnet *ifp = bp->bp_ifp; 1155 struct ifmediareq ifmr; 1156 int error = 0; 1157 1158 BSTP_LOCK_ASSERT(bs); 1159 1160 bzero((char *)&ifmr, sizeof(ifmr)); 1161 error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr); 1162 1163 if ((error == 0) && (ifp->if_flags & IFF_UP)) { 1164 if (ifmr.ifm_status & IFM_ACTIVE) { 1165 if (bp->bp_state == BSTP_IFSTATE_DISABLED) 1166 bstp_enable_port(bs, bp); 1167 1168 } else { 1169 if (bp->bp_state != BSTP_IFSTATE_DISABLED) 1170 bstp_disable_port(bs, bp); 1171 } 1172 return; 1173 } 1174 1175 if (bp->bp_state != BSTP_IFSTATE_DISABLED) 1176 bstp_disable_port(bs, bp); 1177 } 1178 1179 static void 1180 bstp_tick(void *arg) 1181 { 1182 struct bstp_state *bs = arg; 1183 struct bstp_port *bp; 1184 1185 BSTP_LOCK_ASSERT(bs); 1186 1187 /* slow timer to catch missed link events */ 1188 if (bstp_timer_expired(&bs->bs_link_timer, BSTP_LINK_TIMER)) { 1189 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { 1190 bstp_ifupdstatus(bs, bp); 1191 } 1192 bstp_timer_start(&bs->bs_link_timer, 0); 1193 } 1194 1195 if (bstp_timer_expired(&bs->bs_hello_timer, bs->bs_hello_time)) 1196 bstp_hello_timer_expiry(bs); 1197 1198 if (bstp_timer_expired(&bs->bs_tcn_timer, bs->bs_bridge_hello_time)) 1199 bstp_tcn_timer_expiry(bs); 1200 1201 if (bstp_timer_expired(&bs->bs_topology_change_timer, 1202 bs->bs_topology_change_time)) 1203 bstp_topology_change_timer_expiry(bs); 1204 1205 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { 1206 if (bstp_timer_expired(&bp->bp_message_age_timer, 1207 bs->bs_max_age)) 1208 bstp_message_age_timer_expiry(bs, bp); 1209 } 1210 1211 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { 1212 if (bstp_timer_expired(&bp->bp_forward_delay_timer, 1213 bs->bs_forward_delay)) 1214 bstp_forward_delay_timer_expiry(bs, bp); 1215 1216 if (bstp_timer_expired(&bp->bp_hold_timer, 1217 bs->bs_hold_time)) 1218 bstp_hold_timer_expiry(bs, bp); 1219 } 1220 1221 callout_reset(&bs->bs_bstpcallout, hz, bstp_tick, bs); 1222 } 1223 1224 static void 1225 bstp_timer_start(struct bstp_timer *t, uint16_t v) 1226 { 1227 t->value = v; 1228 t->active = 1; 1229 } 1230 1231 static void 1232 bstp_timer_stop(struct bstp_timer *t) 1233 { 1234 t->value = 0; 1235 t->active = 0; 1236 } 1237 1238 static int 1239 bstp_timer_expired(struct bstp_timer *t, uint16_t v) 1240 { 1241 if (t->active == 0) 1242 return (0); 1243 t->value += BSTP_TICK_VAL; 1244 if (t->value >= v) { 1245 bstp_timer_stop(t); 1246 return (1); 1247 } 1248 return (0); 1249 1250 } 1251 1252 int 1253 bstp_add(struct bstp_state *bs, struct bstp_port *bp, struct ifnet *ifp) 1254 { 1255 KASSERT(bp->bp_active == 0, ("already a bstp member")); 1256 1257 switch (ifp->if_type) { 1258 case IFT_ETHER: /* These can do spanning tree. */ 1259 break; 1260 default: 1261 /* Nothing else can. */ 1262 return (EINVAL); 1263 } 1264 1265 BSTP_LOCK(bs); 1266 bp->bp_ifp = ifp; 1267 bp->bp_bs = bs; 1268 bp->bp_active = 1; 1269 bp->bp_priority = BSTP_DEFAULT_PORT_PRIORITY; 1270 bp->bp_path_cost = BSTP_DEFAULT_PATH_COST; 1271 1272 LIST_INSERT_HEAD(&bs->bs_bplist, bp, bp_next); 1273 TASK_INIT(&bp->bp_statetask, 0, bstp_state_change, bp); 1274 BSTP_UNLOCK(bs); 1275 bstp_reinit(bs); 1276 1277 return (0); 1278 } 1279 1280 void 1281 bstp_delete(struct bstp_port *bp) 1282 { 1283 struct bstp_state *bs = bp->bp_bs; 1284 1285 KASSERT(bp->bp_active == 1, ("not a bstp member")); 1286 1287 BSTP_LOCK(bs); 1288 if (bp->bp_state != BSTP_IFSTATE_DISABLED) 1289 bstp_disable_port(bs, bp); 1290 LIST_REMOVE(bp, bp_next); 1291 BSTP_UNLOCK(bs); 1292 bp->bp_bs = NULL; 1293 bp->bp_active = 0; 1294 1295 bstp_reinit(bs); 1296 } 1297 1298 /* 1299 * The bstp_port structure is about to be freed by the parent bridge. 1300 */ 1301 void 1302 bstp_drain(struct bstp_port *bp) 1303 { 1304 KASSERT(bp->bp_active == 0, ("port is still attached")); 1305 taskqueue_drain(taskqueue_swi, &bp->bp_statetask); 1306 } 1307