void smt_add_para()

in fddi/skfp/pmf.c [542:1062]


void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para,
		  int index, int local)
{
	struct smt_para	*pa ;
	const struct s_p_tab	*pt ;
	struct fddi_mib_m *mib_m = NULL;
	struct fddi_mib_p *mib_p = NULL;
	int		len ;
	int		plen ;
	char		*from ;
	char		*to ;
	const char	*swap ;
	char		c ;
	int		range ;
	char		*mib_addr ;
	int		mac ;
	int		path ;
	int		port ;
	int		sp_len ;

	/*
	 * skip if error
	 */
	if (pcon->pc_err)
		return ;

	/*
	 * actions don't have a value
	 */
	pt = smt_get_ptab(para) ;
	if (pt && pt->p_access == AC_S)
		return ;

	to = (char *) (pcon->pc_p) ;	/* destination pointer */
	len = pcon->pc_len ;		/* free space */
	plen = len ;			/* remember start length */
	pa = (struct smt_para *) to ;	/* type/length pointer */
	to += PARA_LEN ;		/* skip smt_para */
	len -= PARA_LEN ;
	/*
	 * set index if required
	 */
	if (((range = (para & 0xf000)) == 0x2000) ||
		range == 0x3000 || range == 0x4000) {
		if (len < 4)
			goto wrong_error ;
		to[0] = 0 ;
		to[1] = 0 ;
		to[2] = 0 ;
		to[3] = index ;
		len -= 4 ;
		to += 4 ;
	}
	mac = index - INDEX_MAC ;
	path = index - INDEX_PATH ;
	port = index - INDEX_PORT ;
	/*
	 * get pointer to mib
	 */
	switch (range) {
	case 0x1000 :
	default :
		mib_addr = (char *) (&smc->mib) ;
		break ;
	case 0x2000 :
		if (mac < 0 || mac >= NUMMACS) {
			pcon->pc_err = SMT_RDF_NOPARAM ;
			return ;
		}
		mib_addr = (char *) (&smc->mib.m[mac]) ;
		mib_m = (struct fddi_mib_m *) mib_addr ;
		break ;
	case 0x3000 :
		if (path < 0 || path >= NUMPATHS) {
			pcon->pc_err = SMT_RDF_NOPARAM ;
			return ;
		}
		mib_addr = (char *) (&smc->mib.a[path]) ;
		break ;
	case 0x4000 :
		if (port < 0 || port >= smt_mib_phys(smc)) {
			pcon->pc_err = SMT_RDF_NOPARAM ;
			return ;
		}
		mib_addr = (char *) (&smc->mib.p[port_to_mib(smc,port)]) ;
		mib_p = (struct fddi_mib_p *) mib_addr ;
		break ;
	}
	/*
	 * check special paras
	 */
	swap = NULL;
	switch (para) {
	case SMT_P10F0 :
	case SMT_P10F1 :
#ifdef	ESS
	case SMT_P10F2 :
	case SMT_P10F3 :
	case SMT_P10F4 :
	case SMT_P10F5 :
	case SMT_P10F6 :
	case SMT_P10F7 :
#endif
#ifdef	SBA
	case SMT_P10F8 :
	case SMT_P10F9 :
#endif
	case SMT_P20F1 :
		if (!local) {
			pcon->pc_err = SMT_RDF_NOPARAM ;
			return ;
		}
		break ;
	case SMT_P2034 :
	case SMT_P2046 :
	case SMT_P2047 :
	case SMT_P204A :
	case SMT_P2051 :
	case SMT_P2052 :
		mac_update_counter(smc) ;
		break ;
	case SMT_P4022:
		mib_p->fddiPORTPC_LS = LS2MIB(
			sm_pm_get_ls(smc,port_to_mib(smc,port))) ;
		break ;
	case SMT_P_REASON :
		*(u32 *)to = 0 ;
		sp_len = 4 ;
		goto sp_done ;
	case SMT_P1033 :			/* time stamp */
		smt_set_timestamp(smc,smc->mib.fddiSMTTimeStamp) ;
		break ;

	case SMT_P1020:				/* port indexes */
#if	NUMPHYS == 12
		swap = "IIIIIIIIIIII" ;
#else
#if	NUMPHYS == 2
		if (smc->s.sas == SMT_SAS)
			swap = "I" ;
		else
			swap = "II" ;
#else
#if	NUMPHYS == 24
		swap = "IIIIIIIIIIIIIIIIIIIIIIII" ;
#else
	????
#endif
#endif
#endif
		break ;
	case SMT_P3212 :
		{
			sp_len = cem_build_path(smc,to,path) ;
			goto sp_done ;
		}
	case SMT_P1048 :		/* peer wrap condition */
		{
			struct smt_p_1048	*sp ;
			sp = (struct smt_p_1048 *) to ;
			sp->p1048_flag = smc->mib.fddiSMTPeerWrapFlag ;
			sp->p1048_cf_state = smc->mib.fddiSMTCF_State ;
			sp_len = sizeof(struct smt_p_1048) ;
			goto sp_done ;
		}
	case SMT_P208C :
		{
			struct smt_p_208c	*sp ;
			sp = (struct smt_p_208c *) to ;
			sp->p208c_flag =
				smc->mib.m[MAC0].fddiMACDuplicateAddressCond ;
			sp->p208c_dupcondition =
				(mib_m->fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0) |
				(mib_m->fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0);
			sp->p208c_fddilong =
				mib_m->fddiMACSMTAddress ;
			sp->p208c_fddiunalong =
				mib_m->fddiMACUpstreamNbr ;
			sp->p208c_pad = 0 ;
			sp_len = sizeof(struct smt_p_208c) ;
			goto sp_done ;
		}
	case SMT_P208D :		/* frame error condition */
		{
			struct smt_p_208d	*sp ;
			sp = (struct smt_p_208d *) to ;
			sp->p208d_flag =
				mib_m->fddiMACFrameErrorFlag ;
			sp->p208d_frame_ct =
				mib_m->fddiMACFrame_Ct ;
			sp->p208d_error_ct =
				mib_m->fddiMACError_Ct ;
			sp->p208d_lost_ct =
				mib_m->fddiMACLost_Ct ;
			sp->p208d_ratio =
				mib_m->fddiMACFrameErrorRatio ;
			sp_len = sizeof(struct smt_p_208d) ;
			goto sp_done ;
		}
	case SMT_P208E :		/* not copied condition */
		{
			struct smt_p_208e	*sp ;
			sp = (struct smt_p_208e *) to ;
			sp->p208e_flag =
				mib_m->fddiMACNotCopiedFlag ;
			sp->p208e_not_copied =
				mib_m->fddiMACNotCopied_Ct ;
			sp->p208e_copied =
				mib_m->fddiMACCopied_Ct ;
			sp->p208e_not_copied_ratio =
				mib_m->fddiMACNotCopiedRatio ;
			sp_len = sizeof(struct smt_p_208e) ;
			goto sp_done ;
		}
	case SMT_P208F :	/* neighbor change event */
		{
			struct smt_p_208f	*sp ;
			sp = (struct smt_p_208f *) to ;
			sp->p208f_multiple =
				mib_m->fddiMACMultiple_N ;
			sp->p208f_nacondition =
				mib_m->fddiMACDuplicateAddressCond ;
			sp->p208f_old_una =
				mib_m->fddiMACOldUpstreamNbr ;
			sp->p208f_new_una =
				mib_m->fddiMACUpstreamNbr ;
			sp->p208f_old_dna =
				mib_m->fddiMACOldDownstreamNbr ;
			sp->p208f_new_dna =
				mib_m->fddiMACDownstreamNbr ;
			sp->p208f_curren_path =
				mib_m->fddiMACCurrentPath ;
			sp->p208f_smt_address =
				mib_m->fddiMACSMTAddress ;
			sp_len = sizeof(struct smt_p_208f) ;
			goto sp_done ;
		}
	case SMT_P2090 :
		{
			struct smt_p_2090	*sp ;
			sp = (struct smt_p_2090 *) to ;
			sp->p2090_multiple =
				mib_m->fddiMACMultiple_P ;
			sp->p2090_availablepaths =
				mib_m->fddiMACAvailablePaths ;
			sp->p2090_currentpath =
				mib_m->fddiMACCurrentPath ;
			sp->p2090_requestedpaths =
				mib_m->fddiMACRequestedPaths ;
			sp_len = sizeof(struct smt_p_2090) ;
			goto sp_done ;
		}
	case SMT_P4050 :
		{
			struct smt_p_4050	*sp ;
			sp = (struct smt_p_4050 *) to ;
			sp->p4050_flag =
				mib_p->fddiPORTLerFlag ;
			sp->p4050_pad = 0 ;
			sp->p4050_cutoff =
				mib_p->fddiPORTLer_Cutoff ;
			sp->p4050_alarm =
				mib_p->fddiPORTLer_Alarm ;
			sp->p4050_estimate =
				mib_p->fddiPORTLer_Estimate ;
			sp->p4050_reject_ct =
				mib_p->fddiPORTLem_Reject_Ct ;
			sp->p4050_ct =
				mib_p->fddiPORTLem_Ct ;
			sp_len = sizeof(struct smt_p_4050) ;
			goto sp_done ;
		}

	case SMT_P4051 :
		{
			struct smt_p_4051	*sp ;
			sp = (struct smt_p_4051 *) to ;
			sp->p4051_multiple =
				mib_p->fddiPORTMultiple_U ;
			sp->p4051_porttype =
				mib_p->fddiPORTMy_Type ;
			sp->p4051_connectstate =
				mib_p->fddiPORTConnectState ;
			sp->p4051_pc_neighbor =
				mib_p->fddiPORTNeighborType ;
			sp->p4051_pc_withhold =
				mib_p->fddiPORTPC_Withhold ;
			sp_len = sizeof(struct smt_p_4051) ;
			goto sp_done ;
		}
	case SMT_P4052 :
		{
			struct smt_p_4052	*sp ;
			sp = (struct smt_p_4052 *) to ;
			sp->p4052_flag =
				mib_p->fddiPORTEB_Condition ;
			sp->p4052_eberrorcount =
				mib_p->fddiPORTEBError_Ct ;
			sp_len = sizeof(struct smt_p_4052) ;
			goto sp_done ;
		}
	case SMT_P4053 :
		{
			struct smt_p_4053	*sp ;
			sp = (struct smt_p_4053 *) to ;
			sp->p4053_multiple =
				mib_p->fddiPORTMultiple_P ;
			sp->p4053_availablepaths =
				mib_p->fddiPORTAvailablePaths ;
			sp->p4053_currentpath =
				mib_p->fddiPORTCurrentPath ;
			memcpy(	(char *) &sp->p4053_requestedpaths,
				(char *) mib_p->fddiPORTRequestedPaths,4) ;
			sp->p4053_mytype =
				mib_p->fddiPORTMy_Type ;
			sp->p4053_neighbortype =
				mib_p->fddiPORTNeighborType ;
			sp_len = sizeof(struct smt_p_4053) ;
			goto sp_done ;
		}
	default :
		break ;
	}
	/*
	 * in table ?
	 */
	if (!pt) {
		pcon->pc_err = (para & 0xff00) ? SMT_RDF_NOPARAM :
						SMT_RDF_ILLEGAL ;
		return ;
	}
	/*
	 * check access rights
	 */
	switch (pt->p_access) {
	case AC_G :
	case AC_GR :
		break ;
	default :
		pcon->pc_err = SMT_RDF_ILLEGAL ;
		return ;
	}
	from = mib_addr + pt->p_offset ;
	if (!swap)
		swap = pt->p_swap ;		/* pointer to swap string */

	/*
	 * copy values
	 */
	while ((c = *swap++)) {
		switch(c) {
		case 'b' :
		case 'w' :
		case 'l' :
			break ;
		case 'S' :
		case 'E' :
		case 'R' :
		case 'r' :
			if (len < 4)
				goto len_error ;
			to[0] = 0 ;
			to[1] = 0 ;
#ifdef	LITTLE_ENDIAN
			if (c == 'r') {
				to[2] = *from++ ;
				to[3] = *from++ ;
			}
			else {
				to[3] = *from++ ;
				to[2] = *from++ ;
			}
#else
			to[2] = *from++ ;
			to[3] = *from++ ;
#endif
			to += 4 ;
			len -= 4 ;
			break ;
		case 'I' :		/* for SET of port indexes */
			if (len < 2)
				goto len_error ;
#ifdef	LITTLE_ENDIAN
			to[1] = *from++ ;
			to[0] = *from++ ;
#else
			to[0] = *from++ ;
			to[1] = *from++ ;
#endif
			to += 2 ;
			len -= 2 ;
			break ;
		case 'F' :
		case 'B' :
			if (len < 4)
				goto len_error ;
			len -= 4 ;
			to[0] = 0 ;
			to[1] = 0 ;
			to[2] = 0 ;
			to[3] = *from++ ;
			to += 4 ;
			break ;
		case 'C' :
		case 'T' :
		case 'L' :
			if (len < 4)
				goto len_error ;
#ifdef	LITTLE_ENDIAN
			to[3] = *from++ ;
			to[2] = *from++ ;
			to[1] = *from++ ;
			to[0] = *from++ ;
#else
			to[0] = *from++ ;
			to[1] = *from++ ;
			to[2] = *from++ ;
			to[3] = *from++ ;
#endif
			len -= 4 ;
			to += 4 ;
			break ;
		case '2' :		/* PortMacIndicated */
			if (len < 4)
				goto len_error ;
			to[0] = 0 ;
			to[1] = 0 ;
			to[2] = *from++ ;
			to[3] = *from++ ;
			len -= 4 ;
			to += 4 ;
			break ;
		case '4' :
			if (len < 4)
				goto len_error ;
			to[0] = *from++ ;
			to[1] = *from++ ;
			to[2] = *from++ ;
			to[3] = *from++ ;
			len -= 4 ;
			to += 4 ;
			break ;
		case 'A' :
			if (len < 8)
				goto len_error ;
			to[0] = 0 ;
			to[1] = 0 ;
			memcpy((char *) to+2,(char *) from,6) ;
			to += 8 ;
			from += 8 ;
			len -= 8 ;
			break ;
		case '8' :
			if (len < 8)
				goto len_error ;
			memcpy((char *) to,(char *) from,8) ;
			to += 8 ;
			from += 8 ;
			len -= 8 ;
			break ;
		case 'D' :
			if (len < 32)
				goto len_error ;
			memcpy((char *) to,(char *) from,32) ;
			to += 32 ;
			from += 32 ;
			len -= 32 ;
			break ;
		case 'P' :		/* timestamp is NOT swapped */
			if (len < 8)
				goto len_error ;
			to[0] = *from++ ;
			to[1] = *from++ ;
			to[2] = *from++ ;
			to[3] = *from++ ;
			to[4] = *from++ ;
			to[5] = *from++ ;
			to[6] = *from++ ;
			to[7] = *from++ ;
			to += 8 ;
			len -= 8 ;
			break ;
		default :
			SMT_PANIC(smc,SMT_E0119, SMT_E0119_MSG) ;
			break ;
		}
	}

done:
	/*
	 * make it even (in case of 'I' encoding)
	 * note: len is DECREMENTED
	 */
	if (len & 3) {
		to[0] = 0 ;
		to[1] = 0 ;
		to += 4 - (len & 3 ) ;
		len = len & ~ 3 ;
	}

	/* set type and length */
	pa->p_type = para ;
	pa->p_len = plen - len - PARA_LEN ;
	/* return values */
	pcon->pc_p = (void *) to ;
	pcon->pc_len = len ;
	return ;

sp_done:
	len -= sp_len ;
	to += sp_len ;
	goto done ;

len_error:
	/* parameter does not fit in frame */
	pcon->pc_err = SMT_RDF_TOOLONG ;
	return ;

wrong_error:
	pcon->pc_err = SMT_RDF_LENGTH ;
}