1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /******************************************************************************
3  *
4  *	(C)Copyright 1998,1999 SysKonnect,
5  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
6  *
7  *	See the file "skfddi.c" for further information.
8  *
9  *	The information in this file is provided "AS IS" without warranty.
10  *
11  ******************************************************************************/
12 
13 /*
14 	SMT 7.2 Status Response Frame Implementation
15 	SRF state machine and frame generation
16 */
17 
18 #include "h/types.h"
19 #include "h/fddi.h"
20 #include "h/smc.h"
21 #include "h/smt_p.h"
22 
23 #define KERNEL
24 #include "h/smtstate.h"
25 
26 #ifndef	SLIM_SMT
27 #ifndef	BOOT
28 
29 /*
30  * function declarations
31  */
32 static void clear_all_rep(struct s_smc *smc);
33 static void clear_reported(struct s_smc *smc);
34 static void smt_send_srf(struct s_smc *smc);
35 static struct s_srf_evc *smt_get_evc(struct s_smc *smc, int code, int index);
36 
37 #define MAX_EVCS	ARRAY_SIZE(smc->evcs)
38 
39 struct evc_init {
40 	u_char code ;
41 	u_char index ;
42 	u_char n ;
43 	u_short	para ;
44 }  ;
45 
46 static const struct evc_init evc_inits[] = {
47 	{ SMT_COND_SMT_PEER_WRAP,		0,1,SMT_P1048	} ,
48 
49 	{ SMT_COND_MAC_DUP_ADDR,		INDEX_MAC, NUMMACS,SMT_P208C } ,
50 	{ SMT_COND_MAC_FRAME_ERROR,		INDEX_MAC, NUMMACS,SMT_P208D } ,
51 	{ SMT_COND_MAC_NOT_COPIED,		INDEX_MAC, NUMMACS,SMT_P208E } ,
52 	{ SMT_EVENT_MAC_NEIGHBOR_CHANGE,	INDEX_MAC, NUMMACS,SMT_P208F } ,
53 	{ SMT_EVENT_MAC_PATH_CHANGE,		INDEX_MAC, NUMMACS,SMT_P2090 } ,
54 
55 	{ SMT_COND_PORT_LER,			INDEX_PORT,NUMPHYS,SMT_P4050 } ,
56 	{ SMT_COND_PORT_EB_ERROR,		INDEX_PORT,NUMPHYS,SMT_P4052 } ,
57 	{ SMT_EVENT_PORT_CONNECTION,		INDEX_PORT,NUMPHYS,SMT_P4051 } ,
58 	{ SMT_EVENT_PORT_PATH_CHANGE,		INDEX_PORT,NUMPHYS,SMT_P4053 } ,
59 } ;
60 
61 #define MAX_INIT_EVC	ARRAY_SIZE(evc_inits)
62 
smt_init_evc(struct s_smc * smc)63 void smt_init_evc(struct s_smc *smc)
64 {
65 	struct s_srf_evc	*evc ;
66 	const struct evc_init 	*init ;
67 	unsigned int		i ;
68 	int			index ;
69 	int			offset ;
70 
71 	static u_char		fail_safe = FALSE ;
72 
73 	memset((char *)smc->evcs,0,sizeof(smc->evcs)) ;
74 
75 	evc = smc->evcs ;
76 	init = evc_inits ;
77 
78 	for (i = 0 ; i < MAX_INIT_EVC ; i++) {
79 		for (index = 0 ; index < init->n ; index++) {
80 			evc->evc_code = init->code ;
81 			evc->evc_para = init->para ;
82 			evc->evc_index = init->index + index ;
83 #ifndef	DEBUG
84 			evc->evc_multiple = &fail_safe ;
85 			evc->evc_cond_state = &fail_safe ;
86 #endif
87 			evc++ ;
88 		}
89 		init++ ;
90 	}
91 
92 	if ((unsigned int) (evc - smc->evcs) > MAX_EVCS) {
93 		SMT_PANIC(smc,SMT_E0127, SMT_E0127_MSG) ;
94 	}
95 
96 	/*
97 	 * conditions
98 	 */
99 	smc->evcs[0].evc_cond_state = &smc->mib.fddiSMTPeerWrapFlag ;
100 	smc->evcs[1].evc_cond_state =
101 		&smc->mib.m[MAC0].fddiMACDuplicateAddressCond ;
102 	smc->evcs[2].evc_cond_state =
103 		&smc->mib.m[MAC0].fddiMACFrameErrorFlag ;
104 	smc->evcs[3].evc_cond_state =
105 		&smc->mib.m[MAC0].fddiMACNotCopiedFlag ;
106 
107 	/*
108 	 * events
109 	 */
110 	smc->evcs[4].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_N ;
111 	smc->evcs[5].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_P ;
112 
113 	offset = 6 ;
114 	for (i = 0 ; i < NUMPHYS ; i++) {
115 		/*
116 		 * conditions
117 		 */
118 		smc->evcs[offset + 0*NUMPHYS].evc_cond_state =
119 			&smc->mib.p[i].fddiPORTLerFlag ;
120 		smc->evcs[offset + 1*NUMPHYS].evc_cond_state =
121 			&smc->mib.p[i].fddiPORTEB_Condition ;
122 
123 		/*
124 		 * events
125 		 */
126 		smc->evcs[offset + 2*NUMPHYS].evc_multiple =
127 			&smc->mib.p[i].fddiPORTMultiple_U ;
128 		smc->evcs[offset + 3*NUMPHYS].evc_multiple =
129 			&smc->mib.p[i].fddiPORTMultiple_P ;
130 		offset++ ;
131 	}
132 #ifdef	DEBUG
133 	for (i = 0, evc = smc->evcs ; i < MAX_EVCS ; i++, evc++) {
134 		if (SMT_IS_CONDITION(evc->evc_code)) {
135 			if (!evc->evc_cond_state) {
136 				SMT_PANIC(smc,SMT_E0128, SMT_E0128_MSG) ;
137 			}
138 			evc->evc_multiple = &fail_safe ;
139 		}
140 		else {
141 			if (!evc->evc_multiple) {
142 				SMT_PANIC(smc,SMT_E0129, SMT_E0129_MSG) ;
143 			}
144 			evc->evc_cond_state = &fail_safe ;
145 		}
146 	}
147 #endif
148 	smc->srf.TSR = smt_get_time() ;
149 	smc->srf.sr_state = SR0_WAIT ;
150 }
151 
smt_get_evc(struct s_smc * smc,int code,int index)152 static struct s_srf_evc *smt_get_evc(struct s_smc *smc, int code, int index)
153 {
154 	unsigned int		i ;
155 	struct s_srf_evc	*evc ;
156 
157 	for (i = 0, evc = smc->evcs ; i < MAX_EVCS ; i++, evc++) {
158 		if (evc->evc_code == code && evc->evc_index == index)
159 			return evc;
160 	}
161 	return NULL;
162 }
163 
164 #define THRESHOLD_2	(2*TICKS_PER_SECOND)
165 #define THRESHOLD_32	(32*TICKS_PER_SECOND)
166 
167 static const char * const srf_names[] = {
168 	"None","MACPathChangeEvent",	"MACNeighborChangeEvent",
169 	"PORTPathChangeEvent",		"PORTUndesiredConnectionAttemptEvent",
170 	"SMTPeerWrapCondition",		"SMTHoldCondition",
171 	"MACFrameErrorCondition",	"MACDuplicateAddressCondition",
172 	"MACNotCopiedCondition",	"PORTEBErrorCondition",
173 	"PORTLerCondition"
174 } ;
175 
smt_srf_event(struct s_smc * smc,int code,int index,int cond)176 void smt_srf_event(struct s_smc *smc, int code, int index, int cond)
177 {
178 	struct s_srf_evc	*evc ;
179 	int			cond_asserted = 0 ;
180 	int			cond_deasserted = 0 ;
181 	int			event_occurred = 0 ;
182 	int			tsr ;
183 	int			T_Limit = 2*TICKS_PER_SECOND ;
184 
185 	if (code == SMT_COND_MAC_DUP_ADDR && cond) {
186 		RS_SET(smc,RS_DUPADDR) ;
187 	}
188 
189 	if (code) {
190 		DB_SMT("SRF: %s index %d", srf_names[code], index);
191 
192 		if (!(evc = smt_get_evc(smc,code,index))) {
193 			DB_SMT("SRF : smt_get_evc() failed");
194 			return ;
195 		}
196 		/*
197 		 * ignore condition if no change
198 		 */
199 		if (SMT_IS_CONDITION(code)) {
200 			if (*evc->evc_cond_state == cond)
201 				return ;
202 		}
203 
204 		/*
205 		 * set transition time stamp
206 		 */
207 		smt_set_timestamp(smc,smc->mib.fddiSMTTransitionTimeStamp) ;
208 		if (SMT_IS_CONDITION(code)) {
209 			DB_SMT("SRF: condition is %s", cond ? "ON" : "OFF");
210 			if (cond) {
211 				*evc->evc_cond_state = TRUE ;
212 				evc->evc_rep_required = TRUE ;
213 				smc->srf.any_report = TRUE ;
214 				cond_asserted = TRUE ;
215 			}
216 			else {
217 				*evc->evc_cond_state = FALSE ;
218 				cond_deasserted = TRUE ;
219 			}
220 		}
221 		else {
222 			if (evc->evc_rep_required) {
223 				*evc->evc_multiple  = TRUE ;
224 			}
225 			else {
226 				evc->evc_rep_required = TRUE ;
227 				*evc->evc_multiple  = FALSE ;
228 			}
229 			smc->srf.any_report = TRUE ;
230 			event_occurred = TRUE ;
231 		}
232 #ifdef	FDDI_MIB
233 		snmp_srf_event(smc,evc) ;
234 #endif	/* FDDI_MIB */
235 	}
236 	tsr = smt_get_time() - smc->srf.TSR ;
237 
238 	switch (smc->srf.sr_state) {
239 	case SR0_WAIT :
240 		/* SR01a */
241 		if (cond_asserted && tsr < T_Limit) {
242 			smc->srf.SRThreshold = THRESHOLD_2 ;
243 			smc->srf.sr_state = SR1_HOLDOFF ;
244 			break ;
245 		}
246 		/* SR01b */
247 		if (cond_deasserted && tsr < T_Limit) {
248 			smc->srf.sr_state = SR1_HOLDOFF ;
249 			break ;
250 		}
251 		/* SR01c */
252 		if (event_occurred && tsr < T_Limit) {
253 			smc->srf.sr_state = SR1_HOLDOFF ;
254 			break ;
255 		}
256 		/* SR00b */
257 		if (cond_asserted && tsr >= T_Limit) {
258 			smc->srf.SRThreshold = THRESHOLD_2 ;
259 			smc->srf.TSR = smt_get_time() ;
260 			smt_send_srf(smc) ;
261 			break ;
262 		}
263 		/* SR00c */
264 		if (cond_deasserted && tsr >= T_Limit) {
265 			smc->srf.TSR = smt_get_time() ;
266 			smt_send_srf(smc) ;
267 			break ;
268 		}
269 		/* SR00d */
270 		if (event_occurred && tsr >= T_Limit) {
271 			smc->srf.TSR = smt_get_time() ;
272 			smt_send_srf(smc) ;
273 			break ;
274 		}
275 		/* SR00e */
276 		if (smc->srf.any_report && (u_long) tsr >=
277 			smc->srf.SRThreshold) {
278 			smc->srf.SRThreshold *= 2 ;
279 			if (smc->srf.SRThreshold > THRESHOLD_32)
280 				smc->srf.SRThreshold = THRESHOLD_32 ;
281 			smc->srf.TSR = smt_get_time() ;
282 			smt_send_srf(smc) ;
283 			break ;
284 		}
285 		/* SR02 */
286 		if (!smc->mib.fddiSMTStatRptPolicy) {
287 			smc->srf.sr_state = SR2_DISABLED ;
288 			break ;
289 		}
290 		break ;
291 	case SR1_HOLDOFF :
292 		/* SR10b */
293 		if (tsr >= T_Limit) {
294 			smc->srf.sr_state = SR0_WAIT ;
295 			smc->srf.TSR = smt_get_time() ;
296 			smt_send_srf(smc) ;
297 			break ;
298 		}
299 		/* SR11a */
300 		if (cond_asserted) {
301 			smc->srf.SRThreshold = THRESHOLD_2 ;
302 		}
303 		/* SR11b */
304 		/* SR11c */
305 		/* handled above */
306 		/* SR12 */
307 		if (!smc->mib.fddiSMTStatRptPolicy) {
308 			smc->srf.sr_state = SR2_DISABLED ;
309 			break ;
310 		}
311 		break ;
312 	case SR2_DISABLED :
313 		if (smc->mib.fddiSMTStatRptPolicy) {
314 			smc->srf.sr_state = SR0_WAIT ;
315 			smc->srf.TSR = smt_get_time() ;
316 			smc->srf.SRThreshold = THRESHOLD_2 ;
317 			clear_all_rep(smc) ;
318 			break ;
319 		}
320 		break ;
321 	}
322 }
323 
clear_all_rep(struct s_smc * smc)324 static void clear_all_rep(struct s_smc *smc)
325 {
326 	struct s_srf_evc	*evc ;
327 	unsigned int		i ;
328 
329 	for (i = 0, evc = smc->evcs ; i < MAX_EVCS ; i++, evc++) {
330 		evc->evc_rep_required = FALSE ;
331 		if (SMT_IS_CONDITION(evc->evc_code))
332 			*evc->evc_cond_state = FALSE ;
333 	}
334 	smc->srf.any_report = FALSE ;
335 }
336 
clear_reported(struct s_smc * smc)337 static void clear_reported(struct s_smc *smc)
338 {
339 	struct s_srf_evc	*evc ;
340 	unsigned int		i ;
341 
342 	smc->srf.any_report = FALSE ;
343 	for (i = 0, evc = smc->evcs ; i < MAX_EVCS ; i++, evc++) {
344 		if (SMT_IS_CONDITION(evc->evc_code)) {
345 			if (*evc->evc_cond_state == FALSE)
346 				evc->evc_rep_required = FALSE ;
347 			else
348 				smc->srf.any_report = TRUE ;
349 		}
350 		else {
351 			evc->evc_rep_required = FALSE ;
352 			*evc->evc_multiple = FALSE ;
353 		}
354 	}
355 }
356 
357 /*
358  * build and send SMT SRF frame
359  */
smt_send_srf(struct s_smc * smc)360 static void smt_send_srf(struct s_smc *smc)
361 {
362 
363 	struct smt_header	*smt ;
364 	struct s_srf_evc	*evc ;
365 	SK_LOC_DECL(struct s_pcon,pcon) ;
366 	SMbuf			*mb ;
367 	unsigned int		i ;
368 
369 	static const struct fddi_addr SMT_SRF_DA = {
370 		{ 0x80, 0x01, 0x43, 0x00, 0x80, 0x08 }
371 	} ;
372 
373 	/*
374 	 * build SMT header
375 	 */
376 	if (!smc->r.sm_ma_avail)
377 		return ;
378 	if (!(mb = smt_build_frame(smc,SMT_SRF,SMT_ANNOUNCE,0)))
379 		return ;
380 
381 	RS_SET(smc,RS_SOFTERROR) ;
382 
383 	smt = smtod(mb, struct smt_header *) ;
384 	smt->smt_dest = SMT_SRF_DA ;		/* DA == SRF multicast */
385 
386 	/*
387 	 * setup parameter status
388 	 */
389 	pcon.pc_len = SMT_MAX_INFO_LEN ;	/* max para length */
390 	pcon.pc_err = 0 ;			/* no error */
391 	pcon.pc_badset = 0 ;			/* no bad set count */
392 	pcon.pc_p = (void *) (smt + 1) ;	/* paras start here */
393 
394 	smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ;
395 	smt_add_para(smc,&pcon,(u_short) SMT_P1034,0,0) ;
396 
397 	for (i = 0, evc = smc->evcs ; i < MAX_EVCS ; i++, evc++) {
398 		if (evc->evc_rep_required) {
399 			smt_add_para(smc,&pcon,evc->evc_para,
400 				(int)evc->evc_index,0) ;
401 		}
402 	}
403 	smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ;
404 	mb->sm_len = smt->smt_len + sizeof(struct smt_header) ;
405 
406 	DB_SMT("SRF: sending SRF at %p, len %d", smt, mb->sm_len);
407 	DB_SMT("SRF: state SR%d Threshold %lu",
408 	       smc->srf.sr_state, smc->srf.SRThreshold / TICKS_PER_SECOND);
409 #ifdef	DEBUG
410 	dump_smt(smc,smt,"SRF Send") ;
411 #endif
412 	smt_send_frame(smc,mb,FC_SMT_INFO,0) ;
413 	clear_reported(smc) ;
414 }
415 
416 #endif	/* no BOOT */
417 #endif	/* no SLIM_SMT */
418 
419