📄 smt.c
字号:
/****************************************************************************** * * (C)Copyright 1998,1999 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * * See the file "skfddi.c" for further information. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * The information in this file is provided "AS IS" without warranty. * ******************************************************************************/#include "h/types.h"#include "h/fddi.h"#include "h/smc.h"#include "h/smt_p.h"#define KERNEL#include "h/smtstate.h"#ifndef lintstatic const char ID_sccs[] = "@(#)smt.c 2.43 98/11/23 (C) SK " ;#endifextern const u_char canonical[256] ;/* * FC in SMbuf */#define m_fc(mb) ((mb)->sm_data[0])#define SMT_TID_MAGIC 0x1f0a7b3c#ifdef DEBUGstatic const char *const smt_type_name[] = { "SMT_00??", "SMT_INFO", "SMT_02??", "SMT_03??", "SMT_04??", "SMT_05??", "SMT_06??", "SMT_07??", "SMT_08??", "SMT_09??", "SMT_0A??", "SMT_0B??", "SMT_0C??", "SMT_0D??", "SMT_0E??", "SMT_NSA"} ;static const char *const smt_class_name[] = { "UNKNOWN","NIF","SIF_CONFIG","SIF_OPER","ECF","RAF","RDF", "SRF","PMF_GET","PMF_SET","ESF"} ;#endif#define LAST_CLASS (SMT_PMF_SET)static const struct fddi_addr SMT_Unknown = { { 0,0,0x1f,0,0,0 }} ;/* * external variables */extern const struct fddi_addr fddi_broadcast ;/* * external functions */int pcm_status_twisted() ;void pcm_status_state() ;int pcm_status_type() ;extern SMbuf *smt_get_mbuf() ;#define EXPORT_PMF/* * function prototypes */u_long smt_get_tid() ;EXPORT_PMF SMbuf *smt_build_frame() ;EXPORT_PMF void *sm_to_para() ;#ifdef LITTLE_ENDIANstatic int smt_swap_short() ;#endifstatic int mac_index() ;static int phy_index() ;static int mac_con_resource_index() ;static int phy_con_resource_index() ;EXPORT_PMF void smt_send_frame() ;EXPORT_PMF void smt_set_timestamp() ;static void smt_send_rdf() ;static void smt_send_nif() ;static void smt_send_ecf() ;static void smt_echo_test() ;static void smt_send_sif_config() ;static void smt_send_sif_operation() ;EXPORT_PMF void smt_swap_para() ;#ifdef LITTLE_ENDIANstatic void smt_string_swap() ;#endifstatic void smt_add_frame_len() ;static void smt_fill_una() ;static void smt_fill_sde() ;static void smt_fill_state() ;static void smt_fill_timestamp() ;static void smt_fill_policy() ;static void smt_fill_latency() ;static void smt_fill_neighbor() ;static int smt_fill_path() ;static void smt_fill_mac_status() ;static void smt_fill_lem() ;static void smt_fill_version() ;static void smt_fill_fsc() ;static void smt_fill_mac_counter() ;static void smt_fill_mac_fnc() ;static void smt_fill_manufacturer() ;static void smt_fill_user() ;static void smt_fill_setcount() ;static void smt_fill_echo() ;int smt_check_para() ;void smt_clear_una_dna() ;static void smt_clear_old_una_dna() ;#ifdef CONCENTRATORstatic int entity_to_index() ;#endifstatic void update_dac() ;static int div_ratio() ;#ifdef USE_CAN_ADDRvoid hwm_conv_can() ;#else#define hwm_conv_can(smc,data,len)#endif/* * list of mandatory paras in frames */static const u_short plist_nif[] = { SMT_P_UNA,SMT_P_SDE,SMT_P_STATE,0 } ;/* * init SMT agent */void smt_agent_init(smc)struct s_smc *smc ;{ int i ; /* * get MAC address */ smc->mib.m[MAC0].fddiMACSMTAddress = smc->hw.fddi_home_addr ; /* * get OUI address from driver (bia == built-in-address) */ smc->mib.fddiSMTStationId.sid_oem[0] = 0 ; smc->mib.fddiSMTStationId.sid_oem[1] = 0 ; driver_get_bia(smc,&smc->mib.fddiSMTStationId.sid_node) ; for (i = 0 ; i < 6 ; i ++) { smc->mib.fddiSMTStationId.sid_node.a[i] = canonical[smc->mib.fddiSMTStationId.sid_node.a[i]] ; } smc->mib.fddiSMTManufacturerData[0] = smc->mib.fddiSMTStationId.sid_node.a[0] ; smc->mib.fddiSMTManufacturerData[1] = smc->mib.fddiSMTStationId.sid_node.a[1] ; smc->mib.fddiSMTManufacturerData[2] = smc->mib.fddiSMTStationId.sid_node.a[2] ; smc->sm.smt_tid = 0 ; smc->mib.m[MAC0].fddiMACDupAddressTest = DA_NONE ; smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ;#ifndef SLIM_SMT smt_clear_una_dna(smc) ; smt_clear_old_una_dna(smc) ;#endif for (i = 0 ; i < SMT_MAX_TEST ; i++) smc->sm.pend[i] = 0 ; smc->sm.please_reconnect = 0 ; smc->sm.uniq_ticks = 0 ;}/* * SMT task * forever * delay 30 seconds * send NIF * check tvu & tvd * end */void smt_agent_task(smc)struct s_smc *smc ;{ smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L, EV_TOKEN(EVENT_SMT,SM_TIMER)) ; DB_SMT("SMT agent task\n",0,0) ;}void smt_please_reconnect(smc,reconn_time)struct s_smc *smc ; /* Pointer to SMT context */int reconn_time ; /* Wait for reconnect time in seconds */{ /* * The please reconnect variable is used as a timer. * It is decremented each time smt_event is called. * This happens every second or when smt_force_irq is called. * Note: smt_force_irq () is called on some packet receives and * when a multicast address is changed. Since nothing * is received during the disconnect and the multicast * address changes can be viewed as not very often and * the timer runs out close to its given value * (reconn_time). */ smc->sm.please_reconnect = reconn_time ;}#ifndef SMT_REAL_TOKEN_CTvoid smt_emulate_token_ct(smc, mac_index)struct s_smc *smc;int mac_index;{ u_long count; u_long time; time = smt_get_time(); count = ((time - smc->sm.last_tok_time[mac_index]) * 100)/TICKS_PER_SECOND; /* * Only when ring is up we will have a token count. The * flag is unfortunatly a single instance value. This * doesn't matter now, because we currently have only * one MAC instance. */ if (smc->hw.mac_ring_is_up){ smc->mib.m[mac_index].fddiMACToken_Ct += count; } /* Remember current time */ smc->sm.last_tok_time[mac_index] = time;}#endif/*ARGSUSED1*/void smt_event(smc,event)struct s_smc *smc ;int event ;{ u_long time ;#ifndef SMT_REAL_TOKEN_CT int i ;#endif if (smc->sm.please_reconnect) { smc->sm.please_reconnect -- ; if (smc->sm.please_reconnect == 0) { /* Counted down */ queue_event(smc,EVENT_ECM,EC_CONNECT) ; } } if (event == SM_FAST) return ; /* * timer for periodic cleanup in driver * reset and start the watchdog (FM2) * ESS timer * SBA timer */ smt_timer_poll(smc) ; smt_start_watchdog(smc) ;#ifndef SLIM_SMT#ifndef BOOT#ifdef ESS ess_timer_poll(smc) ;#endif#endif#ifdef SBA sba_timer_poll(smc) ;#endif smt_srf_event(smc,0,0,0) ;#endif /* no SLIM_SMT */ time = smt_get_time() ; if (time - smc->sm.smt_last_lem >= TICKS_PER_SECOND*8) { /* * Use 8 sec. for the time intervall, it simplifies the * LER estimation. */ struct fddi_mib_m *mib ; u_long upper ; u_long lower ; int cond ; int port; struct s_phy *phy ; /* * calculate LEM bit error rate */ sm_lem_evaluate(smc) ; smc->sm.smt_last_lem = time ; /* * check conditions */#ifndef SLIM_SMT mac_update_counter(smc) ; mib = smc->mib.m ; upper = (mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) + (mib->fddiMACError_Ct - mib->fddiMACOld_Error_Ct) ; lower = (mib->fddiMACFrame_Ct - mib->fddiMACOld_Frame_Ct) + (mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) ; mib->fddiMACFrameErrorRatio = div_ratio(upper,lower) ; cond = ((!mib->fddiMACFrameErrorThreshold && mib->fddiMACError_Ct != mib->fddiMACOld_Error_Ct) || (mib->fddiMACFrameErrorRatio > mib->fddiMACFrameErrorThreshold)) ; if (cond != mib->fddiMACFrameErrorFlag) smt_srf_event(smc,SMT_COND_MAC_FRAME_ERROR, INDEX_MAC,cond) ; upper = (mib->fddiMACNotCopied_Ct - mib->fddiMACOld_NotCopied_Ct) ; lower = upper + (mib->fddiMACCopied_Ct - mib->fddiMACOld_Copied_Ct) ; mib->fddiMACNotCopiedRatio = div_ratio(upper,lower) ; cond = ((!mib->fddiMACNotCopiedThreshold && mib->fddiMACNotCopied_Ct != mib->fddiMACOld_NotCopied_Ct)|| (mib->fddiMACNotCopiedRatio > mib->fddiMACNotCopiedThreshold)) ; if (cond != mib->fddiMACNotCopiedFlag) smt_srf_event(smc,SMT_COND_MAC_NOT_COPIED, INDEX_MAC,cond) ; /* * set old values */ mib->fddiMACOld_Frame_Ct = mib->fddiMACFrame_Ct ; mib->fddiMACOld_Copied_Ct = mib->fddiMACCopied_Ct ; mib->fddiMACOld_Error_Ct = mib->fddiMACError_Ct ; mib->fddiMACOld_Lost_Ct = mib->fddiMACLost_Ct ; mib->fddiMACOld_NotCopied_Ct = mib->fddiMACNotCopied_Ct ; /* * Check port EBError Condition */ for (port = 0; port < NUMPHYS; port ++) { phy = &smc->y[port] ; if (!phy->mib->fddiPORTHardwarePresent) { continue; } cond = (phy->mib->fddiPORTEBError_Ct - phy->mib->fddiPORTOldEBError_Ct > 5) ; /* If ratio is more than 5 in 8 seconds * Set the condition. */ smt_srf_event(smc,SMT_COND_PORT_EB_ERROR, (int) (INDEX_PORT+ phy->np) ,cond) ; /* * set old values */ phy->mib->fddiPORTOldEBError_Ct = phy->mib->fddiPORTEBError_Ct ; }#endif /* no SLIM_SMT */ }#ifndef SLIM_SMT if (time - smc->sm.smt_last_notify >= (u_long) (smc->mib.fddiSMTTT_Notify * TICKS_PER_SECOND) ) { /* * we can either send an announcement or a request * a request will trigger a reply so that we can update * our dna * note: same tid must be used until reply is received */ if (!smc->sm.pend[SMT_TID_NIF]) smc->sm.pend[SMT_TID_NIF] = smt_get_tid(smc) ; smt_send_nif(smc,&fddi_broadcast,FC_SMT_NSA, smc->sm.pend[SMT_TID_NIF], SMT_REQUEST,0) ; smc->sm.smt_last_notify = time ; } /* * check timer */ if (smc->sm.smt_tvu && time - smc->sm.smt_tvu > 228*TICKS_PER_SECOND) { DB_SMT("SMT : UNA expired\n",0,0) ; smc->sm.smt_tvu = 0 ; if (!is_equal(&smc->mib.m[MAC0].fddiMACUpstreamNbr, &SMT_Unknown)){ /* Do not update unknown address */ smc->mib.m[MAC0].fddiMACOldUpstreamNbr= smc->mib.m[MAC0].fddiMACUpstreamNbr ; } smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ; smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ; /* * Make sure the fddiMACUNDA_Flag = FALSE is * included in the SRF so we don't generate * a seperate SRF for the deassertion of this * condition */ update_dac(smc,0) ; smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE, INDEX_MAC,0) ; } if (smc->sm.smt_tvd && time - smc->sm.smt_tvd > 228*TICKS_PER_SECOND) { DB_SMT("SMT : DNA expired\n",0,0) ; smc->sm.smt_tvd = 0 ; if (!is_equal(&smc->mib.m[MAC0].fddiMACDownstreamNbr, &SMT_Unknown)){ /* Do not update unknown address */ smc->mib.m[MAC0].fddiMACOldDownstreamNbr= smc->mib.m[MAC0].fddiMACDownstreamNbr ; } smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ; smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE, INDEX_MAC,0) ; }#endif /* no SLIM_SMT */#ifndef SMT_REAL_TOKEN_CT /* * Token counter emulation section. If hardware supports the token * count, the token counter will be updated in mac_update_counter. */ for (i = MAC0; i < NUMMACS; i++ ){ if (time - smc->sm.last_tok_time[i] > 2*TICKS_PER_SECOND ){ smt_emulate_token_ct( smc, i ); } }#endif smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L, EV_TOKEN(EVENT_SMT,SM_TIMER)) ;}static int div_ratio(upper,lower)u_long upper ;u_long lower ;{ if ((upper<<16L) < upper) upper = 0xffff0000L ; else upper <<= 16L ; if (!lower) return(0) ; return((int)(upper/lower)) ;}#ifndef SLIM_SMT/* * receive packet handler */void smt_received_pack(smc,mb,fs)struct s_smc *smc ;SMbuf *mb ;int fs ; /* frame status */{ struct smt_header *sm ; int local ; int illegal = 0 ; switch (m_fc(mb)) { case FC_SMT_INFO : case FC_SMT_LAN_LOC : case FC_SMT_LOC : case FC_SMT_NSA : break ; default : smt_free_mbuf(smc,mb) ; return ; } smc->mib.m[MAC0].fddiMACSMTCopied_Ct++ ; sm = smtod(mb,struct smt_header *) ; local = ((fs & L_INDICATOR) != 0) ; hwm_conv_can(smc,(char *)sm,12) ; /* check destination address */ if (is_individual(&sm->smt_dest) && !is_my_addr(smc,&sm->smt_dest)) { smt_free_mbuf(smc,mb) ; return ; }#if 0 /* for DUP recognition, do NOT filter them */ /* ignore loop back packets */ if (is_my_addr(smc,&sm->smt_source) && !local) { smt_free_mbuf(smc,mb) ; return ; }#endif smt_swap_para(sm,(int) mb->sm_len,1) ; DB_SMT("SMT : received packet [%s] at 0x%x\n", smt_type_name[m_fc(mb) & 0xf],sm) ; DB_SMT("SMT : version %d, class %s\n",sm->smt_version, smt_class_name[(sm->smt_class>LAST_CLASS)?0 : sm->smt_class]) ;#ifdef SBA /* * check if NSA frame */ if (m_fc(mb) == FC_SMT_NSA && sm->smt_class == SMT_NIF && (sm->smt_type == SMT_ANNOUNCE || sm->smt_type == SMT_REQUEST)) { smc->sba.sm = sm ; sba(smc,NIF) ; }#endif /* * ignore any packet with NSA and A-indicator set */ if ( (fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) { DB_SMT("SMT : ignoring NSA with A-indicator set from %s\n", addr_to_string(&sm->smt_source),0) ; smt_free_mbuf(smc,mb) ; return ; } /* * ignore frames with illegal length */ if (((sm->smt_class == SMT_ECF) && (sm->smt_len > SMT_MAX_ECHO_LEN)) || ((sm->smt_class != SMT_ECF) && (sm->smt_len > SMT_MAX_INFO_LEN))) { smt_free_mbuf(smc,mb) ; return ; } /* * check SMT version */ switch (sm->smt_class) { case SMT_NIF :
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -