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#include "h/types.h"
1462306a36Sopenharmony_ci#include "h/fddi.h"
1562306a36Sopenharmony_ci#include "h/smc.h"
1662306a36Sopenharmony_ci#include "h/smt_p.h"
1762306a36Sopenharmony_ci#include <linux/bitrev.h>
1862306a36Sopenharmony_ci#include <linux/kernel.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define KERNEL
2162306a36Sopenharmony_ci#include "h/smtstate.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/*
2462306a36Sopenharmony_ci * FC in SMbuf
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_ci#define m_fc(mb)	((mb)->sm_data[0])
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define SMT_TID_MAGIC	0x1f0a7b3c
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic const char *const smt_type_name[] = {
3162306a36Sopenharmony_ci	"SMT_00??", "SMT_INFO", "SMT_02??", "SMT_03??",
3262306a36Sopenharmony_ci	"SMT_04??", "SMT_05??", "SMT_06??", "SMT_07??",
3362306a36Sopenharmony_ci	"SMT_08??", "SMT_09??", "SMT_0A??", "SMT_0B??",
3462306a36Sopenharmony_ci	"SMT_0C??", "SMT_0D??", "SMT_0E??", "SMT_NSA"
3562306a36Sopenharmony_ci} ;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic const char *const smt_class_name[] = {
3862306a36Sopenharmony_ci	"UNKNOWN","NIF","SIF_CONFIG","SIF_OPER","ECF","RAF","RDF",
3962306a36Sopenharmony_ci	"SRF","PMF_GET","PMF_SET","ESF"
4062306a36Sopenharmony_ci} ;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define LAST_CLASS	(SMT_PMF_SET)
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic const struct fddi_addr SMT_Unknown = {
4562306a36Sopenharmony_ci	{ 0,0,0x1f,0,0,0 }
4662306a36Sopenharmony_ci} ;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/*
4962306a36Sopenharmony_ci * function prototypes
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_ci#ifdef	LITTLE_ENDIAN
5262306a36Sopenharmony_cistatic int smt_swap_short(u_short s);
5362306a36Sopenharmony_ci#endif
5462306a36Sopenharmony_cistatic int mac_index(struct s_smc *smc, int mac);
5562306a36Sopenharmony_cistatic int phy_index(struct s_smc *smc, int phy);
5662306a36Sopenharmony_cistatic int mac_con_resource_index(struct s_smc *smc, int mac);
5762306a36Sopenharmony_cistatic int phy_con_resource_index(struct s_smc *smc, int phy);
5862306a36Sopenharmony_cistatic void smt_send_rdf(struct s_smc *smc, SMbuf *rej, int fc, int reason,
5962306a36Sopenharmony_ci			 int local);
6062306a36Sopenharmony_cistatic void smt_send_nif(struct s_smc *smc, const struct fddi_addr *dest,
6162306a36Sopenharmony_ci			 int fc, u_long tid, int type, int local);
6262306a36Sopenharmony_cistatic void smt_send_ecf(struct s_smc *smc, struct fddi_addr *dest, int fc,
6362306a36Sopenharmony_ci                         u_long tid, int type, int len);
6462306a36Sopenharmony_cistatic void smt_echo_test(struct s_smc *smc, int dna);
6562306a36Sopenharmony_cistatic void smt_send_sif_config(struct s_smc *smc, struct fddi_addr *dest,
6662306a36Sopenharmony_ci				u_long tid, int local);
6762306a36Sopenharmony_cistatic void smt_send_sif_operation(struct s_smc *smc, struct fddi_addr *dest,
6862306a36Sopenharmony_ci				   u_long tid, int local);
6962306a36Sopenharmony_ci#ifdef LITTLE_ENDIAN
7062306a36Sopenharmony_cistatic void smt_string_swap(char *data, const char *format, int len);
7162306a36Sopenharmony_ci#endif
7262306a36Sopenharmony_cistatic void smt_add_frame_len(SMbuf *mb, int len);
7362306a36Sopenharmony_cistatic void smt_fill_una(struct s_smc *smc, struct smt_p_una *una);
7462306a36Sopenharmony_cistatic void smt_fill_sde(struct s_smc *smc, struct smt_p_sde *sde);
7562306a36Sopenharmony_cistatic void smt_fill_state(struct s_smc *smc, struct smt_p_state *state);
7662306a36Sopenharmony_cistatic void smt_fill_timestamp(struct s_smc *smc, struct smt_p_timestamp *ts);
7762306a36Sopenharmony_cistatic void smt_fill_policy(struct s_smc *smc, struct smt_p_policy *policy);
7862306a36Sopenharmony_cistatic void smt_fill_latency(struct s_smc *smc, struct smt_p_latency *latency);
7962306a36Sopenharmony_cistatic void smt_fill_neighbor(struct s_smc *smc, struct smt_p_neighbor *neighbor);
8062306a36Sopenharmony_cistatic int smt_fill_path(struct s_smc *smc, struct smt_p_path *path);
8162306a36Sopenharmony_cistatic void smt_fill_mac_status(struct s_smc *smc, struct smt_p_mac_status *st);
8262306a36Sopenharmony_cistatic void smt_fill_lem(struct s_smc *smc, struct smt_p_lem *lem, int phy);
8362306a36Sopenharmony_cistatic void smt_fill_version(struct s_smc *smc, struct smt_p_version *vers);
8462306a36Sopenharmony_cistatic void smt_fill_fsc(struct s_smc *smc, struct smt_p_fsc *fsc);
8562306a36Sopenharmony_cistatic void smt_fill_mac_counter(struct s_smc *smc, struct smt_p_mac_counter *mc);
8662306a36Sopenharmony_cistatic void smt_fill_mac_fnc(struct s_smc *smc, struct smt_p_mac_fnc *fnc);
8762306a36Sopenharmony_cistatic void smt_fill_manufacturer(struct s_smc *smc,
8862306a36Sopenharmony_ci				  struct smp_p_manufacturer *man);
8962306a36Sopenharmony_cistatic void smt_fill_user(struct s_smc *smc, struct smp_p_user *user);
9062306a36Sopenharmony_cistatic void smt_fill_setcount(struct s_smc *smc, struct smt_p_setcount *setcount);
9162306a36Sopenharmony_cistatic void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long seed,
9262306a36Sopenharmony_ci			  int len);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic void smt_clear_una_dna(struct s_smc *smc);
9562306a36Sopenharmony_cistatic void smt_clear_old_una_dna(struct s_smc *smc);
9662306a36Sopenharmony_ci#ifdef	CONCENTRATOR
9762306a36Sopenharmony_cistatic int entity_to_index(void);
9862306a36Sopenharmony_ci#endif
9962306a36Sopenharmony_cistatic void update_dac(struct s_smc *smc, int report);
10062306a36Sopenharmony_cistatic int div_ratio(u_long upper, u_long lower);
10162306a36Sopenharmony_ci#ifdef  USE_CAN_ADDR
10262306a36Sopenharmony_cistatic void	hwm_conv_can(struct s_smc *smc, char *data, int len);
10362306a36Sopenharmony_ci#else
10462306a36Sopenharmony_ci#define		hwm_conv_can(smc,data,len)
10562306a36Sopenharmony_ci#endif
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic inline int is_my_addr(const struct s_smc *smc,
10962306a36Sopenharmony_ci			     const struct fddi_addr *addr)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	return(*(short *)(&addr->a[0]) ==
11262306a36Sopenharmony_ci		*(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[0])
11362306a36Sopenharmony_ci	  && *(short *)(&addr->a[2]) ==
11462306a36Sopenharmony_ci		*(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[2])
11562306a36Sopenharmony_ci	  && *(short *)(&addr->a[4]) ==
11662306a36Sopenharmony_ci		*(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[4])) ;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic inline int is_broadcast(const struct fddi_addr *addr)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	return *(u_short *)(&addr->a[0]) == 0xffff &&
12262306a36Sopenharmony_ci	       *(u_short *)(&addr->a[2]) == 0xffff &&
12362306a36Sopenharmony_ci	       *(u_short *)(&addr->a[4]) == 0xffff;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic inline int is_individual(const struct fddi_addr *addr)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	return !(addr->a[0] & GROUP_ADDR);
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic inline int is_equal(const struct fddi_addr *addr1,
13262306a36Sopenharmony_ci			   const struct fddi_addr *addr2)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	return *(u_short *)(&addr1->a[0]) == *(u_short *)(&addr2->a[0]) &&
13562306a36Sopenharmony_ci	       *(u_short *)(&addr1->a[2]) == *(u_short *)(&addr2->a[2]) &&
13662306a36Sopenharmony_ci	       *(u_short *)(&addr1->a[4]) == *(u_short *)(&addr2->a[4]);
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci/*
14062306a36Sopenharmony_ci * list of mandatory paras in frames
14162306a36Sopenharmony_ci */
14262306a36Sopenharmony_cistatic const u_short plist_nif[] = { SMT_P_UNA,SMT_P_SDE,SMT_P_STATE,0 } ;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci/*
14562306a36Sopenharmony_ci * init SMT agent
14662306a36Sopenharmony_ci */
14762306a36Sopenharmony_civoid smt_agent_init(struct s_smc *smc)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	int		i ;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	/*
15262306a36Sopenharmony_ci	 * get MAC address
15362306a36Sopenharmony_ci	 */
15462306a36Sopenharmony_ci	smc->mib.m[MAC0].fddiMACSMTAddress = smc->hw.fddi_home_addr ;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/*
15762306a36Sopenharmony_ci	 * get OUI address from driver (bia == built-in-address)
15862306a36Sopenharmony_ci	 */
15962306a36Sopenharmony_ci	smc->mib.fddiSMTStationId.sid_oem[0] = 0 ;
16062306a36Sopenharmony_ci	smc->mib.fddiSMTStationId.sid_oem[1] = 0 ;
16162306a36Sopenharmony_ci	driver_get_bia(smc,&smc->mib.fddiSMTStationId.sid_node) ;
16262306a36Sopenharmony_ci	for (i = 0 ; i < 6 ; i ++) {
16362306a36Sopenharmony_ci		smc->mib.fddiSMTStationId.sid_node.a[i] =
16462306a36Sopenharmony_ci			bitrev8(smc->mib.fddiSMTStationId.sid_node.a[i]);
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci	smc->mib.fddiSMTManufacturerData[0] =
16762306a36Sopenharmony_ci		smc->mib.fddiSMTStationId.sid_node.a[0] ;
16862306a36Sopenharmony_ci	smc->mib.fddiSMTManufacturerData[1] =
16962306a36Sopenharmony_ci		smc->mib.fddiSMTStationId.sid_node.a[1] ;
17062306a36Sopenharmony_ci	smc->mib.fddiSMTManufacturerData[2] =
17162306a36Sopenharmony_ci		smc->mib.fddiSMTStationId.sid_node.a[2] ;
17262306a36Sopenharmony_ci	smc->sm.smt_tid = 0 ;
17362306a36Sopenharmony_ci	smc->mib.m[MAC0].fddiMACDupAddressTest = DA_NONE ;
17462306a36Sopenharmony_ci	smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ;
17562306a36Sopenharmony_ci#ifndef	SLIM_SMT
17662306a36Sopenharmony_ci	smt_clear_una_dna(smc) ;
17762306a36Sopenharmony_ci	smt_clear_old_una_dna(smc) ;
17862306a36Sopenharmony_ci#endif
17962306a36Sopenharmony_ci	for (i = 0 ; i < SMT_MAX_TEST ; i++)
18062306a36Sopenharmony_ci		smc->sm.pend[i] = 0 ;
18162306a36Sopenharmony_ci	smc->sm.please_reconnect = 0 ;
18262306a36Sopenharmony_ci	smc->sm.uniq_ticks = 0 ;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/*
18662306a36Sopenharmony_ci * SMT task
18762306a36Sopenharmony_ci * forever
18862306a36Sopenharmony_ci *	delay 30 seconds
18962306a36Sopenharmony_ci *	send NIF
19062306a36Sopenharmony_ci *	check tvu & tvd
19162306a36Sopenharmony_ci * end
19262306a36Sopenharmony_ci */
19362306a36Sopenharmony_civoid smt_agent_task(struct s_smc *smc)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L,
19662306a36Sopenharmony_ci		EV_TOKEN(EVENT_SMT,SM_TIMER)) ;
19762306a36Sopenharmony_ci	DB_SMT("SMT agent task");
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci#ifndef SMT_REAL_TOKEN_CT
20162306a36Sopenharmony_civoid smt_emulate_token_ct(struct s_smc *smc, int mac_index)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	u_long	count;
20462306a36Sopenharmony_ci	u_long	time;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	time = smt_get_time();
20862306a36Sopenharmony_ci	count =	((time - smc->sm.last_tok_time[mac_index]) *
20962306a36Sopenharmony_ci					100)/TICKS_PER_SECOND;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	/*
21262306a36Sopenharmony_ci	 * Only when ring is up we will have a token count. The
21362306a36Sopenharmony_ci	 * flag is unfortunately a single instance value. This
21462306a36Sopenharmony_ci	 * doesn't matter now, because we currently have only
21562306a36Sopenharmony_ci	 * one MAC instance.
21662306a36Sopenharmony_ci	 */
21762306a36Sopenharmony_ci	if (smc->hw.mac_ring_is_up){
21862306a36Sopenharmony_ci		smc->mib.m[mac_index].fddiMACToken_Ct += count;
21962306a36Sopenharmony_ci	}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	/* Remember current time */
22262306a36Sopenharmony_ci	smc->sm.last_tok_time[mac_index] = time;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci#endif
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci/*ARGSUSED1*/
22862306a36Sopenharmony_civoid smt_event(struct s_smc *smc, int event)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	u_long		time ;
23162306a36Sopenharmony_ci#ifndef SMT_REAL_TOKEN_CT
23262306a36Sopenharmony_ci	int		i ;
23362306a36Sopenharmony_ci#endif
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	if (smc->sm.please_reconnect) {
23762306a36Sopenharmony_ci		smc->sm.please_reconnect -- ;
23862306a36Sopenharmony_ci		if (smc->sm.please_reconnect == 0) {
23962306a36Sopenharmony_ci			/* Counted down */
24062306a36Sopenharmony_ci			queue_event(smc,EVENT_ECM,EC_CONNECT) ;
24162306a36Sopenharmony_ci		}
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (event == SM_FAST)
24562306a36Sopenharmony_ci		return ;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	/*
24862306a36Sopenharmony_ci	 * timer for periodic cleanup in driver
24962306a36Sopenharmony_ci	 * reset and start the watchdog (FM2)
25062306a36Sopenharmony_ci	 * ESS timer
25162306a36Sopenharmony_ci	 * SBA timer
25262306a36Sopenharmony_ci	 */
25362306a36Sopenharmony_ci	smt_timer_poll(smc) ;
25462306a36Sopenharmony_ci	smt_start_watchdog(smc) ;
25562306a36Sopenharmony_ci#ifndef	SLIM_SMT
25662306a36Sopenharmony_ci#ifndef BOOT
25762306a36Sopenharmony_ci#ifdef	ESS
25862306a36Sopenharmony_ci	ess_timer_poll(smc) ;
25962306a36Sopenharmony_ci#endif
26062306a36Sopenharmony_ci#endif
26162306a36Sopenharmony_ci#ifdef	SBA
26262306a36Sopenharmony_ci	sba_timer_poll(smc) ;
26362306a36Sopenharmony_ci#endif
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	smt_srf_event(smc,0,0,0) ;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci#endif	/* no SLIM_SMT */
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	time = smt_get_time() ;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (time - smc->sm.smt_last_lem >= TICKS_PER_SECOND*8) {
27262306a36Sopenharmony_ci		/*
27362306a36Sopenharmony_ci		 * Use 8 sec. for the time intervall, it simplifies the
27462306a36Sopenharmony_ci		 * LER estimation.
27562306a36Sopenharmony_ci		 */
27662306a36Sopenharmony_ci		struct fddi_mib_m	*mib ;
27762306a36Sopenharmony_ci		u_long			upper ;
27862306a36Sopenharmony_ci		u_long			lower ;
27962306a36Sopenharmony_ci		int			cond ;
28062306a36Sopenharmony_ci		int			port;
28162306a36Sopenharmony_ci		struct s_phy		*phy ;
28262306a36Sopenharmony_ci		/*
28362306a36Sopenharmony_ci		 * calculate LEM bit error rate
28462306a36Sopenharmony_ci		 */
28562306a36Sopenharmony_ci		sm_lem_evaluate(smc) ;
28662306a36Sopenharmony_ci		smc->sm.smt_last_lem = time ;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		/*
28962306a36Sopenharmony_ci		 * check conditions
29062306a36Sopenharmony_ci		 */
29162306a36Sopenharmony_ci#ifndef	SLIM_SMT
29262306a36Sopenharmony_ci		mac_update_counter(smc) ;
29362306a36Sopenharmony_ci		mib = smc->mib.m ;
29462306a36Sopenharmony_ci		upper =
29562306a36Sopenharmony_ci		(mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) +
29662306a36Sopenharmony_ci		(mib->fddiMACError_Ct - mib->fddiMACOld_Error_Ct) ;
29762306a36Sopenharmony_ci		lower =
29862306a36Sopenharmony_ci		(mib->fddiMACFrame_Ct - mib->fddiMACOld_Frame_Ct) +
29962306a36Sopenharmony_ci		(mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) ;
30062306a36Sopenharmony_ci		mib->fddiMACFrameErrorRatio = div_ratio(upper,lower) ;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		cond =
30362306a36Sopenharmony_ci			((!mib->fddiMACFrameErrorThreshold &&
30462306a36Sopenharmony_ci			mib->fddiMACError_Ct != mib->fddiMACOld_Error_Ct) ||
30562306a36Sopenharmony_ci			(mib->fddiMACFrameErrorRatio >
30662306a36Sopenharmony_ci			mib->fddiMACFrameErrorThreshold)) ;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci		if (cond != mib->fddiMACFrameErrorFlag)
30962306a36Sopenharmony_ci			smt_srf_event(smc,SMT_COND_MAC_FRAME_ERROR,
31062306a36Sopenharmony_ci				INDEX_MAC,cond) ;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci		upper =
31362306a36Sopenharmony_ci		(mib->fddiMACNotCopied_Ct - mib->fddiMACOld_NotCopied_Ct) ;
31462306a36Sopenharmony_ci		lower =
31562306a36Sopenharmony_ci		upper +
31662306a36Sopenharmony_ci		(mib->fddiMACCopied_Ct - mib->fddiMACOld_Copied_Ct) ;
31762306a36Sopenharmony_ci		mib->fddiMACNotCopiedRatio = div_ratio(upper,lower) ;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci		cond =
32062306a36Sopenharmony_ci			((!mib->fddiMACNotCopiedThreshold &&
32162306a36Sopenharmony_ci			mib->fddiMACNotCopied_Ct !=
32262306a36Sopenharmony_ci				mib->fddiMACOld_NotCopied_Ct)||
32362306a36Sopenharmony_ci			(mib->fddiMACNotCopiedRatio >
32462306a36Sopenharmony_ci			mib->fddiMACNotCopiedThreshold)) ;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		if (cond != mib->fddiMACNotCopiedFlag)
32762306a36Sopenharmony_ci			smt_srf_event(smc,SMT_COND_MAC_NOT_COPIED,
32862306a36Sopenharmony_ci				INDEX_MAC,cond) ;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci		/*
33162306a36Sopenharmony_ci		 * set old values
33262306a36Sopenharmony_ci		 */
33362306a36Sopenharmony_ci		mib->fddiMACOld_Frame_Ct = mib->fddiMACFrame_Ct ;
33462306a36Sopenharmony_ci		mib->fddiMACOld_Copied_Ct = mib->fddiMACCopied_Ct ;
33562306a36Sopenharmony_ci		mib->fddiMACOld_Error_Ct = mib->fddiMACError_Ct ;
33662306a36Sopenharmony_ci		mib->fddiMACOld_Lost_Ct = mib->fddiMACLost_Ct ;
33762306a36Sopenharmony_ci		mib->fddiMACOld_NotCopied_Ct = mib->fddiMACNotCopied_Ct ;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci		/*
34062306a36Sopenharmony_ci		 * Check port EBError Condition
34162306a36Sopenharmony_ci		 */
34262306a36Sopenharmony_ci		for (port = 0; port < NUMPHYS; port ++) {
34362306a36Sopenharmony_ci			phy = &smc->y[port] ;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci			if (!phy->mib->fddiPORTHardwarePresent) {
34662306a36Sopenharmony_ci				continue;
34762306a36Sopenharmony_ci			}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci			cond = (phy->mib->fddiPORTEBError_Ct -
35062306a36Sopenharmony_ci				phy->mib->fddiPORTOldEBError_Ct > 5) ;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci			/* If ratio is more than 5 in 8 seconds
35362306a36Sopenharmony_ci			 * Set the condition.
35462306a36Sopenharmony_ci			 */
35562306a36Sopenharmony_ci			smt_srf_event(smc,SMT_COND_PORT_EB_ERROR,
35662306a36Sopenharmony_ci				(int) (INDEX_PORT+ phy->np) ,cond) ;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci			/*
35962306a36Sopenharmony_ci			 * set old values
36062306a36Sopenharmony_ci			 */
36162306a36Sopenharmony_ci			phy->mib->fddiPORTOldEBError_Ct =
36262306a36Sopenharmony_ci				phy->mib->fddiPORTEBError_Ct ;
36362306a36Sopenharmony_ci		}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci#endif	/* no SLIM_SMT */
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci#ifndef	SLIM_SMT
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	if (time - smc->sm.smt_last_notify >= (u_long)
37162306a36Sopenharmony_ci		(smc->mib.fddiSMTTT_Notify * TICKS_PER_SECOND) ) {
37262306a36Sopenharmony_ci		/*
37362306a36Sopenharmony_ci		 * we can either send an announcement or a request
37462306a36Sopenharmony_ci		 * a request will trigger a reply so that we can update
37562306a36Sopenharmony_ci		 * our dna
37662306a36Sopenharmony_ci		 * note: same tid must be used until reply is received
37762306a36Sopenharmony_ci		 */
37862306a36Sopenharmony_ci		if (!smc->sm.pend[SMT_TID_NIF])
37962306a36Sopenharmony_ci			smc->sm.pend[SMT_TID_NIF] = smt_get_tid(smc) ;
38062306a36Sopenharmony_ci		smt_send_nif(smc,&fddi_broadcast, FC_SMT_NSA,
38162306a36Sopenharmony_ci			smc->sm.pend[SMT_TID_NIF], SMT_REQUEST,0) ;
38262306a36Sopenharmony_ci		smc->sm.smt_last_notify = time ;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	/*
38662306a36Sopenharmony_ci	 * check timer
38762306a36Sopenharmony_ci	 */
38862306a36Sopenharmony_ci	if (smc->sm.smt_tvu &&
38962306a36Sopenharmony_ci	    time - smc->sm.smt_tvu > 228*TICKS_PER_SECOND) {
39062306a36Sopenharmony_ci		DB_SMT("SMT : UNA expired");
39162306a36Sopenharmony_ci		smc->sm.smt_tvu = 0 ;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci		if (!is_equal(&smc->mib.m[MAC0].fddiMACUpstreamNbr,
39462306a36Sopenharmony_ci			&SMT_Unknown)){
39562306a36Sopenharmony_ci			/* Do not update unknown address */
39662306a36Sopenharmony_ci			smc->mib.m[MAC0].fddiMACOldUpstreamNbr=
39762306a36Sopenharmony_ci				smc->mib.m[MAC0].fddiMACUpstreamNbr ;
39862306a36Sopenharmony_ci		}
39962306a36Sopenharmony_ci		smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ;
40062306a36Sopenharmony_ci		smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ;
40162306a36Sopenharmony_ci		/*
40262306a36Sopenharmony_ci		 * Make sure the fddiMACUNDA_Flag = FALSE is
40362306a36Sopenharmony_ci		 * included in the SRF so we don't generate
40462306a36Sopenharmony_ci		 * a separate SRF for the deassertion of this
40562306a36Sopenharmony_ci		 * condition
40662306a36Sopenharmony_ci		 */
40762306a36Sopenharmony_ci		update_dac(smc,0) ;
40862306a36Sopenharmony_ci		smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE,
40962306a36Sopenharmony_ci			INDEX_MAC,0) ;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci	if (smc->sm.smt_tvd &&
41262306a36Sopenharmony_ci	    time - smc->sm.smt_tvd > 228*TICKS_PER_SECOND) {
41362306a36Sopenharmony_ci		DB_SMT("SMT : DNA expired");
41462306a36Sopenharmony_ci		smc->sm.smt_tvd = 0 ;
41562306a36Sopenharmony_ci		if (!is_equal(&smc->mib.m[MAC0].fddiMACDownstreamNbr,
41662306a36Sopenharmony_ci			&SMT_Unknown)){
41762306a36Sopenharmony_ci			/* Do not update unknown address */
41862306a36Sopenharmony_ci			smc->mib.m[MAC0].fddiMACOldDownstreamNbr=
41962306a36Sopenharmony_ci				smc->mib.m[MAC0].fddiMACDownstreamNbr ;
42062306a36Sopenharmony_ci		}
42162306a36Sopenharmony_ci		smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ;
42262306a36Sopenharmony_ci		smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE,
42362306a36Sopenharmony_ci			INDEX_MAC,0) ;
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci#endif	/* no SLIM_SMT */
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci#ifndef SMT_REAL_TOKEN_CT
42962306a36Sopenharmony_ci	/*
43062306a36Sopenharmony_ci	 * Token counter emulation section. If hardware supports the token
43162306a36Sopenharmony_ci	 * count, the token counter will be updated in mac_update_counter.
43262306a36Sopenharmony_ci	 */
43362306a36Sopenharmony_ci	for (i = MAC0; i < NUMMACS; i++ ){
43462306a36Sopenharmony_ci		if (time - smc->sm.last_tok_time[i] > 2*TICKS_PER_SECOND ){
43562306a36Sopenharmony_ci			smt_emulate_token_ct( smc, i );
43662306a36Sopenharmony_ci		}
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci#endif
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L,
44162306a36Sopenharmony_ci		EV_TOKEN(EVENT_SMT,SM_TIMER)) ;
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic int div_ratio(u_long upper, u_long lower)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	if ((upper<<16L) < upper)
44762306a36Sopenharmony_ci		upper = 0xffff0000L ;
44862306a36Sopenharmony_ci	else
44962306a36Sopenharmony_ci		upper <<= 16L ;
45062306a36Sopenharmony_ci	if (!lower)
45162306a36Sopenharmony_ci		return 0;
45262306a36Sopenharmony_ci	return (int)(upper/lower) ;
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci#ifndef	SLIM_SMT
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci/*
45862306a36Sopenharmony_ci * receive packet handler
45962306a36Sopenharmony_ci */
46062306a36Sopenharmony_civoid smt_received_pack(struct s_smc *smc, SMbuf *mb, int fs)
46162306a36Sopenharmony_ci/* int fs;  frame status */
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	struct smt_header	*sm ;
46462306a36Sopenharmony_ci	int			local ;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	int			illegal = 0 ;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	switch (m_fc(mb)) {
46962306a36Sopenharmony_ci	case FC_SMT_INFO :
47062306a36Sopenharmony_ci	case FC_SMT_LAN_LOC :
47162306a36Sopenharmony_ci	case FC_SMT_LOC :
47262306a36Sopenharmony_ci	case FC_SMT_NSA :
47362306a36Sopenharmony_ci		break ;
47462306a36Sopenharmony_ci	default :
47562306a36Sopenharmony_ci		smt_free_mbuf(smc,mb) ;
47662306a36Sopenharmony_ci		return ;
47762306a36Sopenharmony_ci	}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	smc->mib.m[MAC0].fddiMACSMTCopied_Ct++ ;
48062306a36Sopenharmony_ci	sm = smtod(mb,struct smt_header *) ;
48162306a36Sopenharmony_ci	local = ((fs & L_INDICATOR) != 0) ;
48262306a36Sopenharmony_ci	hwm_conv_can(smc,(char *)sm,12) ;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	/* check destination address */
48562306a36Sopenharmony_ci	if (is_individual(&sm->smt_dest) && !is_my_addr(smc,&sm->smt_dest)) {
48662306a36Sopenharmony_ci		smt_free_mbuf(smc,mb) ;
48762306a36Sopenharmony_ci		return ;
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci#if	0		/* for DUP recognition, do NOT filter them */
49062306a36Sopenharmony_ci	/* ignore loop back packets */
49162306a36Sopenharmony_ci	if (is_my_addr(smc,&sm->smt_source) && !local) {
49262306a36Sopenharmony_ci		smt_free_mbuf(smc,mb) ;
49362306a36Sopenharmony_ci		return ;
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci#endif
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	smt_swap_para(sm,(int) mb->sm_len,1) ;
49862306a36Sopenharmony_ci	DB_SMT("SMT : received packet [%s] at 0x%p",
49962306a36Sopenharmony_ci	       smt_type_name[m_fc(mb) & 0xf], sm);
50062306a36Sopenharmony_ci	DB_SMT("SMT : version %d, class %s",
50162306a36Sopenharmony_ci	       sm->smt_version,
50262306a36Sopenharmony_ci	       smt_class_name[sm->smt_class > LAST_CLASS ? 0 : sm->smt_class]);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci#ifdef	SBA
50562306a36Sopenharmony_ci	/*
50662306a36Sopenharmony_ci	 * check if NSA frame
50762306a36Sopenharmony_ci	 */
50862306a36Sopenharmony_ci	if (m_fc(mb) == FC_SMT_NSA && sm->smt_class == SMT_NIF &&
50962306a36Sopenharmony_ci		(sm->smt_type == SMT_ANNOUNCE || sm->smt_type == SMT_REQUEST)) {
51062306a36Sopenharmony_ci			smc->sba.sm = sm ;
51162306a36Sopenharmony_ci			sba(smc,NIF) ;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci#endif
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	/*
51662306a36Sopenharmony_ci	 * ignore any packet with NSA and A-indicator set
51762306a36Sopenharmony_ci	 */
51862306a36Sopenharmony_ci	if ( (fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) {
51962306a36Sopenharmony_ci		DB_SMT("SMT : ignoring NSA with A-indicator set from %pM",
52062306a36Sopenharmony_ci		       &sm->smt_source);
52162306a36Sopenharmony_ci		smt_free_mbuf(smc,mb) ;
52262306a36Sopenharmony_ci		return ;
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	/*
52662306a36Sopenharmony_ci	 * ignore frames with illegal length
52762306a36Sopenharmony_ci	 */
52862306a36Sopenharmony_ci	if (((sm->smt_class == SMT_ECF) && (sm->smt_len > SMT_MAX_ECHO_LEN)) ||
52962306a36Sopenharmony_ci	    ((sm->smt_class != SMT_ECF) && (sm->smt_len > SMT_MAX_INFO_LEN))) {
53062306a36Sopenharmony_ci		smt_free_mbuf(smc,mb) ;
53162306a36Sopenharmony_ci		return ;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	/*
53562306a36Sopenharmony_ci	 * check SMT version
53662306a36Sopenharmony_ci	 */
53762306a36Sopenharmony_ci	switch (sm->smt_class) {
53862306a36Sopenharmony_ci	case SMT_NIF :
53962306a36Sopenharmony_ci	case SMT_SIF_CONFIG :
54062306a36Sopenharmony_ci	case SMT_SIF_OPER :
54162306a36Sopenharmony_ci	case SMT_ECF :
54262306a36Sopenharmony_ci		if (sm->smt_version != SMT_VID)
54362306a36Sopenharmony_ci			illegal = 1;
54462306a36Sopenharmony_ci		break ;
54562306a36Sopenharmony_ci	default :
54662306a36Sopenharmony_ci		if (sm->smt_version != SMT_VID_2)
54762306a36Sopenharmony_ci			illegal = 1;
54862306a36Sopenharmony_ci		break ;
54962306a36Sopenharmony_ci	}
55062306a36Sopenharmony_ci	if (illegal) {
55162306a36Sopenharmony_ci		DB_SMT("SMT : version = %d, dest = %pM",
55262306a36Sopenharmony_ci		       sm->smt_version, &sm->smt_source);
55362306a36Sopenharmony_ci		smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_VERSION,local) ;
55462306a36Sopenharmony_ci		smt_free_mbuf(smc,mb) ;
55562306a36Sopenharmony_ci		return ;
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci	if ((sm->smt_len > mb->sm_len - sizeof(struct smt_header)) ||
55862306a36Sopenharmony_ci	    ((sm->smt_len & 3) && (sm->smt_class != SMT_ECF))) {
55962306a36Sopenharmony_ci		DB_SMT("SMT: info length error, len = %d", sm->smt_len);
56062306a36Sopenharmony_ci		smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH,local) ;
56162306a36Sopenharmony_ci		smt_free_mbuf(smc,mb) ;
56262306a36Sopenharmony_ci		return ;
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci	switch (sm->smt_class) {
56562306a36Sopenharmony_ci	case SMT_NIF :
56662306a36Sopenharmony_ci		if (smt_check_para(smc,sm,plist_nif)) {
56762306a36Sopenharmony_ci			DB_SMT("SMT: NIF with para problem, ignoring");
56862306a36Sopenharmony_ci			break ;
56962306a36Sopenharmony_ci		}
57062306a36Sopenharmony_ci		switch (sm->smt_type) {
57162306a36Sopenharmony_ci		case SMT_ANNOUNCE :
57262306a36Sopenharmony_ci		case SMT_REQUEST :
57362306a36Sopenharmony_ci			if (!(fs & C_INDICATOR) && m_fc(mb) == FC_SMT_NSA
57462306a36Sopenharmony_ci				&& is_broadcast(&sm->smt_dest)) {
57562306a36Sopenharmony_ci				struct smt_p_state	*st ;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci				/* set my UNA */
57862306a36Sopenharmony_ci				if (!is_equal(
57962306a36Sopenharmony_ci					&smc->mib.m[MAC0].fddiMACUpstreamNbr,
58062306a36Sopenharmony_ci					&sm->smt_source)) {
58162306a36Sopenharmony_ci					DB_SMT("SMT : updated my UNA = %pM",
58262306a36Sopenharmony_ci					       &sm->smt_source);
58362306a36Sopenharmony_ci					if (!is_equal(&smc->mib.m[MAC0].
58462306a36Sopenharmony_ci					    fddiMACUpstreamNbr,&SMT_Unknown)){
58562306a36Sopenharmony_ci					 /* Do not update unknown address */
58662306a36Sopenharmony_ci					 smc->mib.m[MAC0].fddiMACOldUpstreamNbr=
58762306a36Sopenharmony_ci					 smc->mib.m[MAC0].fddiMACUpstreamNbr ;
58862306a36Sopenharmony_ci					}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci					smc->mib.m[MAC0].fddiMACUpstreamNbr =
59162306a36Sopenharmony_ci						sm->smt_source ;
59262306a36Sopenharmony_ci					smt_srf_event(smc,
59362306a36Sopenharmony_ci						SMT_EVENT_MAC_NEIGHBOR_CHANGE,
59462306a36Sopenharmony_ci						INDEX_MAC,0) ;
59562306a36Sopenharmony_ci					smt_echo_test(smc,0) ;
59662306a36Sopenharmony_ci				}
59762306a36Sopenharmony_ci				smc->sm.smt_tvu = smt_get_time() ;
59862306a36Sopenharmony_ci				st = (struct smt_p_state *)
59962306a36Sopenharmony_ci					sm_to_para(smc,sm,SMT_P_STATE) ;
60062306a36Sopenharmony_ci				if (st) {
60162306a36Sopenharmony_ci					smc->mib.m[MAC0].fddiMACUNDA_Flag =
60262306a36Sopenharmony_ci					(st->st_dupl_addr & SMT_ST_MY_DUPA) ?
60362306a36Sopenharmony_ci					TRUE : FALSE ;
60462306a36Sopenharmony_ci					update_dac(smc,1) ;
60562306a36Sopenharmony_ci				}
60662306a36Sopenharmony_ci			}
60762306a36Sopenharmony_ci			if ((sm->smt_type == SMT_REQUEST) &&
60862306a36Sopenharmony_ci			    is_individual(&sm->smt_source) &&
60962306a36Sopenharmony_ci			    ((!(fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) ||
61062306a36Sopenharmony_ci			     (m_fc(mb) != FC_SMT_NSA))) {
61162306a36Sopenharmony_ci				DB_SMT("SMT : replying to NIF request %pM",
61262306a36Sopenharmony_ci				       &sm->smt_source);
61362306a36Sopenharmony_ci				smt_send_nif(smc,&sm->smt_source,
61462306a36Sopenharmony_ci					FC_SMT_INFO,
61562306a36Sopenharmony_ci					sm->smt_tid,
61662306a36Sopenharmony_ci					SMT_REPLY,local) ;
61762306a36Sopenharmony_ci			}
61862306a36Sopenharmony_ci			break ;
61962306a36Sopenharmony_ci		case SMT_REPLY :
62062306a36Sopenharmony_ci			DB_SMT("SMT : received NIF response from %pM",
62162306a36Sopenharmony_ci			       &sm->smt_source);
62262306a36Sopenharmony_ci			if (fs & A_INDICATOR) {
62362306a36Sopenharmony_ci				smc->sm.pend[SMT_TID_NIF] = 0 ;
62462306a36Sopenharmony_ci				DB_SMT("SMT : duplicate address");
62562306a36Sopenharmony_ci				smc->mib.m[MAC0].fddiMACDupAddressTest =
62662306a36Sopenharmony_ci					DA_FAILED ;
62762306a36Sopenharmony_ci				smc->r.dup_addr_test = DA_FAILED ;
62862306a36Sopenharmony_ci				queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ;
62962306a36Sopenharmony_ci				smc->mib.m[MAC0].fddiMACDA_Flag = TRUE ;
63062306a36Sopenharmony_ci				update_dac(smc,1) ;
63162306a36Sopenharmony_ci				break ;
63262306a36Sopenharmony_ci			}
63362306a36Sopenharmony_ci			if (sm->smt_tid == smc->sm.pend[SMT_TID_NIF]) {
63462306a36Sopenharmony_ci				smc->sm.pend[SMT_TID_NIF] = 0 ;
63562306a36Sopenharmony_ci				/* set my DNA */
63662306a36Sopenharmony_ci				if (!is_equal(
63762306a36Sopenharmony_ci					&smc->mib.m[MAC0].fddiMACDownstreamNbr,
63862306a36Sopenharmony_ci					&sm->smt_source)) {
63962306a36Sopenharmony_ci					DB_SMT("SMT : updated my DNA");
64062306a36Sopenharmony_ci					if (!is_equal(&smc->mib.m[MAC0].
64162306a36Sopenharmony_ci					 fddiMACDownstreamNbr, &SMT_Unknown)){
64262306a36Sopenharmony_ci					 /* Do not update unknown address */
64362306a36Sopenharmony_ci				smc->mib.m[MAC0].fddiMACOldDownstreamNbr =
64462306a36Sopenharmony_ci					 smc->mib.m[MAC0].fddiMACDownstreamNbr ;
64562306a36Sopenharmony_ci					}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci					smc->mib.m[MAC0].fddiMACDownstreamNbr =
64862306a36Sopenharmony_ci						sm->smt_source ;
64962306a36Sopenharmony_ci					smt_srf_event(smc,
65062306a36Sopenharmony_ci						SMT_EVENT_MAC_NEIGHBOR_CHANGE,
65162306a36Sopenharmony_ci						INDEX_MAC,0) ;
65262306a36Sopenharmony_ci					smt_echo_test(smc,1) ;
65362306a36Sopenharmony_ci				}
65462306a36Sopenharmony_ci				smc->mib.m[MAC0].fddiMACDA_Flag = FALSE ;
65562306a36Sopenharmony_ci				update_dac(smc,1) ;
65662306a36Sopenharmony_ci				smc->sm.smt_tvd = smt_get_time() ;
65762306a36Sopenharmony_ci				smc->mib.m[MAC0].fddiMACDupAddressTest =
65862306a36Sopenharmony_ci					DA_PASSED ;
65962306a36Sopenharmony_ci				if (smc->r.dup_addr_test != DA_PASSED) {
66062306a36Sopenharmony_ci					smc->r.dup_addr_test = DA_PASSED ;
66162306a36Sopenharmony_ci					queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ;
66262306a36Sopenharmony_ci				}
66362306a36Sopenharmony_ci			}
66462306a36Sopenharmony_ci			else if (sm->smt_tid ==
66562306a36Sopenharmony_ci				smc->sm.pend[SMT_TID_NIF_TEST]) {
66662306a36Sopenharmony_ci				DB_SMT("SMT : NIF test TID ok");
66762306a36Sopenharmony_ci			}
66862306a36Sopenharmony_ci			else {
66962306a36Sopenharmony_ci				DB_SMT("SMT : expected TID %lx, got %x",
67062306a36Sopenharmony_ci				       smc->sm.pend[SMT_TID_NIF], sm->smt_tid);
67162306a36Sopenharmony_ci			}
67262306a36Sopenharmony_ci			break ;
67362306a36Sopenharmony_ci		default :
67462306a36Sopenharmony_ci			illegal = 2 ;
67562306a36Sopenharmony_ci			break ;
67662306a36Sopenharmony_ci		}
67762306a36Sopenharmony_ci		break ;
67862306a36Sopenharmony_ci	case SMT_SIF_CONFIG :	/* station information */
67962306a36Sopenharmony_ci		if (sm->smt_type != SMT_REQUEST)
68062306a36Sopenharmony_ci			break ;
68162306a36Sopenharmony_ci		DB_SMT("SMT : replying to SIF Config request from %pM",
68262306a36Sopenharmony_ci		       &sm->smt_source);
68362306a36Sopenharmony_ci		smt_send_sif_config(smc,&sm->smt_source,sm->smt_tid,local) ;
68462306a36Sopenharmony_ci		break ;
68562306a36Sopenharmony_ci	case SMT_SIF_OPER :	/* station information */
68662306a36Sopenharmony_ci		if (sm->smt_type != SMT_REQUEST)
68762306a36Sopenharmony_ci			break ;
68862306a36Sopenharmony_ci		DB_SMT("SMT : replying to SIF Operation request from %pM",
68962306a36Sopenharmony_ci		       &sm->smt_source);
69062306a36Sopenharmony_ci		smt_send_sif_operation(smc,&sm->smt_source,sm->smt_tid,local) ;
69162306a36Sopenharmony_ci		break ;
69262306a36Sopenharmony_ci	case SMT_ECF :		/* echo frame */
69362306a36Sopenharmony_ci		switch (sm->smt_type) {
69462306a36Sopenharmony_ci		case SMT_REPLY :
69562306a36Sopenharmony_ci			smc->mib.priv.fddiPRIVECF_Reply_Rx++ ;
69662306a36Sopenharmony_ci			DB_SMT("SMT: received ECF reply from %pM",
69762306a36Sopenharmony_ci			       &sm->smt_source);
69862306a36Sopenharmony_ci			if (sm_to_para(smc,sm,SMT_P_ECHODATA) == NULL) {
69962306a36Sopenharmony_ci				DB_SMT("SMT: ECHODATA missing");
70062306a36Sopenharmony_ci				break ;
70162306a36Sopenharmony_ci			}
70262306a36Sopenharmony_ci			if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF]) {
70362306a36Sopenharmony_ci				DB_SMT("SMT : ECF test TID ok");
70462306a36Sopenharmony_ci			}
70562306a36Sopenharmony_ci			else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_UNA]) {
70662306a36Sopenharmony_ci				DB_SMT("SMT : ECF test UNA ok");
70762306a36Sopenharmony_ci			}
70862306a36Sopenharmony_ci			else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_DNA]) {
70962306a36Sopenharmony_ci				DB_SMT("SMT : ECF test DNA ok");
71062306a36Sopenharmony_ci			}
71162306a36Sopenharmony_ci			else {
71262306a36Sopenharmony_ci				DB_SMT("SMT : expected TID %lx, got %x",
71362306a36Sopenharmony_ci				       smc->sm.pend[SMT_TID_ECF],
71462306a36Sopenharmony_ci				       sm->smt_tid);
71562306a36Sopenharmony_ci			}
71662306a36Sopenharmony_ci			break ;
71762306a36Sopenharmony_ci		case SMT_REQUEST :
71862306a36Sopenharmony_ci			smc->mib.priv.fddiPRIVECF_Req_Rx++ ;
71962306a36Sopenharmony_ci			{
72062306a36Sopenharmony_ci			if (sm->smt_len && !sm_to_para(smc,sm,SMT_P_ECHODATA)) {
72162306a36Sopenharmony_ci				DB_SMT("SMT: ECF with para problem,sending RDF");
72262306a36Sopenharmony_ci				smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH,
72362306a36Sopenharmony_ci					local) ;
72462306a36Sopenharmony_ci				break ;
72562306a36Sopenharmony_ci			}
72662306a36Sopenharmony_ci			DB_SMT("SMT - sending ECF reply to %pM",
72762306a36Sopenharmony_ci			       &sm->smt_source);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci			/* set destination addr.  & reply */
73062306a36Sopenharmony_ci			sm->smt_dest = sm->smt_source ;
73162306a36Sopenharmony_ci			sm->smt_type = SMT_REPLY ;
73262306a36Sopenharmony_ci			dump_smt(smc,sm,"ECF REPLY") ;
73362306a36Sopenharmony_ci			smc->mib.priv.fddiPRIVECF_Reply_Tx++ ;
73462306a36Sopenharmony_ci			smt_send_frame(smc,mb,FC_SMT_INFO,local) ;
73562306a36Sopenharmony_ci			return ;		/* DON'T free mbuf */
73662306a36Sopenharmony_ci			}
73762306a36Sopenharmony_ci		default :
73862306a36Sopenharmony_ci			illegal = 1 ;
73962306a36Sopenharmony_ci			break ;
74062306a36Sopenharmony_ci		}
74162306a36Sopenharmony_ci		break ;
74262306a36Sopenharmony_ci#ifndef	BOOT
74362306a36Sopenharmony_ci	case SMT_RAF :		/* resource allocation */
74462306a36Sopenharmony_ci#ifdef	ESS
74562306a36Sopenharmony_ci		DB_ESSN(2, "ESS: RAF frame received");
74662306a36Sopenharmony_ci		fs = ess_raf_received_pack(smc,mb,sm,fs) ;
74762306a36Sopenharmony_ci#endif
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci#ifdef	SBA
75062306a36Sopenharmony_ci		DB_SBAN(2, "SBA: RAF frame received") ;
75162306a36Sopenharmony_ci		sba_raf_received_pack(smc,sm,fs) ;
75262306a36Sopenharmony_ci#endif
75362306a36Sopenharmony_ci		break ;
75462306a36Sopenharmony_ci	case SMT_RDF :		/* request denied */
75562306a36Sopenharmony_ci		smc->mib.priv.fddiPRIVRDF_Rx++ ;
75662306a36Sopenharmony_ci		break ;
75762306a36Sopenharmony_ci	case SMT_ESF :		/* extended service - not supported */
75862306a36Sopenharmony_ci		if (sm->smt_type == SMT_REQUEST) {
75962306a36Sopenharmony_ci			DB_SMT("SMT - received ESF, sending RDF");
76062306a36Sopenharmony_ci			smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ;
76162306a36Sopenharmony_ci		}
76262306a36Sopenharmony_ci		break ;
76362306a36Sopenharmony_ci	case SMT_PMF_GET :
76462306a36Sopenharmony_ci	case SMT_PMF_SET :
76562306a36Sopenharmony_ci		if (sm->smt_type != SMT_REQUEST)
76662306a36Sopenharmony_ci			break ;
76762306a36Sopenharmony_ci		/* update statistics */
76862306a36Sopenharmony_ci		if (sm->smt_class == SMT_PMF_GET)
76962306a36Sopenharmony_ci			smc->mib.priv.fddiPRIVPMF_Get_Rx++ ;
77062306a36Sopenharmony_ci		else
77162306a36Sopenharmony_ci			smc->mib.priv.fddiPRIVPMF_Set_Rx++ ;
77262306a36Sopenharmony_ci		/*
77362306a36Sopenharmony_ci		 * ignore PMF SET with I/G set
77462306a36Sopenharmony_ci		 */
77562306a36Sopenharmony_ci		if ((sm->smt_class == SMT_PMF_SET) &&
77662306a36Sopenharmony_ci			!is_individual(&sm->smt_dest)) {
77762306a36Sopenharmony_ci			DB_SMT("SMT: ignoring PMF-SET with I/G set");
77862306a36Sopenharmony_ci			break ;
77962306a36Sopenharmony_ci		}
78062306a36Sopenharmony_ci		smt_pmf_received_pack(smc,mb, local) ;
78162306a36Sopenharmony_ci		break ;
78262306a36Sopenharmony_ci	case SMT_SRF :
78362306a36Sopenharmony_ci		dump_smt(smc,sm,"SRF received") ;
78462306a36Sopenharmony_ci		break ;
78562306a36Sopenharmony_ci	default :
78662306a36Sopenharmony_ci		if (sm->smt_type != SMT_REQUEST)
78762306a36Sopenharmony_ci			break ;
78862306a36Sopenharmony_ci		/*
78962306a36Sopenharmony_ci		 * For frames with unknown class:
79062306a36Sopenharmony_ci		 * we need to send a RDF frame according to 8.1.3.1.1,
79162306a36Sopenharmony_ci		 * only if it is a REQUEST.
79262306a36Sopenharmony_ci		 */
79362306a36Sopenharmony_ci		DB_SMT("SMT : class = %d, send RDF to %pM",
79462306a36Sopenharmony_ci		       sm->smt_class, &sm->smt_source);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci		smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ;
79762306a36Sopenharmony_ci		break ;
79862306a36Sopenharmony_ci#endif
79962306a36Sopenharmony_ci	}
80062306a36Sopenharmony_ci	if (illegal) {
80162306a36Sopenharmony_ci		DB_SMT("SMT: discarding invalid frame, reason = %d", illegal);
80262306a36Sopenharmony_ci	}
80362306a36Sopenharmony_ci	smt_free_mbuf(smc,mb) ;
80462306a36Sopenharmony_ci}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_cistatic void update_dac(struct s_smc *smc, int report)
80762306a36Sopenharmony_ci{
80862306a36Sopenharmony_ci	int	cond ;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	cond = ( smc->mib.m[MAC0].fddiMACUNDA_Flag |
81162306a36Sopenharmony_ci		smc->mib.m[MAC0].fddiMACDA_Flag) != 0 ;
81262306a36Sopenharmony_ci	if (report && (cond != smc->mib.m[MAC0].fddiMACDuplicateAddressCond))
81362306a36Sopenharmony_ci		smt_srf_event(smc, SMT_COND_MAC_DUP_ADDR,INDEX_MAC,cond) ;
81462306a36Sopenharmony_ci	else
81562306a36Sopenharmony_ci		smc->mib.m[MAC0].fddiMACDuplicateAddressCond = cond ;
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci/*
81962306a36Sopenharmony_ci * send SMT frame
82062306a36Sopenharmony_ci *	set source address
82162306a36Sopenharmony_ci *	set station ID
82262306a36Sopenharmony_ci *	send frame
82362306a36Sopenharmony_ci */
82462306a36Sopenharmony_civoid smt_send_frame(struct s_smc *smc, SMbuf *mb, int fc, int local)
82562306a36Sopenharmony_ci/* SMbuf *mb;	buffer to send */
82662306a36Sopenharmony_ci/* int fc;	FC value */
82762306a36Sopenharmony_ci{
82862306a36Sopenharmony_ci	struct smt_header	*sm ;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	if (!smc->r.sm_ma_avail && !local) {
83162306a36Sopenharmony_ci		smt_free_mbuf(smc,mb) ;
83262306a36Sopenharmony_ci		return ;
83362306a36Sopenharmony_ci	}
83462306a36Sopenharmony_ci	sm = smtod(mb,struct smt_header *) ;
83562306a36Sopenharmony_ci	sm->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ;
83662306a36Sopenharmony_ci	sm->smt_sid = smc->mib.fddiSMTStationId ;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	smt_swap_para(sm,(int) mb->sm_len,0) ;		/* swap para & header */
83962306a36Sopenharmony_ci	hwm_conv_can(smc,(char *)sm,12) ;		/* convert SA and DA */
84062306a36Sopenharmony_ci	smc->mib.m[MAC0].fddiMACSMTTransmit_Ct++ ;
84162306a36Sopenharmony_ci	smt_send_mbuf(smc,mb,local ? FC_SMT_LOC : fc) ;
84262306a36Sopenharmony_ci}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci/*
84562306a36Sopenharmony_ci * generate and send RDF
84662306a36Sopenharmony_ci */
84762306a36Sopenharmony_cistatic void smt_send_rdf(struct s_smc *smc, SMbuf *rej, int fc, int reason,
84862306a36Sopenharmony_ci			 int local)
84962306a36Sopenharmony_ci/* SMbuf *rej;	mbuf of offending frame */
85062306a36Sopenharmony_ci/* int fc;	FC of denied frame */
85162306a36Sopenharmony_ci/* int reason;	reason code */
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	SMbuf	*mb ;
85462306a36Sopenharmony_ci	struct smt_header	*sm ;	/* header of offending frame */
85562306a36Sopenharmony_ci	struct smt_rdf	*rdf ;
85662306a36Sopenharmony_ci	int		len ;
85762306a36Sopenharmony_ci	int		frame_len ;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	sm = smtod(rej,struct smt_header *) ;
86062306a36Sopenharmony_ci	if (sm->smt_type != SMT_REQUEST)
86162306a36Sopenharmony_ci		return ;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	DB_SMT("SMT: sending RDF to %pM,reason = 0x%x",
86462306a36Sopenharmony_ci	       &sm->smt_source, reason);
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	/*
86862306a36Sopenharmony_ci	 * note: get framelength from MAC length, NOT from SMT header
86962306a36Sopenharmony_ci	 * smt header length is included in sm_len
87062306a36Sopenharmony_ci	 */
87162306a36Sopenharmony_ci	frame_len = rej->sm_len ;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	if (!(mb=smt_build_frame(smc,SMT_RDF,SMT_REPLY,sizeof(struct smt_rdf))))
87462306a36Sopenharmony_ci		return ;
87562306a36Sopenharmony_ci	rdf = smtod(mb,struct smt_rdf *) ;
87662306a36Sopenharmony_ci	rdf->smt.smt_tid = sm->smt_tid ;		/* use TID from sm */
87762306a36Sopenharmony_ci	rdf->smt.smt_dest = sm->smt_source ;		/* set dest = source */
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	/* set P12 */
88062306a36Sopenharmony_ci	rdf->reason.para.p_type = SMT_P_REASON ;
88162306a36Sopenharmony_ci	rdf->reason.para.p_len = sizeof(struct smt_p_reason) - PARA_LEN ;
88262306a36Sopenharmony_ci	rdf->reason.rdf_reason = reason ;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	/* set P14 */
88562306a36Sopenharmony_ci	rdf->version.para.p_type = SMT_P_VERSION ;
88662306a36Sopenharmony_ci	rdf->version.para.p_len = sizeof(struct smt_p_version) - PARA_LEN ;
88762306a36Sopenharmony_ci	rdf->version.v_pad = 0 ;
88862306a36Sopenharmony_ci	rdf->version.v_n = 1 ;
88962306a36Sopenharmony_ci	rdf->version.v_index = 1 ;
89062306a36Sopenharmony_ci	rdf->version.v_version[0] = SMT_VID_2 ;
89162306a36Sopenharmony_ci	rdf->version.v_pad2 = 0 ;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	/* set P13 */
89462306a36Sopenharmony_ci	if ((unsigned int) frame_len <= SMT_MAX_INFO_LEN - sizeof(*rdf) +
89562306a36Sopenharmony_ci		2*sizeof(struct smt_header))
89662306a36Sopenharmony_ci		len = frame_len ;
89762306a36Sopenharmony_ci	else
89862306a36Sopenharmony_ci		len = SMT_MAX_INFO_LEN - sizeof(*rdf) +
89962306a36Sopenharmony_ci			2*sizeof(struct smt_header) ;
90062306a36Sopenharmony_ci	/* make length multiple of 4 */
90162306a36Sopenharmony_ci	len &= ~3 ;
90262306a36Sopenharmony_ci	rdf->refused.para.p_type = SMT_P_REFUSED ;
90362306a36Sopenharmony_ci	/* length of para is smt_frame + ref_fc */
90462306a36Sopenharmony_ci	rdf->refused.para.p_len = len + 4 ;
90562306a36Sopenharmony_ci	rdf->refused.ref_fc = fc ;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	/* swap it back */
90862306a36Sopenharmony_ci	smt_swap_para(sm,frame_len,0) ;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	memcpy((char *) &rdf->refused.ref_header,(char *) sm,len) ;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	len -= sizeof(struct smt_header) ;
91362306a36Sopenharmony_ci	mb->sm_len += len ;
91462306a36Sopenharmony_ci	rdf->smt.smt_len += len ;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	dump_smt(smc,(struct smt_header *)rdf,"RDF") ;
91762306a36Sopenharmony_ci	smc->mib.priv.fddiPRIVRDF_Tx++ ;
91862306a36Sopenharmony_ci	smt_send_frame(smc,mb,FC_SMT_INFO,local) ;
91962306a36Sopenharmony_ci}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci/*
92262306a36Sopenharmony_ci * generate and send NIF
92362306a36Sopenharmony_ci */
92462306a36Sopenharmony_cistatic void smt_send_nif(struct s_smc *smc, const struct fddi_addr *dest,
92562306a36Sopenharmony_ci			 int fc, u_long tid, int type, int local)
92662306a36Sopenharmony_ci/* struct fddi_addr *dest;	dest address */
92762306a36Sopenharmony_ci/* int fc;			frame control */
92862306a36Sopenharmony_ci/* u_long tid;			transaction id */
92962306a36Sopenharmony_ci/* int type;			frame type */
93062306a36Sopenharmony_ci{
93162306a36Sopenharmony_ci	struct smt_nif	*nif ;
93262306a36Sopenharmony_ci	SMbuf		*mb ;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	if (!(mb = smt_build_frame(smc,SMT_NIF,type,sizeof(struct smt_nif))))
93562306a36Sopenharmony_ci		return ;
93662306a36Sopenharmony_ci	nif = smtod(mb, struct smt_nif *) ;
93762306a36Sopenharmony_ci	smt_fill_una(smc,&nif->una) ;	/* set UNA */
93862306a36Sopenharmony_ci	smt_fill_sde(smc,&nif->sde) ;	/* set station descriptor */
93962306a36Sopenharmony_ci	smt_fill_state(smc,&nif->state) ;	/* set state information */
94062306a36Sopenharmony_ci#ifdef	SMT6_10
94162306a36Sopenharmony_ci	smt_fill_fsc(smc,&nif->fsc) ;	/* set frame status cap. */
94262306a36Sopenharmony_ci#endif
94362306a36Sopenharmony_ci	nif->smt.smt_dest = *dest ;	/* destination address */
94462306a36Sopenharmony_ci	nif->smt.smt_tid = tid ;	/* transaction ID */
94562306a36Sopenharmony_ci	dump_smt(smc,(struct smt_header *)nif,"NIF") ;
94662306a36Sopenharmony_ci	smt_send_frame(smc,mb,fc,local) ;
94762306a36Sopenharmony_ci}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci#ifdef	DEBUG
95062306a36Sopenharmony_ci/*
95162306a36Sopenharmony_ci * send NIF request (test purpose)
95262306a36Sopenharmony_ci */
95362306a36Sopenharmony_cistatic void smt_send_nif_request(struct s_smc *smc, struct fddi_addr *dest)
95462306a36Sopenharmony_ci{
95562306a36Sopenharmony_ci	smc->sm.pend[SMT_TID_NIF_TEST] = smt_get_tid(smc) ;
95662306a36Sopenharmony_ci	smt_send_nif(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_NIF_TEST],
95762306a36Sopenharmony_ci		SMT_REQUEST,0) ;
95862306a36Sopenharmony_ci}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci/*
96162306a36Sopenharmony_ci * send ECF request (test purpose)
96262306a36Sopenharmony_ci */
96362306a36Sopenharmony_cistatic void smt_send_ecf_request(struct s_smc *smc, struct fddi_addr *dest,
96462306a36Sopenharmony_ci				 int len)
96562306a36Sopenharmony_ci{
96662306a36Sopenharmony_ci	smc->sm.pend[SMT_TID_ECF] = smt_get_tid(smc) ;
96762306a36Sopenharmony_ci	smt_send_ecf(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_ECF],
96862306a36Sopenharmony_ci		SMT_REQUEST,len) ;
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ci#endif
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci/*
97362306a36Sopenharmony_ci * echo test
97462306a36Sopenharmony_ci */
97562306a36Sopenharmony_cistatic void smt_echo_test(struct s_smc *smc, int dna)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci	u_long	tid ;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	smc->sm.pend[dna ? SMT_TID_ECF_DNA : SMT_TID_ECF_UNA] =
98062306a36Sopenharmony_ci		tid = smt_get_tid(smc) ;
98162306a36Sopenharmony_ci	smt_send_ecf(smc, dna ?
98262306a36Sopenharmony_ci		&smc->mib.m[MAC0].fddiMACDownstreamNbr :
98362306a36Sopenharmony_ci		&smc->mib.m[MAC0].fddiMACUpstreamNbr,
98462306a36Sopenharmony_ci		FC_SMT_INFO,tid, SMT_REQUEST, (SMT_TEST_ECHO_LEN & ~3)-8) ;
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci/*
98862306a36Sopenharmony_ci * generate and send ECF
98962306a36Sopenharmony_ci */
99062306a36Sopenharmony_cistatic void smt_send_ecf(struct s_smc *smc, struct fddi_addr *dest, int fc,
99162306a36Sopenharmony_ci			 u_long tid, int type, int len)
99262306a36Sopenharmony_ci/* struct fddi_addr *dest;	dest address */
99362306a36Sopenharmony_ci/* int fc;			frame control */
99462306a36Sopenharmony_ci/* u_long tid;			transaction id */
99562306a36Sopenharmony_ci/* int type;			frame type */
99662306a36Sopenharmony_ci/* int len;			frame length */
99762306a36Sopenharmony_ci{
99862306a36Sopenharmony_ci	struct smt_ecf	*ecf ;
99962306a36Sopenharmony_ci	SMbuf		*mb ;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	if (!(mb = smt_build_frame(smc,SMT_ECF,type,SMT_ECF_LEN + len)))
100262306a36Sopenharmony_ci		return ;
100362306a36Sopenharmony_ci	ecf = smtod(mb, struct smt_ecf *) ;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	smt_fill_echo(smc,&ecf->ec_echo,tid,len) ;	/* set ECHO */
100662306a36Sopenharmony_ci	ecf->smt.smt_dest = *dest ;	/* destination address */
100762306a36Sopenharmony_ci	ecf->smt.smt_tid = tid ;	/* transaction ID */
100862306a36Sopenharmony_ci	smc->mib.priv.fddiPRIVECF_Req_Tx++ ;
100962306a36Sopenharmony_ci	smt_send_frame(smc,mb,fc,0) ;
101062306a36Sopenharmony_ci}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci/*
101362306a36Sopenharmony_ci * generate and send SIF config response
101462306a36Sopenharmony_ci */
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_cistatic void smt_send_sif_config(struct s_smc *smc, struct fddi_addr *dest,
101762306a36Sopenharmony_ci				u_long tid, int local)
101862306a36Sopenharmony_ci/* struct fddi_addr *dest;	dest address */
101962306a36Sopenharmony_ci/* u_long tid;			transaction id */
102062306a36Sopenharmony_ci{
102162306a36Sopenharmony_ci	struct smt_sif_config	*sif ;
102262306a36Sopenharmony_ci	SMbuf			*mb ;
102362306a36Sopenharmony_ci	int			len ;
102462306a36Sopenharmony_ci	if (!(mb = smt_build_frame(smc,SMT_SIF_CONFIG,SMT_REPLY,
102562306a36Sopenharmony_ci		SIZEOF_SMT_SIF_CONFIG)))
102662306a36Sopenharmony_ci		return ;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	sif = smtod(mb, struct smt_sif_config *) ;
102962306a36Sopenharmony_ci	smt_fill_timestamp(smc,&sif->ts) ;	/* set time stamp */
103062306a36Sopenharmony_ci	smt_fill_sde(smc,&sif->sde) ;		/* set station descriptor */
103162306a36Sopenharmony_ci	smt_fill_version(smc,&sif->version) ;	/* set version information */
103262306a36Sopenharmony_ci	smt_fill_state(smc,&sif->state) ;	/* set state information */
103362306a36Sopenharmony_ci	smt_fill_policy(smc,&sif->policy) ;	/* set station policy */
103462306a36Sopenharmony_ci	smt_fill_latency(smc,&sif->latency);	/* set station latency */
103562306a36Sopenharmony_ci	smt_fill_neighbor(smc,&sif->neighbor);	/* set station neighbor */
103662306a36Sopenharmony_ci	smt_fill_setcount(smc,&sif->setcount) ;	/* set count */
103762306a36Sopenharmony_ci	len = smt_fill_path(smc,&sif->path);	/* set station path descriptor*/
103862306a36Sopenharmony_ci	sif->smt.smt_dest = *dest ;		/* destination address */
103962306a36Sopenharmony_ci	sif->smt.smt_tid = tid ;		/* transaction ID */
104062306a36Sopenharmony_ci	smt_add_frame_len(mb,len) ;		/* adjust length fields */
104162306a36Sopenharmony_ci	dump_smt(smc,(struct smt_header *)sif,"SIF Configuration Reply") ;
104262306a36Sopenharmony_ci	smt_send_frame(smc,mb,FC_SMT_INFO,local) ;
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci/*
104662306a36Sopenharmony_ci * generate and send SIF operation response
104762306a36Sopenharmony_ci */
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_cistatic void smt_send_sif_operation(struct s_smc *smc, struct fddi_addr *dest,
105062306a36Sopenharmony_ci				   u_long tid, int local)
105162306a36Sopenharmony_ci/* struct fddi_addr *dest;	dest address */
105262306a36Sopenharmony_ci/* u_long tid;			transaction id */
105362306a36Sopenharmony_ci{
105462306a36Sopenharmony_ci	struct smt_sif_operation *sif ;
105562306a36Sopenharmony_ci	SMbuf			*mb ;
105662306a36Sopenharmony_ci	int			ports ;
105762306a36Sopenharmony_ci	int			i ;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	ports = NUMPHYS ;
106062306a36Sopenharmony_ci#ifndef	CONCENTRATOR
106162306a36Sopenharmony_ci	if (smc->s.sas == SMT_SAS)
106262306a36Sopenharmony_ci		ports = 1 ;
106362306a36Sopenharmony_ci#endif
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	if (!(mb = smt_build_frame(smc,SMT_SIF_OPER,SMT_REPLY,
106662306a36Sopenharmony_ci				   struct_size(sif, lem, ports))))
106762306a36Sopenharmony_ci		return ;
106862306a36Sopenharmony_ci	sif = smtod(mb, typeof(sif));
106962306a36Sopenharmony_ci	smt_fill_timestamp(smc,&sif->ts) ;	/* set time stamp */
107062306a36Sopenharmony_ci	smt_fill_mac_status(smc,&sif->status) ; /* set mac status */
107162306a36Sopenharmony_ci	smt_fill_mac_counter(smc,&sif->mc) ; /* set mac counter field */
107262306a36Sopenharmony_ci	smt_fill_mac_fnc(smc,&sif->fnc) ; /* set frame not copied counter */
107362306a36Sopenharmony_ci	smt_fill_manufacturer(smc,&sif->man) ; /* set manufacturer field */
107462306a36Sopenharmony_ci	smt_fill_user(smc,&sif->user) ;		/* set user field */
107562306a36Sopenharmony_ci	smt_fill_setcount(smc,&sif->setcount) ;	/* set count */
107662306a36Sopenharmony_ci	/*
107762306a36Sopenharmony_ci	 * set link error mon information
107862306a36Sopenharmony_ci	 */
107962306a36Sopenharmony_ci	if (ports == 1) {
108062306a36Sopenharmony_ci		smt_fill_lem(smc,sif->lem,PS) ;
108162306a36Sopenharmony_ci	}
108262306a36Sopenharmony_ci	else {
108362306a36Sopenharmony_ci		for (i = 0 ; i < ports ; i++) {
108462306a36Sopenharmony_ci			smt_fill_lem(smc,&sif->lem[i],i) ;
108562306a36Sopenharmony_ci		}
108662306a36Sopenharmony_ci	}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	sif->smt.smt_dest = *dest ;	/* destination address */
108962306a36Sopenharmony_ci	sif->smt.smt_tid = tid ;	/* transaction ID */
109062306a36Sopenharmony_ci	dump_smt(smc,(struct smt_header *)sif,"SIF Operation Reply") ;
109162306a36Sopenharmony_ci	smt_send_frame(smc,mb,FC_SMT_INFO,local) ;
109262306a36Sopenharmony_ci}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci/*
109562306a36Sopenharmony_ci * get and initialize SMT frame
109662306a36Sopenharmony_ci */
109762306a36Sopenharmony_ciSMbuf *smt_build_frame(struct s_smc *smc, int class, int type,
109862306a36Sopenharmony_ci				  int length)
109962306a36Sopenharmony_ci{
110062306a36Sopenharmony_ci	SMbuf			*mb ;
110162306a36Sopenharmony_ci	struct smt_header	*smt ;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci#if	0
110462306a36Sopenharmony_ci	if (!smc->r.sm_ma_avail) {
110562306a36Sopenharmony_ci		return 0;
110662306a36Sopenharmony_ci	}
110762306a36Sopenharmony_ci#endif
110862306a36Sopenharmony_ci	if (!(mb = smt_get_mbuf(smc)))
110962306a36Sopenharmony_ci		return mb;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	mb->sm_len = length ;
111262306a36Sopenharmony_ci	smt = smtod(mb, struct smt_header *) ;
111362306a36Sopenharmony_ci	smt->smt_dest = fddi_broadcast ; /* set dest = broadcast */
111462306a36Sopenharmony_ci	smt->smt_class = class ;
111562306a36Sopenharmony_ci	smt->smt_type = type ;
111662306a36Sopenharmony_ci	switch (class) {
111762306a36Sopenharmony_ci	case SMT_NIF :
111862306a36Sopenharmony_ci	case SMT_SIF_CONFIG :
111962306a36Sopenharmony_ci	case SMT_SIF_OPER :
112062306a36Sopenharmony_ci	case SMT_ECF :
112162306a36Sopenharmony_ci		smt->smt_version = SMT_VID ;
112262306a36Sopenharmony_ci		break ;
112362306a36Sopenharmony_ci	default :
112462306a36Sopenharmony_ci		smt->smt_version = SMT_VID_2 ;
112562306a36Sopenharmony_ci		break ;
112662306a36Sopenharmony_ci	}
112762306a36Sopenharmony_ci	smt->smt_tid = smt_get_tid(smc) ;	/* set transaction ID */
112862306a36Sopenharmony_ci	smt->smt_pad = 0 ;
112962306a36Sopenharmony_ci	smt->smt_len = length - sizeof(struct smt_header) ;
113062306a36Sopenharmony_ci	return mb;
113162306a36Sopenharmony_ci}
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_cistatic void smt_add_frame_len(SMbuf *mb, int len)
113462306a36Sopenharmony_ci{
113562306a36Sopenharmony_ci	struct smt_header	*smt ;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	smt = smtod(mb, struct smt_header *) ;
113862306a36Sopenharmony_ci	smt->smt_len += len ;
113962306a36Sopenharmony_ci	mb->sm_len += len ;
114062306a36Sopenharmony_ci}
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci/*
114562306a36Sopenharmony_ci * fill values in UNA parameter
114662306a36Sopenharmony_ci */
114762306a36Sopenharmony_cistatic void smt_fill_una(struct s_smc *smc, struct smt_p_una *una)
114862306a36Sopenharmony_ci{
114962306a36Sopenharmony_ci	SMTSETPARA(una,SMT_P_UNA) ;
115062306a36Sopenharmony_ci	una->una_pad = 0 ;
115162306a36Sopenharmony_ci	una->una_node = smc->mib.m[MAC0].fddiMACUpstreamNbr ;
115262306a36Sopenharmony_ci}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci/*
115562306a36Sopenharmony_ci * fill values in SDE parameter
115662306a36Sopenharmony_ci */
115762306a36Sopenharmony_cistatic void smt_fill_sde(struct s_smc *smc, struct smt_p_sde *sde)
115862306a36Sopenharmony_ci{
115962306a36Sopenharmony_ci	SMTSETPARA(sde,SMT_P_SDE) ;
116062306a36Sopenharmony_ci	sde->sde_non_master = smc->mib.fddiSMTNonMaster_Ct ;
116162306a36Sopenharmony_ci	sde->sde_master = smc->mib.fddiSMTMaster_Ct ;
116262306a36Sopenharmony_ci	sde->sde_mac_count = NUMMACS ;		/* only 1 MAC */
116362306a36Sopenharmony_ci#ifdef	CONCENTRATOR
116462306a36Sopenharmony_ci	sde->sde_type = SMT_SDE_CONCENTRATOR ;
116562306a36Sopenharmony_ci#else
116662306a36Sopenharmony_ci	sde->sde_type = SMT_SDE_STATION ;
116762306a36Sopenharmony_ci#endif
116862306a36Sopenharmony_ci}
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci/*
117162306a36Sopenharmony_ci * fill in values in station state parameter
117262306a36Sopenharmony_ci */
117362306a36Sopenharmony_cistatic void smt_fill_state(struct s_smc *smc, struct smt_p_state *state)
117462306a36Sopenharmony_ci{
117562306a36Sopenharmony_ci	int	top ;
117662306a36Sopenharmony_ci	int	twist ;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	SMTSETPARA(state,SMT_P_STATE) ;
117962306a36Sopenharmony_ci	state->st_pad = 0 ;
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	/* determine topology */
118262306a36Sopenharmony_ci	top = 0 ;
118362306a36Sopenharmony_ci	if (smc->mib.fddiSMTPeerWrapFlag) {
118462306a36Sopenharmony_ci		top |= SMT_ST_WRAPPED ;		/* state wrapped */
118562306a36Sopenharmony_ci	}
118662306a36Sopenharmony_ci#ifdef	CONCENTRATOR
118762306a36Sopenharmony_ci	if (cfm_status_unattached(smc)) {
118862306a36Sopenharmony_ci		top |= SMT_ST_UNATTACHED ;	/* unattached concentrator */
118962306a36Sopenharmony_ci	}
119062306a36Sopenharmony_ci#endif
119162306a36Sopenharmony_ci	if ((twist = pcm_status_twisted(smc)) & 1) {
119262306a36Sopenharmony_ci		top |= SMT_ST_TWISTED_A ;	/* twisted cable */
119362306a36Sopenharmony_ci	}
119462306a36Sopenharmony_ci	if (twist & 2) {
119562306a36Sopenharmony_ci		top |= SMT_ST_TWISTED_B ;	/* twisted cable */
119662306a36Sopenharmony_ci	}
119762306a36Sopenharmony_ci#ifdef	OPT_SRF
119862306a36Sopenharmony_ci	top |= SMT_ST_SRF ;
119962306a36Sopenharmony_ci#endif
120062306a36Sopenharmony_ci	if (pcm_rooted_station(smc))
120162306a36Sopenharmony_ci		top |= SMT_ST_ROOTED_S ;
120262306a36Sopenharmony_ci	if (smc->mib.a[0].fddiPATHSbaPayload != 0)
120362306a36Sopenharmony_ci		top |= SMT_ST_SYNC_SERVICE ;
120462306a36Sopenharmony_ci	state->st_topology = top ;
120562306a36Sopenharmony_ci	state->st_dupl_addr =
120662306a36Sopenharmony_ci		((smc->mib.m[MAC0].fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0 ) |
120762306a36Sopenharmony_ci		 (smc->mib.m[MAC0].fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0)) ;
120862306a36Sopenharmony_ci}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci/*
121162306a36Sopenharmony_ci * fill values in timestamp parameter
121262306a36Sopenharmony_ci */
121362306a36Sopenharmony_cistatic void smt_fill_timestamp(struct s_smc *smc, struct smt_p_timestamp *ts)
121462306a36Sopenharmony_ci{
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	SMTSETPARA(ts,SMT_P_TIMESTAMP) ;
121762306a36Sopenharmony_ci	smt_set_timestamp(smc,ts->ts_time) ;
121862306a36Sopenharmony_ci}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_civoid smt_set_timestamp(struct s_smc *smc, u_char *p)
122162306a36Sopenharmony_ci{
122262306a36Sopenharmony_ci	u_long	time ;
122362306a36Sopenharmony_ci	u_long	utime ;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	/*
122662306a36Sopenharmony_ci	 * timestamp is 64 bits long ; resolution is 80 nS
122762306a36Sopenharmony_ci	 * our clock resolution is 10mS
122862306a36Sopenharmony_ci	 * 10mS/80ns = 125000 ~ 2^17 = 131072
122962306a36Sopenharmony_ci	 */
123062306a36Sopenharmony_ci	utime = smt_get_time() ;
123162306a36Sopenharmony_ci	time = utime * 100 ;
123262306a36Sopenharmony_ci	time /= TICKS_PER_SECOND ;
123362306a36Sopenharmony_ci	p[0] = 0 ;
123462306a36Sopenharmony_ci	p[1] = (u_char)((time>>(8+8+8+8-1)) & 1) ;
123562306a36Sopenharmony_ci	p[2] = (u_char)(time>>(8+8+8-1)) ;
123662306a36Sopenharmony_ci	p[3] = (u_char)(time>>(8+8-1)) ;
123762306a36Sopenharmony_ci	p[4] = (u_char)(time>>(8-1)) ;
123862306a36Sopenharmony_ci	p[5] = (u_char)(time<<1) ;
123962306a36Sopenharmony_ci	p[6] = (u_char)(smc->sm.uniq_ticks>>8) ;
124062306a36Sopenharmony_ci	p[7] = (u_char)smc->sm.uniq_ticks ;
124162306a36Sopenharmony_ci	/*
124262306a36Sopenharmony_ci	 * make sure we don't wrap: restart whenever the upper digits change
124362306a36Sopenharmony_ci	 */
124462306a36Sopenharmony_ci	if (utime != smc->sm.uniq_time) {
124562306a36Sopenharmony_ci		smc->sm.uniq_ticks = 0 ;
124662306a36Sopenharmony_ci	}
124762306a36Sopenharmony_ci	smc->sm.uniq_ticks++ ;
124862306a36Sopenharmony_ci	smc->sm.uniq_time = utime ;
124962306a36Sopenharmony_ci}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci/*
125262306a36Sopenharmony_ci * fill values in station policy parameter
125362306a36Sopenharmony_ci */
125462306a36Sopenharmony_cistatic void smt_fill_policy(struct s_smc *smc, struct smt_p_policy *policy)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	int	i ;
125762306a36Sopenharmony_ci	const u_char *map ;
125862306a36Sopenharmony_ci	u_short	in ;
125962306a36Sopenharmony_ci	u_short	out ;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	/*
126262306a36Sopenharmony_ci	 * MIB para 101b (fddiSMTConnectionPolicy) coding
126362306a36Sopenharmony_ci	 * is different from 0005 coding
126462306a36Sopenharmony_ci	 */
126562306a36Sopenharmony_ci	static const u_char ansi_weirdness[16] = {
126662306a36Sopenharmony_ci		0,7,5,3,8,1,6,4,9,10,2,11,12,13,14,15
126762306a36Sopenharmony_ci	} ;
126862306a36Sopenharmony_ci	SMTSETPARA(policy,SMT_P_POLICY) ;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	out = 0 ;
127162306a36Sopenharmony_ci	in = smc->mib.fddiSMTConnectionPolicy ;
127262306a36Sopenharmony_ci	for (i = 0, map = ansi_weirdness ; i < 16 ; i++) {
127362306a36Sopenharmony_ci		if (in & 1)
127462306a36Sopenharmony_ci			out |= (1<<*map) ;
127562306a36Sopenharmony_ci		in >>= 1 ;
127662306a36Sopenharmony_ci		map++ ;
127762306a36Sopenharmony_ci	}
127862306a36Sopenharmony_ci	policy->pl_config = smc->mib.fddiSMTConfigPolicy ;
127962306a36Sopenharmony_ci	policy->pl_connect = out ;
128062306a36Sopenharmony_ci}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci/*
128362306a36Sopenharmony_ci * fill values in latency equivalent parameter
128462306a36Sopenharmony_ci */
128562306a36Sopenharmony_cistatic void smt_fill_latency(struct s_smc *smc, struct smt_p_latency *latency)
128662306a36Sopenharmony_ci{
128762306a36Sopenharmony_ci	SMTSETPARA(latency,SMT_P_LATENCY) ;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	latency->lt_phyout_idx1 = phy_index(smc,0) ;
129062306a36Sopenharmony_ci	latency->lt_latency1 = 10 ;	/* in octets (byte clock) */
129162306a36Sopenharmony_ci	/*
129262306a36Sopenharmony_ci	 * note: latency has two phy entries by definition
129362306a36Sopenharmony_ci	 * for a SAS, the 2nd one is null
129462306a36Sopenharmony_ci	 */
129562306a36Sopenharmony_ci	if (smc->s.sas == SMT_DAS) {
129662306a36Sopenharmony_ci		latency->lt_phyout_idx2 = phy_index(smc,1) ;
129762306a36Sopenharmony_ci		latency->lt_latency2 = 10 ;	/* in octets (byte clock) */
129862306a36Sopenharmony_ci	}
129962306a36Sopenharmony_ci	else {
130062306a36Sopenharmony_ci		latency->lt_phyout_idx2 = 0 ;
130162306a36Sopenharmony_ci		latency->lt_latency2 = 0 ;
130262306a36Sopenharmony_ci	}
130362306a36Sopenharmony_ci}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci/*
130662306a36Sopenharmony_ci * fill values in MAC neighbors parameter
130762306a36Sopenharmony_ci */
130862306a36Sopenharmony_cistatic void smt_fill_neighbor(struct s_smc *smc, struct smt_p_neighbor *neighbor)
130962306a36Sopenharmony_ci{
131062306a36Sopenharmony_ci	SMTSETPARA(neighbor,SMT_P_NEIGHBORS) ;
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	neighbor->nb_mib_index = INDEX_MAC ;
131362306a36Sopenharmony_ci	neighbor->nb_mac_index = mac_index(smc,1) ;
131462306a36Sopenharmony_ci	neighbor->nb_una = smc->mib.m[MAC0].fddiMACUpstreamNbr ;
131562306a36Sopenharmony_ci	neighbor->nb_dna = smc->mib.m[MAC0].fddiMACDownstreamNbr ;
131662306a36Sopenharmony_ci}
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci/*
131962306a36Sopenharmony_ci * fill values in path descriptor
132062306a36Sopenharmony_ci */
132162306a36Sopenharmony_ci#ifdef	CONCENTRATOR
132262306a36Sopenharmony_ci#define ALLPHYS	NUMPHYS
132362306a36Sopenharmony_ci#else
132462306a36Sopenharmony_ci#define ALLPHYS	((smc->s.sas == SMT_SAS) ? 1 : 2)
132562306a36Sopenharmony_ci#endif
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_cistatic int smt_fill_path(struct s_smc *smc, struct smt_p_path *path)
132862306a36Sopenharmony_ci{
132962306a36Sopenharmony_ci	SK_LOC_DECL(int,type) ;
133062306a36Sopenharmony_ci	SK_LOC_DECL(int,state) ;
133162306a36Sopenharmony_ci	SK_LOC_DECL(int,remote) ;
133262306a36Sopenharmony_ci	SK_LOC_DECL(int,mac) ;
133362306a36Sopenharmony_ci	int	len ;
133462306a36Sopenharmony_ci	int	p ;
133562306a36Sopenharmony_ci	int	physp ;
133662306a36Sopenharmony_ci	struct smt_phy_rec	*phy ;
133762306a36Sopenharmony_ci	struct smt_mac_rec	*pd_mac ;
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	len =	PARA_LEN +
134062306a36Sopenharmony_ci		sizeof(struct smt_mac_rec) * NUMMACS +
134162306a36Sopenharmony_ci		sizeof(struct smt_phy_rec) * ALLPHYS ;
134262306a36Sopenharmony_ci	path->para.p_type = SMT_P_PATH ;
134362306a36Sopenharmony_ci	path->para.p_len = len - PARA_LEN ;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	/* PHYs */
134662306a36Sopenharmony_ci	for (p = 0,phy = path->pd_phy ; p < ALLPHYS ; p++, phy++) {
134762306a36Sopenharmony_ci		physp = p ;
134862306a36Sopenharmony_ci#ifndef	CONCENTRATOR
134962306a36Sopenharmony_ci		if (smc->s.sas == SMT_SAS)
135062306a36Sopenharmony_ci			physp = PS ;
135162306a36Sopenharmony_ci#endif
135262306a36Sopenharmony_ci		pcm_status_state(smc,physp,&type,&state,&remote,&mac) ;
135362306a36Sopenharmony_ci#ifdef	LITTLE_ENDIAN
135462306a36Sopenharmony_ci		phy->phy_mib_index = smt_swap_short((u_short)p+INDEX_PORT) ;
135562306a36Sopenharmony_ci#else
135662306a36Sopenharmony_ci		phy->phy_mib_index = p+INDEX_PORT ;
135762306a36Sopenharmony_ci#endif
135862306a36Sopenharmony_ci		phy->phy_type = type ;
135962306a36Sopenharmony_ci		phy->phy_connect_state = state ;
136062306a36Sopenharmony_ci		phy->phy_remote_type = remote ;
136162306a36Sopenharmony_ci		phy->phy_remote_mac = mac ;
136262306a36Sopenharmony_ci		phy->phy_resource_idx = phy_con_resource_index(smc,p) ;
136362306a36Sopenharmony_ci	}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	/* MAC */
136662306a36Sopenharmony_ci	pd_mac = (struct smt_mac_rec *) phy ;
136762306a36Sopenharmony_ci	pd_mac->mac_addr = smc->mib.m[MAC0].fddiMACSMTAddress ;
136862306a36Sopenharmony_ci	pd_mac->mac_resource_idx = mac_con_resource_index(smc,1) ;
136962306a36Sopenharmony_ci	return len;
137062306a36Sopenharmony_ci}
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci/*
137362306a36Sopenharmony_ci * fill values in mac status
137462306a36Sopenharmony_ci */
137562306a36Sopenharmony_cistatic void smt_fill_mac_status(struct s_smc *smc, struct smt_p_mac_status *st)
137662306a36Sopenharmony_ci{
137762306a36Sopenharmony_ci	SMTSETPARA(st,SMT_P_MAC_STATUS) ;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	st->st_mib_index = INDEX_MAC ;
138062306a36Sopenharmony_ci	st->st_mac_index = mac_index(smc,1) ;
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	mac_update_counter(smc) ;
138362306a36Sopenharmony_ci	/*
138462306a36Sopenharmony_ci	 * timer values are represented in SMT as 2's complement numbers
138562306a36Sopenharmony_ci	 * units :	internal :  2's complement BCLK
138662306a36Sopenharmony_ci	 */
138762306a36Sopenharmony_ci	st->st_t_req = smc->mib.m[MAC0].fddiMACT_Req ;
138862306a36Sopenharmony_ci	st->st_t_neg = smc->mib.m[MAC0].fddiMACT_Neg ;
138962306a36Sopenharmony_ci	st->st_t_max = smc->mib.m[MAC0].fddiMACT_Max ;
139062306a36Sopenharmony_ci	st->st_tvx_value = smc->mib.m[MAC0].fddiMACTvxValue ;
139162306a36Sopenharmony_ci	st->st_t_min = smc->mib.m[MAC0].fddiMACT_Min ;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	st->st_sba = smc->mib.a[PATH0].fddiPATHSbaPayload ;
139462306a36Sopenharmony_ci	st->st_frame_ct = smc->mib.m[MAC0].fddiMACFrame_Ct ;
139562306a36Sopenharmony_ci	st->st_error_ct = smc->mib.m[MAC0].fddiMACError_Ct ;
139662306a36Sopenharmony_ci	st->st_lost_ct = smc->mib.m[MAC0].fddiMACLost_Ct ;
139762306a36Sopenharmony_ci}
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci/*
140062306a36Sopenharmony_ci * fill values in LEM status
140162306a36Sopenharmony_ci */
140262306a36Sopenharmony_cistatic void smt_fill_lem(struct s_smc *smc, struct smt_p_lem *lem, int phy)
140362306a36Sopenharmony_ci{
140462306a36Sopenharmony_ci	struct fddi_mib_p	*mib ;
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	mib = smc->y[phy].mib ;
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	SMTSETPARA(lem,SMT_P_LEM) ;
140962306a36Sopenharmony_ci	lem->lem_mib_index = phy+INDEX_PORT ;
141062306a36Sopenharmony_ci	lem->lem_phy_index = phy_index(smc,phy) ;
141162306a36Sopenharmony_ci	lem->lem_pad2 = 0 ;
141262306a36Sopenharmony_ci	lem->lem_cutoff = mib->fddiPORTLer_Cutoff ;
141362306a36Sopenharmony_ci	lem->lem_alarm = mib->fddiPORTLer_Alarm ;
141462306a36Sopenharmony_ci	/* long term bit error rate */
141562306a36Sopenharmony_ci	lem->lem_estimate = mib->fddiPORTLer_Estimate ;
141662306a36Sopenharmony_ci	/* # of rejected connections */
141762306a36Sopenharmony_ci	lem->lem_reject_ct = mib->fddiPORTLem_Reject_Ct ;
141862306a36Sopenharmony_ci	lem->lem_ct = mib->fddiPORTLem_Ct ;	/* total number of errors */
141962306a36Sopenharmony_ci}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci/*
142262306a36Sopenharmony_ci * fill version parameter
142362306a36Sopenharmony_ci */
142462306a36Sopenharmony_cistatic void smt_fill_version(struct s_smc *smc, struct smt_p_version *vers)
142562306a36Sopenharmony_ci{
142662306a36Sopenharmony_ci	SK_UNUSED(smc) ;
142762306a36Sopenharmony_ci	SMTSETPARA(vers,SMT_P_VERSION) ;
142862306a36Sopenharmony_ci	vers->v_pad = 0 ;
142962306a36Sopenharmony_ci	vers->v_n = 1 ;				/* one version is enough .. */
143062306a36Sopenharmony_ci	vers->v_index = 1 ;
143162306a36Sopenharmony_ci	vers->v_version[0] = SMT_VID_2 ;
143262306a36Sopenharmony_ci	vers->v_pad2 = 0 ;
143362306a36Sopenharmony_ci}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci#ifdef	SMT6_10
143662306a36Sopenharmony_ci/*
143762306a36Sopenharmony_ci * fill frame status capabilities
143862306a36Sopenharmony_ci */
143962306a36Sopenharmony_ci/*
144062306a36Sopenharmony_ci * note: this para 200B is NOT in swap table, because it's also set in
144162306a36Sopenharmony_ci * PMF add_para
144262306a36Sopenharmony_ci */
144362306a36Sopenharmony_cistatic void smt_fill_fsc(struct s_smc *smc, struct smt_p_fsc *fsc)
144462306a36Sopenharmony_ci{
144562306a36Sopenharmony_ci	SK_UNUSED(smc) ;
144662306a36Sopenharmony_ci	SMTSETPARA(fsc,SMT_P_FSC) ;
144762306a36Sopenharmony_ci	fsc->fsc_pad0 = 0 ;
144862306a36Sopenharmony_ci	fsc->fsc_mac_index = INDEX_MAC ;	/* this is MIB ; MIB is NOT
144962306a36Sopenharmony_ci						 * mac_index ()i !
145062306a36Sopenharmony_ci						 */
145162306a36Sopenharmony_ci	fsc->fsc_pad1 = 0 ;
145262306a36Sopenharmony_ci	fsc->fsc_value = FSC_TYPE0 ;		/* "normal" node */
145362306a36Sopenharmony_ci#ifdef	LITTLE_ENDIAN
145462306a36Sopenharmony_ci	fsc->fsc_mac_index = smt_swap_short(INDEX_MAC) ;
145562306a36Sopenharmony_ci	fsc->fsc_value = smt_swap_short(FSC_TYPE0) ;
145662306a36Sopenharmony_ci#endif
145762306a36Sopenharmony_ci}
145862306a36Sopenharmony_ci#endif
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci/*
146162306a36Sopenharmony_ci * fill mac counter field
146262306a36Sopenharmony_ci */
146362306a36Sopenharmony_cistatic void smt_fill_mac_counter(struct s_smc *smc, struct smt_p_mac_counter *mc)
146462306a36Sopenharmony_ci{
146562306a36Sopenharmony_ci	SMTSETPARA(mc,SMT_P_MAC_COUNTER) ;
146662306a36Sopenharmony_ci	mc->mc_mib_index = INDEX_MAC ;
146762306a36Sopenharmony_ci	mc->mc_index = mac_index(smc,1) ;
146862306a36Sopenharmony_ci	mc->mc_receive_ct = smc->mib.m[MAC0].fddiMACCopied_Ct ;
146962306a36Sopenharmony_ci	mc->mc_transmit_ct =  smc->mib.m[MAC0].fddiMACTransmit_Ct ;
147062306a36Sopenharmony_ci}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci/*
147362306a36Sopenharmony_ci * fill mac frame not copied counter
147462306a36Sopenharmony_ci */
147562306a36Sopenharmony_cistatic void smt_fill_mac_fnc(struct s_smc *smc, struct smt_p_mac_fnc *fnc)
147662306a36Sopenharmony_ci{
147762306a36Sopenharmony_ci	SMTSETPARA(fnc,SMT_P_MAC_FNC) ;
147862306a36Sopenharmony_ci	fnc->nc_mib_index = INDEX_MAC ;
147962306a36Sopenharmony_ci	fnc->nc_index = mac_index(smc,1) ;
148062306a36Sopenharmony_ci	fnc->nc_counter = smc->mib.m[MAC0].fddiMACNotCopied_Ct ;
148162306a36Sopenharmony_ci}
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci/*
148562306a36Sopenharmony_ci * fill manufacturer field
148662306a36Sopenharmony_ci */
148762306a36Sopenharmony_cistatic void smt_fill_manufacturer(struct s_smc *smc,
148862306a36Sopenharmony_ci				  struct smp_p_manufacturer *man)
148962306a36Sopenharmony_ci{
149062306a36Sopenharmony_ci	SMTSETPARA(man,SMT_P_MANUFACTURER) ;
149162306a36Sopenharmony_ci	memcpy((char *) man->mf_data,
149262306a36Sopenharmony_ci		(char *) smc->mib.fddiSMTManufacturerData,
149362306a36Sopenharmony_ci		sizeof(man->mf_data)) ;
149462306a36Sopenharmony_ci}
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci/*
149762306a36Sopenharmony_ci * fill user field
149862306a36Sopenharmony_ci */
149962306a36Sopenharmony_cistatic void smt_fill_user(struct s_smc *smc, struct smp_p_user *user)
150062306a36Sopenharmony_ci{
150162306a36Sopenharmony_ci	SMTSETPARA(user,SMT_P_USER) ;
150262306a36Sopenharmony_ci	memcpy((char *) user->us_data,
150362306a36Sopenharmony_ci		(char *) smc->mib.fddiSMTUserData,
150462306a36Sopenharmony_ci		sizeof(user->us_data)) ;
150562306a36Sopenharmony_ci}
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci/*
150862306a36Sopenharmony_ci * fill set count
150962306a36Sopenharmony_ci */
151062306a36Sopenharmony_cistatic void smt_fill_setcount(struct s_smc *smc, struct smt_p_setcount *setcount)
151162306a36Sopenharmony_ci{
151262306a36Sopenharmony_ci	SK_UNUSED(smc) ;
151362306a36Sopenharmony_ci	SMTSETPARA(setcount,SMT_P_SETCOUNT) ;
151462306a36Sopenharmony_ci	setcount->count = smc->mib.fddiSMTSetCount.count ;
151562306a36Sopenharmony_ci	memcpy((char *)setcount->timestamp,
151662306a36Sopenharmony_ci		(char *)smc->mib.fddiSMTSetCount.timestamp,8) ;
151762306a36Sopenharmony_ci}
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci/*
152062306a36Sopenharmony_ci * fill echo data
152162306a36Sopenharmony_ci */
152262306a36Sopenharmony_cistatic void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long seed,
152362306a36Sopenharmony_ci			  int len)
152462306a36Sopenharmony_ci{
152562306a36Sopenharmony_ci	u_char	*p ;
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	SK_UNUSED(smc) ;
152862306a36Sopenharmony_ci	SMTSETPARA(echo,SMT_P_ECHODATA) ;
152962306a36Sopenharmony_ci	echo->para.p_len = len ;
153062306a36Sopenharmony_ci	for (p = echo->ec_data ; len ; len--) {
153162306a36Sopenharmony_ci		*p++ = (u_char) seed ;
153262306a36Sopenharmony_ci		seed += 13 ;
153362306a36Sopenharmony_ci	}
153462306a36Sopenharmony_ci}
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci/*
153762306a36Sopenharmony_ci * clear DNA and UNA
153862306a36Sopenharmony_ci * called from CFM if configuration changes
153962306a36Sopenharmony_ci */
154062306a36Sopenharmony_cistatic void smt_clear_una_dna(struct s_smc *smc)
154162306a36Sopenharmony_ci{
154262306a36Sopenharmony_ci	smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ;
154362306a36Sopenharmony_ci	smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ;
154462306a36Sopenharmony_ci}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_cistatic void smt_clear_old_una_dna(struct s_smc *smc)
154762306a36Sopenharmony_ci{
154862306a36Sopenharmony_ci	smc->mib.m[MAC0].fddiMACOldUpstreamNbr = SMT_Unknown ;
154962306a36Sopenharmony_ci	smc->mib.m[MAC0].fddiMACOldDownstreamNbr = SMT_Unknown ;
155062306a36Sopenharmony_ci}
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ciu_long smt_get_tid(struct s_smc *smc)
155362306a36Sopenharmony_ci{
155462306a36Sopenharmony_ci	u_long	tid ;
155562306a36Sopenharmony_ci	while ((tid = ++(smc->sm.smt_tid) ^ SMT_TID_MAGIC) == 0)
155662306a36Sopenharmony_ci		;
155762306a36Sopenharmony_ci	return tid & 0x3fffffffL;
155862306a36Sopenharmony_ci}
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci#ifdef	LITTLE_ENDIAN
156162306a36Sopenharmony_ci/*
156262306a36Sopenharmony_ci * table of parameter lengths
156362306a36Sopenharmony_ci */
156462306a36Sopenharmony_cistatic const struct smt_pdef {
156562306a36Sopenharmony_ci	int	ptype ;
156662306a36Sopenharmony_ci	int	plen ;
156762306a36Sopenharmony_ci	const char	*pswap ;
156862306a36Sopenharmony_ci} smt_pdef[] = {
156962306a36Sopenharmony_ci	{ SMT_P_UNA,	sizeof(struct smt_p_una) ,
157062306a36Sopenharmony_ci		SWAP_SMT_P_UNA					} ,
157162306a36Sopenharmony_ci	{ SMT_P_SDE,	sizeof(struct smt_p_sde) ,
157262306a36Sopenharmony_ci		SWAP_SMT_P_SDE					} ,
157362306a36Sopenharmony_ci	{ SMT_P_STATE,	sizeof(struct smt_p_state) ,
157462306a36Sopenharmony_ci		SWAP_SMT_P_STATE				} ,
157562306a36Sopenharmony_ci	{ SMT_P_TIMESTAMP,sizeof(struct smt_p_timestamp) ,
157662306a36Sopenharmony_ci		SWAP_SMT_P_TIMESTAMP				} ,
157762306a36Sopenharmony_ci	{ SMT_P_POLICY,	sizeof(struct smt_p_policy) ,
157862306a36Sopenharmony_ci		SWAP_SMT_P_POLICY				} ,
157962306a36Sopenharmony_ci	{ SMT_P_LATENCY,	sizeof(struct smt_p_latency) ,
158062306a36Sopenharmony_ci		SWAP_SMT_P_LATENCY				} ,
158162306a36Sopenharmony_ci	{ SMT_P_NEIGHBORS,sizeof(struct smt_p_neighbor) ,
158262306a36Sopenharmony_ci		SWAP_SMT_P_NEIGHBORS				} ,
158362306a36Sopenharmony_ci	{ SMT_P_PATH,	sizeof(struct smt_p_path) ,
158462306a36Sopenharmony_ci		SWAP_SMT_P_PATH					} ,
158562306a36Sopenharmony_ci	{ SMT_P_MAC_STATUS,sizeof(struct smt_p_mac_status) ,
158662306a36Sopenharmony_ci		SWAP_SMT_P_MAC_STATUS				} ,
158762306a36Sopenharmony_ci	{ SMT_P_LEM,	sizeof(struct smt_p_lem) ,
158862306a36Sopenharmony_ci		SWAP_SMT_P_LEM					} ,
158962306a36Sopenharmony_ci	{ SMT_P_MAC_COUNTER,sizeof(struct smt_p_mac_counter) ,
159062306a36Sopenharmony_ci		SWAP_SMT_P_MAC_COUNTER				} ,
159162306a36Sopenharmony_ci	{ SMT_P_MAC_FNC,sizeof(struct smt_p_mac_fnc) ,
159262306a36Sopenharmony_ci		SWAP_SMT_P_MAC_FNC				} ,
159362306a36Sopenharmony_ci	{ SMT_P_PRIORITY,sizeof(struct smt_p_priority) ,
159462306a36Sopenharmony_ci		SWAP_SMT_P_PRIORITY				} ,
159562306a36Sopenharmony_ci	{ SMT_P_EB,sizeof(struct smt_p_eb) ,
159662306a36Sopenharmony_ci		SWAP_SMT_P_EB					} ,
159762306a36Sopenharmony_ci	{ SMT_P_MANUFACTURER,sizeof(struct smp_p_manufacturer) ,
159862306a36Sopenharmony_ci		SWAP_SMT_P_MANUFACTURER				} ,
159962306a36Sopenharmony_ci	{ SMT_P_REASON,	sizeof(struct smt_p_reason) ,
160062306a36Sopenharmony_ci		SWAP_SMT_P_REASON				} ,
160162306a36Sopenharmony_ci	{ SMT_P_REFUSED, sizeof(struct smt_p_refused) ,
160262306a36Sopenharmony_ci		SWAP_SMT_P_REFUSED				} ,
160362306a36Sopenharmony_ci	{ SMT_P_VERSION, sizeof(struct smt_p_version) ,
160462306a36Sopenharmony_ci		SWAP_SMT_P_VERSION				} ,
160562306a36Sopenharmony_ci#ifdef ESS
160662306a36Sopenharmony_ci	{ SMT_P0015, sizeof(struct smt_p_0015) , SWAP_SMT_P0015 } ,
160762306a36Sopenharmony_ci	{ SMT_P0016, sizeof(struct smt_p_0016) , SWAP_SMT_P0016 } ,
160862306a36Sopenharmony_ci	{ SMT_P0017, sizeof(struct smt_p_0017) , SWAP_SMT_P0017 } ,
160962306a36Sopenharmony_ci	{ SMT_P0018, sizeof(struct smt_p_0018) , SWAP_SMT_P0018 } ,
161062306a36Sopenharmony_ci	{ SMT_P0019, sizeof(struct smt_p_0019) , SWAP_SMT_P0019 } ,
161162306a36Sopenharmony_ci	{ SMT_P001A, sizeof(struct smt_p_001a) , SWAP_SMT_P001A } ,
161262306a36Sopenharmony_ci	{ SMT_P001B, sizeof(struct smt_p_001b) , SWAP_SMT_P001B } ,
161362306a36Sopenharmony_ci	{ SMT_P001C, sizeof(struct smt_p_001c) , SWAP_SMT_P001C } ,
161462306a36Sopenharmony_ci	{ SMT_P001D, sizeof(struct smt_p_001d) , SWAP_SMT_P001D } ,
161562306a36Sopenharmony_ci#endif
161662306a36Sopenharmony_ci#if	0
161762306a36Sopenharmony_ci	{ SMT_P_FSC,	sizeof(struct smt_p_fsc) ,
161862306a36Sopenharmony_ci		SWAP_SMT_P_FSC					} ,
161962306a36Sopenharmony_ci#endif
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	{ SMT_P_SETCOUNT,0,	SWAP_SMT_P_SETCOUNT		} ,
162262306a36Sopenharmony_ci	{ SMT_P1048,	0,	SWAP_SMT_P1048			} ,
162362306a36Sopenharmony_ci	{ SMT_P208C,	0,	SWAP_SMT_P208C			} ,
162462306a36Sopenharmony_ci	{ SMT_P208D,	0,	SWAP_SMT_P208D			} ,
162562306a36Sopenharmony_ci	{ SMT_P208E,	0,	SWAP_SMT_P208E			} ,
162662306a36Sopenharmony_ci	{ SMT_P208F,	0,	SWAP_SMT_P208F			} ,
162762306a36Sopenharmony_ci	{ SMT_P2090,	0,	SWAP_SMT_P2090			} ,
162862306a36Sopenharmony_ci#ifdef	ESS
162962306a36Sopenharmony_ci	{ SMT_P320B, sizeof(struct smt_p_320b) , SWAP_SMT_P320B } ,
163062306a36Sopenharmony_ci	{ SMT_P320F, sizeof(struct smt_p_320f) , SWAP_SMT_P320F } ,
163162306a36Sopenharmony_ci	{ SMT_P3210, sizeof(struct smt_p_3210) , SWAP_SMT_P3210 } ,
163262306a36Sopenharmony_ci#endif
163362306a36Sopenharmony_ci	{ SMT_P4050,	0,	SWAP_SMT_P4050			} ,
163462306a36Sopenharmony_ci	{ SMT_P4051,	0,	SWAP_SMT_P4051			} ,
163562306a36Sopenharmony_ci	{ SMT_P4052,	0,	SWAP_SMT_P4052			} ,
163662306a36Sopenharmony_ci	{ SMT_P4053,	0,	SWAP_SMT_P4053			} ,
163762306a36Sopenharmony_ci} ;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci#define N_SMT_PLEN	ARRAY_SIZE(smt_pdef)
164062306a36Sopenharmony_ci#endif
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ciint smt_check_para(struct s_smc *smc, struct smt_header	*sm,
164362306a36Sopenharmony_ci		   const u_short list[])
164462306a36Sopenharmony_ci{
164562306a36Sopenharmony_ci	const u_short		*p = list ;
164662306a36Sopenharmony_ci	while (*p) {
164762306a36Sopenharmony_ci		if (!sm_to_para(smc,sm,(int) *p)) {
164862306a36Sopenharmony_ci			DB_SMT("SMT: smt_check_para - missing para %hx", *p);
164962306a36Sopenharmony_ci			return -1;
165062306a36Sopenharmony_ci		}
165162306a36Sopenharmony_ci		p++ ;
165262306a36Sopenharmony_ci	}
165362306a36Sopenharmony_ci	return 0;
165462306a36Sopenharmony_ci}
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_civoid *sm_to_para(struct s_smc *smc, struct smt_header *sm, int para)
165762306a36Sopenharmony_ci{
165862306a36Sopenharmony_ci	char	*p ;
165962306a36Sopenharmony_ci	int	len ;
166062306a36Sopenharmony_ci	int	plen ;
166162306a36Sopenharmony_ci	void	*found = NULL;
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	SK_UNUSED(smc) ;
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	len = sm->smt_len ;
166662306a36Sopenharmony_ci	p = (char *)(sm+1) ;		/* pointer to info */
166762306a36Sopenharmony_ci	while (len > 0 ) {
166862306a36Sopenharmony_ci		if (((struct smt_para *)p)->p_type == para)
166962306a36Sopenharmony_ci			found = (void *) p ;
167062306a36Sopenharmony_ci		plen = ((struct smt_para *)p)->p_len + PARA_LEN ;
167162306a36Sopenharmony_ci		p += plen ;
167262306a36Sopenharmony_ci		len -= plen ;
167362306a36Sopenharmony_ci		if (len < 0) {
167462306a36Sopenharmony_ci			DB_SMT("SMT : sm_to_para - length error %d", plen);
167562306a36Sopenharmony_ci			return NULL;
167662306a36Sopenharmony_ci		}
167762306a36Sopenharmony_ci		if ((plen & 3) && (para != SMT_P_ECHODATA)) {
167862306a36Sopenharmony_ci			DB_SMT("SMT : sm_to_para - odd length %d", plen);
167962306a36Sopenharmony_ci			return NULL;
168062306a36Sopenharmony_ci		}
168162306a36Sopenharmony_ci		if (found)
168262306a36Sopenharmony_ci			return found;
168362306a36Sopenharmony_ci	}
168462306a36Sopenharmony_ci	return NULL;
168562306a36Sopenharmony_ci}
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci#if	0
168862306a36Sopenharmony_ci/*
168962306a36Sopenharmony_ci * send ANTC data test frame
169062306a36Sopenharmony_ci */
169162306a36Sopenharmony_civoid fddi_send_antc(struct s_smc *smc, struct fddi_addr *dest)
169262306a36Sopenharmony_ci{
169362306a36Sopenharmony_ci	SK_UNUSED(smc) ;
169462306a36Sopenharmony_ci	SK_UNUSED(dest) ;
169562306a36Sopenharmony_ci#if	0
169662306a36Sopenharmony_ci	SMbuf			*mb ;
169762306a36Sopenharmony_ci	struct smt_header	*smt ;
169862306a36Sopenharmony_ci	int			i ;
169962306a36Sopenharmony_ci	char			*p ;
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	mb = smt_get_mbuf() ;
170262306a36Sopenharmony_ci	mb->sm_len = 3000+12 ;
170362306a36Sopenharmony_ci	p = smtod(mb, char *) + 12 ;
170462306a36Sopenharmony_ci	for (i = 0 ; i < 3000 ; i++)
170562306a36Sopenharmony_ci		*p++ = 1 << (i&7) ;
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	smt = smtod(mb, struct smt_header *) ;
170862306a36Sopenharmony_ci	smt->smt_dest = *dest ;
170962306a36Sopenharmony_ci	smt->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ;
171062306a36Sopenharmony_ci	smt_send_mbuf(smc,mb,FC_ASYNC_LLC) ;
171162306a36Sopenharmony_ci#endif
171262306a36Sopenharmony_ci}
171362306a36Sopenharmony_ci#endif
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci/*
171662306a36Sopenharmony_ci * return static mac index
171762306a36Sopenharmony_ci */
171862306a36Sopenharmony_cistatic int mac_index(struct s_smc *smc, int mac)
171962306a36Sopenharmony_ci{
172062306a36Sopenharmony_ci	SK_UNUSED(mac) ;
172162306a36Sopenharmony_ci#ifdef	CONCENTRATOR
172262306a36Sopenharmony_ci	SK_UNUSED(smc) ;
172362306a36Sopenharmony_ci	return NUMPHYS + 1;
172462306a36Sopenharmony_ci#else
172562306a36Sopenharmony_ci	return (smc->s.sas == SMT_SAS) ? 2 : 3;
172662306a36Sopenharmony_ci#endif
172762306a36Sopenharmony_ci}
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci/*
173062306a36Sopenharmony_ci * return static phy index
173162306a36Sopenharmony_ci */
173262306a36Sopenharmony_cistatic int phy_index(struct s_smc *smc, int phy)
173362306a36Sopenharmony_ci{
173462306a36Sopenharmony_ci	SK_UNUSED(smc) ;
173562306a36Sopenharmony_ci	return phy + 1;
173662306a36Sopenharmony_ci}
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci/*
173962306a36Sopenharmony_ci * return dynamic mac connection resource index
174062306a36Sopenharmony_ci */
174162306a36Sopenharmony_cistatic int mac_con_resource_index(struct s_smc *smc, int mac)
174262306a36Sopenharmony_ci{
174362306a36Sopenharmony_ci#ifdef	CONCENTRATOR
174462306a36Sopenharmony_ci	SK_UNUSED(smc) ;
174562306a36Sopenharmony_ci	SK_UNUSED(mac) ;
174662306a36Sopenharmony_ci	return entity_to_index(smc, cem_get_downstream(smc, ENTITY_MAC));
174762306a36Sopenharmony_ci#else
174862306a36Sopenharmony_ci	SK_UNUSED(mac) ;
174962306a36Sopenharmony_ci	switch (smc->mib.fddiSMTCF_State) {
175062306a36Sopenharmony_ci	case SC9_C_WRAP_A :
175162306a36Sopenharmony_ci	case SC5_THRU_B :
175262306a36Sopenharmony_ci	case SC11_C_WRAP_S :
175362306a36Sopenharmony_ci		return 1;
175462306a36Sopenharmony_ci	case SC10_C_WRAP_B :
175562306a36Sopenharmony_ci	case SC4_THRU_A :
175662306a36Sopenharmony_ci		return 2;
175762306a36Sopenharmony_ci	}
175862306a36Sopenharmony_ci	return smc->s.sas == SMT_SAS ? 2 : 3;
175962306a36Sopenharmony_ci#endif
176062306a36Sopenharmony_ci}
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci/*
176362306a36Sopenharmony_ci * return dynamic phy connection resource index
176462306a36Sopenharmony_ci */
176562306a36Sopenharmony_cistatic int phy_con_resource_index(struct s_smc *smc, int phy)
176662306a36Sopenharmony_ci{
176762306a36Sopenharmony_ci#ifdef	CONCENTRATOR
176862306a36Sopenharmony_ci	return entity_to_index(smc, cem_get_downstream(smc, ENTITY_PHY(phy))) ;
176962306a36Sopenharmony_ci#else
177062306a36Sopenharmony_ci	switch (smc->mib.fddiSMTCF_State) {
177162306a36Sopenharmony_ci	case SC9_C_WRAP_A :
177262306a36Sopenharmony_ci		return phy == PA ? 3 : 2;
177362306a36Sopenharmony_ci	case SC10_C_WRAP_B :
177462306a36Sopenharmony_ci		return phy == PA ? 1 : 3;
177562306a36Sopenharmony_ci	case SC4_THRU_A :
177662306a36Sopenharmony_ci		return phy == PA ? 3 : 1;
177762306a36Sopenharmony_ci	case SC5_THRU_B :
177862306a36Sopenharmony_ci		return phy == PA ? 2 : 3;
177962306a36Sopenharmony_ci	case SC11_C_WRAP_S :
178062306a36Sopenharmony_ci		return 2;
178162306a36Sopenharmony_ci	}
178262306a36Sopenharmony_ci	return phy;
178362306a36Sopenharmony_ci#endif
178462306a36Sopenharmony_ci}
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci#ifdef	CONCENTRATOR
178762306a36Sopenharmony_cistatic int entity_to_index(struct s_smc *smc, int e)
178862306a36Sopenharmony_ci{
178962306a36Sopenharmony_ci	if (e == ENTITY_MAC)
179062306a36Sopenharmony_ci		return mac_index(smc, 1);
179162306a36Sopenharmony_ci	else
179262306a36Sopenharmony_ci		return phy_index(smc, e - ENTITY_PHY(0));
179362306a36Sopenharmony_ci}
179462306a36Sopenharmony_ci#endif
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci#ifdef	LITTLE_ENDIAN
179762306a36Sopenharmony_cistatic int smt_swap_short(u_short s)
179862306a36Sopenharmony_ci{
179962306a36Sopenharmony_ci	return ((s>>8)&0xff) | ((s&0xff)<<8);
180062306a36Sopenharmony_ci}
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_civoid smt_swap_para(struct smt_header *sm, int len, int direction)
180362306a36Sopenharmony_ci/* int direction;	0 encode 1 decode */
180462306a36Sopenharmony_ci{
180562306a36Sopenharmony_ci	struct smt_para	*pa ;
180662306a36Sopenharmony_ci	const  struct smt_pdef	*pd ;
180762306a36Sopenharmony_ci	char	*p ;
180862306a36Sopenharmony_ci	int	plen ;
180962306a36Sopenharmony_ci	int	type ;
181062306a36Sopenharmony_ci	int	i ;
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci/*	printf("smt_swap_para sm %x len %d dir %d\n",
181362306a36Sopenharmony_ci		sm,len,direction) ;
181462306a36Sopenharmony_ci */
181562306a36Sopenharmony_ci	smt_string_swap((char *)sm,SWAP_SMTHEADER,len) ;
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	/* swap args */
181862306a36Sopenharmony_ci	len -= sizeof(struct smt_header) ;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	p = (char *) (sm + 1) ;
182162306a36Sopenharmony_ci	while (len > 0) {
182262306a36Sopenharmony_ci		pa = (struct smt_para *) p ;
182362306a36Sopenharmony_ci		plen = pa->p_len ;
182462306a36Sopenharmony_ci		type = pa->p_type ;
182562306a36Sopenharmony_ci		pa->p_type = smt_swap_short(pa->p_type) ;
182662306a36Sopenharmony_ci		pa->p_len = smt_swap_short(pa->p_len) ;
182762306a36Sopenharmony_ci		if (direction) {
182862306a36Sopenharmony_ci			plen = pa->p_len ;
182962306a36Sopenharmony_ci			type = pa->p_type ;
183062306a36Sopenharmony_ci		}
183162306a36Sopenharmony_ci		/*
183262306a36Sopenharmony_ci		 * note: paras can have 0 length !
183362306a36Sopenharmony_ci		 */
183462306a36Sopenharmony_ci		if (plen < 0)
183562306a36Sopenharmony_ci			break ;
183662306a36Sopenharmony_ci		plen += PARA_LEN ;
183762306a36Sopenharmony_ci		for (i = N_SMT_PLEN, pd = smt_pdef; i ; i--,pd++) {
183862306a36Sopenharmony_ci			if (pd->ptype == type)
183962306a36Sopenharmony_ci				break ;
184062306a36Sopenharmony_ci		}
184162306a36Sopenharmony_ci		if (i && pd->pswap) {
184262306a36Sopenharmony_ci			smt_string_swap(p+PARA_LEN,pd->pswap,len) ;
184362306a36Sopenharmony_ci		}
184462306a36Sopenharmony_ci		len -= plen ;
184562306a36Sopenharmony_ci		p += plen ;
184662306a36Sopenharmony_ci	}
184762306a36Sopenharmony_ci}
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_cistatic void smt_string_swap(char *data, const char *format, int len)
185162306a36Sopenharmony_ci{
185262306a36Sopenharmony_ci	const char	*open_paren = NULL ;
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	while (len > 0  && *format) {
185562306a36Sopenharmony_ci		switch (*format) {
185662306a36Sopenharmony_ci		case '[' :
185762306a36Sopenharmony_ci			open_paren = format ;
185862306a36Sopenharmony_ci			break ;
185962306a36Sopenharmony_ci		case ']' :
186062306a36Sopenharmony_ci			format = open_paren ;
186162306a36Sopenharmony_ci			break ;
186262306a36Sopenharmony_ci		case '1' :
186362306a36Sopenharmony_ci		case '2' :
186462306a36Sopenharmony_ci		case '3' :
186562306a36Sopenharmony_ci		case '4' :
186662306a36Sopenharmony_ci		case '5' :
186762306a36Sopenharmony_ci		case '6' :
186862306a36Sopenharmony_ci		case '7' :
186962306a36Sopenharmony_ci		case '8' :
187062306a36Sopenharmony_ci		case '9' :
187162306a36Sopenharmony_ci			data  += *format - '0' ;
187262306a36Sopenharmony_ci			len   -= *format - '0' ;
187362306a36Sopenharmony_ci			break ;
187462306a36Sopenharmony_ci		case 'c':
187562306a36Sopenharmony_ci			data++ ;
187662306a36Sopenharmony_ci			len-- ;
187762306a36Sopenharmony_ci			break ;
187862306a36Sopenharmony_ci		case 's' :
187962306a36Sopenharmony_ci			swap(data[0], data[1]) ;
188062306a36Sopenharmony_ci			data += 2 ;
188162306a36Sopenharmony_ci			len -= 2 ;
188262306a36Sopenharmony_ci			break ;
188362306a36Sopenharmony_ci		case 'l' :
188462306a36Sopenharmony_ci			swap(data[0], data[3]) ;
188562306a36Sopenharmony_ci			swap(data[1], data[2]) ;
188662306a36Sopenharmony_ci			data += 4 ;
188762306a36Sopenharmony_ci			len -= 4 ;
188862306a36Sopenharmony_ci			break ;
188962306a36Sopenharmony_ci		}
189062306a36Sopenharmony_ci		format++ ;
189162306a36Sopenharmony_ci	}
189262306a36Sopenharmony_ci}
189362306a36Sopenharmony_ci#else
189462306a36Sopenharmony_civoid smt_swap_para(struct smt_header *sm, int len, int direction)
189562306a36Sopenharmony_ci/* int direction;	0 encode 1 decode */
189662306a36Sopenharmony_ci{
189762306a36Sopenharmony_ci	SK_UNUSED(sm) ;
189862306a36Sopenharmony_ci	SK_UNUSED(len) ;
189962306a36Sopenharmony_ci	SK_UNUSED(direction) ;
190062306a36Sopenharmony_ci}
190162306a36Sopenharmony_ci#endif
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci/*
190462306a36Sopenharmony_ci * PMF actions
190562306a36Sopenharmony_ci */
190662306a36Sopenharmony_ciint smt_action(struct s_smc *smc, int class, int code, int index)
190762306a36Sopenharmony_ci{
190862306a36Sopenharmony_ci	int	event ;
190962306a36Sopenharmony_ci	int	port ;
191062306a36Sopenharmony_ci	DB_SMT("SMT: action %d code %d", class, code);
191162306a36Sopenharmony_ci	switch(class) {
191262306a36Sopenharmony_ci	case SMT_STATION_ACTION :
191362306a36Sopenharmony_ci		switch(code) {
191462306a36Sopenharmony_ci		case SMT_STATION_ACTION_CONNECT :
191562306a36Sopenharmony_ci			smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ;
191662306a36Sopenharmony_ci			queue_event(smc,EVENT_ECM,EC_CONNECT) ;
191762306a36Sopenharmony_ci			break ;
191862306a36Sopenharmony_ci		case SMT_STATION_ACTION_DISCONNECT :
191962306a36Sopenharmony_ci			queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
192062306a36Sopenharmony_ci			smc->mib.fddiSMTRemoteDisconnectFlag = TRUE ;
192162306a36Sopenharmony_ci			RS_SET(smc,RS_DISCONNECT) ;
192262306a36Sopenharmony_ci			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
192362306a36Sopenharmony_ci				FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_DISCONNECT,
192462306a36Sopenharmony_ci				smt_get_event_word(smc));
192562306a36Sopenharmony_ci			break ;
192662306a36Sopenharmony_ci		case SMT_STATION_ACTION_PATHTEST :
192762306a36Sopenharmony_ci			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
192862306a36Sopenharmony_ci				FDDI_SMT_EVENT, (u_long) FDDI_PATH_TEST,
192962306a36Sopenharmony_ci				smt_get_event_word(smc));
193062306a36Sopenharmony_ci			break ;
193162306a36Sopenharmony_ci		case SMT_STATION_ACTION_SELFTEST :
193262306a36Sopenharmony_ci			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
193362306a36Sopenharmony_ci				FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_SELF_TEST,
193462306a36Sopenharmony_ci				smt_get_event_word(smc));
193562306a36Sopenharmony_ci			break ;
193662306a36Sopenharmony_ci		case SMT_STATION_ACTION_DISABLE_A :
193762306a36Sopenharmony_ci			if (smc->y[PA].pc_mode == PM_PEER) {
193862306a36Sopenharmony_ci				RS_SET(smc,RS_EVENT) ;
193962306a36Sopenharmony_ci				queue_event(smc,EVENT_PCM+PA,PC_DISABLE) ;
194062306a36Sopenharmony_ci			}
194162306a36Sopenharmony_ci			break ;
194262306a36Sopenharmony_ci		case SMT_STATION_ACTION_DISABLE_B :
194362306a36Sopenharmony_ci			if (smc->y[PB].pc_mode == PM_PEER) {
194462306a36Sopenharmony_ci				RS_SET(smc,RS_EVENT) ;
194562306a36Sopenharmony_ci				queue_event(smc,EVENT_PCM+PB,PC_DISABLE) ;
194662306a36Sopenharmony_ci			}
194762306a36Sopenharmony_ci			break ;
194862306a36Sopenharmony_ci		case SMT_STATION_ACTION_DISABLE_M :
194962306a36Sopenharmony_ci			for (port = 0 ; port <  NUMPHYS ; port++) {
195062306a36Sopenharmony_ci				if (smc->mib.p[port].fddiPORTMy_Type != TM)
195162306a36Sopenharmony_ci					continue ;
195262306a36Sopenharmony_ci				RS_SET(smc,RS_EVENT) ;
195362306a36Sopenharmony_ci				queue_event(smc,EVENT_PCM+port,PC_DISABLE) ;
195462306a36Sopenharmony_ci			}
195562306a36Sopenharmony_ci			break ;
195662306a36Sopenharmony_ci		default :
195762306a36Sopenharmony_ci			return 1;
195862306a36Sopenharmony_ci		}
195962306a36Sopenharmony_ci		break ;
196062306a36Sopenharmony_ci	case SMT_PORT_ACTION :
196162306a36Sopenharmony_ci		switch(code) {
196262306a36Sopenharmony_ci		case SMT_PORT_ACTION_ENABLE :
196362306a36Sopenharmony_ci			event = PC_ENABLE ;
196462306a36Sopenharmony_ci			break ;
196562306a36Sopenharmony_ci		case SMT_PORT_ACTION_DISABLE :
196662306a36Sopenharmony_ci			event = PC_DISABLE ;
196762306a36Sopenharmony_ci			break ;
196862306a36Sopenharmony_ci		case SMT_PORT_ACTION_MAINT :
196962306a36Sopenharmony_ci			event = PC_MAINT ;
197062306a36Sopenharmony_ci			break ;
197162306a36Sopenharmony_ci		case SMT_PORT_ACTION_START :
197262306a36Sopenharmony_ci			event = PC_START ;
197362306a36Sopenharmony_ci			break ;
197462306a36Sopenharmony_ci		case SMT_PORT_ACTION_STOP :
197562306a36Sopenharmony_ci			event = PC_STOP ;
197662306a36Sopenharmony_ci			break ;
197762306a36Sopenharmony_ci		default :
197862306a36Sopenharmony_ci			return 1;
197962306a36Sopenharmony_ci		}
198062306a36Sopenharmony_ci		queue_event(smc,EVENT_PCM+index,event) ;
198162306a36Sopenharmony_ci		break ;
198262306a36Sopenharmony_ci	default :
198362306a36Sopenharmony_ci		return 1;
198462306a36Sopenharmony_ci	}
198562306a36Sopenharmony_ci	return 0;
198662306a36Sopenharmony_ci}
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci/*
198962306a36Sopenharmony_ci * canonical conversion of <len> bytes beginning form *data
199062306a36Sopenharmony_ci */
199162306a36Sopenharmony_ci#ifdef  USE_CAN_ADDR
199262306a36Sopenharmony_cistatic void hwm_conv_can(struct s_smc *smc, char *data, int len)
199362306a36Sopenharmony_ci{
199462306a36Sopenharmony_ci	int i ;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	SK_UNUSED(smc) ;
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	for (i = len; i ; i--, data++)
199962306a36Sopenharmony_ci		*data = bitrev8(*data);
200062306a36Sopenharmony_ci}
200162306a36Sopenharmony_ci#endif
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci#endif	/* no SLIM_SMT */
200462306a36Sopenharmony_ci
2005