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 /* STP PORT instance : 17.18, 17.15 */
24
25 #include "base.h"
26 #include "stpm.h"
27 #include "stp_in.h"
28
29 /* #include "rolesel.h" */
30 #include "portinfo.h"
31 #include "roletrns.h"
32 #include "sttrans.h"
33 #include "topoch.h"
34 #include "migrate.h"
35 #include "transmit.h"
36 #include "p2p.h"
37 #include "pcost.h"
38 #include "edge.h"
39
40 #include "stp_to.h" /* for STP_OUT_get_port_name & STP_OUT_get_port_link_status */
41
42 int port_trace_flags;
43
44 PORT_T *
STP_port_create(STPM_T * stpm,int port_index)45 STP_port_create (STPM_T* stpm, int port_index)
46 {
47 PORT_T* this;
48 UID_STP_PORT_CFG_T port_cfg;
49 register int iii;
50 unsigned short port_prio;
51
52 /* check, if the port has just been added */
53 for (this = stpm->ports; this; this = this->next) {
54 if (this->port_index == port_index) {
55 return NULL;
56 }
57 }
58
59 STP_NEW_IN_LIST(this, PORT_T, stpm->ports, "port create");
60
61 this->owner = stpm;
62 this->machines = NULL;
63 this->port_index = port_index;
64 this->port_name = strdup (STP_OUT_get_port_name (port_index));
65 this->uptime = 0;
66
67 STP_OUT_get_init_port_cfg (stpm->vlan_id, port_index, &port_cfg);
68 port_prio = port_cfg.port_priority;
69 this->admin_non_stp = port_cfg.admin_non_stp;
70 this->adminEdge = port_cfg.admin_edge;
71 this->adminPCost = port_cfg.admin_port_path_cost;
72 this->adminPointToPointMac = port_cfg.admin_point2point;
73
74 this->LinkDelay = DEF_LINK_DELAY;
75 this->port_id = (port_prio << 8) + port_index;
76
77 iii = 0;
78 this->timers[iii++] = &this->fdWhile;
79 this->timers[iii++] = &this->helloWhen;
80 this->timers[iii++] = &this->mdelayWhile;
81 this->timers[iii++] = &this->rbWhile;
82 this->timers[iii++] = &this->rcvdInfoWhile;
83 this->timers[iii++] = &this->rrWhile;
84 this->timers[iii++] = &this->tcWhile;
85 this->timers[iii++] = &this->txCount;
86 this->timers[iii++] = &this->lnkWhile;
87
88 /* create and bind port state machines */
89 STP_STATE_MACH_IN_LIST(topoch);
90
91 STP_STATE_MACH_IN_LIST(migrate);
92
93 STP_STATE_MACH_IN_LIST(p2p);
94
95 STP_STATE_MACH_IN_LIST(edge);
96
97 STP_STATE_MACH_IN_LIST(pcost)
98
99 STP_STATE_MACH_IN_LIST(info);
100
101 STP_STATE_MACH_IN_LIST(roletrns);
102
103 STP_STATE_MACH_IN_LIST(sttrans);
104
105 STP_STATE_MACH_IN_LIST(transmit);
106
107 #ifdef STP_DBG
108
109 #if 0
110 this->roletrns->ignoreHop2State = 14; /* DESIGNATED_PORT; */
111 this->info->ignoreHop2State = 3; /* CURRENT */
112 this->transmit->ignoreHop2State = 3; /* IDLE */
113 this->edge->ignoreHop2State = 0; /* DISABLED; */
114 #endif
115
116 #if 0
117 this->info->debug = 1;
118 this->pcost->debug = 1;
119 this->p2p->debug = 1;
120 this->edge->debug = 1;
121 this->migrate->debug = 1;
122 this->sttrans->debug = 1;
123 this->topoch->debug = 1;
124 this->roletrns->debug = 1;
125 #endif
126 this->sttrans->debug = 1;
127
128 #endif
129 return this;
130 }
131
132 void
STP_port_init(PORT_T * this,STPM_T * stpm,Bool check_link)133 STP_port_init (PORT_T* this, STPM_T* stpm, Bool check_link)
134 {
135 if (check_link) {
136 this->adminEnable = STP_OUT_get_port_link_status (this->port_index);
137 STP_VECT_create (&this->designPrio,
138 &stpm->BrId,
139 0,
140 &stpm->BrId,
141 this->port_id,
142 this->port_id);
143 STP_copy_times (&this->designTimes, &stpm->rootTimes);
144 }
145
146 /* reset timers */
147 this->fdWhile =
148 this->helloWhen =
149 this->mdelayWhile =
150 this->rbWhile =
151 this->rcvdInfoWhile =
152 this->rrWhile =
153 this->tcWhile =
154 this->txCount = 0;
155
156 this->msgPortRole = RSTP_PORT_ROLE_UNKN;
157 this->selectedRole = DisabledPort;
158 this->sendRSTP = True;
159 this->operSpeed = STP_OUT_get_port_oper_speed (this->port_index);
160 this->p2p_recompute = True;
161 }
162
163 void
STP_port_delete(PORT_T * this)164 STP_port_delete (PORT_T* this)
165 {
166 STPM_T* stpm;
167 register PORT_T* prev;
168 register PORT_T* tmp;
169 register STATE_MACH_T* stater;
170 register void* pv;
171
172 stpm = this->owner;
173
174 free (this->port_name);
175 for (stater = this->machines; stater; ) {
176 pv = (void*) stater->next;
177 STP_state_mach_delete (stater);
178 stater = (STATE_MACH_T*) pv;
179 }
180
181 prev = NULL;
182 for (tmp = stpm->ports; tmp; tmp = tmp->next) {
183 if (tmp->port_index == this->port_index) {
184 if (prev) {
185 prev->next = this->next;
186 } else {
187 stpm->ports = this->next;
188 }
189 STP_FREE(this, "stp instance");
190 break;
191 }
192 prev = tmp;
193 }
194 }
195
196 int
STP_port_rx_bpdu(PORT_T * this,BPDU_T * bpdu,size_t len)197 STP_port_rx_bpdu (PORT_T* this, BPDU_T* bpdu, size_t len)
198 {
199 STP_info_rx_bpdu (this, bpdu, len);
200
201 return 0;
202 }
203
204 #ifdef STP_DBG
STP_port_trace_state_machine(PORT_T * this,char * mach_name,int enadis)205 int STP_port_trace_state_machine (PORT_T* this, char* mach_name, int enadis)
206 {
207 STATE_MACH_T *stater;
208 int nmatch = 0;
209
210 for (stater = this->machines; stater; stater = stater->next) {
211 if (! strcmp (mach_name, "all") || ! strcmp (mach_name, stater->name)) {
212 if (stater->debug != enadis)
213 {
214 stp_trace ("port %s on %s trace %-8s (was %s) now %s",
215 this->port_name, this->owner->name,
216 stater->name,
217 stater->debug ? " enabled" :"disabled",
218 enadis ? " enabled" :"disabled");
219 }
220 stater->debug = enadis;
221 nmatch++;
222 }
223 }
224
225 if (nmatch == 0) {
226 stp_trace("port %s no such state machine as '%s'", this->port_name,
227 mach_name);
228 return STP_No_Such_State_Machine;
229 }
230
231 return 0;
232 }
233
STP_port_trace_flags(char * title,PORT_T * this)234 void STP_port_trace_flags (char* title, PORT_T* this)
235 {
236 unsigned long flag = 0L;
237
238 if (!port_trace_flags) return;
239
240 if (this->reRoot) flag |= 0x000001L;
241 if (this->sync) flag |= 0x000002L;
242 if (this->synced) flag |= 0x000004L;
243
244 if (this->proposed) flag |= 0x000010L;
245 if (this->proposing) flag |= 0x000020L;
246 if (this->agreed) flag |= 0x000040L;
247 if (this->updtInfo) flag |= 0x000080L;
248
249 if (this->operEdge) flag |= 0x000100L;
250 stp_trace (" %-12s: flags=0x%04lx fdWhile=%d port=%s", title, flag, this->fdWhile, this->port_name);
251 }
252
253 #endif
254