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