1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /******************************************************************************
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * (C)Copyright 1998,1999 SysKonnect,
5*4882a593Smuzhiyun * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * See the file "skfddi.c" for further information.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * The information in this file is provided "AS IS" without warranty.
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun ******************************************************************************/
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun /*
14*4882a593Smuzhiyun SMT RMT
15*4882a593Smuzhiyun Ring Management
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun /*
19*4882a593Smuzhiyun * Hardware independent state machine implemantation
20*4882a593Smuzhiyun * The following external SMT functions are referenced :
21*4882a593Smuzhiyun *
22*4882a593Smuzhiyun * queue_event()
23*4882a593Smuzhiyun * smt_timer_start()
24*4882a593Smuzhiyun * smt_timer_stop()
25*4882a593Smuzhiyun *
26*4882a593Smuzhiyun * The following external HW dependent functions are referenced :
27*4882a593Smuzhiyun * sm_ma_control()
28*4882a593Smuzhiyun * sm_mac_check_beacon_claim()
29*4882a593Smuzhiyun *
30*4882a593Smuzhiyun * The following HW dependent events are required :
31*4882a593Smuzhiyun * RM_RING_OP
32*4882a593Smuzhiyun * RM_RING_NON_OP
33*4882a593Smuzhiyun * RM_MY_BEACON
34*4882a593Smuzhiyun * RM_OTHER_BEACON
35*4882a593Smuzhiyun * RM_MY_CLAIM
36*4882a593Smuzhiyun * RM_TRT_EXP
37*4882a593Smuzhiyun * RM_VALID_CLAIM
38*4882a593Smuzhiyun *
39*4882a593Smuzhiyun */
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #include "h/types.h"
42*4882a593Smuzhiyun #include "h/fddi.h"
43*4882a593Smuzhiyun #include "h/smc.h"
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #define KERNEL
46*4882a593Smuzhiyun #include "h/smtstate.h"
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun #ifndef lint
49*4882a593Smuzhiyun static const char ID_sccs[] = "@(#)rmt.c 2.13 99/07/02 (C) SK " ;
50*4882a593Smuzhiyun #endif
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /*
53*4882a593Smuzhiyun * FSM Macros
54*4882a593Smuzhiyun */
55*4882a593Smuzhiyun #define AFLAG 0x10
56*4882a593Smuzhiyun #define GO_STATE(x) (smc->mib.m[MAC0].fddiMACRMTState = (x)|AFLAG)
57*4882a593Smuzhiyun #define ACTIONS_DONE() (smc->mib.m[MAC0].fddiMACRMTState &= ~AFLAG)
58*4882a593Smuzhiyun #define ACTIONS(x) (x|AFLAG)
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun #define RM0_ISOLATED 0
61*4882a593Smuzhiyun #define RM1_NON_OP 1 /* not operational */
62*4882a593Smuzhiyun #define RM2_RING_OP 2 /* ring operational */
63*4882a593Smuzhiyun #define RM3_DETECT 3 /* detect dupl addresses */
64*4882a593Smuzhiyun #define RM4_NON_OP_DUP 4 /* dupl. addr detected */
65*4882a593Smuzhiyun #define RM5_RING_OP_DUP 5 /* ring oper. with dupl. addr */
66*4882a593Smuzhiyun #define RM6_DIRECTED 6 /* sending directed beacons */
67*4882a593Smuzhiyun #define RM7_TRACE 7 /* trace initiated */
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /*
70*4882a593Smuzhiyun * symbolic state names
71*4882a593Smuzhiyun */
72*4882a593Smuzhiyun static const char * const rmt_states[] = {
73*4882a593Smuzhiyun "RM0_ISOLATED","RM1_NON_OP","RM2_RING_OP","RM3_DETECT",
74*4882a593Smuzhiyun "RM4_NON_OP_DUP","RM5_RING_OP_DUP","RM6_DIRECTED",
75*4882a593Smuzhiyun "RM7_TRACE"
76*4882a593Smuzhiyun } ;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun /*
79*4882a593Smuzhiyun * symbolic event names
80*4882a593Smuzhiyun */
81*4882a593Smuzhiyun static const char * const rmt_events[] = {
82*4882a593Smuzhiyun "NONE","RM_RING_OP","RM_RING_NON_OP","RM_MY_BEACON",
83*4882a593Smuzhiyun "RM_OTHER_BEACON","RM_MY_CLAIM","RM_TRT_EXP","RM_VALID_CLAIM",
84*4882a593Smuzhiyun "RM_JOIN","RM_LOOP","RM_DUP_ADDR","RM_ENABLE_FLAG",
85*4882a593Smuzhiyun "RM_TIMEOUT_NON_OP","RM_TIMEOUT_T_STUCK",
86*4882a593Smuzhiyun "RM_TIMEOUT_ANNOUNCE","RM_TIMEOUT_T_DIRECT",
87*4882a593Smuzhiyun "RM_TIMEOUT_D_MAX","RM_TIMEOUT_POLL","RM_TX_STATE_CHANGE"
88*4882a593Smuzhiyun } ;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /*
91*4882a593Smuzhiyun * Globals
92*4882a593Smuzhiyun * in struct s_rmt
93*4882a593Smuzhiyun */
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun /*
97*4882a593Smuzhiyun * function declarations
98*4882a593Smuzhiyun */
99*4882a593Smuzhiyun static void rmt_fsm(struct s_smc *smc, int cmd);
100*4882a593Smuzhiyun static void start_rmt_timer0(struct s_smc *smc, u_long value, int event);
101*4882a593Smuzhiyun static void start_rmt_timer1(struct s_smc *smc, u_long value, int event);
102*4882a593Smuzhiyun static void start_rmt_timer2(struct s_smc *smc, u_long value, int event);
103*4882a593Smuzhiyun static void stop_rmt_timer0(struct s_smc *smc);
104*4882a593Smuzhiyun static void stop_rmt_timer1(struct s_smc *smc);
105*4882a593Smuzhiyun static void stop_rmt_timer2(struct s_smc *smc);
106*4882a593Smuzhiyun static void rmt_dup_actions(struct s_smc *smc);
107*4882a593Smuzhiyun static void rmt_reinsert_actions(struct s_smc *smc);
108*4882a593Smuzhiyun static void rmt_leave_actions(struct s_smc *smc);
109*4882a593Smuzhiyun static void rmt_new_dup_actions(struct s_smc *smc);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun #ifndef SUPERNET_3
112*4882a593Smuzhiyun extern void restart_trt_for_dbcn() ;
113*4882a593Smuzhiyun #endif /*SUPERNET_3*/
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun /*
116*4882a593Smuzhiyun init RMT state machine
117*4882a593Smuzhiyun clear all RMT vars and flags
118*4882a593Smuzhiyun */
rmt_init(struct s_smc * smc)119*4882a593Smuzhiyun void rmt_init(struct s_smc *smc)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun smc->mib.m[MAC0].fddiMACRMTState = ACTIONS(RM0_ISOLATED) ;
122*4882a593Smuzhiyun smc->r.dup_addr_test = DA_NONE ;
123*4882a593Smuzhiyun smc->r.da_flag = 0 ;
124*4882a593Smuzhiyun smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
125*4882a593Smuzhiyun smc->r.sm_ma_avail = FALSE ;
126*4882a593Smuzhiyun smc->r.loop_avail = 0 ;
127*4882a593Smuzhiyun smc->r.bn_flag = 0 ;
128*4882a593Smuzhiyun smc->r.jm_flag = 0 ;
129*4882a593Smuzhiyun smc->r.no_flag = TRUE ;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun /*
133*4882a593Smuzhiyun RMT state machine
134*4882a593Smuzhiyun called by dispatcher
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun do
137*4882a593Smuzhiyun display state change
138*4882a593Smuzhiyun process event
139*4882a593Smuzhiyun until SM is stable
140*4882a593Smuzhiyun */
rmt(struct s_smc * smc,int event)141*4882a593Smuzhiyun void rmt(struct s_smc *smc, int event)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun int state ;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun do {
146*4882a593Smuzhiyun DB_RMT("RMT : state %s%s event %s",
147*4882a593Smuzhiyun smc->mib.m[MAC0].fddiMACRMTState & AFLAG ? "ACTIONS " : "",
148*4882a593Smuzhiyun rmt_states[smc->mib.m[MAC0].fddiMACRMTState & ~AFLAG],
149*4882a593Smuzhiyun rmt_events[event]);
150*4882a593Smuzhiyun state = smc->mib.m[MAC0].fddiMACRMTState ;
151*4882a593Smuzhiyun rmt_fsm(smc,event) ;
152*4882a593Smuzhiyun event = 0 ;
153*4882a593Smuzhiyun } while (state != smc->mib.m[MAC0].fddiMACRMTState) ;
154*4882a593Smuzhiyun rmt_state_change(smc,(int)smc->mib.m[MAC0].fddiMACRMTState) ;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun /*
158*4882a593Smuzhiyun process RMT event
159*4882a593Smuzhiyun */
rmt_fsm(struct s_smc * smc,int cmd)160*4882a593Smuzhiyun static void rmt_fsm(struct s_smc *smc, int cmd)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun /*
163*4882a593Smuzhiyun * RM00-RM70 : from all states
164*4882a593Smuzhiyun */
165*4882a593Smuzhiyun if (!smc->r.rm_join && !smc->r.rm_loop &&
166*4882a593Smuzhiyun smc->mib.m[MAC0].fddiMACRMTState != ACTIONS(RM0_ISOLATED) &&
167*4882a593Smuzhiyun smc->mib.m[MAC0].fddiMACRMTState != RM0_ISOLATED) {
168*4882a593Smuzhiyun RS_SET(smc,RS_NORINGOP) ;
169*4882a593Smuzhiyun rmt_indication(smc,0) ;
170*4882a593Smuzhiyun GO_STATE(RM0_ISOLATED) ;
171*4882a593Smuzhiyun return ;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun switch(smc->mib.m[MAC0].fddiMACRMTState) {
175*4882a593Smuzhiyun case ACTIONS(RM0_ISOLATED) :
176*4882a593Smuzhiyun stop_rmt_timer0(smc) ;
177*4882a593Smuzhiyun stop_rmt_timer1(smc) ;
178*4882a593Smuzhiyun stop_rmt_timer2(smc) ;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun /*
181*4882a593Smuzhiyun * Disable MAC.
182*4882a593Smuzhiyun */
183*4882a593Smuzhiyun sm_ma_control(smc,MA_OFFLINE) ;
184*4882a593Smuzhiyun smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
185*4882a593Smuzhiyun smc->r.loop_avail = FALSE ;
186*4882a593Smuzhiyun smc->r.sm_ma_avail = FALSE ;
187*4882a593Smuzhiyun smc->r.no_flag = TRUE ;
188*4882a593Smuzhiyun DB_RMTN(1, "RMT : ISOLATED");
189*4882a593Smuzhiyun ACTIONS_DONE() ;
190*4882a593Smuzhiyun break ;
191*4882a593Smuzhiyun case RM0_ISOLATED :
192*4882a593Smuzhiyun /*RM01*/
193*4882a593Smuzhiyun if (smc->r.rm_join || smc->r.rm_loop) {
194*4882a593Smuzhiyun /*
195*4882a593Smuzhiyun * According to the standard the MAC must be reset
196*4882a593Smuzhiyun * here. The FORMAC will be initialized and Claim
197*4882a593Smuzhiyun * and Beacon Frames will be uploaded to the MAC.
198*4882a593Smuzhiyun * So any change of Treq will take effect NOW.
199*4882a593Smuzhiyun */
200*4882a593Smuzhiyun sm_ma_control(smc,MA_RESET) ;
201*4882a593Smuzhiyun GO_STATE(RM1_NON_OP) ;
202*4882a593Smuzhiyun break ;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun break ;
205*4882a593Smuzhiyun case ACTIONS(RM1_NON_OP) :
206*4882a593Smuzhiyun start_rmt_timer0(smc,smc->s.rmt_t_non_op,RM_TIMEOUT_NON_OP) ;
207*4882a593Smuzhiyun stop_rmt_timer1(smc) ;
208*4882a593Smuzhiyun stop_rmt_timer2(smc) ;
209*4882a593Smuzhiyun sm_ma_control(smc,MA_BEACON) ;
210*4882a593Smuzhiyun DB_RMTN(1, "RMT : RING DOWN");
211*4882a593Smuzhiyun RS_SET(smc,RS_NORINGOP) ;
212*4882a593Smuzhiyun smc->r.sm_ma_avail = FALSE ;
213*4882a593Smuzhiyun rmt_indication(smc,0) ;
214*4882a593Smuzhiyun ACTIONS_DONE() ;
215*4882a593Smuzhiyun break ;
216*4882a593Smuzhiyun case RM1_NON_OP :
217*4882a593Smuzhiyun /*RM12*/
218*4882a593Smuzhiyun if (cmd == RM_RING_OP) {
219*4882a593Smuzhiyun RS_SET(smc,RS_RINGOPCHANGE) ;
220*4882a593Smuzhiyun GO_STATE(RM2_RING_OP) ;
221*4882a593Smuzhiyun break ;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun /*RM13*/
224*4882a593Smuzhiyun else if (cmd == RM_TIMEOUT_NON_OP) {
225*4882a593Smuzhiyun smc->r.bn_flag = FALSE ;
226*4882a593Smuzhiyun smc->r.no_flag = TRUE ;
227*4882a593Smuzhiyun GO_STATE(RM3_DETECT) ;
228*4882a593Smuzhiyun break ;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun break ;
231*4882a593Smuzhiyun case ACTIONS(RM2_RING_OP) :
232*4882a593Smuzhiyun stop_rmt_timer0(smc) ;
233*4882a593Smuzhiyun stop_rmt_timer1(smc) ;
234*4882a593Smuzhiyun stop_rmt_timer2(smc) ;
235*4882a593Smuzhiyun smc->r.no_flag = FALSE ;
236*4882a593Smuzhiyun if (smc->r.rm_loop)
237*4882a593Smuzhiyun smc->r.loop_avail = TRUE ;
238*4882a593Smuzhiyun if (smc->r.rm_join) {
239*4882a593Smuzhiyun smc->r.sm_ma_avail = TRUE ;
240*4882a593Smuzhiyun if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
241*4882a593Smuzhiyun smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;
242*4882a593Smuzhiyun else
243*4882a593Smuzhiyun smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun DB_RMTN(1, "RMT : RING UP");
246*4882a593Smuzhiyun RS_CLEAR(smc,RS_NORINGOP) ;
247*4882a593Smuzhiyun RS_SET(smc,RS_RINGOPCHANGE) ;
248*4882a593Smuzhiyun rmt_indication(smc,1) ;
249*4882a593Smuzhiyun smt_stat_counter(smc,0) ;
250*4882a593Smuzhiyun ACTIONS_DONE() ;
251*4882a593Smuzhiyun break ;
252*4882a593Smuzhiyun case RM2_RING_OP :
253*4882a593Smuzhiyun /*RM21*/
254*4882a593Smuzhiyun if (cmd == RM_RING_NON_OP) {
255*4882a593Smuzhiyun smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
256*4882a593Smuzhiyun smc->r.loop_avail = FALSE ;
257*4882a593Smuzhiyun RS_SET(smc,RS_RINGOPCHANGE) ;
258*4882a593Smuzhiyun GO_STATE(RM1_NON_OP) ;
259*4882a593Smuzhiyun break ;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun /*RM22a*/
262*4882a593Smuzhiyun else if (cmd == RM_ENABLE_FLAG) {
263*4882a593Smuzhiyun if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
264*4882a593Smuzhiyun smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;
265*4882a593Smuzhiyun else
266*4882a593Smuzhiyun smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun /*RM25*/
269*4882a593Smuzhiyun else if (smc->r.dup_addr_test == DA_FAILED) {
270*4882a593Smuzhiyun smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
271*4882a593Smuzhiyun smc->r.loop_avail = FALSE ;
272*4882a593Smuzhiyun smc->r.da_flag = TRUE ;
273*4882a593Smuzhiyun GO_STATE(RM5_RING_OP_DUP) ;
274*4882a593Smuzhiyun break ;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun break ;
277*4882a593Smuzhiyun case ACTIONS(RM3_DETECT) :
278*4882a593Smuzhiyun start_rmt_timer0(smc,smc->s.mac_d_max*2,RM_TIMEOUT_D_MAX) ;
279*4882a593Smuzhiyun start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
280*4882a593Smuzhiyun start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
281*4882a593Smuzhiyun sm_mac_check_beacon_claim(smc) ;
282*4882a593Smuzhiyun DB_RMTN(1, "RMT : RM3_DETECT");
283*4882a593Smuzhiyun ACTIONS_DONE() ;
284*4882a593Smuzhiyun break ;
285*4882a593Smuzhiyun case RM3_DETECT :
286*4882a593Smuzhiyun if (cmd == RM_TIMEOUT_POLL) {
287*4882a593Smuzhiyun start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
288*4882a593Smuzhiyun sm_mac_check_beacon_claim(smc) ;
289*4882a593Smuzhiyun break ;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun if (cmd == RM_TIMEOUT_D_MAX) {
292*4882a593Smuzhiyun smc->r.timer0_exp = TRUE ;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun /*
295*4882a593Smuzhiyun *jd(22-Feb-1999)
296*4882a593Smuzhiyun * We need a time ">= 2*mac_d_max" since we had finished
297*4882a593Smuzhiyun * Claim or Beacon state. So we will restart timer0 at
298*4882a593Smuzhiyun * every state change.
299*4882a593Smuzhiyun */
300*4882a593Smuzhiyun if (cmd == RM_TX_STATE_CHANGE) {
301*4882a593Smuzhiyun start_rmt_timer0(smc,
302*4882a593Smuzhiyun smc->s.mac_d_max*2,
303*4882a593Smuzhiyun RM_TIMEOUT_D_MAX) ;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun /*RM32*/
306*4882a593Smuzhiyun if (cmd == RM_RING_OP) {
307*4882a593Smuzhiyun GO_STATE(RM2_RING_OP) ;
308*4882a593Smuzhiyun break ;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun /*RM33a*/
311*4882a593Smuzhiyun else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON)
312*4882a593Smuzhiyun && smc->r.bn_flag) {
313*4882a593Smuzhiyun smc->r.bn_flag = FALSE ;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun /*RM33b*/
316*4882a593Smuzhiyun else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
317*4882a593Smuzhiyun int tx ;
318*4882a593Smuzhiyun /*
319*4882a593Smuzhiyun * set bn_flag only if in state T4 or T5:
320*4882a593Smuzhiyun * only if we're the beaconer should we start the
321*4882a593Smuzhiyun * trace !
322*4882a593Smuzhiyun */
323*4882a593Smuzhiyun if ((tx = sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
324*4882a593Smuzhiyun DB_RMTN(2, "RMT : DETECT && TRT_EXPIRED && T4/T5");
325*4882a593Smuzhiyun smc->r.bn_flag = TRUE ;
326*4882a593Smuzhiyun /*
327*4882a593Smuzhiyun * If one of the upstream stations beaconed
328*4882a593Smuzhiyun * and the link to the upstream neighbor is
329*4882a593Smuzhiyun * lost we need to restart the stuck timer to
330*4882a593Smuzhiyun * check the "stuck beacon" condition.
331*4882a593Smuzhiyun */
332*4882a593Smuzhiyun start_rmt_timer1(smc,smc->s.rmt_t_stuck,
333*4882a593Smuzhiyun RM_TIMEOUT_T_STUCK) ;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun /*
336*4882a593Smuzhiyun * We do NOT need to clear smc->r.bn_flag in case of
337*4882a593Smuzhiyun * not being in state T4 or T5, because the flag
338*4882a593Smuzhiyun * must be cleared in order to get in this condition.
339*4882a593Smuzhiyun */
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun DB_RMTN(2, "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)",
342*4882a593Smuzhiyun tx, smc->r.bn_flag);
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun /*RM34a*/
345*4882a593Smuzhiyun else if (cmd == RM_MY_CLAIM && smc->r.timer0_exp) {
346*4882a593Smuzhiyun rmt_new_dup_actions(smc) ;
347*4882a593Smuzhiyun GO_STATE(RM4_NON_OP_DUP) ;
348*4882a593Smuzhiyun break ;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun /*RM34b*/
351*4882a593Smuzhiyun else if (cmd == RM_MY_BEACON && smc->r.timer0_exp) {
352*4882a593Smuzhiyun rmt_new_dup_actions(smc) ;
353*4882a593Smuzhiyun GO_STATE(RM4_NON_OP_DUP) ;
354*4882a593Smuzhiyun break ;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun /*RM34c*/
357*4882a593Smuzhiyun else if (cmd == RM_VALID_CLAIM) {
358*4882a593Smuzhiyun rmt_new_dup_actions(smc) ;
359*4882a593Smuzhiyun GO_STATE(RM4_NON_OP_DUP) ;
360*4882a593Smuzhiyun break ;
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun /*RM36*/
363*4882a593Smuzhiyun else if (cmd == RM_TIMEOUT_T_STUCK &&
364*4882a593Smuzhiyun smc->r.rm_join && smc->r.bn_flag) {
365*4882a593Smuzhiyun GO_STATE(RM6_DIRECTED) ;
366*4882a593Smuzhiyun break ;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun break ;
369*4882a593Smuzhiyun case ACTIONS(RM4_NON_OP_DUP) :
370*4882a593Smuzhiyun start_rmt_timer0(smc,smc->s.rmt_t_announce,RM_TIMEOUT_ANNOUNCE);
371*4882a593Smuzhiyun start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
372*4882a593Smuzhiyun start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
373*4882a593Smuzhiyun sm_mac_check_beacon_claim(smc) ;
374*4882a593Smuzhiyun DB_RMTN(1, "RMT : RM4_NON_OP_DUP");
375*4882a593Smuzhiyun ACTIONS_DONE() ;
376*4882a593Smuzhiyun break ;
377*4882a593Smuzhiyun case RM4_NON_OP_DUP :
378*4882a593Smuzhiyun if (cmd == RM_TIMEOUT_POLL) {
379*4882a593Smuzhiyun start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
380*4882a593Smuzhiyun sm_mac_check_beacon_claim(smc) ;
381*4882a593Smuzhiyun break ;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun /*RM41*/
384*4882a593Smuzhiyun if (!smc->r.da_flag) {
385*4882a593Smuzhiyun GO_STATE(RM1_NON_OP) ;
386*4882a593Smuzhiyun break ;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun /*RM44a*/
389*4882a593Smuzhiyun else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
390*4882a593Smuzhiyun smc->r.bn_flag) {
391*4882a593Smuzhiyun smc->r.bn_flag = FALSE ;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun /*RM44b*/
394*4882a593Smuzhiyun else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
395*4882a593Smuzhiyun int tx ;
396*4882a593Smuzhiyun /*
397*4882a593Smuzhiyun * set bn_flag only if in state T4 or T5:
398*4882a593Smuzhiyun * only if we're the beaconer should we start the
399*4882a593Smuzhiyun * trace !
400*4882a593Smuzhiyun */
401*4882a593Smuzhiyun if ((tx = sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
402*4882a593Smuzhiyun DB_RMTN(2, "RMT : NOPDUP && TRT_EXPIRED && T4/T5");
403*4882a593Smuzhiyun smc->r.bn_flag = TRUE ;
404*4882a593Smuzhiyun /*
405*4882a593Smuzhiyun * If one of the upstream stations beaconed
406*4882a593Smuzhiyun * and the link to the upstream neighbor is
407*4882a593Smuzhiyun * lost we need to restart the stuck timer to
408*4882a593Smuzhiyun * check the "stuck beacon" condition.
409*4882a593Smuzhiyun */
410*4882a593Smuzhiyun start_rmt_timer1(smc,smc->s.rmt_t_stuck,
411*4882a593Smuzhiyun RM_TIMEOUT_T_STUCK) ;
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun /*
414*4882a593Smuzhiyun * We do NOT need to clear smc->r.bn_flag in case of
415*4882a593Smuzhiyun * not being in state T4 or T5, because the flag
416*4882a593Smuzhiyun * must be cleared in order to get in this condition.
417*4882a593Smuzhiyun */
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun DB_RMTN(2, "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)",
420*4882a593Smuzhiyun tx, smc->r.bn_flag);
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun /*RM44c*/
423*4882a593Smuzhiyun else if (cmd == RM_TIMEOUT_ANNOUNCE && !smc->r.bn_flag) {
424*4882a593Smuzhiyun rmt_dup_actions(smc) ;
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun /*RM45*/
427*4882a593Smuzhiyun else if (cmd == RM_RING_OP) {
428*4882a593Smuzhiyun smc->r.no_flag = FALSE ;
429*4882a593Smuzhiyun GO_STATE(RM5_RING_OP_DUP) ;
430*4882a593Smuzhiyun break ;
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun /*RM46*/
433*4882a593Smuzhiyun else if (cmd == RM_TIMEOUT_T_STUCK &&
434*4882a593Smuzhiyun smc->r.rm_join && smc->r.bn_flag) {
435*4882a593Smuzhiyun GO_STATE(RM6_DIRECTED) ;
436*4882a593Smuzhiyun break ;
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun break ;
439*4882a593Smuzhiyun case ACTIONS(RM5_RING_OP_DUP) :
440*4882a593Smuzhiyun stop_rmt_timer0(smc) ;
441*4882a593Smuzhiyun stop_rmt_timer1(smc) ;
442*4882a593Smuzhiyun stop_rmt_timer2(smc) ;
443*4882a593Smuzhiyun DB_RMTN(1, "RMT : RM5_RING_OP_DUP");
444*4882a593Smuzhiyun ACTIONS_DONE() ;
445*4882a593Smuzhiyun break;
446*4882a593Smuzhiyun case RM5_RING_OP_DUP :
447*4882a593Smuzhiyun /*RM52*/
448*4882a593Smuzhiyun if (smc->r.dup_addr_test == DA_PASSED) {
449*4882a593Smuzhiyun smc->r.da_flag = FALSE ;
450*4882a593Smuzhiyun GO_STATE(RM2_RING_OP) ;
451*4882a593Smuzhiyun break ;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun /*RM54*/
454*4882a593Smuzhiyun else if (cmd == RM_RING_NON_OP) {
455*4882a593Smuzhiyun smc->r.jm_flag = FALSE ;
456*4882a593Smuzhiyun smc->r.bn_flag = FALSE ;
457*4882a593Smuzhiyun GO_STATE(RM4_NON_OP_DUP) ;
458*4882a593Smuzhiyun break ;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun break ;
461*4882a593Smuzhiyun case ACTIONS(RM6_DIRECTED) :
462*4882a593Smuzhiyun start_rmt_timer0(smc,smc->s.rmt_t_direct,RM_TIMEOUT_T_DIRECT) ;
463*4882a593Smuzhiyun stop_rmt_timer1(smc) ;
464*4882a593Smuzhiyun start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
465*4882a593Smuzhiyun sm_ma_control(smc,MA_DIRECTED) ;
466*4882a593Smuzhiyun RS_SET(smc,RS_BEACON) ;
467*4882a593Smuzhiyun DB_RMTN(1, "RMT : RM6_DIRECTED");
468*4882a593Smuzhiyun ACTIONS_DONE() ;
469*4882a593Smuzhiyun break ;
470*4882a593Smuzhiyun case RM6_DIRECTED :
471*4882a593Smuzhiyun /*RM63*/
472*4882a593Smuzhiyun if (cmd == RM_TIMEOUT_POLL) {
473*4882a593Smuzhiyun start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
474*4882a593Smuzhiyun sm_mac_check_beacon_claim(smc) ;
475*4882a593Smuzhiyun #ifndef SUPERNET_3
476*4882a593Smuzhiyun /* Because of problems with the Supernet II chip set
477*4882a593Smuzhiyun * sending of Directed Beacon will stop after 165ms
478*4882a593Smuzhiyun * therefore restart_trt_for_dbcn(smc) will be called
479*4882a593Smuzhiyun * to prevent this.
480*4882a593Smuzhiyun */
481*4882a593Smuzhiyun restart_trt_for_dbcn(smc) ;
482*4882a593Smuzhiyun #endif /*SUPERNET_3*/
483*4882a593Smuzhiyun break ;
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
486*4882a593Smuzhiyun !smc->r.da_flag) {
487*4882a593Smuzhiyun smc->r.bn_flag = FALSE ;
488*4882a593Smuzhiyun GO_STATE(RM3_DETECT) ;
489*4882a593Smuzhiyun break ;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun /*RM64*/
492*4882a593Smuzhiyun else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
493*4882a593Smuzhiyun smc->r.da_flag) {
494*4882a593Smuzhiyun smc->r.bn_flag = FALSE ;
495*4882a593Smuzhiyun GO_STATE(RM4_NON_OP_DUP) ;
496*4882a593Smuzhiyun break ;
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun /*RM67*/
499*4882a593Smuzhiyun else if (cmd == RM_TIMEOUT_T_DIRECT) {
500*4882a593Smuzhiyun GO_STATE(RM7_TRACE) ;
501*4882a593Smuzhiyun break ;
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun break ;
504*4882a593Smuzhiyun case ACTIONS(RM7_TRACE) :
505*4882a593Smuzhiyun stop_rmt_timer0(smc) ;
506*4882a593Smuzhiyun stop_rmt_timer1(smc) ;
507*4882a593Smuzhiyun stop_rmt_timer2(smc) ;
508*4882a593Smuzhiyun smc->e.trace_prop |= ENTITY_BIT(ENTITY_MAC) ;
509*4882a593Smuzhiyun queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ;
510*4882a593Smuzhiyun DB_RMTN(1, "RMT : RM7_TRACE");
511*4882a593Smuzhiyun ACTIONS_DONE() ;
512*4882a593Smuzhiyun break ;
513*4882a593Smuzhiyun case RM7_TRACE :
514*4882a593Smuzhiyun break ;
515*4882a593Smuzhiyun default:
516*4882a593Smuzhiyun SMT_PANIC(smc,SMT_E0122, SMT_E0122_MSG) ;
517*4882a593Smuzhiyun break;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun }
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun /*
522*4882a593Smuzhiyun * (jd) RMT duplicate address actions
523*4882a593Smuzhiyun * leave the ring or reinsert just as configured
524*4882a593Smuzhiyun */
rmt_dup_actions(struct s_smc * smc)525*4882a593Smuzhiyun static void rmt_dup_actions(struct s_smc *smc)
526*4882a593Smuzhiyun {
527*4882a593Smuzhiyun if (smc->r.jm_flag) {
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun else {
530*4882a593Smuzhiyun if (smc->s.rmt_dup_mac_behavior) {
531*4882a593Smuzhiyun SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
532*4882a593Smuzhiyun rmt_reinsert_actions(smc) ;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun else {
535*4882a593Smuzhiyun SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
536*4882a593Smuzhiyun rmt_leave_actions(smc) ;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun /*
542*4882a593Smuzhiyun * Reconnect to the Ring
543*4882a593Smuzhiyun */
rmt_reinsert_actions(struct s_smc * smc)544*4882a593Smuzhiyun static void rmt_reinsert_actions(struct s_smc *smc)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
547*4882a593Smuzhiyun queue_event(smc,EVENT_ECM,EC_CONNECT) ;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun /*
551*4882a593Smuzhiyun * duplicate address detected
552*4882a593Smuzhiyun */
rmt_new_dup_actions(struct s_smc * smc)553*4882a593Smuzhiyun static void rmt_new_dup_actions(struct s_smc *smc)
554*4882a593Smuzhiyun {
555*4882a593Smuzhiyun smc->r.da_flag = TRUE ;
556*4882a593Smuzhiyun smc->r.bn_flag = FALSE ;
557*4882a593Smuzhiyun smc->r.jm_flag = FALSE ;
558*4882a593Smuzhiyun /*
559*4882a593Smuzhiyun * we have three options : change address, jam or leave
560*4882a593Smuzhiyun * we leave the ring as default
561*4882a593Smuzhiyun * Optionally it's possible to reinsert after leaving the Ring
562*4882a593Smuzhiyun * but this will not conform with SMT Spec.
563*4882a593Smuzhiyun */
564*4882a593Smuzhiyun if (smc->s.rmt_dup_mac_behavior) {
565*4882a593Smuzhiyun SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
566*4882a593Smuzhiyun rmt_reinsert_actions(smc) ;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun else {
569*4882a593Smuzhiyun SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
570*4882a593Smuzhiyun rmt_leave_actions(smc) ;
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun /*
576*4882a593Smuzhiyun * leave the ring
577*4882a593Smuzhiyun */
rmt_leave_actions(struct s_smc * smc)578*4882a593Smuzhiyun static void rmt_leave_actions(struct s_smc *smc)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
581*4882a593Smuzhiyun /*
582*4882a593Smuzhiyun * Note: Do NOT try again later. (with please reconnect)
583*4882a593Smuzhiyun * The station must be left from the ring!
584*4882a593Smuzhiyun */
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun /*
588*4882a593Smuzhiyun * SMT timer interface
589*4882a593Smuzhiyun * start RMT timer 0
590*4882a593Smuzhiyun */
start_rmt_timer0(struct s_smc * smc,u_long value,int event)591*4882a593Smuzhiyun static void start_rmt_timer0(struct s_smc *smc, u_long value, int event)
592*4882a593Smuzhiyun {
593*4882a593Smuzhiyun smc->r.timer0_exp = FALSE ; /* clear timer event flag */
594*4882a593Smuzhiyun smt_timer_start(smc,&smc->r.rmt_timer0,value,EV_TOKEN(EVENT_RMT,event));
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun /*
598*4882a593Smuzhiyun * SMT timer interface
599*4882a593Smuzhiyun * start RMT timer 1
600*4882a593Smuzhiyun */
start_rmt_timer1(struct s_smc * smc,u_long value,int event)601*4882a593Smuzhiyun static void start_rmt_timer1(struct s_smc *smc, u_long value, int event)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun smc->r.timer1_exp = FALSE ; /* clear timer event flag */
604*4882a593Smuzhiyun smt_timer_start(smc,&smc->r.rmt_timer1,value,EV_TOKEN(EVENT_RMT,event));
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun /*
608*4882a593Smuzhiyun * SMT timer interface
609*4882a593Smuzhiyun * start RMT timer 2
610*4882a593Smuzhiyun */
start_rmt_timer2(struct s_smc * smc,u_long value,int event)611*4882a593Smuzhiyun static void start_rmt_timer2(struct s_smc *smc, u_long value, int event)
612*4882a593Smuzhiyun {
613*4882a593Smuzhiyun smc->r.timer2_exp = FALSE ; /* clear timer event flag */
614*4882a593Smuzhiyun smt_timer_start(smc,&smc->r.rmt_timer2,value,EV_TOKEN(EVENT_RMT,event));
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun /*
618*4882a593Smuzhiyun * SMT timer interface
619*4882a593Smuzhiyun * stop RMT timer 0
620*4882a593Smuzhiyun */
stop_rmt_timer0(struct s_smc * smc)621*4882a593Smuzhiyun static void stop_rmt_timer0(struct s_smc *smc)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun if (smc->r.rmt_timer0.tm_active)
624*4882a593Smuzhiyun smt_timer_stop(smc,&smc->r.rmt_timer0) ;
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun /*
628*4882a593Smuzhiyun * SMT timer interface
629*4882a593Smuzhiyun * stop RMT timer 1
630*4882a593Smuzhiyun */
stop_rmt_timer1(struct s_smc * smc)631*4882a593Smuzhiyun static void stop_rmt_timer1(struct s_smc *smc)
632*4882a593Smuzhiyun {
633*4882a593Smuzhiyun if (smc->r.rmt_timer1.tm_active)
634*4882a593Smuzhiyun smt_timer_stop(smc,&smc->r.rmt_timer1) ;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun /*
638*4882a593Smuzhiyun * SMT timer interface
639*4882a593Smuzhiyun * stop RMT timer 2
640*4882a593Smuzhiyun */
stop_rmt_timer2(struct s_smc * smc)641*4882a593Smuzhiyun static void stop_rmt_timer2(struct s_smc *smc)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun if (smc->r.rmt_timer2.tm_active)
644*4882a593Smuzhiyun smt_timer_stop(smc,&smc->r.rmt_timer2) ;
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun
647