]>
git.ipfire.org Git - people/ms/rstp.git/blob - rstplib/transmit.c
bbf0ff00fee56d2f4edc436988330f8d9b72aa0a
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 memcpy (&bpdu_packet
.eth
.len8023
, &len8023
, 2);
114 if (pkt_len
< MIN_FRAME_LENGTH
) pkt_len
= MIN_FRAME_LENGTH
;
116 /* Don't do this. LLC puts in 802.3 length based on what we transmit */
122 txTcn (STATE_MACH_T
* this)
123 { /* 17.19.17 (page 68) & 9.3.2 (page 25) */
124 register size_t pkt_len
;
125 register int port_index
, vlan_id
;
128 if (this->owner
.port
->skip_tx
> 0) {
129 if (1 == this->owner
.port
->skip_tx
)
130 stp_trace ("port %s stop tx skipping",
131 this->owner
.port
->port_name
);
132 this->owner
.port
->skip_tx
--;
133 return STP_Nothing_To_Do
;
137 if (this->owner
.port
->admin_non_stp
) return 1;
138 port_index
= this->owner
.port
->port_index
;
139 vlan_id
= this->owner
.port
->owner
->vlan_id
;
141 pkt_len
= build_bpdu_header (port_index
,
142 BPDU_TOPO_CHANGE_TYPE
,
143 sizeof (BPDU_HEADER_T
));
147 stp_trace ("port %s txTcn", this->owner
.port
->port_name
);
149 return STP_OUT_tx_bpdu (port_index
, vlan_id
,
150 (unsigned char *) &bpdu_packet
,
155 build_config_bpdu (PORT_T
* port
, Bool set_topo_ack_flag
)
157 bpdu_packet
.body
.flags
= 0;
160 if (port
->topoch
->debug
)
161 stp_trace ("tcWhile=%d =>tx TOLPLOGY_CHANGE_BIT to port %s",
162 (int) port
->tcWhile
, port
->port_name
);
164 bpdu_packet
.body
.flags
|= TOLPLOGY_CHANGE_BIT
;
167 if (set_topo_ack_flag
&& port
->tcAck
) {
168 bpdu_packet
.body
.flags
|= TOLPLOGY_CHANGE_ACK_BIT
;
171 STP_VECT_set_vector (&port
->portPrio
, &bpdu_packet
.body
);
172 STP_set_times (&port
->portTimes
, &bpdu_packet
.body
);
176 txConfig (STATE_MACH_T
* this)
177 {/* 17.19.15 (page 67) & 9.3.1 (page 23) */
178 register size_t pkt_len
;
179 register PORT_T
* port
= NULL
;
180 register int port_index
, vlan_id
;
183 if (this->owner
.port
->skip_tx
> 0) {
184 if (1 == this->owner
.port
->skip_tx
)
185 stp_trace ("port %s stop tx skipping",
186 this->owner
.port
->port_name
);
187 this->owner
.port
->skip_tx
--;
188 return STP_Nothing_To_Do
;
192 port
= this->owner
.port
;
193 if (port
->admin_non_stp
) return 1;
194 port_index
= port
->port_index
;
195 vlan_id
= port
->owner
->vlan_id
;
197 pkt_len
= build_bpdu_header (port
->port_index
,
199 sizeof (BPDU_HEADER_T
) + sizeof (BPDU_BODY_T
));
200 build_config_bpdu (port
, True
);
204 stp_trace ("port %s txConfig flags=0X%lx",
206 (unsigned long) bpdu_packet
.body
.flags
);
208 return STP_OUT_tx_bpdu (port_index
, vlan_id
,
209 (unsigned char *) &bpdu_packet
,
214 txRstp (STATE_MACH_T
* this)
215 {/* 17.19.16 (page 68) & 9.3.3 (page 25) */
216 register size_t pkt_len
;
217 register PORT_T
* port
= NULL
;
218 register int port_index
, vlan_id
;
222 if (this->owner
.port
->skip_tx
> 0) {
223 if (1 == this->owner
.port
->skip_tx
)
224 stp_trace ("port %s stop tx skipping",
225 this->owner
.port
->port_name
);
227 stp_trace ("port %s skip tx %d",
228 this->owner
.port
->port_name
, this->owner
.port
->skip_tx
);
230 this->owner
.port
->skip_tx
--;
231 return STP_Nothing_To_Do
;
235 port
= this->owner
.port
;
236 if (port
->admin_non_stp
) return 1;
237 port_index
= port
->port_index
;
238 vlan_id
= port
->owner
->vlan_id
;
240 pkt_len
= build_bpdu_header (port
->port_index
,
242 sizeof (BPDU_HEADER_T
) + sizeof (BPDU_BODY_T
) + 1);
243 build_config_bpdu (port
, False
);
245 switch (port
->selectedRole
) {
248 role
= RSTP_PORT_ROLE_UNKN
;
251 role
= RSTP_PORT_ROLE_ALTBACK
;
254 role
= RSTP_PORT_ROLE_ALTBACK
;
257 role
= RSTP_PORT_ROLE_ROOT
;
260 role
= RSTP_PORT_ROLE_DESGN
;
264 bpdu_packet
.body
.flags
|= (role
<< PORT_ROLE_OFFS
);
266 if (port
->forwarding
)
267 bpdu_packet
.body
.flags
|= FORWARD_BIT
;
269 bpdu_packet
.body
.flags
|= LEARN_BIT
;
272 #if 0 /* def STP_DBG */
273 if (port
->roletrns
->debug
)
274 stp_trace ("tx AGREEMENT_BIT to port %s", port
->port_name
);
276 bpdu_packet
.body
.flags
|= AGREEMENT_BIT
;
279 if (port
->proposing
) {
280 #if 0 /* def STP_DBG */
281 if (port
->roletrns
->debug
)
282 stp_trace ("tx PROPOSAL_BIT to port %s", port
->port_name
);
284 bpdu_packet
.body
.flags
|= PROPOSAL_BIT
;
289 stp_trace ("port %s txRstp flags=0X%lx",
291 (unsigned long) bpdu_packet
.body
.flags
);
294 return STP_OUT_tx_bpdu (port_index
, vlan_id
,
295 (unsigned char *) &bpdu_packet
,
300 STP_transmit_enter_state (STATE_MACH_T
* this)
302 register PORT_T
* port
= this->owner
.port
;
304 switch (this->State
) {
307 port
->newInfo
= False
;
311 case TRANSMIT_PERIODIC
:
312 port
->newInfo
= port
->newInfo
||
313 ((port
->role
== DesignatedPort
) ||
314 ((port
->role
== RootPort
) && port
->tcWhile
));
315 port
->helloWhen
= port
->owner
->rootTimes
.HelloTime
;
319 case TRANSMIT_CONFIG
:
320 port
->newInfo
= False
;
326 port
->newInfo
= False
;
331 port
->newInfo
= False
;
340 STP_transmit_check_conditions (STATE_MACH_T
* this)
342 register PORT_T
* port
= this->owner
.port
;
344 if (BEGIN
== this->State
) return STP_hop_2_state (this, TRANSMIT_INIT
);
346 switch (this->State
) {
348 return STP_hop_2_state (this, IDLE
);
349 case TRANSMIT_PERIODIC
:
350 return STP_hop_2_state (this, IDLE
);
352 if (!port
->helloWhen
) return STP_hop_2_state (this, TRANSMIT_PERIODIC
);
353 if (!port
->sendRSTP
&& port
->newInfo
&&
354 (port
->txCount
< TxHoldCount
) &&
355 (port
->role
== DesignatedPort
) &&
357 return STP_hop_2_state (this, TRANSMIT_CONFIG
);
358 if (!port
->sendRSTP
&& port
->newInfo
&&
359 (port
->txCount
< TxHoldCount
) &&
360 (port
->role
== RootPort
) &&
362 return STP_hop_2_state (this, TRANSMIT_TCN
);
363 if (port
->sendRSTP
&& port
->newInfo
&&
364 (port
->txCount
< TxHoldCount
) &&
365 ((port
->role
== RootPort
) ||
366 (port
->role
== DesignatedPort
)))
367 return STP_hop_2_state (this, TRANSMIT_RSTP
);
369 case TRANSMIT_CONFIG
:
370 return STP_hop_2_state (this, IDLE
);
372 return STP_hop_2_state (this, IDLE
);
374 return STP_hop_2_state (this, IDLE
);