162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *	(C)Copyright 1998,1999 SysKonnect,
562306a36Sopenharmony_ci *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *	See the file "skfddi.c" for further information.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *	The information in this file is provided "AS IS" without warranty.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci ******************************************************************************/
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/*
1462306a36Sopenharmony_ci	SMT RMT
1562306a36Sopenharmony_ci	Ring Management
1662306a36Sopenharmony_ci*/
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/*
1962306a36Sopenharmony_ci * Hardware independent state machine implemantation
2062306a36Sopenharmony_ci * The following external SMT functions are referenced :
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * 		queue_event()
2362306a36Sopenharmony_ci * 		smt_timer_start()
2462306a36Sopenharmony_ci * 		smt_timer_stop()
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * 	The following external HW dependent functions are referenced :
2762306a36Sopenharmony_ci *		sm_ma_control()
2862306a36Sopenharmony_ci *		sm_mac_check_beacon_claim()
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * 	The following HW dependent events are required :
3162306a36Sopenharmony_ci *		RM_RING_OP
3262306a36Sopenharmony_ci *		RM_RING_NON_OP
3362306a36Sopenharmony_ci *		RM_MY_BEACON
3462306a36Sopenharmony_ci *		RM_OTHER_BEACON
3562306a36Sopenharmony_ci *		RM_MY_CLAIM
3662306a36Sopenharmony_ci *		RM_TRT_EXP
3762306a36Sopenharmony_ci *		RM_VALID_CLAIM
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#include "h/types.h"
4262306a36Sopenharmony_ci#include "h/fddi.h"
4362306a36Sopenharmony_ci#include "h/smc.h"
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define KERNEL
4662306a36Sopenharmony_ci#include "h/smtstate.h"
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/*
4962306a36Sopenharmony_ci * FSM Macros
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_ci#define AFLAG	0x10
5262306a36Sopenharmony_ci#define GO_STATE(x)	(smc->mib.m[MAC0].fddiMACRMTState = (x)|AFLAG)
5362306a36Sopenharmony_ci#define ACTIONS_DONE()	(smc->mib.m[MAC0].fddiMACRMTState &= ~AFLAG)
5462306a36Sopenharmony_ci#define ACTIONS(x)	(x|AFLAG)
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#define RM0_ISOLATED	0
5762306a36Sopenharmony_ci#define RM1_NON_OP	1		/* not operational */
5862306a36Sopenharmony_ci#define RM2_RING_OP	2		/* ring operational */
5962306a36Sopenharmony_ci#define RM3_DETECT	3		/* detect dupl addresses */
6062306a36Sopenharmony_ci#define RM4_NON_OP_DUP	4		/* dupl. addr detected */
6162306a36Sopenharmony_ci#define RM5_RING_OP_DUP	5		/* ring oper. with dupl. addr */
6262306a36Sopenharmony_ci#define RM6_DIRECTED	6		/* sending directed beacons */
6362306a36Sopenharmony_ci#define RM7_TRACE	7		/* trace initiated */
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/*
6662306a36Sopenharmony_ci * symbolic state names
6762306a36Sopenharmony_ci */
6862306a36Sopenharmony_cistatic const char * const rmt_states[] = {
6962306a36Sopenharmony_ci	"RM0_ISOLATED","RM1_NON_OP","RM2_RING_OP","RM3_DETECT",
7062306a36Sopenharmony_ci	"RM4_NON_OP_DUP","RM5_RING_OP_DUP","RM6_DIRECTED",
7162306a36Sopenharmony_ci	"RM7_TRACE"
7262306a36Sopenharmony_ci} ;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/*
7562306a36Sopenharmony_ci * symbolic event names
7662306a36Sopenharmony_ci */
7762306a36Sopenharmony_cistatic const char * const rmt_events[] = {
7862306a36Sopenharmony_ci	"NONE","RM_RING_OP","RM_RING_NON_OP","RM_MY_BEACON",
7962306a36Sopenharmony_ci	"RM_OTHER_BEACON","RM_MY_CLAIM","RM_TRT_EXP","RM_VALID_CLAIM",
8062306a36Sopenharmony_ci	"RM_JOIN","RM_LOOP","RM_DUP_ADDR","RM_ENABLE_FLAG",
8162306a36Sopenharmony_ci	"RM_TIMEOUT_NON_OP","RM_TIMEOUT_T_STUCK",
8262306a36Sopenharmony_ci	"RM_TIMEOUT_ANNOUNCE","RM_TIMEOUT_T_DIRECT",
8362306a36Sopenharmony_ci	"RM_TIMEOUT_D_MAX","RM_TIMEOUT_POLL","RM_TX_STATE_CHANGE"
8462306a36Sopenharmony_ci} ;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci/*
8762306a36Sopenharmony_ci * Globals
8862306a36Sopenharmony_ci * in struct s_rmt
8962306a36Sopenharmony_ci */
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/*
9362306a36Sopenharmony_ci * function declarations
9462306a36Sopenharmony_ci */
9562306a36Sopenharmony_cistatic void rmt_fsm(struct s_smc *smc, int cmd);
9662306a36Sopenharmony_cistatic void start_rmt_timer0(struct s_smc *smc, u_long value, int event);
9762306a36Sopenharmony_cistatic void start_rmt_timer1(struct s_smc *smc, u_long value, int event);
9862306a36Sopenharmony_cistatic void start_rmt_timer2(struct s_smc *smc, u_long value, int event);
9962306a36Sopenharmony_cistatic void stop_rmt_timer0(struct s_smc *smc);
10062306a36Sopenharmony_cistatic void stop_rmt_timer1(struct s_smc *smc);
10162306a36Sopenharmony_cistatic void stop_rmt_timer2(struct s_smc *smc);
10262306a36Sopenharmony_cistatic void rmt_dup_actions(struct s_smc *smc);
10362306a36Sopenharmony_cistatic void rmt_reinsert_actions(struct s_smc *smc);
10462306a36Sopenharmony_cistatic void rmt_leave_actions(struct s_smc *smc);
10562306a36Sopenharmony_cistatic void rmt_new_dup_actions(struct s_smc *smc);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#ifndef SUPERNET_3
10862306a36Sopenharmony_ciextern void restart_trt_for_dbcn() ;
10962306a36Sopenharmony_ci#endif /*SUPERNET_3*/
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/*
11262306a36Sopenharmony_ci	init RMT state machine
11362306a36Sopenharmony_ci	clear all RMT vars and flags
11462306a36Sopenharmony_ci*/
11562306a36Sopenharmony_civoid rmt_init(struct s_smc *smc)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	smc->mib.m[MAC0].fddiMACRMTState = ACTIONS(RM0_ISOLATED) ;
11862306a36Sopenharmony_ci	smc->r.dup_addr_test = DA_NONE ;
11962306a36Sopenharmony_ci	smc->r.da_flag = 0 ;
12062306a36Sopenharmony_ci	smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
12162306a36Sopenharmony_ci	smc->r.sm_ma_avail = FALSE ;
12262306a36Sopenharmony_ci	smc->r.loop_avail = 0 ;
12362306a36Sopenharmony_ci	smc->r.bn_flag = 0 ;
12462306a36Sopenharmony_ci	smc->r.jm_flag = 0 ;
12562306a36Sopenharmony_ci	smc->r.no_flag = TRUE ;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/*
12962306a36Sopenharmony_ci	RMT state machine
13062306a36Sopenharmony_ci	called by dispatcher
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	do
13362306a36Sopenharmony_ci		display state change
13462306a36Sopenharmony_ci		process event
13562306a36Sopenharmony_ci	until SM is stable
13662306a36Sopenharmony_ci*/
13762306a36Sopenharmony_civoid rmt(struct s_smc *smc, int event)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	int	state ;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	do {
14262306a36Sopenharmony_ci		DB_RMT("RMT : state %s%s event %s",
14362306a36Sopenharmony_ci		       smc->mib.m[MAC0].fddiMACRMTState & AFLAG ? "ACTIONS " : "",
14462306a36Sopenharmony_ci		       rmt_states[smc->mib.m[MAC0].fddiMACRMTState & ~AFLAG],
14562306a36Sopenharmony_ci		       rmt_events[event]);
14662306a36Sopenharmony_ci		state = smc->mib.m[MAC0].fddiMACRMTState ;
14762306a36Sopenharmony_ci		rmt_fsm(smc,event) ;
14862306a36Sopenharmony_ci		event = 0 ;
14962306a36Sopenharmony_ci	} while (state != smc->mib.m[MAC0].fddiMACRMTState) ;
15062306a36Sopenharmony_ci	rmt_state_change(smc,(int)smc->mib.m[MAC0].fddiMACRMTState) ;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci/*
15462306a36Sopenharmony_ci	process RMT event
15562306a36Sopenharmony_ci*/
15662306a36Sopenharmony_cistatic void rmt_fsm(struct s_smc *smc, int cmd)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	/*
15962306a36Sopenharmony_ci	 * RM00-RM70 : from all states
16062306a36Sopenharmony_ci	 */
16162306a36Sopenharmony_ci	if (!smc->r.rm_join && !smc->r.rm_loop &&
16262306a36Sopenharmony_ci		smc->mib.m[MAC0].fddiMACRMTState != ACTIONS(RM0_ISOLATED) &&
16362306a36Sopenharmony_ci		smc->mib.m[MAC0].fddiMACRMTState != RM0_ISOLATED) {
16462306a36Sopenharmony_ci		RS_SET(smc,RS_NORINGOP) ;
16562306a36Sopenharmony_ci		rmt_indication(smc,0) ;
16662306a36Sopenharmony_ci		GO_STATE(RM0_ISOLATED) ;
16762306a36Sopenharmony_ci		return ;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	switch(smc->mib.m[MAC0].fddiMACRMTState) {
17162306a36Sopenharmony_ci	case ACTIONS(RM0_ISOLATED) :
17262306a36Sopenharmony_ci		stop_rmt_timer0(smc) ;
17362306a36Sopenharmony_ci		stop_rmt_timer1(smc) ;
17462306a36Sopenharmony_ci		stop_rmt_timer2(smc) ;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci		/*
17762306a36Sopenharmony_ci		 * Disable MAC.
17862306a36Sopenharmony_ci		 */
17962306a36Sopenharmony_ci		sm_ma_control(smc,MA_OFFLINE) ;
18062306a36Sopenharmony_ci		smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
18162306a36Sopenharmony_ci		smc->r.loop_avail = FALSE ;
18262306a36Sopenharmony_ci		smc->r.sm_ma_avail = FALSE ;
18362306a36Sopenharmony_ci		smc->r.no_flag = TRUE ;
18462306a36Sopenharmony_ci		DB_RMTN(1, "RMT : ISOLATED");
18562306a36Sopenharmony_ci		ACTIONS_DONE() ;
18662306a36Sopenharmony_ci		break ;
18762306a36Sopenharmony_ci	case RM0_ISOLATED :
18862306a36Sopenharmony_ci		/*RM01*/
18962306a36Sopenharmony_ci		if (smc->r.rm_join || smc->r.rm_loop) {
19062306a36Sopenharmony_ci			/*
19162306a36Sopenharmony_ci			 * According to the standard the MAC must be reset
19262306a36Sopenharmony_ci			 * here. The FORMAC will be initialized and Claim
19362306a36Sopenharmony_ci			 * and Beacon Frames will be uploaded to the MAC.
19462306a36Sopenharmony_ci			 * So any change of Treq will take effect NOW.
19562306a36Sopenharmony_ci			 */
19662306a36Sopenharmony_ci			sm_ma_control(smc,MA_RESET) ;
19762306a36Sopenharmony_ci			GO_STATE(RM1_NON_OP) ;
19862306a36Sopenharmony_ci			break ;
19962306a36Sopenharmony_ci		}
20062306a36Sopenharmony_ci		break ;
20162306a36Sopenharmony_ci	case ACTIONS(RM1_NON_OP) :
20262306a36Sopenharmony_ci		start_rmt_timer0(smc,smc->s.rmt_t_non_op,RM_TIMEOUT_NON_OP) ;
20362306a36Sopenharmony_ci		stop_rmt_timer1(smc) ;
20462306a36Sopenharmony_ci		stop_rmt_timer2(smc) ;
20562306a36Sopenharmony_ci		sm_ma_control(smc,MA_BEACON) ;
20662306a36Sopenharmony_ci		DB_RMTN(1, "RMT : RING DOWN");
20762306a36Sopenharmony_ci		RS_SET(smc,RS_NORINGOP) ;
20862306a36Sopenharmony_ci		smc->r.sm_ma_avail = FALSE ;
20962306a36Sopenharmony_ci		rmt_indication(smc,0) ;
21062306a36Sopenharmony_ci		ACTIONS_DONE() ;
21162306a36Sopenharmony_ci		break ;
21262306a36Sopenharmony_ci	case RM1_NON_OP :
21362306a36Sopenharmony_ci		/*RM12*/
21462306a36Sopenharmony_ci		if (cmd == RM_RING_OP) {
21562306a36Sopenharmony_ci			RS_SET(smc,RS_RINGOPCHANGE) ;
21662306a36Sopenharmony_ci			GO_STATE(RM2_RING_OP) ;
21762306a36Sopenharmony_ci			break ;
21862306a36Sopenharmony_ci		}
21962306a36Sopenharmony_ci		/*RM13*/
22062306a36Sopenharmony_ci		else if (cmd == RM_TIMEOUT_NON_OP) {
22162306a36Sopenharmony_ci			smc->r.bn_flag = FALSE ;
22262306a36Sopenharmony_ci			smc->r.no_flag = TRUE ;
22362306a36Sopenharmony_ci			GO_STATE(RM3_DETECT) ;
22462306a36Sopenharmony_ci			break ;
22562306a36Sopenharmony_ci		}
22662306a36Sopenharmony_ci		break ;
22762306a36Sopenharmony_ci	case ACTIONS(RM2_RING_OP) :
22862306a36Sopenharmony_ci		stop_rmt_timer0(smc) ;
22962306a36Sopenharmony_ci		stop_rmt_timer1(smc) ;
23062306a36Sopenharmony_ci		stop_rmt_timer2(smc) ;
23162306a36Sopenharmony_ci		smc->r.no_flag = FALSE ;
23262306a36Sopenharmony_ci		if (smc->r.rm_loop)
23362306a36Sopenharmony_ci			smc->r.loop_avail = TRUE ;
23462306a36Sopenharmony_ci		if (smc->r.rm_join) {
23562306a36Sopenharmony_ci			smc->r.sm_ma_avail = TRUE ;
23662306a36Sopenharmony_ci			if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
23762306a36Sopenharmony_ci				smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE;
23862306a36Sopenharmony_ci			else
23962306a36Sopenharmony_ci				smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE;
24062306a36Sopenharmony_ci		}
24162306a36Sopenharmony_ci		DB_RMTN(1, "RMT : RING UP");
24262306a36Sopenharmony_ci		RS_CLEAR(smc,RS_NORINGOP) ;
24362306a36Sopenharmony_ci		RS_SET(smc,RS_RINGOPCHANGE) ;
24462306a36Sopenharmony_ci		rmt_indication(smc,1) ;
24562306a36Sopenharmony_ci		smt_stat_counter(smc,0) ;
24662306a36Sopenharmony_ci		ACTIONS_DONE() ;
24762306a36Sopenharmony_ci		break ;
24862306a36Sopenharmony_ci	case RM2_RING_OP :
24962306a36Sopenharmony_ci		/*RM21*/
25062306a36Sopenharmony_ci		if (cmd == RM_RING_NON_OP) {
25162306a36Sopenharmony_ci			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
25262306a36Sopenharmony_ci			smc->r.loop_avail = FALSE ;
25362306a36Sopenharmony_ci			RS_SET(smc,RS_RINGOPCHANGE) ;
25462306a36Sopenharmony_ci			GO_STATE(RM1_NON_OP) ;
25562306a36Sopenharmony_ci			break ;
25662306a36Sopenharmony_ci		}
25762306a36Sopenharmony_ci		/*RM22a*/
25862306a36Sopenharmony_ci		else if (cmd == RM_ENABLE_FLAG) {
25962306a36Sopenharmony_ci			if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
26062306a36Sopenharmony_ci			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;
26162306a36Sopenharmony_ci				else
26262306a36Sopenharmony_ci			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
26362306a36Sopenharmony_ci		}
26462306a36Sopenharmony_ci		/*RM25*/
26562306a36Sopenharmony_ci		else if (smc->r.dup_addr_test == DA_FAILED) {
26662306a36Sopenharmony_ci			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
26762306a36Sopenharmony_ci			smc->r.loop_avail = FALSE ;
26862306a36Sopenharmony_ci			smc->r.da_flag = TRUE ;
26962306a36Sopenharmony_ci			GO_STATE(RM5_RING_OP_DUP) ;
27062306a36Sopenharmony_ci			break ;
27162306a36Sopenharmony_ci		}
27262306a36Sopenharmony_ci		break ;
27362306a36Sopenharmony_ci	case ACTIONS(RM3_DETECT) :
27462306a36Sopenharmony_ci		start_rmt_timer0(smc,smc->s.mac_d_max*2,RM_TIMEOUT_D_MAX) ;
27562306a36Sopenharmony_ci		start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
27662306a36Sopenharmony_ci		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
27762306a36Sopenharmony_ci		sm_mac_check_beacon_claim(smc) ;
27862306a36Sopenharmony_ci		DB_RMTN(1, "RMT : RM3_DETECT");
27962306a36Sopenharmony_ci		ACTIONS_DONE() ;
28062306a36Sopenharmony_ci		break ;
28162306a36Sopenharmony_ci	case RM3_DETECT :
28262306a36Sopenharmony_ci		if (cmd == RM_TIMEOUT_POLL) {
28362306a36Sopenharmony_ci			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
28462306a36Sopenharmony_ci			sm_mac_check_beacon_claim(smc) ;
28562306a36Sopenharmony_ci			break ;
28662306a36Sopenharmony_ci		}
28762306a36Sopenharmony_ci		if (cmd == RM_TIMEOUT_D_MAX) {
28862306a36Sopenharmony_ci			smc->r.timer0_exp = TRUE ;
28962306a36Sopenharmony_ci		}
29062306a36Sopenharmony_ci		/*
29162306a36Sopenharmony_ci		 *jd(22-Feb-1999)
29262306a36Sopenharmony_ci		 * We need a time ">= 2*mac_d_max" since we had finished
29362306a36Sopenharmony_ci		 * Claim or Beacon state. So we will restart timer0 at
29462306a36Sopenharmony_ci		 * every state change.
29562306a36Sopenharmony_ci		 */
29662306a36Sopenharmony_ci		if (cmd == RM_TX_STATE_CHANGE) {
29762306a36Sopenharmony_ci			start_rmt_timer0(smc,
29862306a36Sopenharmony_ci					 smc->s.mac_d_max*2,
29962306a36Sopenharmony_ci					 RM_TIMEOUT_D_MAX) ;
30062306a36Sopenharmony_ci		}
30162306a36Sopenharmony_ci		/*RM32*/
30262306a36Sopenharmony_ci		if (cmd == RM_RING_OP) {
30362306a36Sopenharmony_ci			GO_STATE(RM2_RING_OP) ;
30462306a36Sopenharmony_ci			break ;
30562306a36Sopenharmony_ci		}
30662306a36Sopenharmony_ci		/*RM33a*/
30762306a36Sopenharmony_ci		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON)
30862306a36Sopenharmony_ci			&& smc->r.bn_flag) {
30962306a36Sopenharmony_ci			smc->r.bn_flag = FALSE ;
31062306a36Sopenharmony_ci		}
31162306a36Sopenharmony_ci		/*RM33b*/
31262306a36Sopenharmony_ci		else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
31362306a36Sopenharmony_ci			int	tx ;
31462306a36Sopenharmony_ci			/*
31562306a36Sopenharmony_ci			 * set bn_flag only if in state T4 or T5:
31662306a36Sopenharmony_ci			 * only if we're the beaconer should we start the
31762306a36Sopenharmony_ci			 * trace !
31862306a36Sopenharmony_ci			 */
31962306a36Sopenharmony_ci			if ((tx =  sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
32062306a36Sopenharmony_ci			DB_RMTN(2, "RMT : DETECT && TRT_EXPIRED && T4/T5");
32162306a36Sopenharmony_ci				smc->r.bn_flag = TRUE ;
32262306a36Sopenharmony_ci				/*
32362306a36Sopenharmony_ci				 * If one of the upstream stations beaconed
32462306a36Sopenharmony_ci				 * and the link to the upstream neighbor is
32562306a36Sopenharmony_ci				 * lost we need to restart the stuck timer to
32662306a36Sopenharmony_ci				 * check the "stuck beacon" condition.
32762306a36Sopenharmony_ci				 */
32862306a36Sopenharmony_ci				start_rmt_timer1(smc,smc->s.rmt_t_stuck,
32962306a36Sopenharmony_ci					RM_TIMEOUT_T_STUCK) ;
33062306a36Sopenharmony_ci			}
33162306a36Sopenharmony_ci			/*
33262306a36Sopenharmony_ci			 * We do NOT need to clear smc->r.bn_flag in case of
33362306a36Sopenharmony_ci			 * not being in state T4 or T5, because the flag
33462306a36Sopenharmony_ci			 * must be cleared in order to get in this condition.
33562306a36Sopenharmony_ci			 */
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci			DB_RMTN(2, "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)",
33862306a36Sopenharmony_ci				tx, smc->r.bn_flag);
33962306a36Sopenharmony_ci		}
34062306a36Sopenharmony_ci		/*RM34a*/
34162306a36Sopenharmony_ci		else if (cmd == RM_MY_CLAIM && smc->r.timer0_exp) {
34262306a36Sopenharmony_ci			rmt_new_dup_actions(smc) ;
34362306a36Sopenharmony_ci			GO_STATE(RM4_NON_OP_DUP) ;
34462306a36Sopenharmony_ci			break ;
34562306a36Sopenharmony_ci		}
34662306a36Sopenharmony_ci		/*RM34b*/
34762306a36Sopenharmony_ci		else if (cmd == RM_MY_BEACON && smc->r.timer0_exp) {
34862306a36Sopenharmony_ci			rmt_new_dup_actions(smc) ;
34962306a36Sopenharmony_ci			GO_STATE(RM4_NON_OP_DUP) ;
35062306a36Sopenharmony_ci			break ;
35162306a36Sopenharmony_ci		}
35262306a36Sopenharmony_ci		/*RM34c*/
35362306a36Sopenharmony_ci		else if (cmd == RM_VALID_CLAIM) {
35462306a36Sopenharmony_ci			rmt_new_dup_actions(smc) ;
35562306a36Sopenharmony_ci			GO_STATE(RM4_NON_OP_DUP) ;
35662306a36Sopenharmony_ci			break ;
35762306a36Sopenharmony_ci		}
35862306a36Sopenharmony_ci		/*RM36*/
35962306a36Sopenharmony_ci		else if (cmd == RM_TIMEOUT_T_STUCK &&
36062306a36Sopenharmony_ci			smc->r.rm_join && smc->r.bn_flag) {
36162306a36Sopenharmony_ci			GO_STATE(RM6_DIRECTED) ;
36262306a36Sopenharmony_ci			break ;
36362306a36Sopenharmony_ci		}
36462306a36Sopenharmony_ci		break ;
36562306a36Sopenharmony_ci	case ACTIONS(RM4_NON_OP_DUP) :
36662306a36Sopenharmony_ci		start_rmt_timer0(smc,smc->s.rmt_t_announce,RM_TIMEOUT_ANNOUNCE);
36762306a36Sopenharmony_ci		start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
36862306a36Sopenharmony_ci		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
36962306a36Sopenharmony_ci		sm_mac_check_beacon_claim(smc) ;
37062306a36Sopenharmony_ci		DB_RMTN(1, "RMT : RM4_NON_OP_DUP");
37162306a36Sopenharmony_ci		ACTIONS_DONE() ;
37262306a36Sopenharmony_ci		break ;
37362306a36Sopenharmony_ci	case RM4_NON_OP_DUP :
37462306a36Sopenharmony_ci		if (cmd == RM_TIMEOUT_POLL) {
37562306a36Sopenharmony_ci			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
37662306a36Sopenharmony_ci			sm_mac_check_beacon_claim(smc) ;
37762306a36Sopenharmony_ci			break ;
37862306a36Sopenharmony_ci		}
37962306a36Sopenharmony_ci		/*RM41*/
38062306a36Sopenharmony_ci		if (!smc->r.da_flag) {
38162306a36Sopenharmony_ci			GO_STATE(RM1_NON_OP) ;
38262306a36Sopenharmony_ci			break ;
38362306a36Sopenharmony_ci		}
38462306a36Sopenharmony_ci		/*RM44a*/
38562306a36Sopenharmony_ci		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
38662306a36Sopenharmony_ci			smc->r.bn_flag) {
38762306a36Sopenharmony_ci			smc->r.bn_flag = FALSE ;
38862306a36Sopenharmony_ci		}
38962306a36Sopenharmony_ci		/*RM44b*/
39062306a36Sopenharmony_ci		else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
39162306a36Sopenharmony_ci			int	tx ;
39262306a36Sopenharmony_ci			/*
39362306a36Sopenharmony_ci			 * set bn_flag only if in state T4 or T5:
39462306a36Sopenharmony_ci			 * only if we're the beaconer should we start the
39562306a36Sopenharmony_ci			 * trace !
39662306a36Sopenharmony_ci			 */
39762306a36Sopenharmony_ci			if ((tx =  sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
39862306a36Sopenharmony_ci			DB_RMTN(2, "RMT : NOPDUP && TRT_EXPIRED && T4/T5");
39962306a36Sopenharmony_ci				smc->r.bn_flag = TRUE ;
40062306a36Sopenharmony_ci				/*
40162306a36Sopenharmony_ci				 * If one of the upstream stations beaconed
40262306a36Sopenharmony_ci				 * and the link to the upstream neighbor is
40362306a36Sopenharmony_ci				 * lost we need to restart the stuck timer to
40462306a36Sopenharmony_ci				 * check the "stuck beacon" condition.
40562306a36Sopenharmony_ci				 */
40662306a36Sopenharmony_ci				start_rmt_timer1(smc,smc->s.rmt_t_stuck,
40762306a36Sopenharmony_ci					RM_TIMEOUT_T_STUCK) ;
40862306a36Sopenharmony_ci			}
40962306a36Sopenharmony_ci			/*
41062306a36Sopenharmony_ci			 * We do NOT need to clear smc->r.bn_flag in case of
41162306a36Sopenharmony_ci			 * not being in state T4 or T5, because the flag
41262306a36Sopenharmony_ci			 * must be cleared in order to get in this condition.
41362306a36Sopenharmony_ci			 */
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci			DB_RMTN(2, "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)",
41662306a36Sopenharmony_ci				tx, smc->r.bn_flag);
41762306a36Sopenharmony_ci		}
41862306a36Sopenharmony_ci		/*RM44c*/
41962306a36Sopenharmony_ci		else if (cmd == RM_TIMEOUT_ANNOUNCE && !smc->r.bn_flag) {
42062306a36Sopenharmony_ci			rmt_dup_actions(smc) ;
42162306a36Sopenharmony_ci		}
42262306a36Sopenharmony_ci		/*RM45*/
42362306a36Sopenharmony_ci		else if (cmd == RM_RING_OP) {
42462306a36Sopenharmony_ci			smc->r.no_flag = FALSE ;
42562306a36Sopenharmony_ci			GO_STATE(RM5_RING_OP_DUP) ;
42662306a36Sopenharmony_ci			break ;
42762306a36Sopenharmony_ci		}
42862306a36Sopenharmony_ci		/*RM46*/
42962306a36Sopenharmony_ci		else if (cmd == RM_TIMEOUT_T_STUCK &&
43062306a36Sopenharmony_ci			smc->r.rm_join && smc->r.bn_flag) {
43162306a36Sopenharmony_ci			GO_STATE(RM6_DIRECTED) ;
43262306a36Sopenharmony_ci			break ;
43362306a36Sopenharmony_ci		}
43462306a36Sopenharmony_ci		break ;
43562306a36Sopenharmony_ci	case ACTIONS(RM5_RING_OP_DUP) :
43662306a36Sopenharmony_ci		stop_rmt_timer0(smc) ;
43762306a36Sopenharmony_ci		stop_rmt_timer1(smc) ;
43862306a36Sopenharmony_ci		stop_rmt_timer2(smc) ;
43962306a36Sopenharmony_ci		DB_RMTN(1, "RMT : RM5_RING_OP_DUP");
44062306a36Sopenharmony_ci		ACTIONS_DONE() ;
44162306a36Sopenharmony_ci		break;
44262306a36Sopenharmony_ci	case RM5_RING_OP_DUP :
44362306a36Sopenharmony_ci		/*RM52*/
44462306a36Sopenharmony_ci		if (smc->r.dup_addr_test == DA_PASSED) {
44562306a36Sopenharmony_ci			smc->r.da_flag = FALSE ;
44662306a36Sopenharmony_ci			GO_STATE(RM2_RING_OP) ;
44762306a36Sopenharmony_ci			break ;
44862306a36Sopenharmony_ci		}
44962306a36Sopenharmony_ci		/*RM54*/
45062306a36Sopenharmony_ci		else if (cmd == RM_RING_NON_OP) {
45162306a36Sopenharmony_ci			smc->r.jm_flag = FALSE ;
45262306a36Sopenharmony_ci			smc->r.bn_flag = FALSE ;
45362306a36Sopenharmony_ci			GO_STATE(RM4_NON_OP_DUP) ;
45462306a36Sopenharmony_ci			break ;
45562306a36Sopenharmony_ci		}
45662306a36Sopenharmony_ci		break ;
45762306a36Sopenharmony_ci	case ACTIONS(RM6_DIRECTED) :
45862306a36Sopenharmony_ci		start_rmt_timer0(smc,smc->s.rmt_t_direct,RM_TIMEOUT_T_DIRECT) ;
45962306a36Sopenharmony_ci		stop_rmt_timer1(smc) ;
46062306a36Sopenharmony_ci		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
46162306a36Sopenharmony_ci		sm_ma_control(smc,MA_DIRECTED) ;
46262306a36Sopenharmony_ci		RS_SET(smc,RS_BEACON) ;
46362306a36Sopenharmony_ci		DB_RMTN(1, "RMT : RM6_DIRECTED");
46462306a36Sopenharmony_ci		ACTIONS_DONE() ;
46562306a36Sopenharmony_ci		break ;
46662306a36Sopenharmony_ci	case RM6_DIRECTED :
46762306a36Sopenharmony_ci		/*RM63*/
46862306a36Sopenharmony_ci		if (cmd == RM_TIMEOUT_POLL) {
46962306a36Sopenharmony_ci			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
47062306a36Sopenharmony_ci			sm_mac_check_beacon_claim(smc) ;
47162306a36Sopenharmony_ci#ifndef SUPERNET_3
47262306a36Sopenharmony_ci			/* Because of problems with the Supernet II chip set
47362306a36Sopenharmony_ci			 * sending of Directed Beacon will stop after 165ms
47462306a36Sopenharmony_ci			 * therefore restart_trt_for_dbcn(smc) will be called
47562306a36Sopenharmony_ci			 * to prevent this.
47662306a36Sopenharmony_ci			 */
47762306a36Sopenharmony_ci			restart_trt_for_dbcn(smc) ;
47862306a36Sopenharmony_ci#endif /*SUPERNET_3*/
47962306a36Sopenharmony_ci			break ;
48062306a36Sopenharmony_ci		}
48162306a36Sopenharmony_ci		if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
48262306a36Sopenharmony_ci			!smc->r.da_flag) {
48362306a36Sopenharmony_ci			smc->r.bn_flag = FALSE ;
48462306a36Sopenharmony_ci			GO_STATE(RM3_DETECT) ;
48562306a36Sopenharmony_ci			break ;
48662306a36Sopenharmony_ci		}
48762306a36Sopenharmony_ci		/*RM64*/
48862306a36Sopenharmony_ci		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
48962306a36Sopenharmony_ci			smc->r.da_flag) {
49062306a36Sopenharmony_ci			smc->r.bn_flag = FALSE ;
49162306a36Sopenharmony_ci			GO_STATE(RM4_NON_OP_DUP) ;
49262306a36Sopenharmony_ci			break ;
49362306a36Sopenharmony_ci		}
49462306a36Sopenharmony_ci		/*RM67*/
49562306a36Sopenharmony_ci		else if (cmd == RM_TIMEOUT_T_DIRECT) {
49662306a36Sopenharmony_ci			GO_STATE(RM7_TRACE) ;
49762306a36Sopenharmony_ci			break ;
49862306a36Sopenharmony_ci		}
49962306a36Sopenharmony_ci		break ;
50062306a36Sopenharmony_ci	case ACTIONS(RM7_TRACE) :
50162306a36Sopenharmony_ci		stop_rmt_timer0(smc) ;
50262306a36Sopenharmony_ci		stop_rmt_timer1(smc) ;
50362306a36Sopenharmony_ci		stop_rmt_timer2(smc) ;
50462306a36Sopenharmony_ci		smc->e.trace_prop |= ENTITY_BIT(ENTITY_MAC) ;
50562306a36Sopenharmony_ci		queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ;
50662306a36Sopenharmony_ci		DB_RMTN(1, "RMT : RM7_TRACE");
50762306a36Sopenharmony_ci		ACTIONS_DONE() ;
50862306a36Sopenharmony_ci		break ;
50962306a36Sopenharmony_ci	case RM7_TRACE :
51062306a36Sopenharmony_ci		break ;
51162306a36Sopenharmony_ci	default:
51262306a36Sopenharmony_ci		SMT_PANIC(smc,SMT_E0122, SMT_E0122_MSG) ;
51362306a36Sopenharmony_ci		break;
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci/*
51862306a36Sopenharmony_ci * (jd) RMT duplicate address actions
51962306a36Sopenharmony_ci * leave the ring or reinsert just as configured
52062306a36Sopenharmony_ci */
52162306a36Sopenharmony_cistatic void rmt_dup_actions(struct s_smc *smc)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	if (smc->r.jm_flag) {
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci	else {
52662306a36Sopenharmony_ci		if (smc->s.rmt_dup_mac_behavior) {
52762306a36Sopenharmony_ci			SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
52862306a36Sopenharmony_ci                        rmt_reinsert_actions(smc) ;
52962306a36Sopenharmony_ci		}
53062306a36Sopenharmony_ci		else {
53162306a36Sopenharmony_ci			SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
53262306a36Sopenharmony_ci			rmt_leave_actions(smc) ;
53362306a36Sopenharmony_ci		}
53462306a36Sopenharmony_ci	}
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci/*
53862306a36Sopenharmony_ci * Reconnect to the Ring
53962306a36Sopenharmony_ci */
54062306a36Sopenharmony_cistatic void rmt_reinsert_actions(struct s_smc *smc)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
54362306a36Sopenharmony_ci	queue_event(smc,EVENT_ECM,EC_CONNECT) ;
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci/*
54762306a36Sopenharmony_ci * duplicate address detected
54862306a36Sopenharmony_ci */
54962306a36Sopenharmony_cistatic void rmt_new_dup_actions(struct s_smc *smc)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	smc->r.da_flag = TRUE ;
55262306a36Sopenharmony_ci	smc->r.bn_flag = FALSE ;
55362306a36Sopenharmony_ci	smc->r.jm_flag = FALSE ;
55462306a36Sopenharmony_ci	/*
55562306a36Sopenharmony_ci	 * we have three options : change address, jam or leave
55662306a36Sopenharmony_ci	 * we leave the ring as default
55762306a36Sopenharmony_ci	 * Optionally it's possible to reinsert after leaving the Ring
55862306a36Sopenharmony_ci	 * but this will not conform with SMT Spec.
55962306a36Sopenharmony_ci	 */
56062306a36Sopenharmony_ci	if (smc->s.rmt_dup_mac_behavior) {
56162306a36Sopenharmony_ci		SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
56262306a36Sopenharmony_ci		rmt_reinsert_actions(smc) ;
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci	else {
56562306a36Sopenharmony_ci		SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
56662306a36Sopenharmony_ci		rmt_leave_actions(smc) ;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci/*
57262306a36Sopenharmony_ci * leave the ring
57362306a36Sopenharmony_ci */
57462306a36Sopenharmony_cistatic void rmt_leave_actions(struct s_smc *smc)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
57762306a36Sopenharmony_ci	/*
57862306a36Sopenharmony_ci	 * Note: Do NOT try again later. (with please reconnect)
57962306a36Sopenharmony_ci	 * The station must be left from the ring!
58062306a36Sopenharmony_ci	 */
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci/*
58462306a36Sopenharmony_ci * SMT timer interface
58562306a36Sopenharmony_ci *	start RMT timer 0
58662306a36Sopenharmony_ci */
58762306a36Sopenharmony_cistatic void start_rmt_timer0(struct s_smc *smc, u_long value, int event)
58862306a36Sopenharmony_ci{
58962306a36Sopenharmony_ci	smc->r.timer0_exp = FALSE ;		/* clear timer event flag */
59062306a36Sopenharmony_ci	smt_timer_start(smc,&smc->r.rmt_timer0,value,EV_TOKEN(EVENT_RMT,event));
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci/*
59462306a36Sopenharmony_ci * SMT timer interface
59562306a36Sopenharmony_ci *	start RMT timer 1
59662306a36Sopenharmony_ci */
59762306a36Sopenharmony_cistatic void start_rmt_timer1(struct s_smc *smc, u_long value, int event)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	smc->r.timer1_exp = FALSE ;	/* clear timer event flag */
60062306a36Sopenharmony_ci	smt_timer_start(smc,&smc->r.rmt_timer1,value,EV_TOKEN(EVENT_RMT,event));
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci/*
60462306a36Sopenharmony_ci * SMT timer interface
60562306a36Sopenharmony_ci *	start RMT timer 2
60662306a36Sopenharmony_ci */
60762306a36Sopenharmony_cistatic void start_rmt_timer2(struct s_smc *smc, u_long value, int event)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	smc->r.timer2_exp = FALSE ;		/* clear timer event flag */
61062306a36Sopenharmony_ci	smt_timer_start(smc,&smc->r.rmt_timer2,value,EV_TOKEN(EVENT_RMT,event));
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci/*
61462306a36Sopenharmony_ci * SMT timer interface
61562306a36Sopenharmony_ci *	stop RMT timer 0
61662306a36Sopenharmony_ci */
61762306a36Sopenharmony_cistatic void stop_rmt_timer0(struct s_smc *smc)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	if (smc->r.rmt_timer0.tm_active)
62062306a36Sopenharmony_ci		smt_timer_stop(smc,&smc->r.rmt_timer0) ;
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci/*
62462306a36Sopenharmony_ci * SMT timer interface
62562306a36Sopenharmony_ci *	stop RMT timer 1
62662306a36Sopenharmony_ci */
62762306a36Sopenharmony_cistatic void stop_rmt_timer1(struct s_smc *smc)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	if (smc->r.rmt_timer1.tm_active)
63062306a36Sopenharmony_ci		smt_timer_stop(smc,&smc->r.rmt_timer1) ;
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci/*
63462306a36Sopenharmony_ci * SMT timer interface
63562306a36Sopenharmony_ci *	stop RMT timer 2
63662306a36Sopenharmony_ci */
63762306a36Sopenharmony_cistatic void stop_rmt_timer2(struct s_smc *smc)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	if (smc->r.rmt_timer2.tm_active)
64062306a36Sopenharmony_ci		smt_timer_stop(smc,&smc->r.rmt_timer2) ;
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci
643