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 | |
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 | |
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 | |
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,p: 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 | |
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 | |
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 | */ |
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,length: 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: &pcon,para: (u_short) SMT_P1033,index: 0,local: 0) ; |
395 | smt_add_para(smc,pcon: &pcon,para: (u_short) SMT_P1034,index: 0,local: 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: &pcon,para: evc->evc_para, |
400 | index: (int)evc->evc_index,local: 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,local: 0) ; |
413 | clear_reported(smc) ; |
414 | } |
415 | |
416 | #endif /* no BOOT */ |
417 | #endif /* no SLIM_SMT */ |
418 | |
419 | |