void smt_send_frame(struct s_smc *smc, SMbuf *mb, int fc, int local) { struct smt_header *sm ; if (!smc->r.sm_ma_avail && !local) { smt_free_mbuf(smc,mb) ; return ; } sm = smtod(mb,struct smt_header *) ; sm->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ; sm->smt_sid = smc->mib.fddiSMTStationId ; smt_swap_para(sm,(int) mb->sm_len,0) ; hwm_conv_can(smc,(char *)sm,12) ; smc->mib.m[MAC0].fddiMACSMTTransmit_Ct++ ; smt_send_mbuf(smc,mb,local ? FC_SMT_LOC : fc) ; }
static void smt_send_rdf(struct s_smc *smc, SMbuf *rej, int fc, int reason, int local) { SMbuf *mb ; struct smt_header *sm ; struct smt_rdf *rdf ; int len ; int frame_len ; sm = smtod(rej,struct smt_header *) ; if (sm->smt_type != SMT_REQUEST) return ; DB_SMT("SMT: sending RDF to %s,reason = 0x%x\n", addr_to_string(&sm->smt_source),reason) ; frame_len = rej->sm_len ; if (!(mb=smt_build_frame(smc,SMT_RDF,SMT_REPLY,sizeof(struct smt_rdf)))) return ; rdf = smtod(mb,struct smt_rdf *) ; rdf->smt.smt_tid = sm->smt_tid ; rdf->smt.smt_dest = sm->smt_source ; rdf->reason.para.p_type = SMT_P_REASON ; rdf->reason.para.p_len = sizeof(struct smt_p_reason) - PARA_LEN ; rdf->reason.rdf_reason = reason ; rdf->version.para.p_type = SMT_P_VERSION ; rdf->version.para.p_len = sizeof(struct smt_p_version) - PARA_LEN ; rdf->version.v_pad = 0 ; rdf->version.v_n = 1 ; rdf->version.v_index = 1 ; rdf->version.v_version[0] = SMT_VID_2 ; rdf->version.v_pad2 = 0 ; if ((unsigned) frame_len <= SMT_MAX_INFO_LEN - sizeof(*rdf) + 2*sizeof(struct smt_header)) len = frame_len ; else len = SMT_MAX_INFO_LEN - sizeof(*rdf) + 2*sizeof(struct smt_header) ; len &= ~3 ; rdf->refused.para.p_type = SMT_P_REFUSED ; rdf->refused.para.p_len = len + 4 ; rdf->refused.ref_fc = fc ; smt_swap_para(sm,frame_len,0) ; memcpy((char *) &rdf->refused.ref_header,(char *) sm,len) ; len -= sizeof(struct smt_header) ; mb->sm_len += len ; rdf->smt.smt_len += len ; dump_smt(smc,(struct smt_header *)rdf,"RDF") ; smc->mib.priv.fddiPRIVRDF_Tx++ ; smt_send_frame(smc,mb,FC_SMT_INFO,local) ; }
void smt_received_pack(struct s_smc *smc, SMbuf *mb, int fs) { 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) ; if (is_individual(&sm->smt_dest) && !is_my_addr(smc,&sm->smt_dest)) { smt_free_mbuf(smc,mb) ; return ; } #if 0 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 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 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 ; } 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 ; } switch (sm->smt_class) { case SMT_NIF : case SMT_SIF_CONFIG : case SMT_SIF_OPER : case SMT_ECF : if (sm->smt_version != SMT_VID) illegal = 1; break ; default : if (sm->smt_version != SMT_VID_2) illegal = 1; break ; } if (illegal) { DB_SMT("SMT : version = %d, dest = %s\n", sm->smt_version,addr_to_string(&sm->smt_source)) ; smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_VERSION,local) ; smt_free_mbuf(smc,mb) ; return ; } if ((sm->smt_len > mb->sm_len - sizeof(struct smt_header)) || ((sm->smt_len & 3) && (sm->smt_class != SMT_ECF))) { DB_SMT("SMT: info length error, len = %d\n",sm->smt_len,0) ; smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH,local) ; smt_free_mbuf(smc,mb) ; return ; } switch (sm->smt_class) { case SMT_NIF : if (smt_check_para(smc,sm,plist_nif)) { DB_SMT("SMT: NIF with para problem, ignoring\n",0,0) ; break ; } ; switch (sm->smt_type) { case SMT_ANNOUNCE : case SMT_REQUEST : if (!(fs & C_INDICATOR) && m_fc(mb) == FC_SMT_NSA && is_broadcast(&sm->smt_dest)) { struct smt_p_state *st ; if (!is_equal( &smc->mib.m[MAC0].fddiMACUpstreamNbr, &sm->smt_source)) { DB_SMT("SMT : updated my UNA = %s\n", addr_to_string(&sm->smt_source),0) ; if (!is_equal(&smc->mib.m[MAC0]. fddiMACUpstreamNbr,&SMT_Unknown)){ smc->mib.m[MAC0].fddiMACOldUpstreamNbr= smc->mib.m[MAC0].fddiMACUpstreamNbr ; } smc->mib.m[MAC0].fddiMACUpstreamNbr = sm->smt_source ; smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE, INDEX_MAC,0) ; smt_echo_test(smc,0) ; } smc->sm.smt_tvu = smt_get_time() ; st = (struct smt_p_state *) sm_to_para(smc,sm,SMT_P_STATE) ; if (st) { smc->mib.m[MAC0].fddiMACUNDA_Flag = (st->st_dupl_addr & SMT_ST_MY_DUPA) ? TRUE : FALSE ; update_dac(smc,1) ; } } if ((sm->smt_type == SMT_REQUEST) && is_individual(&sm->smt_source) && ((!(fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) || (m_fc(mb) != FC_SMT_NSA))) { DB_SMT("SMT : replying to NIF request %s\n", addr_to_string(&sm->smt_source),0) ; smt_send_nif(smc,&sm->smt_source, FC_SMT_INFO, sm->smt_tid, SMT_REPLY,local) ; } break ; case SMT_REPLY : DB_SMT("SMT : received NIF response from %s\n", addr_to_string(&sm->smt_source),0) ; if (fs & A_INDICATOR) { smc->sm.pend[SMT_TID_NIF] = 0 ; DB_SMT("SMT : duplicate address\n",0,0) ; smc->mib.m[MAC0].fddiMACDupAddressTest = DA_FAILED ; smc->r.dup_addr_test = DA_FAILED ; queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ; smc->mib.m[MAC0].fddiMACDA_Flag = TRUE ; update_dac(smc,1) ; break ; } if (sm->smt_tid == smc->sm.pend[SMT_TID_NIF]) { smc->sm.pend[SMT_TID_NIF] = 0 ; if (!is_equal( &smc->mib.m[MAC0].fddiMACDownstreamNbr, &sm->smt_source)) { DB_SMT("SMT : updated my DNA\n",0,0) ; if (!is_equal(&smc->mib.m[MAC0]. fddiMACDownstreamNbr, &SMT_Unknown)){ smc->mib.m[MAC0].fddiMACOldDownstreamNbr = smc->mib.m[MAC0].fddiMACDownstreamNbr ; } smc->mib.m[MAC0].fddiMACDownstreamNbr = sm->smt_source ; smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE, INDEX_MAC,0) ; smt_echo_test(smc,1) ; } smc->mib.m[MAC0].fddiMACDA_Flag = FALSE ; update_dac(smc,1) ; smc->sm.smt_tvd = smt_get_time() ; smc->mib.m[MAC0].fddiMACDupAddressTest = DA_PASSED ; if (smc->r.dup_addr_test != DA_PASSED) { smc->r.dup_addr_test = DA_PASSED ; queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ; } } else if (sm->smt_tid == smc->sm.pend[SMT_TID_NIF_TEST]) { DB_SMT("SMT : NIF test TID ok\n",0,0) ; } else { DB_SMT("SMT : expected TID %lx, got %lx\n", smc->sm.pend[SMT_TID_NIF],sm->smt_tid) ; } break ; default : illegal = 2 ; break ; } break ; case SMT_SIF_CONFIG : if (sm->smt_type != SMT_REQUEST) break ; DB_SMT("SMT : replying to SIF Config request from %s\n", addr_to_string(&sm->smt_source),0) ; smt_send_sif_config(smc,&sm->smt_source,sm->smt_tid,local) ; break ; case SMT_SIF_OPER : if (sm->smt_type != SMT_REQUEST) break ; DB_SMT("SMT : replying to SIF Operation request from %s\n", addr_to_string(&sm->smt_source),0) ; smt_send_sif_operation(smc,&sm->smt_source,sm->smt_tid,local) ; break ; case SMT_ECF : switch (sm->smt_type) { case SMT_REPLY : smc->mib.priv.fddiPRIVECF_Reply_Rx++ ; DB_SMT("SMT: received ECF reply from %s\n", addr_to_string(&sm->smt_source),0) ; if (sm_to_para(smc,sm,SMT_P_ECHODATA) == NULL) { DB_SMT("SMT: ECHODATA missing\n",0,0) ; break ; } if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF]) { DB_SMT("SMT : ECF test TID ok\n",0,0) ; } else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_UNA]) { DB_SMT("SMT : ECF test UNA ok\n",0,0) ; } else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_DNA]) { DB_SMT("SMT : ECF test DNA ok\n",0,0) ; } else { DB_SMT("SMT : expected TID %lx, got %lx\n", smc->sm.pend[SMT_TID_ECF], sm->smt_tid) ; } break ; case SMT_REQUEST : smc->mib.priv.fddiPRIVECF_Req_Rx++ ; { if (sm->smt_len && !sm_to_para(smc,sm,SMT_P_ECHODATA)) { DB_SMT("SMT: ECF with para problem,sending RDF\n",0,0) ; smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH, local) ; break ; } DB_SMT("SMT - sending ECF reply to %s\n", addr_to_string(&sm->smt_source),0) ; sm->smt_dest = sm->smt_source ; sm->smt_type = SMT_REPLY ; dump_smt(smc,sm,"ECF REPLY") ; smc->mib.priv.fddiPRIVECF_Reply_Tx++ ; smt_send_frame(smc,mb,FC_SMT_INFO,local) ; return ; } default : illegal = 1 ; break ; } break ; #ifndef BOOT case SMT_RAF : #ifdef ESS DB_ESSN(2,"ESS: RAF frame received\n",0,0) ; fs = ess_raf_received_pack(smc,mb,sm,fs) ; #endif #ifdef SBA DB_SBAN(2,"SBA: RAF frame received\n",0,0) ; sba_raf_received_pack(smc,sm,fs) ; #endif break ; case SMT_RDF : smc->mib.priv.fddiPRIVRDF_Rx++ ; break ; case SMT_ESF : if (sm->smt_type == SMT_REQUEST) { DB_SMT("SMT - received ESF, sending RDF\n",0,0) ; smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ; } break ; case SMT_PMF_GET : case SMT_PMF_SET : if (sm->smt_type != SMT_REQUEST) break ; if (sm->smt_class == SMT_PMF_GET) smc->mib.priv.fddiPRIVPMF_Get_Rx++ ; else smc->mib.priv.fddiPRIVPMF_Set_Rx++ ; if ((sm->smt_class == SMT_PMF_SET) && !is_individual(&sm->smt_dest)) { DB_SMT("SMT: ignoring PMF-SET with I/G set\n",0,0) ; break ; } smt_pmf_received_pack(smc,mb, local) ; break ; case SMT_SRF : dump_smt(smc,sm,"SRF received") ; break ; default : if (sm->smt_type != SMT_REQUEST) break ; DB_SMT("SMT : class = %d, send RDF to %s\n", sm->smt_class, addr_to_string(&sm->smt_source)) ; smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ; break ; #endif } if (illegal) { DB_SMT("SMT: discarding invalid frame, reason = %d\n", illegal,0) ; } smt_free_mbuf(smc,mb) ; }
static void smt_send_rdf(struct s_smc *smc, SMbuf *rej, int fc, int reason, int local) /* SMbuf *rej; mbuf of offending frame */ /* int fc; FC of denied frame */ /* int reason; reason code */ { SMbuf *mb ; struct smt_header *sm ; /* header of offending frame */ struct smt_rdf *rdf ; int len ; int frame_len ; sm = smtod(rej,struct smt_header *) ; if (sm->smt_type != SMT_REQUEST) return ; DB_SMT("SMT: sending RDF to %s,reason = 0x%x\n", addr_to_string(&sm->smt_source),reason) ; /* * note: get framelength from MAC length, NOT from SMT header * smt header length is included in sm_len */ frame_len = rej->sm_len ; if (!(mb=smt_build_frame(smc,SMT_RDF,SMT_REPLY,sizeof(struct smt_rdf)))) return ; rdf = smtod(mb,struct smt_rdf *) ; rdf->smt.smt_tid = sm->smt_tid ; /* use TID from sm */ rdf->smt.smt_dest = sm->smt_source ; /* set dest = source */ /* set P12 */ rdf->reason.para.p_type = SMT_P_REASON ; rdf->reason.para.p_len = sizeof(struct smt_p_reason) - PARA_LEN ; rdf->reason.rdf_reason = reason ; /* set P14 */ rdf->version.para.p_type = SMT_P_VERSION ; rdf->version.para.p_len = sizeof(struct smt_p_version) - PARA_LEN ; rdf->version.v_pad = 0 ; rdf->version.v_n = 1 ; rdf->version.v_index = 1 ; rdf->version.v_version[0] = SMT_VID_2 ; rdf->version.v_pad2 = 0 ; /* set P13 */ if ((unsigned) frame_len <= SMT_MAX_INFO_LEN - sizeof(*rdf) + 2*sizeof(struct smt_header)) len = frame_len ; else len = SMT_MAX_INFO_LEN - sizeof(*rdf) + 2*sizeof(struct smt_header) ; /* make length multiple of 4 */ len &= ~3 ; rdf->refused.para.p_type = SMT_P_REFUSED ; /* length of para is smt_frame + ref_fc */ rdf->refused.para.p_len = len + 4 ; rdf->refused.ref_fc = fc ; /* swap it back */ smt_swap_para(sm,frame_len,0) ; memcpy((char *) &rdf->refused.ref_header,(char *) sm,len) ; len -= sizeof(struct smt_header) ; mb->sm_len += len ; rdf->smt.smt_len += len ; dump_smt(smc,(struct smt_header *)rdf,"RDF") ; smc->mib.priv.fddiPRIVRDF_Tx++ ; smt_send_frame(smc,mb,FC_SMT_INFO,local) ; }