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 *
stp_in_stpm_create(int vlan_id,char * name,int * err_code)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
_stp_in_stpm_enable(int vlan_id,char * name,UID_STP_MODE_T admin_state)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 *
stpapi_stpm_find(int vlan_id)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 *
_stpapi_port_find(STPM_T * this,int port_index)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
_conv_br_id_2_uid(IN BRIDGE_ID * f,OUT UID_BRIDGE_ID_T * t)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
_check_stpm_config(IN UID_STP_CFG_T * uid_cfg)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
_stp_in_enable_port_on_stpm(STPM_T * stpm,int port_index,Bool enable)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
STP_IN_init(STP_VECTORS_T * vectors)231 STP_IN_init (STP_VECTORS_T *vectors)
232 {
233 RSTP_INIT_CRITICAL_PATH_PROTECTIO;
234 stp_vectors = vectors;
235 }
236
237 int
STP_IN_stpm_get_cfg(IN int vlan_id,OUT UID_STP_CFG_T * uid_cfg)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
STP_IN_port_get_cfg(int vlan_id,int port_index,UID_STP_PORT_CFG_T * uid_cfg)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
STP_IN_port_get_state(IN int vlan_id,INOUT UID_STP_PORT_STATE_T * entry)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
STP_IN_stpm_get_state(IN int vlan_id,OUT UID_STP_STATE_T * entry)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
STP_IN_stpm_get_name_by_vlan_id(int vlan_id,char * name,size_t buffsize)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 */
STP_IN_enable_port(int port_index,Bool enable)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 */
STP_IN_changed_port_speed(int port_index,long speed)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 */
STP_IN_changed_port_duplex(int port_index)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
STP_IN_check_bpdu_header(BPDU_T * bpdu,size_t len)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
STP_IN_rx_bpdu(int vlan_id,int port_index,BPDU_T * bpdu,size_t len)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
STP_IN_one_second(void)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
STP_IN_stpm_set_cfg(IN int vlan_id,IN UID_STP_CFG_T * uid_cfg)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
STP_IN_port_set_cfg(IN int vlan_id,IN int port_index,IN UID_STP_PORT_CFG_T * uid_cfg)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
STP_IN_dbg_set_port_trace(char * mach_name,int enadis,int vlan_id,int port_no)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*
STP_IN_get_error_explanation(int rstp_err_no)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
STP_IN_port_add(int vlan_id,int port_index)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
STP_IN_port_remove(int vlan_id,int port_index)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
STP_IN_get_bridge_id(int vlan_id,unsigned short * priority,unsigned char * mac)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 *
STP_IN_state2str(RSTP_PORT_STATE state)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