1 /************************************************************************
2 * RSTP library - Rapid Spanning Tree (802.1t, 802.1w)
3 * Copyright (C) 2001-2003 Optical Access
6 * This file is part of RSTP library.
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
21 **********************************************************************/
23 /* Port Transmit state machine : 17.27 */
27 #include "stp_to.h" /* for STP_OUT_get_port_mac & STP_OUT_tx_bpdu */
29 #define BPDU_LEN8023_OFF 12
32 CHOOSE(TRANSMIT_INIT), \
33 CHOOSE(TRANSMIT_PERIODIC), \
35 CHOOSE(TRANSMIT_CONFIG), \
36 CHOOSE(TRANSMIT_TCN), \
37 CHOOSE(TRANSMIT_RSTP) \
40 #define GET_STATE_NAME STP_transmit_get_state_name
43 #define MIN_FRAME_LENGTH 64
46 typedef struct tx_tcn_bpdu_t
{
52 typedef struct tx_stp_bpdu_t
{
59 typedef struct tx_rstp_bpdu_t
{
64 unsigned char ver_1_length
[2];
68 static RSTP_BPDU_T bpdu_packet
= {
70 {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00}, /* dst_mac */
71 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* src_mac */
74 {0x00, 0x00}, /* len8023 */
75 BPDU_L_SAP
, BPDU_L_SAP
, LLC_UI
/* dsap, ssap, llc */
78 {0x00, 0x00}, /* protocol */
79 BPDU_VERSION_ID
, 0x00 /* version, bpdu_type */
83 {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /* root_id[8]; */
84 {0x00,0x00,0x00,0x00}, /* root_path_cost[4]; */
85 {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /* bridge_id[8]; */
86 {0x00,0x00}, /* port_id[2]; */
87 {0x00,0x00}, /* message_age[2]; */
88 {0x00,0x00}, /* max_age[2]; */
89 {0x00,0x00}, /* hello_time[2]; */
90 {0x00,0x00}, /* forward_delay[2]; */
92 {0x00,0x00}, /* ver_1_length[2]; */
96 build_bpdu_header (int port_index
,
97 unsigned char bpdu_type
,
98 unsigned short pkt_len
)
100 unsigned short len8023
;
102 STP_OUT_get_port_mac (port_index
, bpdu_packet
.mac
.src_mac
);
104 bpdu_packet
.hdr
.bpdu_type
= bpdu_type
;
105 bpdu_packet
.hdr
.version
= (BPDU_RSTP
== bpdu_type
) ?
106 BPDU_VERSION_RAPID_ID
:
109 /* NOTE: I suppose, that sizeof(unsigned short)=2 ! */
110 len8023
= htons ((unsigned short) (pkt_len
+ 3));
111 (void) memcpy (&bpdu_packet
.eth
.len8023
, &len8023
, 2);
113 if (pkt_len
< MIN_FRAME_LENGTH
) pkt_len
= MIN_FRAME_LENGTH
;
118 txTcn (STATE_MACH_T
* this)
119 { /* 17.19.17 (page 68) & 9.3.2 (page 25) */
120 register size_t pkt_len
;
121 register int port_index
, vlan_id
;
124 if (this->owner
.port
->skip_tx
> 0) {
125 if (1 == this->owner
.port
->skip_tx
)
126 stp_trace ("port %s stop tx skipping",
127 this->owner
.port
->port_name
);
128 this->owner
.port
->skip_tx
--;
129 return STP_Nothing_To_Do
;
133 if (this->owner
.port
->admin_non_stp
) return 1;
134 port_index
= this->owner
.port
->port_index
;
135 vlan_id
= this->owner
.port
->owner
->vlan_id
;
137 pkt_len
= build_bpdu_header (port_index
,
138 BPDU_TOPO_CHANGE_TYPE
,
139 sizeof (BPDU_HEADER_T
));
143 stp_trace ("port %s txTcn", this->owner
.port
->port_name
);
145 return STP_OUT_tx_bpdu (port_index
, vlan_id
,
146 (unsigned char *) &bpdu_packet
,
151 build_config_bpdu (PORT_T
* port
, Bool set_topo_ack_flag
)
153 bpdu_packet
.body
.flags
= 0;
156 if (port
->topoch
->debug
)
157 stp_trace ("tcWhile=%d =>tx TOPOLOGY_CHANGE_BIT to port %s",
158 (int) port
->tcWhile
, port
->port_name
);
160 bpdu_packet
.body
.flags
|= TOPOLOGY_CHANGE_BIT
;
163 if (set_topo_ack_flag
&& port
->tcAck
) {
164 bpdu_packet
.body
.flags
|= TOPOLOGY_CHANGE_ACK_BIT
;
167 STP_VECT_set_vector (&port
->portPrio
, &bpdu_packet
.body
);
168 STP_set_times (&port
->portTimes
, &bpdu_packet
.body
);
172 txConfig (STATE_MACH_T
* this)
173 {/* 17.19.15 (page 67) & 9.3.1 (page 23) */
174 register size_t pkt_len
;
175 register PORT_T
* port
= NULL
;
176 register int port_index
, vlan_id
;
179 if (this->owner
.port
->skip_tx
> 0) {
180 if (1 == this->owner
.port
->skip_tx
)
181 stp_trace ("port %s stop tx skipping",
182 this->owner
.port
->port_name
);
183 this->owner
.port
->skip_tx
--;
184 return STP_Nothing_To_Do
;
188 port
= this->owner
.port
;
189 if (port
->admin_non_stp
) return 1;
190 port_index
= port
->port_index
;
191 vlan_id
= port
->owner
->vlan_id
;
193 pkt_len
= build_bpdu_header (port
->port_index
,
195 sizeof (BPDU_HEADER_T
) + sizeof (BPDU_BODY_T
));
196 build_config_bpdu (port
, True
);
200 stp_trace ("port %s txConfig flags=0X%lx",
202 (unsigned long) bpdu_packet
.body
.flags
);
204 return STP_OUT_tx_bpdu (port_index
, vlan_id
,
205 (unsigned char *) &bpdu_packet
,
210 txRstp (STATE_MACH_T
* this)
211 {/* 17.19.16 (page 68) & 9.3.3 (page 25) */
212 register size_t pkt_len
;
213 register PORT_T
* port
= NULL
;
214 register int port_index
, vlan_id
;
218 if (this->owner
.port
->skip_tx
> 0) {
219 if (1 == this->owner
.port
->skip_tx
)
220 stp_trace ("port %s stop tx skipping",
221 this->owner
.port
->port_name
);
223 stp_trace ("port %s skip tx %d",
224 this->owner
.port
->port_name
, this->owner
.port
->skip_tx
);
226 this->owner
.port
->skip_tx
--;
227 return STP_Nothing_To_Do
;
231 port
= this->owner
.port
;
232 if (port
->admin_non_stp
) return 1;
233 port_index
= port
->port_index
;
234 vlan_id
= port
->owner
->vlan_id
;
236 pkt_len
= build_bpdu_header (port
->port_index
,
238 sizeof (BPDU_HEADER_T
) + sizeof (BPDU_BODY_T
) + 2);
239 build_config_bpdu (port
, False
);
241 switch (port
->selectedRole
) {
244 role
= RSTP_PORT_ROLE_UNKN
;
247 role
= RSTP_PORT_ROLE_ALTBACK
;
250 role
= RSTP_PORT_ROLE_ALTBACK
;
253 role
= RSTP_PORT_ROLE_ROOT
;
256 role
= RSTP_PORT_ROLE_DESGN
;
260 bpdu_packet
.body
.flags
|= (role
<< PORT_ROLE_OFFS
);
263 #if 0 /* def STP_DBG */
264 if (port
->roletrns
->debug
)
265 stp_trace ("tx AGREEMENT_BIT to port %s", port
->port_name
);
267 bpdu_packet
.body
.flags
|= AGREEMENT_BIT
;
270 if (port
->proposing
) {
271 #if 0 /* def STP_DBG */
272 if (port
->roletrns
->debug
)
273 stp_trace ("tx PROPOSAL_BIT to port %s", port
->port_name
);
275 bpdu_packet
.body
.flags
|= PROPOSAL_BIT
;
280 stp_trace ("port %s txRstp flags=0X%lx",
282 (unsigned long) bpdu_packet
.body
.flags
);
285 return STP_OUT_tx_bpdu (port_index
, vlan_id
,
286 (unsigned char *) &bpdu_packet
,
291 STP_transmit_enter_state (STATE_MACH_T
* this)
293 register PORT_T
* port
= this->owner
.port
;
295 switch (this->State
) {
298 port
->newInfo
= False
;
302 case TRANSMIT_PERIODIC
:
303 port
->newInfo
= port
->newInfo
||
304 ((port
->role
== DesignatedPort
) ||
305 ((port
->role
== RootPort
) && port
->tcWhile
));
306 port
->helloWhen
= port
->owner
->rootTimes
.HelloTime
;
310 case TRANSMIT_CONFIG
:
311 port
->newInfo
= False
;
312 (void) txConfig (this);
317 port
->newInfo
= False
;
322 port
->newInfo
= False
;
323 (void) txRstp (this);
331 STP_transmit_check_conditions (STATE_MACH_T
* this)
333 register PORT_T
* port
= this->owner
.port
;
335 switch (this->State
) {
337 return STP_hop_2_state (this, TRANSMIT_INIT
);
339 return STP_hop_2_state (this, IDLE
);
340 case TRANSMIT_PERIODIC
:
341 return STP_hop_2_state (this, IDLE
);
343 if (!port
->helloWhen
) return STP_hop_2_state (this, TRANSMIT_PERIODIC
);
344 if (!port
->sendRSTP
&& port
->newInfo
&&
345 (port
->txCount
< TxHoldCount
) &&
346 (port
->role
== DesignatedPort
) &&
348 return STP_hop_2_state (this, TRANSMIT_CONFIG
);
349 if (!port
->sendRSTP
&& port
->newInfo
&&
350 (port
->txCount
< TxHoldCount
) &&
351 (port
->role
== RootPort
) &&
353 return STP_hop_2_state (this, TRANSMIT_TCN
);
354 if (port
->sendRSTP
&& port
->newInfo
&&
355 (port
->txCount
< TxHoldCount
) &&
356 ((port
->role
== RootPort
) ||
357 (port
->role
== DesignatedPort
)))
358 return STP_hop_2_state (this, TRANSMIT_RSTP
);
360 case TRANSMIT_CONFIG
:
361 return STP_hop_2_state (this, IDLE
);
363 return STP_hop_2_state (this, IDLE
);
365 return STP_hop_2_state (this, IDLE
);