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