removed apps
[luayats.git] / src / rstp / portinfo.c
blobfec25870ce71507240f6c44a8e8aa5d51d957871
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
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.
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 #define this _this
23 #include "base.h"
24 #include "stpm.h"
27 /* The Port Information State Machine : 17.21 */
28 /*kd: unter hinzufĆ¼gte man die neu Namen, die im 802.1D definieren*/
29 #define STATES { \
30 CHOOSE(DISABLED), \
31 CHOOSE(ENABLED), \
32 CHOOSE(AGED), \
33 CHOOSE(UPDATE), \
34 CHOOSE(CURRENT), \
35 CHOOSE(RECEIVE), \
36 CHOOSE(AGREEMENT), \
37 CHOOSE(SUPERIOR_DESIGNATED), \
38 CHOOSE(REPEATED_DESIGNATED), \
39 CHOOSE(INFERIOR_DESIGNATED), \
40 CHOOSE(NOT_DESIGNATED), \
41 CHOOSE(OTHER), \
44 #define GET_STATE_NAME STP_info_get_state_name
45 #include "choose.h"
47 /******************************************************************/
48 void _stp_dump (char* title, unsigned char* buff, int len)
50 register int iii;
52 printf ("\n%s:", title);
53 for (iii = 0; iii < len; iii++) {
54 if (! (iii % 24)) Print ("\n%6d:", iii);
55 if (! (iii % 8)) Print (" ");
56 Print ("%02lx", (unsigned long) buff[iii]);
58 Print ("\n");
61 /* 17.21.8 checked leu */
62 static RCVD_MSG_T rcvInfo (STATE_MACH_T* this)
64 int bridcmp;
65 register PORT_T* port = this->owner.port;
67 if (port->msgBpduType == BPDU_TOPO_CHANGE_TYPE) {
68 #ifdef STP_DBG
69 if (this->debug) {
70 stp_trace ("%s", "OtherInfo:BPDU_TOPO_CHANGE_TYPE");
72 #endif
73 return OtherInfo;
76 port->msgPortRole = RSTP_PORT_ROLE_UNKN;
78 if (BPDU_RSTP == port->msgBpduType) {
79 port->msgPortRole = (port->msgFlags & PORT_ROLE_MASK) >> PORT_ROLE_OFFS;
82 /* 17.21.8: a)
83 * msgPrio superior to portPrio: < 0 OR
84 * msgPrio same as portPrio: == 0
85 * Note leu: We compare only the following compontents here:
86 * vec = (R:RPC:D:PD:PB)
87 * frist clause: superior
88 * msgPrio = (R:RPC:D:PD:-)
89 * portPrio = (R:RPC:D:PD:-)
90 * second clause: same as - why exclude R, RPC and PB ???
91 * msgPrio = (-:-:D:PD:-)
92 * portPrio = (-:-:D:PD:-)
95 if (RSTP_PORT_ROLE_DESGN == port->msgPortRole ||
96 BPDU_CONFIG_TYPE == port->msgBpduType) {
97 bridcmp = STP_VECT_compare_vector(&port->msgPrio, &port->portPrio);
98 /* Clause a) superior info ? */
99 if (((bridcmp < 0) ||
100 ((STP_VECT_compare_bridge_id(&port->msgPrio.design_bridge,
101 &port->portPrio.design_bridge) == 0) &&
102 (port->msgPrio.design_port == port->portPrio.design_port))) ||
103 /* Clause b) times changed */
104 ((bridcmp == 0) &&
105 (STP_compare_times(&port->msgTimes, &port->portTimes) != 0))) {
106 #ifdef STP_DBG
107 if (this->debug) {
108 stp_trace ("SuperiorDesignatednfo: bridcmp=%d", (int) bridcmp);
110 #endif
111 return SuperiorDesignatedInfo;
115 /* 17.21.8: b)
116 * msgPrio same as portPrio: == 0
117 * msgTimes same as portTimes: == 0
119 if (BPDU_CONFIG_TYPE == port->msgBpduType ||
120 RSTP_PORT_ROLE_DESGN == port->msgPortRole) {
121 if ((STP_VECT_compare_vector(&port->msgPrio, &port->portPrio) == 0) &&
122 (STP_compare_times(&port->msgTimes, &port->portTimes) == 0)) {
123 #ifdef STP_DBG
124 if (this->debug) {
125 stp_trace ("%s", "RepeatedDesignatedInfo");
127 #endif
128 return RepeatedDesignatedInfo;
132 /* 17.21.8: c)
133 * msgPrio worse than portPrio: > 0
135 if (RSTP_PORT_ROLE_DESGN == port->msgPortRole ||
136 BPDU_CONFIG_TYPE == port->msgBpduType) {
137 bridcmp = STP_VECT_compare_vector(&port->msgPrio, &port->portPrio);
138 if (bridcmp > 0) {
139 #ifdef STP_DBG
140 if (this->debug) {
141 stp_trace ("%s %d", "InferiorDesignatedInfo", (int) bridcmp);
143 #endif
144 return InferiorDesignatedInfo;
148 /* 17.21.8: d)
149 * msgPrio same as or worse than portPrio: >= 0
152 if (RSTP_PORT_ROLE_ROOT == port->msgPortRole ||
153 RSTP_PORT_ROLE_ALTBACK == port->msgPortRole ||
154 BPDU_CONFIG_TYPE == port->msgBpduType) {
155 bridcmp = STP_VECT_compare_vector (&port->msgPrio, &port->portPrio);
156 #if 0
157 if ((bridcmp >= 0) &&
158 (STP_compare_times (&port->msgTimes, &port->portTimes) == 0)) {
159 #else
160 if (bridcmp >= 0){
161 #endif
162 #ifdef STP_DBG
163 if (this->debug) {
164 stp_trace ("%s", "InferiorRootAlternateInfo");
166 #endif
167 return InferiorRootAlternateInfo;
170 #ifdef STP_DBG
171 if (this->debug) {
172 stp_trace ("%s", "OtherInfo");
174 #endif
175 return OtherInfo; /* kd: die neue Name*/
179 /******************************************************************/
180 /* 17.21.11 checked leu */
181 static Bool recordProposal (STATE_MACH_T* this)
183 register PORT_T* port = this->owner.port;
185 if (RSTP_PORT_ROLE_DESGN == port->msgPortRole &&
186 (PROPOSAL_BIT & port->msgFlags)) {
187 port->proposed = True;
188 return True;
190 return False;
193 /******************************************************************/
194 /* 17.21.1 checked leu */
195 static Bool betterorsameInfo (STATE_MACH_T* this, INFO_IS_T newInfoIs)
197 register PORT_T* port = this->owner.port;
198 int bridcmp_a, bridcmp_b;
199 bridcmp_a = STP_VECT_compare_vector(&port->msgPrio, &port->portPrio);
200 bridcmp_b = STP_VECT_compare_vector(&port->designPrio, &port->portPrio);
201 if (((newInfoIs == Received && port->infoIs == Received) &&
202 (bridcmp_a <= 0)) ||
203 ((newInfoIs == Mine && port->infoIs == Mine) &&
204 (bridcmp_b <= 0))){
205 #ifdef STP_DBG
206 if (port->info->debug){
207 stp_trace("port %s has better or same info: %s True agree=%d cmp(msg,port)=%d cmp(des,port)=%d",
208 port->port_name, newInfoIs == Mine ? "Mine" : "Received",
209 port->agree, bridcmp_a, bridcmp_b);
211 #endif
212 return True;
213 } else {
214 #ifdef STP_DBG
215 if (port->info->debug){
216 stp_trace("port %s has worse info: %s False agree=%d cmp(msg,port)=%d cmp(des,port)=%d",
217 port->port_name, newInfoIs == Mine ? "Mine" : "Received",
218 port->agree, bridcmp_a, bridcmp_b);
220 #endif
221 return False;
225 /****************************************************************/
226 /* 17.21.12 checked leu */
227 static Bool recordPriority (STATE_MACH_T* this)
229 register PORT_T* port = this->owner.port;
231 STP_VECT_copy (&port->portPrio, &port->msgPrio);
232 return True;
235 /*******************************************************************/
236 /* 17.21.10 checked leu */
237 static Bool recordDispute (STATE_MACH_T* this)
239 register PORT_T* port = this->owner.port;
240 register Bool rd = False;
241 if ((BPDU_RSTP == port->msgBpduType) && (port->msgFlags & LEARN_BIT)){
242 rd = port->agreed = True;
243 port->proposing = False;
244 port->disputed = True;
245 #ifdef STP_DBG
246 if (this->debug) {
247 stp_trace ("port %s sets agreed and resets proposing", port->port_name);
249 #endif
251 return rd;
254 /****************************************************************/
255 /* 17.21.13 checked: leu */
256 static unsigned short recordTimes (STATE_MACH_T* this)
258 register PORT_T* port = this->owner.port;
260 port->portTimes.MessageAge = port->msgTimes.MessageAge;
261 port->portTimes.MaxAge = port->msgTimes.MaxAge;
262 port->portTimes.ForwardDelay = port->msgTimes.ForwardDelay;
263 if (port->msgTimes.HelloTime > 1)
264 port->portTimes.HelloTime = port->msgTimes.HelloTime;
265 else
266 port->portTimes.HelloTime = 1;
268 return 0;
271 /****************************************************************/
272 /* 17.21.17 checked: leu */
273 static Bool setTcFlags (STATE_MACH_T* this)
275 register PORT_T* port = this->owner.port;
277 if (BPDU_TOPO_CHANGE_TYPE == port->msgBpduType) {
278 #ifdef STP_DBG
279 if (this->debug) {
280 stp_trace ("port %s rx rcvdTcn", port->port_name);
282 #endif
283 port->rcvdTcn = True;
284 } else {
285 if (TOLPLOGY_CHANGE_BIT & port->msgFlags) {
286 #ifdef STP_DBG
287 if (this->debug) {
288 stp_trace ("(%s-%s) rx rcvdTc 0X%lx",
289 port->owner->name, port->port_name,
290 (unsigned long) port->msgFlags);
292 #endif
293 port->rcvdTc = True;
295 if (TOLPLOGY_CHANGE_ACK_BIT & port->msgFlags) {
296 #ifdef STP_DBG
297 if (this->debug) {
298 stp_trace ("port %s rx rcvdTcAck 0X%lx",
299 port->port_name,
300 (unsigned long) port->msgFlags);
302 #endif
303 port->rcvdTcAck = True;
306 return True;
309 /*****************************************************************/
310 /* 17.29.11 checked leu */
311 static Bool rstpVer (STATE_MACH_T* this)
313 STPM_T *stpm = this->owner.stpm;
314 Bool rstpVersion;
315 if (stpm->ForceVersion >= 2)
316 rstpVersion =True;
317 else
318 rstpVersion = False;
319 return rstpVersion;
323 /*****************************************************************/
324 /* 17.21.9 checked leu */
325 static Bool recordAgreement(STATE_MACH_T* this)
327 register PORT_T* port = this->owner.port;
328 register Bool ra;
329 if (rstpVer(this) == True && port->operPointToPointMac == True
330 && (AGREEMENT_BIT & port->msgFlags)) {
331 ra = port->agreed = True;
332 ra = port->proposing = False;
334 else
335 ra = port->agreed = False;
336 return ra;
339 /****************************************************************/
340 /* 17.21.23: checked leu */
341 static Bool updtRcvdInfoWhile (STATE_MACH_T* this)
343 register int eff_age;
344 register PORT_T* port = this->owner.port;
346 eff_age = port->portTimes.MessageAge + 1;
348 if (eff_age <= port->portTimes.MaxAge) {
349 port->rcvdInfoWhile = 3 * port->portTimes.HelloTime;
350 #ifdef STP_DBG
351 #if 0
352 stp_trace ("port %s: MessageAge=%d EffectiveAge=%d",
353 port->port_name,
354 (int) port->portTimes.MessageAge,
355 (int) eff_age);
356 #endif
357 #endif
358 } else {
359 port->rcvdInfoWhile = 0;
360 #ifdef STP_DBG
361 stp_trace ("port %s: MaxAge=%d MessageAge=%d HelloTime=%d rcvdInfoWhile=null !",
362 port->port_name,
363 (int) port->portTimes.MaxAge,
364 (int) port->portTimes.MessageAge,
365 (int) port->portTimes.HelloTime);
366 #endif
368 return True;
371 /****************************************************************/
372 void STP_info_rx_bpdu (PORT_T* port, struct stp_bpdu_t* bpdu, size_t len)
374 #ifdef STP_DBG_BPDU
375 _stp_dump ("\nall BPDU", ((unsigned char*) bpdu) - 12, len + 12);
376 _stp_dump ("ETH_HEADER", (unsigned char*) &bpdu->eth, 5);
377 _stp_dump ("BPDU_HEADER", (unsigned char*) &bpdu->hdr, 4);
378 printf ("protocol=%02x%02x version=%02x bpdu_type=%02x\n",
379 bpdu->hdr.protocol[0], bpdu->hdr.protocol[1],
380 bpdu->hdr.version, bpdu->hdr.bpdu_type);
382 _stp_dump ("\nBPDU_BODY", (unsigned char*) &bpdu->body, sizeof (BPDU_BODY_T) + 2);
383 printf ("flags=%02x\n", bpdu->body.flags);
384 _stp_dump ("root_id", bpdu->body.root_id, 8);
385 _stp_dump ("root_path_cost", bpdu->body.root_path_cost, 4);
386 _stp_dump ("bridge_id", bpdu->body.bridge_id, 8);
387 _stp_dump ("port_id", bpdu->body.port_id, 2);
388 _stp_dump ("message_age", bpdu->body.message_age, 2);
389 _stp_dump ("max_age", bpdu->body.max_age, 2);
390 _stp_dump ("hello_time", bpdu->body.hello_time, 2);
391 _stp_dump ("forward_delay", bpdu->body.forward_delay, 2);
392 _stp_dump ("ver_1_len", bpdu->ver_1_len, 2);
393 #endif
395 /* check bpdu type */
396 switch (bpdu->hdr.bpdu_type) {
398 case BPDU_CONFIG_TYPE:
399 port->rx_cfg_bpdu_cnt++;
400 #ifdef STP_DBG
401 if (port->info->debug)
402 stp_trace ("CfgBpdu on port %s", port->port_name);
403 #endif
404 if (port->admin_non_stp) return;
405 port->rcvdBpdu = True;
406 break;
408 case BPDU_TOPO_CHANGE_TYPE:
409 port->rx_tcn_bpdu_cnt++;
410 #ifdef STP_DBG
411 if (port->info->debug)
412 stp_trace ("TcnBpdu on port %s", port->port_name);
413 #endif
414 if (port->admin_non_stp) return;
415 port->rcvdBpdu = True;
416 port->msgBpduVersion = bpdu->hdr.version;
417 port->msgBpduType = bpdu->hdr.bpdu_type;
418 return;
420 case BPDU_RSTP:
421 port->rx_rstp_bpdu_cnt++;
422 if (port->admin_non_stp) return;
423 if (port->owner->ForceVersion >= NORMAL_RSTP) {
424 port->rcvdBpdu = True;
425 } else {
426 return;
428 #ifdef STP_DBG
429 if (port->info->debug)
430 stp_trace ("BPDU_RSTP on port %s", port->port_name);
431 #endif
432 break;
434 default:
435 stp_trace ("RX undef bpdu type=%d", (int) bpdu->hdr.bpdu_type);
436 return;
440 port->msgBpduVersion = bpdu->hdr.version;
441 port->msgBpduType = bpdu->hdr.bpdu_type;
442 port->msgFlags = bpdu->body.flags;
444 STP_VECT_get_vector (&bpdu->body, &port->msgPrio);
445 port->msgPrio.bridge_port = port->port_id;
447 STP_get_times (&bpdu->body, &port->msgTimes);
450 /****************************************************************/
451 void STP_info_enter_state (STATE_MACH_T* this)
453 register PORT_T* port = this->owner.port;
455 switch (this->State) {
456 case BEGIN:
457 port->rcvdMsg = OtherInfo;
458 port->msgBpduType = 0xff;
459 port->msgPortRole = RSTP_PORT_ROLE_UNKN;
460 port->msgFlags = 0;
462 /* clear port statistics */
463 port->rx_cfg_bpdu_cnt =
464 port->rx_rstp_bpdu_cnt =
465 port->rx_tcn_bpdu_cnt = 0;
467 case DISABLED:
468 port->rcvdMsg = False;
469 port->agreed = port->proposing =
470 port->proposed = port->agree = False;
471 port->rcvdInfoWhile = 0;
472 port->infoIs = Disabled;
473 port->reselect = True;
474 port->selected = False;
475 break;
477 case ENABLED: /* IEEE 802.1y, 17.21, Z.14 */
478 STP_VECT_copy (&port->portPrio, &port->designPrio);
479 STP_copy_times (&port->portTimes, &port->designTimes);
480 break;
482 case AGED:
483 port->infoIs = Aged;
484 port->reselect = True;
485 port->selected = False;
486 break;
488 case UPDATE:
489 port->proposed = port->proposing = False;
490 port->agreed = port->agreed && betterorsameInfo (this, Mine);
491 port->synced = port->synced && port->agreed;
492 STP_VECT_copy (&port->portPrio, &port->designPrio);
493 STP_copy_times (&port->portTimes, &port->designTimes);
494 port->updtInfo = False;
495 port->infoIs = Mine;
496 port->newInfo = True;
497 #ifdef STP_DBG
498 if (this->debug) {
499 STP_VECT_br_id_print ("updated: portPrio.design_bridge",
500 &port->portPrio.design_bridge, True);
502 #endif
503 break;
505 case CURRENT:
506 break;
508 case RECEIVE:
509 port->rcvdInfo = rcvInfo (this);
511 break;
513 case SUPERIOR_DESIGNATED:
514 port->agreed = False;
515 port->proposing = False;
516 recordProposal (this);
517 setTcFlags (this);
518 port->agree = port->agree && betterorsameInfo (this, Received);
519 recordPriority (this);
520 recordTimes (this);
521 updtRcvdInfoWhile (this);
522 port->infoIs = Received;
523 port->reselect = True;
524 port->selected = False;
525 port-> rcvdMsg = False;
526 #ifdef STP_DBG
527 if (this->debug) {
528 STP_VECT_br_id_print ("stored: portPrio.design_bridge",
529 &port->portPrio.design_bridge, True);
530 stp_trace ("proposed=%d on port %s",
531 (int) port->proposed, port->port_name);
533 #endif
534 break;
536 case REPEATED_DESIGNATED:
537 recordProposal (this);
538 setTcFlags (this);
539 updtRcvdInfoWhile (this);
540 port->rcvdMsg = False;
541 break;
543 case INFERIOR_DESIGNATED:
544 recordDispute (this);
545 port->rcvdMsg = False;
546 break;
548 case NOT_DESIGNATED:
549 recordAgreement (this);
550 setTcFlags(this);
551 port->rcvdMsg = False;
552 break;
554 case OTHER:
555 port->rcvdMsg = False;
556 break;
560 /****************************************************************/
561 Bool STP_info_check_conditions (STATE_MACH_T* this)
563 register PORT_T* port = this->owner.port;
565 if ((! portEnabled(port) && port->infoIs != Disabled) || BEGIN == this->State) {
566 return STP_hop_2_state (this, DISABLED);
569 switch (this->State) {
570 case DISABLED:
571 if (port->rcvdMsg) {
572 return STP_hop_2_state (this, DISABLED);
574 if (portEnabled(port)) {
575 return STP_hop_2_state (this, AGED);
577 break;
579 case ENABLED:
580 return STP_hop_2_state (this, AGED);
581 break;
583 case AGED:
584 if (port->selected && port->updtInfo) {
585 return STP_hop_2_state (this, UPDATE);
587 break;
589 case UPDATE:
590 return STP_hop_2_state (this, CURRENT);
591 break;
593 case CURRENT:
594 if (port->selected && port->updtInfo) {
595 return STP_hop_2_state (this, UPDATE);
598 if (Received == port->infoIs &&
599 port->rcvdInfoWhile==0 &&
600 ! port->updtInfo &&
601 ! port->rcvdMsg) {
602 return STP_hop_2_state (this, AGED);
604 if (port->rcvdMsg && !port->updtInfo) {
605 return STP_hop_2_state (this, RECEIVE);
607 break;
609 case RECEIVE:
610 switch (port->rcvdInfo) {
611 case SuperiorDesignatedInfo:
612 return STP_hop_2_state (this, SUPERIOR_DESIGNATED);
613 case RepeatedDesignatedInfo:
614 return STP_hop_2_state (this, REPEATED_DESIGNATED);
615 case InferiorDesignatedInfo:
616 return STP_hop_2_state (this, INFERIOR_DESIGNATED);
617 case InferiorRootAlternateInfo:
618 return STP_hop_2_state (this, NOT_DESIGNATED);
619 case OtherInfo:
620 return STP_hop_2_state (this, OTHER);
622 break;
624 case SUPERIOR_DESIGNATED:
625 return STP_hop_2_state (this, CURRENT);
626 break;
628 case REPEATED_DESIGNATED:
629 return STP_hop_2_state (this, CURRENT);
630 break;
632 case INFERIOR_DESIGNATED:
633 return STP_hop_2_state (this, CURRENT);
634 break;
636 case NOT_DESIGNATED:
637 return STP_hop_2_state (this, CURRENT);
638 break;
640 case OTHER:
641 return STP_hop_2_state (this, CURRENT);
642 break;
644 return False;