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