xref: /titanic_52/usr/src/lib/librstp/common/stp_in.c (revision 7fd791373689a6af05e27efec3b1ab556e02aa23)
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