1 /************************************************************************ 2 * RSTP library - Rapid Spanning Tree (802.1t, 802.1w) 3 * Copyright (C) 2001-2003 Optical Access 4 * Author: Alex Rozin 5 * 6 * This file is part of RSTP library. 7 * 8 * RSTP library is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU Lesser General Public License as published by the 10 * Free Software Foundation; version 2.1 11 * 12 * RSTP library is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public License 18 * along with RSTP library; see the file COPYING. If not, write to the Free 19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 20 * 02111-1307, USA. 21 **********************************************************************/ 22 23 /* This file contains API from an operation system to the RSTP library */ 24 25 #include "base.h" 26 #include "stpm.h" 27 #include "stp_in.h" 28 #include "stp_to.h" 29 30 #define _stp_in_stpm_enable stp_in_stpm_enable 31 32 STP_VECTORS_T *stp_vectors; 33 34 void * 35 stp_in_stpm_create (int vlan_id, char* name, int* err_code) 36 { 37 register STPM_T* this; 38 39 /* stp_trace ("stp_in_stpm_create(%s)", name); */ 40 this = stpapi_stpm_find (vlan_id); 41 if (this) { /* it had just been created :( */ 42 *err_code = STP_Nothing_To_Do; 43 return this; 44 } 45 46 this = STP_stpm_create (vlan_id, name); 47 if (! this) { /* can't create stpm :( */ 48 *err_code = STP_Cannot_Create_Instance_For_Vlan; 49 return NULL; 50 } 51 52 *err_code = STP_OK; 53 return this; 54 } 55 56 int 57 _stp_in_stpm_enable (int vlan_id, char* name, 58 UID_STP_MODE_T admin_state) 59 { 60 register STPM_T* this; 61 Bool created_here = False; 62 int rc, err_code; 63 64 /* stp_trace ("_stp_in_stpm_enable(%s)", name); */ 65 this = stpapi_stpm_find (vlan_id); 66 67 if (STP_DISABLED != admin_state) { 68 if (! vlan_id) { /* STP_IN_stop_all (); */ 69 register STPM_T* stpm; 70 71 for (stpm = STP_stpm_get_the_list (); stpm; stpm = stpm->next) { 72 if (STP_DISABLED != stpm->admin_state) { 73 STP_OUT_set_hardware_mode (stpm->vlan_id, STP_DISABLED); 74 (void) STP_stpm_enable (stpm, STP_DISABLED); 75 } 76 } 77 } 78 } 79 80 if (! this) { /* it had not yet been created */ 81 if (STP_ENABLED == admin_state) {/* try to create it */ 82 stp_trace ("implicit create to vlan '%s'", name); 83 this = stp_in_stpm_create (vlan_id, name, &err_code); 84 if (! this) { 85 stp_trace ("implicit create to vlan '%s' failed", name); 86 return STP_Implicit_Instance_Create_Failed; 87 } 88 created_here = True; 89 } else {/* try to disable nothing ? */ 90 return 0; 91 } 92 } 93 94 if (this->admin_state == admin_state) { /* nothing to do :) */ 95 return 0; 96 } 97 98 rc = STP_stpm_enable (this, admin_state); 99 if (! rc) { 100 STP_OUT_set_hardware_mode (vlan_id, admin_state); 101 } 102 103 if (rc && created_here) { 104 STP_stpm_delete (this); 105 } 106 107 return rc; 108 } 109 110 111 STPM_T * 112 stpapi_stpm_find (int vlan_id) 113 { 114 register STPM_T* this; 115 116 for (this = STP_stpm_get_the_list (); this; this = this->next) 117 if (vlan_id == this->vlan_id) 118 return this; 119 120 return NULL; 121 } 122 123 static PORT_T * 124 _stpapi_port_find (STPM_T* this, int port_index) 125 { 126 register PORT_T* port; 127 128 for (port = this->ports; port; port = port->next) 129 if (port_index == port->port_index) { 130 return port; 131 } 132 133 return NULL; 134 } 135 136 137 static void 138 _conv_br_id_2_uid (IN BRIDGE_ID* f, OUT UID_BRIDGE_ID_T* t) 139 { 140 (void) memcpy (t, f, sizeof (UID_BRIDGE_ID_T)); 141 } 142 143 static int 144 _check_stpm_config (IN UID_STP_CFG_T* uid_cfg) 145 { 146 if (uid_cfg->bridge_priority < MIN_BR_PRIO) { 147 stp_trace ("%d bridge_priority small", (int) uid_cfg->bridge_priority); 148 return STP_Small_Bridge_Priority; 149 } 150 151 if (uid_cfg->bridge_priority > MAX_BR_PRIO) { 152 stp_trace ("%d bridge_priority large", (int) uid_cfg->bridge_priority); 153 return STP_Large_Bridge_Priority; 154 } 155 156 if (uid_cfg->hello_time < MIN_BR_HELLOT) { 157 stp_trace ("%d hello_time small", (int) uid_cfg->hello_time); 158 return STP_Small_Hello_Time; 159 } 160 161 if (uid_cfg->hello_time > MAX_BR_HELLOT) { 162 stp_trace ("%d hello_time large", (int) uid_cfg->hello_time); 163 return STP_Large_Hello_Time; 164 } 165 166 if (uid_cfg->max_age < MIN_BR_MAXAGE) { 167 stp_trace ("%d max_age small", (int) uid_cfg->max_age); 168 return STP_Small_Max_Age; 169 } 170 171 if (uid_cfg->max_age > MAX_BR_MAXAGE) { 172 stp_trace ("%d max_age large", (int) uid_cfg->max_age); 173 return STP_Large_Max_Age; 174 } 175 176 if (uid_cfg->forward_delay < MIN_BR_FWDELAY) { 177 stp_trace ("%d forward_delay small", (int) uid_cfg->forward_delay); 178 return STP_Small_Forward_Delay; 179 } 180 181 if (uid_cfg->forward_delay > MAX_BR_FWDELAY) { 182 stp_trace ("%d forward_delay large", (int) uid_cfg->forward_delay); 183 return STP_Large_Forward_Delay; 184 } 185 186 if (2 * (uid_cfg->forward_delay - 1) < uid_cfg->max_age) { 187 return STP_Forward_Delay_And_Max_Age_Are_Inconsistent; 188 } 189 190 if (uid_cfg->max_age < 2 * (uid_cfg->hello_time + 1)) { 191 return STP_Hello_Time_And_Max_Age_Are_Inconsistent; 192 } 193 194 return 0; 195 } 196 197 static void 198 _stp_in_enable_port_on_stpm (STPM_T* stpm, int port_index, Bool enable) 199 { 200 register PORT_T* port; 201 202 port = _stpapi_port_find (stpm, port_index); 203 if (! port) return; 204 if (port->portEnabled == enable) {/* nothing to do :) */ 205 return; 206 } 207 208 port->uptime = 0; 209 if (enable) { /* clear port statistics */ 210 port->rx_cfg_bpdu_cnt = 211 port->rx_rstp_bpdu_cnt = 212 port->rx_tcn_bpdu_cnt = 0; 213 } 214 215 #ifdef STP_DBG 216 if (port->edge->debug) { 217 stp_trace ("Port %s became '%s' adminEdge=%c", 218 port->port_name, enable ? "enable" : "disable", 219 port->adminEdge ? 'Y' : 'N'); 220 } 221 #endif 222 223 port->adminEnable = enable; 224 STP_port_init (port, stpm, False); 225 226 port->reselect = True; 227 port->selected = False; 228 } 229 230 void 231 STP_IN_init (STP_VECTORS_T *vectors) 232 { 233 RSTP_INIT_CRITICAL_PATH_PROTECTIO; 234 stp_vectors = vectors; 235 } 236 237 int 238 STP_IN_stpm_get_cfg (IN int vlan_id, OUT UID_STP_CFG_T* uid_cfg) 239 { 240 register STPM_T* this; 241 242 uid_cfg->field_mask = 0; 243 244 RSTP_CRITICAL_PATH_START; 245 this = stpapi_stpm_find (vlan_id); 246 247 if (!this) { /* it had not yet been created :( */ 248 RSTP_CRITICAL_PATH_END; 249 return STP_Vlan_Had_Not_Yet_Been_Created; 250 } 251 252 if (this->admin_state != STP_DISABLED) { 253 uid_cfg->field_mask |= BR_CFG_STATE; 254 } 255 uid_cfg->stp_enabled = this->admin_state; 256 257 if (this->ForceVersion != 2) { 258 uid_cfg->field_mask |= BR_CFG_FORCE_VER; 259 } 260 uid_cfg->force_version = this->ForceVersion; 261 262 if (this->BrId.prio != DEF_BR_PRIO) { 263 uid_cfg->field_mask |= BR_CFG_PRIO; 264 } 265 uid_cfg->bridge_priority = this->BrId.prio; 266 267 if (this->BrTimes.MaxAge != DEF_BR_MAXAGE) { 268 uid_cfg->field_mask |= BR_CFG_AGE; 269 } 270 uid_cfg->max_age = this->BrTimes.MaxAge; 271 272 if (this->BrTimes.HelloTime != DEF_BR_HELLOT) { 273 uid_cfg->field_mask |= BR_CFG_HELLO; 274 } 275 uid_cfg->hello_time = this->BrTimes.HelloTime; 276 277 if (this->BrTimes.ForwardDelay != DEF_BR_FWDELAY) { 278 uid_cfg->field_mask |= BR_CFG_DELAY; 279 } 280 uid_cfg->forward_delay = this->BrTimes.ForwardDelay; 281 282 uid_cfg->hold_time = TxHoldCount; 283 284 RSTP_CRITICAL_PATH_END; 285 return 0; 286 } 287 288 int 289 STP_IN_port_get_cfg (int vlan_id, int port_index, UID_STP_PORT_CFG_T* uid_cfg) 290 { 291 register STPM_T* this; 292 register PORT_T* port; 293 294 RSTP_CRITICAL_PATH_START; 295 this = stpapi_stpm_find (vlan_id); 296 297 if (!this) { /* it had not yet been created :( */ 298 RSTP_CRITICAL_PATH_END; 299 return STP_Vlan_Had_Not_Yet_Been_Created; 300 } 301 302 port = _stpapi_port_find (this, port_index); 303 if (! port) {/* port is absent in the stpm :( */ 304 RSTP_CRITICAL_PATH_END; 305 return STP_Port_Is_Absent_In_The_Vlan; 306 } 307 308 uid_cfg->field_mask = 0; 309 310 uid_cfg->port_priority = port->port_id >> 8; 311 if (uid_cfg->port_priority != DEF_PORT_PRIO) 312 uid_cfg->field_mask |= PT_CFG_PRIO; 313 314 uid_cfg->admin_port_path_cost = port->adminPCost; 315 if (uid_cfg->admin_port_path_cost != ADMIN_PORT_PATH_COST_AUTO) 316 uid_cfg->field_mask |= PT_CFG_COST; 317 318 uid_cfg->admin_point2point = port->adminPointToPointMac; 319 if (uid_cfg->admin_point2point != DEF_P2P) 320 uid_cfg->field_mask |= PT_CFG_P2P; 321 322 uid_cfg->admin_edge = port->adminEdge; 323 if (uid_cfg->admin_edge != DEF_ADMIN_EDGE) 324 uid_cfg->field_mask |= PT_CFG_EDGE; 325 326 uid_cfg->admin_non_stp = port->admin_non_stp; 327 if (uid_cfg->admin_non_stp != DEF_ADMIN_NON_STP) 328 uid_cfg->field_mask |= PT_CFG_NON_STP; 329 330 if (port->mcheck) 331 uid_cfg->field_mask |= PT_CFG_MCHECK; 332 333 RSTP_CRITICAL_PATH_END; 334 return 0; 335 } 336 337 int 338 STP_IN_port_get_state (IN int vlan_id, INOUT UID_STP_PORT_STATE_T* entry) 339 { 340 register STPM_T* this; 341 register PORT_T* port; 342 343 RSTP_CRITICAL_PATH_START; 344 this = stpapi_stpm_find (vlan_id); 345 346 if (!this) { /* it had not yet been created :( */ 347 RSTP_CRITICAL_PATH_END; 348 return STP_Vlan_Had_Not_Yet_Been_Created; 349 } 350 351 port = _stpapi_port_find (this, entry->port_no); 352 if (! port) {/* port is absent in the stpm :( */ 353 RSTP_CRITICAL_PATH_END; 354 return STP_Port_Is_Absent_In_The_Vlan; 355 } 356 357 entry->port_id = port->port_id; 358 if (DisabledPort == port->role) { 359 entry->state = UID_PORT_DISABLED; 360 } else if (! port->forward && ! port->learn) { 361 entry->state = UID_PORT_DISCARDING; 362 } else if (! port->forward && port->learn) { 363 entry->state = UID_PORT_LEARNING; 364 } else { 365 entry->state = UID_PORT_FORWARDING; 366 } 367 368 entry->uptime = port->uptime; 369 entry->path_cost = port->operPCost; 370 _conv_br_id_2_uid (&port->portPrio.root_bridge, &entry->designated_root); 371 entry->designated_cost = port->portPrio.root_path_cost; 372 _conv_br_id_2_uid (&port->portPrio.design_bridge, &entry->designated_bridge); 373 entry->designated_port = port->portPrio.design_port; 374 375 switch (port->role) { 376 case DisabledPort: entry->role = ' '; break; 377 case AlternatePort: entry->role = 'A'; break; 378 case BackupPort: entry->role = 'B'; break; 379 case RootPort: entry->role = 'R'; break; 380 case DesignatedPort: entry->role = 'D'; break; 381 case NonStpPort: entry->role = '-'; break; 382 default: entry->role = '?'; break; 383 } 384 385 if (DisabledPort == port->role || NonStpPort == port->role) { 386 (void) memset (&entry->designated_root, 0, sizeof (UID_BRIDGE_ID_T)); 387 (void) memset (&entry->designated_bridge, 0, sizeof (UID_BRIDGE_ID_T)); 388 entry->designated_cost = 0; 389 entry->designated_port = port->port_id; 390 } 391 392 if (DisabledPort == port->role) { 393 entry->oper_point2point = (P2P_FORCE_FALSE == port->adminPointToPointMac) ? 0 : 1; 394 entry->oper_edge = port->adminEdge; 395 entry->oper_stp_neigb = 0; 396 } else { 397 entry->oper_point2point = port->operPointToPointMac ? 1 : 0; 398 entry->oper_edge = port->operEdge ? 1 : 0; 399 entry->oper_stp_neigb = port->sendRSTP ? 0 : 1; 400 } 401 entry->oper_port_path_cost = port->operPCost; 402 403 entry->rx_cfg_bpdu_cnt = port->rx_cfg_bpdu_cnt; 404 entry->rx_rstp_bpdu_cnt = port->rx_rstp_bpdu_cnt; 405 entry->rx_tcn_bpdu_cnt = port->rx_tcn_bpdu_cnt; 406 407 entry->fdWhile = port->fdWhile; /* 17.15.1 */ 408 entry->helloWhen = port->helloWhen; /* 17.15.2 */ 409 entry->mdelayWhile = port->mdelayWhile; /* 17.15.3 */ 410 entry->rbWhile = port->rbWhile; /* 17.15.4 */ 411 entry->rcvdInfoWhile = port->rcvdInfoWhile;/* 17.15.5 */ 412 entry->rrWhile = port->rrWhile; /* 17.15.6 */ 413 entry->tcWhile = port->tcWhile; /* 17.15.7 */ 414 entry->txCount = port->txCount; /* 17.18.40 */ 415 entry->lnkWhile = port->lnkWhile; 416 417 entry->rcvdInfoWhile = port->rcvdInfoWhile; 418 entry->top_change_ack = port->tcAck; 419 entry->tc = port->tc; 420 421 RSTP_CRITICAL_PATH_END; 422 return 0; 423 } 424 425 int 426 STP_IN_stpm_get_state (IN int vlan_id, OUT UID_STP_STATE_T* entry) 427 { 428 register STPM_T* this; 429 430 RSTP_CRITICAL_PATH_START; 431 this = stpapi_stpm_find (vlan_id); 432 433 if (!this) { /* it had not yet been created :( */ 434 RSTP_CRITICAL_PATH_END; 435 return STP_Vlan_Had_Not_Yet_Been_Created; 436 } 437 438 (void) strncpy (entry->vlan_name, this->name, NAME_LEN); 439 entry->vlan_id = this->vlan_id; 440 _conv_br_id_2_uid (&this->rootPrio.root_bridge, &entry->designated_root); 441 entry->root_path_cost = this->rootPrio.root_path_cost; 442 entry->root_port = this->rootPortId; 443 entry->max_age = this->rootTimes.MaxAge; 444 entry->forward_delay = this->rootTimes.ForwardDelay; 445 entry->hello_time = this->rootTimes.HelloTime; 446 447 _conv_br_id_2_uid (&this->BrId, &entry->bridge_id); 448 449 entry->stp_enabled = this->admin_state; 450 451 entry->timeSince_Topo_Change = this->timeSince_Topo_Change; 452 entry->Topo_Change_Count = this->Topo_Change_Count; 453 entry->Topo_Change = this->Topo_Change; 454 455 RSTP_CRITICAL_PATH_END; 456 return 0; 457 } 458 459 int 460 STP_IN_stpm_get_name_by_vlan_id (int vlan_id, char* name, size_t buffsize) 461 { 462 register STPM_T* stpm; 463 int iret = -1; 464 465 RSTP_CRITICAL_PATH_START; 466 for (stpm = STP_stpm_get_the_list (); stpm; stpm = stpm->next) { 467 if (vlan_id == stpm->vlan_id) { 468 if (stpm->name) 469 (void) strncpy (name, stpm->name, buffsize); 470 else 471 (void) memset (name, 0, buffsize); 472 iret = 0; 473 break; 474 } 475 } 476 RSTP_CRITICAL_PATH_END; 477 return iret; 478 } 479 480 int /* call it, when link Up/Down */ 481 STP_IN_enable_port (int port_index, Bool enable) 482 { 483 register STPM_T* stpm; 484 485 RSTP_CRITICAL_PATH_START; 486 if (! enable) { 487 #ifdef STP_DBG 488 stp_trace("%s (p%02d, all, %s, '%s')", 489 "clearFDB", (int) port_index, "this port", "disable port"); 490 #endif 491 STP_OUT_flush_lt (port_index, 0, LT_FLASH_ONLY_THE_PORT, "disable port"); 492 } 493 494 for (stpm = STP_stpm_get_the_list (); stpm; stpm = stpm->next) { 495 if (STP_ENABLED != stpm->admin_state) continue; 496 497 _stp_in_enable_port_on_stpm (stpm, port_index, enable); 498 /* STP_stpm_update (stpm);*/ 499 } 500 501 RSTP_CRITICAL_PATH_END; 502 return 0; 503 } 504 505 int /* call it, when port speed has been changed, speed in Kb/s */ 506 STP_IN_changed_port_speed (int port_index, long speed) 507 { 508 register STPM_T* stpm; 509 register PORT_T* port; 510 511 RSTP_CRITICAL_PATH_START; 512 for (stpm = STP_stpm_get_the_list (); stpm; stpm = stpm->next) { 513 if (STP_ENABLED != stpm->admin_state) continue; 514 515 port = _stpapi_port_find (stpm, port_index); 516 if (! port) continue; 517 port->operSpeed = speed; 518 #ifdef STP_DBG 519 if (port->pcost->debug) { 520 stp_trace ("changed operSpeed=%lu", port->operSpeed); 521 } 522 #endif 523 524 port->reselect = True; 525 port->selected = False; 526 } 527 RSTP_CRITICAL_PATH_END; 528 return 0; 529 } 530 531 int /* call it, when port duplex mode has been changed */ 532 STP_IN_changed_port_duplex (int port_index) 533 { 534 register STPM_T* stpm; 535 register PORT_T* port; 536 537 RSTP_CRITICAL_PATH_START; 538 for (stpm = STP_stpm_get_the_list (); stpm; stpm = stpm->next) { 539 if (STP_ENABLED != stpm->admin_state) continue; 540 541 port = _stpapi_port_find (stpm, port_index); 542 if (! port) continue; 543 #ifdef STP_DBG 544 if (port->p2p->debug) { 545 stp_trace ("STP_IN_changed_port_duplex(%s)", port->port_name); 546 } 547 #endif 548 port->p2p_recompute = True; 549 port->reselect = True; 550 port->selected = False; 551 } 552 RSTP_CRITICAL_PATH_END; 553 return 0; 554 } 555 556 int 557 STP_IN_check_bpdu_header (BPDU_T* bpdu, size_t len) 558 { 559 unsigned short len8023; 560 561 /* LINTED: alignment */ 562 len8023 = ntohs (*(unsigned short*) bpdu->eth.len8023); 563 if (len8023 > 1500) {/* big len8023 format :( */ 564 return STP_Big_len8023_Format; 565 } 566 567 if (len8023 < MIN_BPDU) { /* small len8023 format :( */ 568 return STP_Small_len8023_Format; 569 } 570 571 if (len8023 + 14 > len) { /* len8023 format gt len :( */ 572 return STP_len8023_Format_Gt_Len; 573 } 574 575 if (bpdu->eth.dsap != BPDU_L_SAP || 576 bpdu->eth.ssap != BPDU_L_SAP || 577 bpdu->eth.llc != LLC_UI) { 578 /* this is not a proper 802.3 pkt! :( */ 579 return STP_Not_Proper_802_3_Packet; 580 } 581 582 if (bpdu->hdr.protocol[0] || bpdu->hdr.protocol[1]) { 583 return STP_Invalid_Protocol; 584 } 585 586 #if 0 587 if (bpdu->hdr.version != BPDU_VERSION_ID) { 588 return STP_Invalid_Version; 589 } 590 #endif 591 /* see also 9.3.4: think & TBD :( */ 592 return 0; 593 } 594 595 #ifdef STP_DBG 596 int dbg_rstp_deny = 0; 597 #endif 598 599 600 int 601 STP_IN_rx_bpdu (int vlan_id, int port_index, BPDU_T* bpdu, size_t len) 602 { 603 register PORT_T* port; 604 register STPM_T* this; 605 int iret; 606 607 #ifdef STP_DBG 608 if (1 == dbg_rstp_deny) { 609 return 0; 610 } 611 #endif 612 613 RSTP_CRITICAL_PATH_START; 614 this = stpapi_stpm_find (vlan_id); 615 if (! this) { /* the stpm had not yet been created :( */ 616 RSTP_CRITICAL_PATH_END; 617 return STP_Vlan_Had_Not_Yet_Been_Created; 618 } 619 620 if (STP_DISABLED == this->admin_state) {/* the stpm had not yet been enabled :( */ 621 RSTP_CRITICAL_PATH_END; 622 return STP_Had_Not_Yet_Been_Enabled_On_The_Vlan; 623 } 624 625 port = _stpapi_port_find (this, port_index); 626 if (! port) {/* port is absent in the stpm :( */ 627 #ifdef STP_DBG 628 stp_trace ("RX bpdu vlan_id=%d port=%d port is absent in the stpm :(", (int) vlan_id, (int) port_index); 629 #endif 630 RSTP_CRITICAL_PATH_END; 631 return STP_Port_Is_Absent_In_The_Vlan; 632 } 633 634 #ifdef STP_DBG 635 if (port->skip_rx > 0) { 636 if (1 == port->skip_rx) 637 stp_trace ("port %s stop rx skipping", 638 port->port_name); 639 else 640 stp_trace ("port %s skip rx %d", 641 port->port_name, port->skip_rx); 642 port->skip_rx--; 643 RSTP_CRITICAL_PATH_END; 644 return STP_Nothing_To_Do; 645 } 646 #endif 647 648 if (port->operEdge && ! port->lnkWhile && port->portEnabled) { 649 #ifdef STP_DBG 650 if (port->topoch->debug) { 651 stp_trace ("port %s tc=TRUE by operEdge", port->port_name); 652 } 653 #endif 654 port->tc = True; /* IEEE 802.1y, 17.30 */ 655 } 656 657 /* port link change indication will come later :( */ 658 if (! port->portEnabled && 659 STP_OUT_get_port_link_status (port->port_index)) { 660 _stp_in_enable_port_on_stpm (this, port->port_index, True); 661 } 662 663 #ifdef STP_DBG 664 if (port->edge->debug && port->operEdge) { 665 stp_trace ("port %s not operEdge !", port->port_name); 666 } 667 #endif 668 669 port->operEdge = False; 670 port->wasInitBpdu = True; 671 672 iret = STP_port_rx_bpdu (port, bpdu, len); 673 (void) STP_stpm_update (this); 674 RSTP_CRITICAL_PATH_END; 675 676 return iret; 677 } 678 679 int 680 STP_IN_one_second (void) 681 { 682 register STPM_T* stpm; 683 register int dbg_cnt = 0; 684 685 RSTP_CRITICAL_PATH_START; 686 for (stpm = STP_stpm_get_the_list (); stpm; stpm = stpm->next) { 687 if (STP_ENABLED == stpm->admin_state) { 688 /* stp_trace ("STP_IN_one_second vlan_id=%d", (int) stpm->vlan_id); */ 689 STP_stpm_one_second (stpm); 690 dbg_cnt++; 691 } 692 } 693 694 RSTP_CRITICAL_PATH_END; 695 696 return dbg_cnt; 697 } 698 699 int 700 STP_IN_stpm_set_cfg (IN int vlan_id, 701 IN UID_STP_CFG_T* uid_cfg) 702 { 703 int rc = 0, prev_prio, err_code; 704 Bool created_here, enabled_here; 705 register STPM_T* this; 706 UID_STP_CFG_T old; 707 708 /* stp_trace ("STP_IN_stpm_set_cfg"); */ 709 if (0 != STP_IN_stpm_get_cfg (vlan_id, &old)) { 710 STP_OUT_get_init_stpm_cfg (vlan_id, &old); 711 } 712 713 RSTP_CRITICAL_PATH_START; 714 if (BR_CFG_PRIO & uid_cfg->field_mask) { 715 old.bridge_priority = uid_cfg->bridge_priority; 716 } 717 718 if (BR_CFG_AGE & uid_cfg->field_mask) { 719 old.max_age = uid_cfg->max_age; 720 } 721 722 if (BR_CFG_HELLO & uid_cfg->field_mask) { 723 old.hello_time = uid_cfg->hello_time; 724 } 725 726 if (BR_CFG_DELAY & uid_cfg->field_mask) { 727 old.forward_delay = uid_cfg->forward_delay; 728 } 729 730 if (BR_CFG_FORCE_VER & uid_cfg->field_mask) { 731 old.force_version = uid_cfg->force_version; 732 } 733 734 rc = _check_stpm_config (&old); 735 if (0 != rc) { 736 stp_trace ("_check_stpm_config failed %d", (int) rc); 737 RSTP_CRITICAL_PATH_END; 738 return rc; 739 } 740 741 if ((BR_CFG_STATE & uid_cfg->field_mask) && 742 (STP_DISABLED == uid_cfg->stp_enabled)) { 743 rc = _stp_in_stpm_enable (vlan_id, uid_cfg->vlan_name, STP_DISABLED); 744 if (0 != rc) { 745 stp_trace ("can't disable rc=%d", (int) rc); 746 RSTP_CRITICAL_PATH_END; 747 return rc; 748 } 749 uid_cfg->field_mask &= ~BR_CFG_STATE; 750 if (! uid_cfg->field_mask) { 751 RSTP_CRITICAL_PATH_END; 752 return 0; 753 } 754 } 755 756 /* get current state */ 757 this = stpapi_stpm_find (vlan_id); 758 created_here = False; 759 enabled_here = False; 760 if (! this) { /* it had not yet been created */ 761 this = stp_in_stpm_create (vlan_id, uid_cfg->vlan_name, &err_code); 762 if (! this) { 763 RSTP_CRITICAL_PATH_END; 764 return err_code; 765 } 766 } 767 768 prev_prio = this->BrId.prio; 769 this->BrId.prio = old.bridge_priority; 770 if (STP_ENABLED == this->admin_state) { 771 if (0 != STP_stpm_check_bridge_priority (this)) { 772 this->BrId.prio = prev_prio; 773 stp_trace ("%s", "STP_stpm_check_bridge_priority failed"); 774 RSTP_CRITICAL_PATH_END; 775 return STP_Invalid_Bridge_Priority; 776 } 777 } 778 779 this->BrTimes.MaxAge = old.max_age; 780 this->BrTimes.HelloTime = old.hello_time; 781 this->BrTimes.ForwardDelay = old.forward_delay; 782 this->ForceVersion = (PROTOCOL_VERSION_T) old.force_version; 783 784 if ((BR_CFG_STATE & uid_cfg->field_mask) && 785 STP_DISABLED != uid_cfg->stp_enabled && 786 STP_DISABLED == this->admin_state) { 787 rc = _stp_in_stpm_enable (vlan_id, uid_cfg->vlan_name, uid_cfg->stp_enabled); 788 if (0 != rc) { 789 stp_trace ("%s", "cannot enable"); 790 if (created_here) { 791 STP_stpm_delete (this); 792 } 793 RSTP_CRITICAL_PATH_END; 794 return rc; 795 } 796 enabled_here = True; 797 } 798 799 if (! enabled_here && STP_DISABLED != this->admin_state) { 800 STP_stpm_update_after_bridge_management (this); 801 } 802 RSTP_CRITICAL_PATH_END; 803 return 0; 804 } 805 806 int 807 STP_IN_port_set_cfg (IN int vlan_id, IN int port_index, 808 IN UID_STP_PORT_CFG_T* uid_cfg) 809 { 810 register STPM_T* this; 811 register PORT_T* port; 812 813 RSTP_CRITICAL_PATH_START; 814 this = stpapi_stpm_find (vlan_id); 815 if (! this) { /* it had not yet been created :( */ 816 RSTP_CRITICAL_PATH_END; 817 stp_trace ("RSTP instance with tag %d hasn't been created\n", vlan_id); 818 return STP_Vlan_Had_Not_Yet_Been_Created; 819 } 820 821 port = _stpapi_port_find (this, port_index); 822 if (! port) {/* port is absent in the stpm :( */ 823 return STP_Port_Is_Absent_In_The_Vlan; 824 } 825 826 if (PT_CFG_MCHECK & uid_cfg->field_mask) { 827 if (this->ForceVersion >= NORMAL_RSTP) 828 port->mcheck = True; 829 } 830 831 if (PT_CFG_COST & uid_cfg->field_mask) { 832 port->adminPCost = uid_cfg->admin_port_path_cost; 833 } 834 835 if (PT_CFG_PRIO & uid_cfg->field_mask) { 836 port->port_id = (uid_cfg->port_priority << 8) + port_index; 837 } 838 839 if (PT_CFG_P2P & uid_cfg->field_mask) { 840 port->adminPointToPointMac = uid_cfg->admin_point2point; 841 port->p2p_recompute = True; 842 } 843 844 if (PT_CFG_EDGE & uid_cfg->field_mask) { 845 port->adminEdge = uid_cfg->admin_edge; 846 port->operEdge = port->adminEdge; 847 #ifdef STP_DBG 848 if (port->edge->debug) { 849 stp_trace ("port %s is operEdge=%c in STP_IN_port_set_cfg", 850 port->port_name, 851 port->operEdge ? 'Y' : 'n'); 852 } 853 #endif 854 } 855 856 if (PT_CFG_NON_STP & uid_cfg->field_mask) { 857 #ifdef STP_DBG 858 if (port->roletrns->debug && port->admin_non_stp != uid_cfg->admin_non_stp) { 859 stp_trace ("port %s is adminNonStp=%c in STP_IN_port_set_cfg", 860 port->port_name, 861 uid_cfg->admin_non_stp ? 'Y' : 'n'); 862 } 863 #endif 864 port->admin_non_stp = uid_cfg->admin_non_stp; 865 } 866 867 #ifdef STP_DBG 868 if (PT_CFG_DBG_SKIP_RX & uid_cfg->field_mask) { 869 port->skip_rx = uid_cfg->skip_rx; 870 } 871 872 if (PT_CFG_DBG_SKIP_TX & uid_cfg->field_mask) { 873 port->skip_tx = uid_cfg->skip_tx; 874 } 875 876 #endif 877 878 port->reselect = True; 879 port->selected = False; 880 881 (void) STP_stpm_update (this); 882 883 RSTP_CRITICAL_PATH_END; 884 885 return 0; 886 } 887 888 #ifdef STP_DBG 889 int 890 891 STP_IN_dbg_set_port_trace (char* mach_name, int enadis, 892 int vlan_id, int port_no) 893 { 894 register STPM_T* this; 895 register PORT_T* port; 896 int rc; 897 898 RSTP_CRITICAL_PATH_START; 899 this = stpapi_stpm_find (vlan_id); 900 if (! this) { /* it had not yet been created :( */ 901 RSTP_CRITICAL_PATH_END; 902 stp_trace ("RSTP instance with tag %d hasn't been created\n", vlan_id); 903 return STP_Vlan_Had_Not_Yet_Been_Created; 904 } 905 906 port = _stpapi_port_find (this, port_no); 907 if (! port) {/* port is absent in the stpm :( */ 908 return STP_Port_Is_Absent_In_The_Vlan; 909 } 910 rc = STP_port_trace_state_machine (port, mach_name, enadis); 911 912 RSTP_CRITICAL_PATH_END; 913 914 return rc; 915 } 916 917 #endif 918 919 const char* 920 STP_IN_get_error_explanation (int rstp_err_no) 921 { 922 #define CHOOSE(a) #a 923 static char* rstp_error_names[] = RSTP_ERRORS; 924 #undef CHOOSE 925 if (rstp_err_no < STP_OK) { 926 return "Too small error code :("; 927 } 928 if (rstp_err_no >= STP_LAST_DUMMY) { 929 return "Too big error code :("; 930 } 931 932 return rstp_error_names[rstp_err_no]; 933 } 934 935 int 936 STP_IN_port_add(int vlan_id, int port_index) 937 { 938 STPM_T *this; 939 PORT_T *port; 940 int rc = STP_OK; 941 942 RSTP_CRITICAL_PATH_START; 943 this = stpapi_stpm_find (vlan_id); 944 945 if (!this) { /* it had not yet been created :( */ 946 RSTP_CRITICAL_PATH_END; 947 return STP_Vlan_Had_Not_Yet_Been_Created; 948 } 949 950 port = this->ports; 951 952 if (! STP_port_create (this, port_index)) { 953 /* can't add port :( */ 954 stp_trace ("can't create port %d", port_index); 955 RSTP_CRITICAL_PATH_END; 956 return STP_Cannot_Create_Instance_For_Port; 957 } 958 959 if (!port) 960 rc = STP_stpm_start (this); 961 962 RSTP_CRITICAL_PATH_END; 963 964 return rc; 965 } 966 967 int 968 STP_IN_port_remove(int vlan_id, int port_index) 969 { 970 STPM_T *this; 971 PORT_T *port; 972 973 RSTP_CRITICAL_PATH_START; 974 this = stpapi_stpm_find (vlan_id); 975 976 if (!this) { /* it had not yet been created :( */ 977 RSTP_CRITICAL_PATH_END; 978 return STP_Vlan_Had_Not_Yet_Been_Created; 979 } 980 981 port = _stpapi_port_find (this, port_index); 982 if (! port) {/* port is absent in the stpm :( */ 983 RSTP_CRITICAL_PATH_END; 984 return STP_Port_Is_Absent_In_The_Vlan; 985 } 986 987 STP_port_delete (port); 988 989 if (!this->ports) 990 STP_stpm_stop (this); 991 RSTP_CRITICAL_PATH_END; 992 993 return STP_OK; 994 } 995 996 void 997 STP_IN_get_bridge_id(int vlan_id, unsigned short *priority, unsigned char *mac) 998 { 999 STPM_T *this; 1000 1001 RSTP_CRITICAL_PATH_START; 1002 this = stpapi_stpm_find (vlan_id); 1003 *priority = this->BrId.prio; 1004 (void) memcpy(mac, this->BrId.addr, 6); 1005 RSTP_CRITICAL_PATH_END; 1006 } 1007 1008 const char * 1009 STP_IN_state2str(RSTP_PORT_STATE state) 1010 { 1011 switch (state) { 1012 case UID_PORT_DISABLED: 1013 return ("disabled"); 1014 case UID_PORT_DISCARDING: 1015 return ("discarding"); 1016 case UID_PORT_LEARNING: 1017 return ("learning"); 1018 case UID_PORT_FORWARDING: 1019 return ("forwarding"); 1020 case UID_PORT_NON_STP: 1021 return ("non-stp"); 1022 case UID_PORT_BADSDU: /* synthetic state used by daemon */ 1023 return ("bad-mtu"); 1024 } 1025 return ("unknown"); 1026 } 1027