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 | #include "h/types.h" |
14 | #include "h/fddi.h" |
15 | #include "h/smc.h" |
16 | #include "h/smt_p.h" |
17 | #include <linux/bitrev.h> |
18 | #include <linux/kernel.h> |
19 | |
20 | #define KERNEL |
21 | #include "h/smtstate.h" |
22 | |
23 | /* |
24 | * FC in SMbuf |
25 | */ |
26 | #define m_fc(mb) ((mb)->sm_data[0]) |
27 | |
28 | #define SMT_TID_MAGIC 0x1f0a7b3c |
29 | |
30 | static const char *const smt_type_name[] = { |
31 | "SMT_00??" , "SMT_INFO" , "SMT_02??" , "SMT_03??" , |
32 | "SMT_04??" , "SMT_05??" , "SMT_06??" , "SMT_07??" , |
33 | "SMT_08??" , "SMT_09??" , "SMT_0A??" , "SMT_0B??" , |
34 | "SMT_0C??" , "SMT_0D??" , "SMT_0E??" , "SMT_NSA" |
35 | } ; |
36 | |
37 | static const char *const smt_class_name[] = { |
38 | "UNKNOWN" ,"NIF" ,"SIF_CONFIG" ,"SIF_OPER" ,"ECF" ,"RAF" ,"RDF" , |
39 | "SRF" ,"PMF_GET" ,"PMF_SET" ,"ESF" |
40 | } ; |
41 | |
42 | #define LAST_CLASS (SMT_PMF_SET) |
43 | |
44 | static const struct fddi_addr SMT_Unknown = { |
45 | { 0,0,0x1f,0,0,0 } |
46 | } ; |
47 | |
48 | /* |
49 | * function prototypes |
50 | */ |
51 | #ifdef LITTLE_ENDIAN |
52 | static int smt_swap_short(u_short s); |
53 | #endif |
54 | static int mac_index(struct s_smc *smc, int mac); |
55 | static int phy_index(struct s_smc *smc, int phy); |
56 | static int mac_con_resource_index(struct s_smc *smc, int mac); |
57 | static int phy_con_resource_index(struct s_smc *smc, int phy); |
58 | static void smt_send_rdf(struct s_smc *smc, SMbuf *rej, int fc, int reason, |
59 | int local); |
60 | static void smt_send_nif(struct s_smc *smc, const struct fddi_addr *dest, |
61 | int fc, u_long tid, int type, int local); |
62 | static void smt_send_ecf(struct s_smc *smc, struct fddi_addr *dest, int fc, |
63 | u_long tid, int type, int len); |
64 | static void smt_echo_test(struct s_smc *smc, int dna); |
65 | static void smt_send_sif_config(struct s_smc *smc, struct fddi_addr *dest, |
66 | u_long tid, int local); |
67 | static void smt_send_sif_operation(struct s_smc *smc, struct fddi_addr *dest, |
68 | u_long tid, int local); |
69 | #ifdef LITTLE_ENDIAN |
70 | static void smt_string_swap(char *data, const char *format, int len); |
71 | #endif |
72 | static void smt_add_frame_len(SMbuf *mb, int len); |
73 | static void smt_fill_una(struct s_smc *smc, struct smt_p_una *una); |
74 | static void smt_fill_sde(struct s_smc *smc, struct smt_p_sde *sde); |
75 | static void smt_fill_state(struct s_smc *smc, struct smt_p_state *state); |
76 | static void smt_fill_timestamp(struct s_smc *smc, struct smt_p_timestamp *ts); |
77 | static void smt_fill_policy(struct s_smc *smc, struct smt_p_policy *policy); |
78 | static void smt_fill_latency(struct s_smc *smc, struct smt_p_latency *latency); |
79 | static void smt_fill_neighbor(struct s_smc *smc, struct smt_p_neighbor *neighbor); |
80 | static int smt_fill_path(struct s_smc *smc, struct smt_p_path *path); |
81 | static void smt_fill_mac_status(struct s_smc *smc, struct smt_p_mac_status *st); |
82 | static void smt_fill_lem(struct s_smc *smc, struct smt_p_lem *lem, int phy); |
83 | static void smt_fill_version(struct s_smc *smc, struct smt_p_version *vers); |
84 | static void smt_fill_fsc(struct s_smc *smc, struct smt_p_fsc *fsc); |
85 | static void smt_fill_mac_counter(struct s_smc *smc, struct smt_p_mac_counter *mc); |
86 | static void smt_fill_mac_fnc(struct s_smc *smc, struct smt_p_mac_fnc *fnc); |
87 | static void smt_fill_manufacturer(struct s_smc *smc, |
88 | struct smp_p_manufacturer *man); |
89 | static void smt_fill_user(struct s_smc *smc, struct smp_p_user *user); |
90 | static void smt_fill_setcount(struct s_smc *smc, struct smt_p_setcount *setcount); |
91 | static void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long seed, |
92 | int len); |
93 | |
94 | static void smt_clear_una_dna(struct s_smc *smc); |
95 | static void smt_clear_old_una_dna(struct s_smc *smc); |
96 | #ifdef CONCENTRATOR |
97 | static int entity_to_index(void); |
98 | #endif |
99 | static void update_dac(struct s_smc *smc, int report); |
100 | static int div_ratio(u_long upper, u_long lower); |
101 | #ifdef USE_CAN_ADDR |
102 | static void hwm_conv_can(struct s_smc *smc, char *data, int len); |
103 | #else |
104 | #define hwm_conv_can(smc,data,len) |
105 | #endif |
106 | |
107 | |
108 | static inline int is_my_addr(const struct s_smc *smc, |
109 | const struct fddi_addr *addr) |
110 | { |
111 | return(*(short *)(&addr->a[0]) == |
112 | *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[0]) |
113 | && *(short *)(&addr->a[2]) == |
114 | *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[2]) |
115 | && *(short *)(&addr->a[4]) == |
116 | *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[4])) ; |
117 | } |
118 | |
119 | static inline int is_broadcast(const struct fddi_addr *addr) |
120 | { |
121 | return *(u_short *)(&addr->a[0]) == 0xffff && |
122 | *(u_short *)(&addr->a[2]) == 0xffff && |
123 | *(u_short *)(&addr->a[4]) == 0xffff; |
124 | } |
125 | |
126 | static inline int is_individual(const struct fddi_addr *addr) |
127 | { |
128 | return !(addr->a[0] & GROUP_ADDR); |
129 | } |
130 | |
131 | static inline int is_equal(const struct fddi_addr *addr1, |
132 | const struct fddi_addr *addr2) |
133 | { |
134 | return *(u_short *)(&addr1->a[0]) == *(u_short *)(&addr2->a[0]) && |
135 | *(u_short *)(&addr1->a[2]) == *(u_short *)(&addr2->a[2]) && |
136 | *(u_short *)(&addr1->a[4]) == *(u_short *)(&addr2->a[4]); |
137 | } |
138 | |
139 | /* |
140 | * list of mandatory paras in frames |
141 | */ |
142 | static const u_short plist_nif[] = { SMT_P_UNA,SMT_P_SDE,SMT_P_STATE,0 } ; |
143 | |
144 | /* |
145 | * init SMT agent |
146 | */ |
147 | void smt_agent_init(struct s_smc *smc) |
148 | { |
149 | int i ; |
150 | |
151 | /* |
152 | * get MAC address |
153 | */ |
154 | smc->mib.m[MAC0].fddiMACSMTAddress = smc->hw.fddi_home_addr ; |
155 | |
156 | /* |
157 | * get OUI address from driver (bia == built-in-address) |
158 | */ |
159 | smc->mib.fddiSMTStationId.sid_oem[0] = 0 ; |
160 | smc->mib.fddiSMTStationId.sid_oem[1] = 0 ; |
161 | driver_get_bia(smc,bia_addr: &smc->mib.fddiSMTStationId.sid_node) ; |
162 | for (i = 0 ; i < 6 ; i ++) { |
163 | smc->mib.fddiSMTStationId.sid_node.a[i] = |
164 | bitrev8(smc->mib.fddiSMTStationId.sid_node.a[i]); |
165 | } |
166 | smc->mib.fddiSMTManufacturerData[0] = |
167 | smc->mib.fddiSMTStationId.sid_node.a[0] ; |
168 | smc->mib.fddiSMTManufacturerData[1] = |
169 | smc->mib.fddiSMTStationId.sid_node.a[1] ; |
170 | smc->mib.fddiSMTManufacturerData[2] = |
171 | smc->mib.fddiSMTStationId.sid_node.a[2] ; |
172 | smc->sm.smt_tid = 0 ; |
173 | smc->mib.m[MAC0].fddiMACDupAddressTest = DA_NONE ; |
174 | smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ; |
175 | #ifndef SLIM_SMT |
176 | smt_clear_una_dna(smc) ; |
177 | smt_clear_old_una_dna(smc) ; |
178 | #endif |
179 | for (i = 0 ; i < SMT_MAX_TEST ; i++) |
180 | smc->sm.pend[i] = 0 ; |
181 | smc->sm.please_reconnect = 0 ; |
182 | smc->sm.uniq_ticks = 0 ; |
183 | } |
184 | |
185 | /* |
186 | * SMT task |
187 | * forever |
188 | * delay 30 seconds |
189 | * send NIF |
190 | * check tvu & tvd |
191 | * end |
192 | */ |
193 | void smt_agent_task(struct s_smc *smc) |
194 | { |
195 | smt_timer_start(smc,timer: &smc->sm.smt_timer, time: (u_long)1000000L, |
196 | EV_TOKEN(EVENT_SMT,SM_TIMER)) ; |
197 | DB_SMT("SMT agent task" ); |
198 | } |
199 | |
200 | #ifndef SMT_REAL_TOKEN_CT |
201 | void smt_emulate_token_ct(struct s_smc *smc, int mac_index) |
202 | { |
203 | u_long count; |
204 | u_long time; |
205 | |
206 | |
207 | time = smt_get_time(); |
208 | count = ((time - smc->sm.last_tok_time[mac_index]) * |
209 | 100)/TICKS_PER_SECOND; |
210 | |
211 | /* |
212 | * Only when ring is up we will have a token count. The |
213 | * flag is unfortunately a single instance value. This |
214 | * doesn't matter now, because we currently have only |
215 | * one MAC instance. |
216 | */ |
217 | if (smc->hw.mac_ring_is_up){ |
218 | smc->mib.m[mac_index].fddiMACToken_Ct += count; |
219 | } |
220 | |
221 | /* Remember current time */ |
222 | smc->sm.last_tok_time[mac_index] = time; |
223 | |
224 | } |
225 | #endif |
226 | |
227 | /*ARGSUSED1*/ |
228 | void smt_event(struct s_smc *smc, int event) |
229 | { |
230 | u_long time ; |
231 | #ifndef SMT_REAL_TOKEN_CT |
232 | int i ; |
233 | #endif |
234 | |
235 | |
236 | if (smc->sm.please_reconnect) { |
237 | smc->sm.please_reconnect -- ; |
238 | if (smc->sm.please_reconnect == 0) { |
239 | /* Counted down */ |
240 | queue_event(smc,EVENT_ECM,EC_CONNECT) ; |
241 | } |
242 | } |
243 | |
244 | if (event == SM_FAST) |
245 | return ; |
246 | |
247 | /* |
248 | * timer for periodic cleanup in driver |
249 | * reset and start the watchdog (FM2) |
250 | * ESS timer |
251 | * SBA timer |
252 | */ |
253 | smt_timer_poll(smc) ; |
254 | smt_start_watchdog(smc) ; |
255 | #ifndef SLIM_SMT |
256 | #ifndef BOOT |
257 | #ifdef ESS |
258 | ess_timer_poll(smc) ; |
259 | #endif |
260 | #endif |
261 | #ifdef SBA |
262 | sba_timer_poll(smc) ; |
263 | #endif |
264 | |
265 | smt_srf_event(smc,code: 0,index: 0,cond: 0) ; |
266 | |
267 | #endif /* no SLIM_SMT */ |
268 | |
269 | time = smt_get_time() ; |
270 | |
271 | if (time - smc->sm.smt_last_lem >= TICKS_PER_SECOND*8) { |
272 | /* |
273 | * Use 8 sec. for the time intervall, it simplifies the |
274 | * LER estimation. |
275 | */ |
276 | struct fddi_mib_m *mib ; |
277 | u_long upper ; |
278 | u_long lower ; |
279 | int cond ; |
280 | int port; |
281 | struct s_phy *phy ; |
282 | /* |
283 | * calculate LEM bit error rate |
284 | */ |
285 | sm_lem_evaluate(smc) ; |
286 | smc->sm.smt_last_lem = time ; |
287 | |
288 | /* |
289 | * check conditions |
290 | */ |
291 | #ifndef SLIM_SMT |
292 | mac_update_counter(smc) ; |
293 | mib = smc->mib.m ; |
294 | upper = |
295 | (mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) + |
296 | (mib->fddiMACError_Ct - mib->fddiMACOld_Error_Ct) ; |
297 | lower = |
298 | (mib->fddiMACFrame_Ct - mib->fddiMACOld_Frame_Ct) + |
299 | (mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) ; |
300 | mib->fddiMACFrameErrorRatio = div_ratio(upper,lower) ; |
301 | |
302 | cond = |
303 | ((!mib->fddiMACFrameErrorThreshold && |
304 | mib->fddiMACError_Ct != mib->fddiMACOld_Error_Ct) || |
305 | (mib->fddiMACFrameErrorRatio > |
306 | mib->fddiMACFrameErrorThreshold)) ; |
307 | |
308 | if (cond != mib->fddiMACFrameErrorFlag) |
309 | smt_srf_event(smc,SMT_COND_MAC_FRAME_ERROR, |
310 | INDEX_MAC,cond) ; |
311 | |
312 | upper = |
313 | (mib->fddiMACNotCopied_Ct - mib->fddiMACOld_NotCopied_Ct) ; |
314 | lower = |
315 | upper + |
316 | (mib->fddiMACCopied_Ct - mib->fddiMACOld_Copied_Ct) ; |
317 | mib->fddiMACNotCopiedRatio = div_ratio(upper,lower) ; |
318 | |
319 | cond = |
320 | ((!mib->fddiMACNotCopiedThreshold && |
321 | mib->fddiMACNotCopied_Ct != |
322 | mib->fddiMACOld_NotCopied_Ct)|| |
323 | (mib->fddiMACNotCopiedRatio > |
324 | mib->fddiMACNotCopiedThreshold)) ; |
325 | |
326 | if (cond != mib->fddiMACNotCopiedFlag) |
327 | smt_srf_event(smc,SMT_COND_MAC_NOT_COPIED, |
328 | INDEX_MAC,cond) ; |
329 | |
330 | /* |
331 | * set old values |
332 | */ |
333 | mib->fddiMACOld_Frame_Ct = mib->fddiMACFrame_Ct ; |
334 | mib->fddiMACOld_Copied_Ct = mib->fddiMACCopied_Ct ; |
335 | mib->fddiMACOld_Error_Ct = mib->fddiMACError_Ct ; |
336 | mib->fddiMACOld_Lost_Ct = mib->fddiMACLost_Ct ; |
337 | mib->fddiMACOld_NotCopied_Ct = mib->fddiMACNotCopied_Ct ; |
338 | |
339 | /* |
340 | * Check port EBError Condition |
341 | */ |
342 | for (port = 0; port < NUMPHYS; port ++) { |
343 | phy = &smc->y[port] ; |
344 | |
345 | if (!phy->mib->fddiPORTHardwarePresent) { |
346 | continue; |
347 | } |
348 | |
349 | cond = (phy->mib->fddiPORTEBError_Ct - |
350 | phy->mib->fddiPORTOldEBError_Ct > 5) ; |
351 | |
352 | /* If ratio is more than 5 in 8 seconds |
353 | * Set the condition. |
354 | */ |
355 | smt_srf_event(smc,SMT_COND_PORT_EB_ERROR, |
356 | index: (int) (INDEX_PORT+ phy->np) ,cond) ; |
357 | |
358 | /* |
359 | * set old values |
360 | */ |
361 | phy->mib->fddiPORTOldEBError_Ct = |
362 | phy->mib->fddiPORTEBError_Ct ; |
363 | } |
364 | |
365 | #endif /* no SLIM_SMT */ |
366 | } |
367 | |
368 | #ifndef SLIM_SMT |
369 | |
370 | if (time - smc->sm.smt_last_notify >= (u_long) |
371 | (smc->mib.fddiSMTTT_Notify * TICKS_PER_SECOND) ) { |
372 | /* |
373 | * we can either send an announcement or a request |
374 | * a request will trigger a reply so that we can update |
375 | * our dna |
376 | * note: same tid must be used until reply is received |
377 | */ |
378 | if (!smc->sm.pend[SMT_TID_NIF]) |
379 | smc->sm.pend[SMT_TID_NIF] = smt_get_tid(smc) ; |
380 | smt_send_nif(smc,dest: &fddi_broadcast, FC_SMT_NSA, |
381 | tid: smc->sm.pend[SMT_TID_NIF], SMT_REQUEST,local: 0) ; |
382 | smc->sm.smt_last_notify = time ; |
383 | } |
384 | |
385 | /* |
386 | * check timer |
387 | */ |
388 | if (smc->sm.smt_tvu && |
389 | time - smc->sm.smt_tvu > 228*TICKS_PER_SECOND) { |
390 | DB_SMT("SMT : UNA expired" ); |
391 | smc->sm.smt_tvu = 0 ; |
392 | |
393 | if (!is_equal(addr1: &smc->mib.m[MAC0].fddiMACUpstreamNbr, |
394 | addr2: &SMT_Unknown)){ |
395 | /* Do not update unknown address */ |
396 | smc->mib.m[MAC0].fddiMACOldUpstreamNbr= |
397 | smc->mib.m[MAC0].fddiMACUpstreamNbr ; |
398 | } |
399 | smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ; |
400 | smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ; |
401 | /* |
402 | * Make sure the fddiMACUNDA_Flag = FALSE is |
403 | * included in the SRF so we don't generate |
404 | * a separate SRF for the deassertion of this |
405 | * condition |
406 | */ |
407 | update_dac(smc,report: 0) ; |
408 | smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE, |
409 | INDEX_MAC,cond: 0) ; |
410 | } |
411 | if (smc->sm.smt_tvd && |
412 | time - smc->sm.smt_tvd > 228*TICKS_PER_SECOND) { |
413 | DB_SMT("SMT : DNA expired" ); |
414 | smc->sm.smt_tvd = 0 ; |
415 | if (!is_equal(addr1: &smc->mib.m[MAC0].fddiMACDownstreamNbr, |
416 | addr2: &SMT_Unknown)){ |
417 | /* Do not update unknown address */ |
418 | smc->mib.m[MAC0].fddiMACOldDownstreamNbr= |
419 | smc->mib.m[MAC0].fddiMACDownstreamNbr ; |
420 | } |
421 | smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ; |
422 | smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE, |
423 | INDEX_MAC,cond: 0) ; |
424 | } |
425 | |
426 | #endif /* no SLIM_SMT */ |
427 | |
428 | #ifndef SMT_REAL_TOKEN_CT |
429 | /* |
430 | * Token counter emulation section. If hardware supports the token |
431 | * count, the token counter will be updated in mac_update_counter. |
432 | */ |
433 | for (i = MAC0; i < NUMMACS; i++ ){ |
434 | if (time - smc->sm.last_tok_time[i] > 2*TICKS_PER_SECOND ){ |
435 | smt_emulate_token_ct( smc, mac_index: i ); |
436 | } |
437 | } |
438 | #endif |
439 | |
440 | smt_timer_start(smc,timer: &smc->sm.smt_timer, time: (u_long)1000000L, |
441 | EV_TOKEN(EVENT_SMT,SM_TIMER)) ; |
442 | } |
443 | |
444 | static int div_ratio(u_long upper, u_long lower) |
445 | { |
446 | if ((upper<<16L) < upper) |
447 | upper = 0xffff0000L ; |
448 | else |
449 | upper <<= 16L ; |
450 | if (!lower) |
451 | return 0; |
452 | return (int)(upper/lower) ; |
453 | } |
454 | |
455 | #ifndef SLIM_SMT |
456 | |
457 | /* |
458 | * receive packet handler |
459 | */ |
460 | void smt_received_pack(struct s_smc *smc, SMbuf *mb, int fs) |
461 | /* int fs; frame status */ |
462 | { |
463 | struct smt_header *sm ; |
464 | int local ; |
465 | |
466 | int illegal = 0 ; |
467 | |
468 | switch (m_fc(mb)) { |
469 | case FC_SMT_INFO : |
470 | case FC_SMT_LAN_LOC : |
471 | case FC_SMT_LOC : |
472 | case FC_SMT_NSA : |
473 | break ; |
474 | default : |
475 | smt_free_mbuf(smc,mb) ; |
476 | return ; |
477 | } |
478 | |
479 | smc->mib.m[MAC0].fddiMACSMTCopied_Ct++ ; |
480 | sm = smtod(mb,struct smt_header *) ; |
481 | local = ((fs & L_INDICATOR) != 0) ; |
482 | hwm_conv_can(smc,data: (char *)sm,len: 12) ; |
483 | |
484 | /* check destination address */ |
485 | if (is_individual(addr: &sm->smt_dest) && !is_my_addr(smc,addr: &sm->smt_dest)) { |
486 | smt_free_mbuf(smc,mb) ; |
487 | return ; |
488 | } |
489 | #if 0 /* for DUP recognition, do NOT filter them */ |
490 | /* ignore loop back packets */ |
491 | if (is_my_addr(smc,&sm->smt_source) && !local) { |
492 | smt_free_mbuf(smc,mb) ; |
493 | return ; |
494 | } |
495 | #endif |
496 | |
497 | smt_swap_para(sm,len: (int) mb->sm_len,direction: 1) ; |
498 | DB_SMT("SMT : received packet [%s] at 0x%p" , |
499 | smt_type_name[m_fc(mb) & 0xf], sm); |
500 | DB_SMT("SMT : version %d, class %s" , |
501 | sm->smt_version, |
502 | smt_class_name[sm->smt_class > LAST_CLASS ? 0 : sm->smt_class]); |
503 | |
504 | #ifdef SBA |
505 | /* |
506 | * check if NSA frame |
507 | */ |
508 | if (m_fc(mb) == FC_SMT_NSA && sm->smt_class == SMT_NIF && |
509 | (sm->smt_type == SMT_ANNOUNCE || sm->smt_type == SMT_REQUEST)) { |
510 | smc->sba.sm = sm ; |
511 | sba(smc,NIF) ; |
512 | } |
513 | #endif |
514 | |
515 | /* |
516 | * ignore any packet with NSA and A-indicator set |
517 | */ |
518 | if ( (fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) { |
519 | DB_SMT("SMT : ignoring NSA with A-indicator set from %pM" , |
520 | &sm->smt_source); |
521 | smt_free_mbuf(smc,mb) ; |
522 | return ; |
523 | } |
524 | |
525 | /* |
526 | * ignore frames with illegal length |
527 | */ |
528 | if (((sm->smt_class == SMT_ECF) && (sm->smt_len > SMT_MAX_ECHO_LEN)) || |
529 | ((sm->smt_class != SMT_ECF) && (sm->smt_len > SMT_MAX_INFO_LEN))) { |
530 | smt_free_mbuf(smc,mb) ; |
531 | return ; |
532 | } |
533 | |
534 | /* |
535 | * check SMT version |
536 | */ |
537 | switch (sm->smt_class) { |
538 | case SMT_NIF : |
539 | case SMT_SIF_CONFIG : |
540 | case SMT_SIF_OPER : |
541 | case SMT_ECF : |
542 | if (sm->smt_version != SMT_VID) |
543 | illegal = 1; |
544 | break ; |
545 | default : |
546 | if (sm->smt_version != SMT_VID_2) |
547 | illegal = 1; |
548 | break ; |
549 | } |
550 | if (illegal) { |
551 | DB_SMT("SMT : version = %d, dest = %pM" , |
552 | sm->smt_version, &sm->smt_source); |
553 | smt_send_rdf(smc,rej: mb,m_fc(mb),SMT_RDF_VERSION,local) ; |
554 | smt_free_mbuf(smc,mb) ; |
555 | return ; |
556 | } |
557 | if ((sm->smt_len > mb->sm_len - sizeof(struct smt_header)) || |
558 | ((sm->smt_len & 3) && (sm->smt_class != SMT_ECF))) { |
559 | DB_SMT("SMT: info length error, len = %d" , sm->smt_len); |
560 | smt_send_rdf(smc,rej: mb,m_fc(mb),SMT_RDF_LENGTH,local) ; |
561 | smt_free_mbuf(smc,mb) ; |
562 | return ; |
563 | } |
564 | switch (sm->smt_class) { |
565 | case SMT_NIF : |
566 | if (smt_check_para(smc,sm,list: plist_nif)) { |
567 | DB_SMT("SMT: NIF with para problem, ignoring" ); |
568 | break ; |
569 | } |
570 | switch (sm->smt_type) { |
571 | case SMT_ANNOUNCE : |
572 | case SMT_REQUEST : |
573 | if (!(fs & C_INDICATOR) && m_fc(mb) == FC_SMT_NSA |
574 | && is_broadcast(addr: &sm->smt_dest)) { |
575 | struct smt_p_state *st ; |
576 | |
577 | /* set my UNA */ |
578 | if (!is_equal( |
579 | addr1: &smc->mib.m[MAC0].fddiMACUpstreamNbr, |
580 | addr2: &sm->smt_source)) { |
581 | DB_SMT("SMT : updated my UNA = %pM" , |
582 | &sm->smt_source); |
583 | if (!is_equal(addr1: &smc->mib.m[MAC0]. |
584 | fddiMACUpstreamNbr,addr2: &SMT_Unknown)){ |
585 | /* Do not update unknown address */ |
586 | smc->mib.m[MAC0].fddiMACOldUpstreamNbr= |
587 | smc->mib.m[MAC0].fddiMACUpstreamNbr ; |
588 | } |
589 | |
590 | smc->mib.m[MAC0].fddiMACUpstreamNbr = |
591 | sm->smt_source ; |
592 | smt_srf_event(smc, |
593 | SMT_EVENT_MAC_NEIGHBOR_CHANGE, |
594 | INDEX_MAC,cond: 0) ; |
595 | smt_echo_test(smc,dna: 0) ; |
596 | } |
597 | smc->sm.smt_tvu = smt_get_time() ; |
598 | st = (struct smt_p_state *) |
599 | sm_to_para(smc,sm,SMT_P_STATE) ; |
600 | if (st) { |
601 | smc->mib.m[MAC0].fddiMACUNDA_Flag = |
602 | (st->st_dupl_addr & SMT_ST_MY_DUPA) ? |
603 | TRUE : FALSE ; |
604 | update_dac(smc,report: 1) ; |
605 | } |
606 | } |
607 | if ((sm->smt_type == SMT_REQUEST) && |
608 | is_individual(addr: &sm->smt_source) && |
609 | ((!(fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) || |
610 | (m_fc(mb) != FC_SMT_NSA))) { |
611 | DB_SMT("SMT : replying to NIF request %pM" , |
612 | &sm->smt_source); |
613 | smt_send_nif(smc,dest: &sm->smt_source, |
614 | FC_SMT_INFO, |
615 | tid: sm->smt_tid, |
616 | SMT_REPLY,local) ; |
617 | } |
618 | break ; |
619 | case SMT_REPLY : |
620 | DB_SMT("SMT : received NIF response from %pM" , |
621 | &sm->smt_source); |
622 | if (fs & A_INDICATOR) { |
623 | smc->sm.pend[SMT_TID_NIF] = 0 ; |
624 | DB_SMT("SMT : duplicate address" ); |
625 | smc->mib.m[MAC0].fddiMACDupAddressTest = |
626 | DA_FAILED ; |
627 | smc->r.dup_addr_test = DA_FAILED ; |
628 | queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ; |
629 | smc->mib.m[MAC0].fddiMACDA_Flag = TRUE ; |
630 | update_dac(smc,report: 1) ; |
631 | break ; |
632 | } |
633 | if (sm->smt_tid == smc->sm.pend[SMT_TID_NIF]) { |
634 | smc->sm.pend[SMT_TID_NIF] = 0 ; |
635 | /* set my DNA */ |
636 | if (!is_equal( |
637 | addr1: &smc->mib.m[MAC0].fddiMACDownstreamNbr, |
638 | addr2: &sm->smt_source)) { |
639 | DB_SMT("SMT : updated my DNA" ); |
640 | if (!is_equal(addr1: &smc->mib.m[MAC0]. |
641 | fddiMACDownstreamNbr, addr2: &SMT_Unknown)){ |
642 | /* Do not update unknown address */ |
643 | smc->mib.m[MAC0].fddiMACOldDownstreamNbr = |
644 | smc->mib.m[MAC0].fddiMACDownstreamNbr ; |
645 | } |
646 | |
647 | smc->mib.m[MAC0].fddiMACDownstreamNbr = |
648 | sm->smt_source ; |
649 | smt_srf_event(smc, |
650 | SMT_EVENT_MAC_NEIGHBOR_CHANGE, |
651 | INDEX_MAC,cond: 0) ; |
652 | smt_echo_test(smc,dna: 1) ; |
653 | } |
654 | smc->mib.m[MAC0].fddiMACDA_Flag = FALSE ; |
655 | update_dac(smc,report: 1) ; |
656 | smc->sm.smt_tvd = smt_get_time() ; |
657 | smc->mib.m[MAC0].fddiMACDupAddressTest = |
658 | DA_PASSED ; |
659 | if (smc->r.dup_addr_test != DA_PASSED) { |
660 | smc->r.dup_addr_test = DA_PASSED ; |
661 | queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ; |
662 | } |
663 | } |
664 | else if (sm->smt_tid == |
665 | smc->sm.pend[SMT_TID_NIF_TEST]) { |
666 | DB_SMT("SMT : NIF test TID ok" ); |
667 | } |
668 | else { |
669 | DB_SMT("SMT : expected TID %lx, got %x" , |
670 | smc->sm.pend[SMT_TID_NIF], sm->smt_tid); |
671 | } |
672 | break ; |
673 | default : |
674 | illegal = 2 ; |
675 | break ; |
676 | } |
677 | break ; |
678 | case SMT_SIF_CONFIG : /* station information */ |
679 | if (sm->smt_type != SMT_REQUEST) |
680 | break ; |
681 | DB_SMT("SMT : replying to SIF Config request from %pM" , |
682 | &sm->smt_source); |
683 | smt_send_sif_config(smc,dest: &sm->smt_source,tid: sm->smt_tid,local) ; |
684 | break ; |
685 | case SMT_SIF_OPER : /* station information */ |
686 | if (sm->smt_type != SMT_REQUEST) |
687 | break ; |
688 | DB_SMT("SMT : replying to SIF Operation request from %pM" , |
689 | &sm->smt_source); |
690 | smt_send_sif_operation(smc,dest: &sm->smt_source,tid: sm->smt_tid,local) ; |
691 | break ; |
692 | case SMT_ECF : /* echo frame */ |
693 | switch (sm->smt_type) { |
694 | case SMT_REPLY : |
695 | smc->mib.priv.fddiPRIVECF_Reply_Rx++ ; |
696 | DB_SMT("SMT: received ECF reply from %pM" , |
697 | &sm->smt_source); |
698 | if (sm_to_para(smc,sm,SMT_P_ECHODATA) == NULL) { |
699 | DB_SMT("SMT: ECHODATA missing" ); |
700 | break ; |
701 | } |
702 | if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF]) { |
703 | DB_SMT("SMT : ECF test TID ok" ); |
704 | } |
705 | else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_UNA]) { |
706 | DB_SMT("SMT : ECF test UNA ok" ); |
707 | } |
708 | else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_DNA]) { |
709 | DB_SMT("SMT : ECF test DNA ok" ); |
710 | } |
711 | else { |
712 | DB_SMT("SMT : expected TID %lx, got %x" , |
713 | smc->sm.pend[SMT_TID_ECF], |
714 | sm->smt_tid); |
715 | } |
716 | break ; |
717 | case SMT_REQUEST : |
718 | smc->mib.priv.fddiPRIVECF_Req_Rx++ ; |
719 | { |
720 | if (sm->smt_len && !sm_to_para(smc,sm,SMT_P_ECHODATA)) { |
721 | DB_SMT("SMT: ECF with para problem,sending RDF" ); |
722 | smt_send_rdf(smc,rej: mb,m_fc(mb),SMT_RDF_LENGTH, |
723 | local) ; |
724 | break ; |
725 | } |
726 | DB_SMT("SMT - sending ECF reply to %pM" , |
727 | &sm->smt_source); |
728 | |
729 | /* set destination addr. & reply */ |
730 | sm->smt_dest = sm->smt_source ; |
731 | sm->smt_type = SMT_REPLY ; |
732 | dump_smt(smc,sm,"ECF REPLY" ) ; |
733 | smc->mib.priv.fddiPRIVECF_Reply_Tx++ ; |
734 | smt_send_frame(smc,mb,FC_SMT_INFO,local) ; |
735 | return ; /* DON'T free mbuf */ |
736 | } |
737 | default : |
738 | illegal = 1 ; |
739 | break ; |
740 | } |
741 | break ; |
742 | #ifndef BOOT |
743 | case SMT_RAF : /* resource allocation */ |
744 | #ifdef ESS |
745 | DB_ESSN(2, "ESS: RAF frame received" ); |
746 | fs = ess_raf_received_pack(smc,mb,sm,fs) ; |
747 | #endif |
748 | |
749 | #ifdef SBA |
750 | DB_SBAN(2, "SBA: RAF frame received" ) ; |
751 | sba_raf_received_pack(smc,sm,fs) ; |
752 | #endif |
753 | break ; |
754 | case SMT_RDF : /* request denied */ |
755 | smc->mib.priv.fddiPRIVRDF_Rx++ ; |
756 | break ; |
757 | case SMT_ESF : /* extended service - not supported */ |
758 | if (sm->smt_type == SMT_REQUEST) { |
759 | DB_SMT("SMT - received ESF, sending RDF" ); |
760 | smt_send_rdf(smc,rej: mb,m_fc(mb),SMT_RDF_CLASS,local) ; |
761 | } |
762 | break ; |
763 | case SMT_PMF_GET : |
764 | case SMT_PMF_SET : |
765 | if (sm->smt_type != SMT_REQUEST) |
766 | break ; |
767 | /* update statistics */ |
768 | if (sm->smt_class == SMT_PMF_GET) |
769 | smc->mib.priv.fddiPRIVPMF_Get_Rx++ ; |
770 | else |
771 | smc->mib.priv.fddiPRIVPMF_Set_Rx++ ; |
772 | /* |
773 | * ignore PMF SET with I/G set |
774 | */ |
775 | if ((sm->smt_class == SMT_PMF_SET) && |
776 | !is_individual(addr: &sm->smt_dest)) { |
777 | DB_SMT("SMT: ignoring PMF-SET with I/G set" ); |
778 | break ; |
779 | } |
780 | smt_pmf_received_pack(smc,mb, local) ; |
781 | break ; |
782 | case SMT_SRF : |
783 | dump_smt(smc,sm,"SRF received" ) ; |
784 | break ; |
785 | default : |
786 | if (sm->smt_type != SMT_REQUEST) |
787 | break ; |
788 | /* |
789 | * For frames with unknown class: |
790 | * we need to send a RDF frame according to 8.1.3.1.1, |
791 | * only if it is a REQUEST. |
792 | */ |
793 | DB_SMT("SMT : class = %d, send RDF to %pM" , |
794 | sm->smt_class, &sm->smt_source); |
795 | |
796 | smt_send_rdf(smc,rej: mb,m_fc(mb),SMT_RDF_CLASS,local) ; |
797 | break ; |
798 | #endif |
799 | } |
800 | if (illegal) { |
801 | DB_SMT("SMT: discarding invalid frame, reason = %d" , illegal); |
802 | } |
803 | smt_free_mbuf(smc,mb) ; |
804 | } |
805 | |
806 | static void update_dac(struct s_smc *smc, int report) |
807 | { |
808 | int cond ; |
809 | |
810 | cond = ( smc->mib.m[MAC0].fddiMACUNDA_Flag | |
811 | smc->mib.m[MAC0].fddiMACDA_Flag) != 0 ; |
812 | if (report && (cond != smc->mib.m[MAC0].fddiMACDuplicateAddressCond)) |
813 | smt_srf_event(smc, SMT_COND_MAC_DUP_ADDR,INDEX_MAC,cond) ; |
814 | else |
815 | smc->mib.m[MAC0].fddiMACDuplicateAddressCond = cond ; |
816 | } |
817 | |
818 | /* |
819 | * send SMT frame |
820 | * set source address |
821 | * set station ID |
822 | * send frame |
823 | */ |
824 | void smt_send_frame(struct s_smc *smc, SMbuf *mb, int fc, int local) |
825 | /* SMbuf *mb; buffer to send */ |
826 | /* int fc; FC value */ |
827 | { |
828 | struct smt_header *sm ; |
829 | |
830 | if (!smc->r.sm_ma_avail && !local) { |
831 | smt_free_mbuf(smc,mb) ; |
832 | return ; |
833 | } |
834 | sm = smtod(mb,struct smt_header *) ; |
835 | sm->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ; |
836 | sm->smt_sid = smc->mib.fddiSMTStationId ; |
837 | |
838 | smt_swap_para(sm,len: (int) mb->sm_len,direction: 0) ; /* swap para & header */ |
839 | hwm_conv_can(smc,data: (char *)sm,len: 12) ; /* convert SA and DA */ |
840 | smc->mib.m[MAC0].fddiMACSMTTransmit_Ct++ ; |
841 | smt_send_mbuf(smc,mb,fc: local ? FC_SMT_LOC : fc) ; |
842 | } |
843 | |
844 | /* |
845 | * generate and send RDF |
846 | */ |
847 | static void smt_send_rdf(struct s_smc *smc, SMbuf *rej, int fc, int reason, |
848 | int local) |
849 | /* SMbuf *rej; mbuf of offending frame */ |
850 | /* int fc; FC of denied frame */ |
851 | /* int reason; reason code */ |
852 | { |
853 | SMbuf *mb ; |
854 | struct smt_header *sm ; /* header of offending frame */ |
855 | struct smt_rdf *rdf ; |
856 | int len ; |
857 | int frame_len ; |
858 | |
859 | sm = smtod(rej,struct smt_header *) ; |
860 | if (sm->smt_type != SMT_REQUEST) |
861 | return ; |
862 | |
863 | DB_SMT("SMT: sending RDF to %pM,reason = 0x%x" , |
864 | &sm->smt_source, reason); |
865 | |
866 | |
867 | /* |
868 | * note: get framelength from MAC length, NOT from SMT header |
869 | * smt header length is included in sm_len |
870 | */ |
871 | frame_len = rej->sm_len ; |
872 | |
873 | if (!(mb=smt_build_frame(smc,SMT_RDF,SMT_REPLY,length: sizeof(struct smt_rdf)))) |
874 | return ; |
875 | rdf = smtod(mb,struct smt_rdf *) ; |
876 | rdf->smt.smt_tid = sm->smt_tid ; /* use TID from sm */ |
877 | rdf->smt.smt_dest = sm->smt_source ; /* set dest = source */ |
878 | |
879 | /* set P12 */ |
880 | rdf->reason.para.p_type = SMT_P_REASON ; |
881 | rdf->reason.para.p_len = sizeof(struct smt_p_reason) - PARA_LEN ; |
882 | rdf->reason.rdf_reason = reason ; |
883 | |
884 | /* set P14 */ |
885 | rdf->version.para.p_type = SMT_P_VERSION ; |
886 | rdf->version.para.p_len = sizeof(struct smt_p_version) - PARA_LEN ; |
887 | rdf->version.v_pad = 0 ; |
888 | rdf->version.v_n = 1 ; |
889 | rdf->version.v_index = 1 ; |
890 | rdf->version.v_version[0] = SMT_VID_2 ; |
891 | rdf->version.v_pad2 = 0 ; |
892 | |
893 | /* set P13 */ |
894 | if ((unsigned int) frame_len <= SMT_MAX_INFO_LEN - sizeof(*rdf) + |
895 | 2*sizeof(struct smt_header)) |
896 | len = frame_len ; |
897 | else |
898 | len = SMT_MAX_INFO_LEN - sizeof(*rdf) + |
899 | 2*sizeof(struct smt_header) ; |
900 | /* make length multiple of 4 */ |
901 | len &= ~3 ; |
902 | rdf->refused.para.p_type = SMT_P_REFUSED ; |
903 | /* length of para is smt_frame + ref_fc */ |
904 | rdf->refused.para.p_len = len + 4 ; |
905 | rdf->refused.ref_fc = fc ; |
906 | |
907 | /* swap it back */ |
908 | smt_swap_para(sm,len: frame_len,direction: 0) ; |
909 | |
910 | memcpy((char *) &rdf->refused.ref_header,(char *) sm,len) ; |
911 | |
912 | len -= sizeof(struct smt_header) ; |
913 | mb->sm_len += len ; |
914 | rdf->smt.smt_len += len ; |
915 | |
916 | dump_smt(smc,(struct smt_header *)rdf,"RDF" ) ; |
917 | smc->mib.priv.fddiPRIVRDF_Tx++ ; |
918 | smt_send_frame(smc,mb,FC_SMT_INFO,local) ; |
919 | } |
920 | |
921 | /* |
922 | * generate and send NIF |
923 | */ |
924 | static void smt_send_nif(struct s_smc *smc, const struct fddi_addr *dest, |
925 | int fc, u_long tid, int type, int local) |
926 | /* struct fddi_addr *dest; dest address */ |
927 | /* int fc; frame control */ |
928 | /* u_long tid; transaction id */ |
929 | /* int type; frame type */ |
930 | { |
931 | struct smt_nif *nif ; |
932 | SMbuf *mb ; |
933 | |
934 | if (!(mb = smt_build_frame(smc,SMT_NIF,type,length: sizeof(struct smt_nif)))) |
935 | return ; |
936 | nif = smtod(mb, struct smt_nif *) ; |
937 | smt_fill_una(smc,una: &nif->una) ; /* set UNA */ |
938 | smt_fill_sde(smc,sde: &nif->sde) ; /* set station descriptor */ |
939 | smt_fill_state(smc,state: &nif->state) ; /* set state information */ |
940 | #ifdef SMT6_10 |
941 | smt_fill_fsc(smc,fsc: &nif->fsc) ; /* set frame status cap. */ |
942 | #endif |
943 | nif->smt.smt_dest = *dest ; /* destination address */ |
944 | nif->smt.smt_tid = tid ; /* transaction ID */ |
945 | dump_smt(smc,(struct smt_header *)nif,"NIF" ) ; |
946 | smt_send_frame(smc,mb,fc,local) ; |
947 | } |
948 | |
949 | #ifdef DEBUG |
950 | /* |
951 | * send NIF request (test purpose) |
952 | */ |
953 | static void smt_send_nif_request(struct s_smc *smc, struct fddi_addr *dest) |
954 | { |
955 | smc->sm.pend[SMT_TID_NIF_TEST] = smt_get_tid(smc) ; |
956 | smt_send_nif(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_NIF_TEST], |
957 | SMT_REQUEST,0) ; |
958 | } |
959 | |
960 | /* |
961 | * send ECF request (test purpose) |
962 | */ |
963 | static void smt_send_ecf_request(struct s_smc *smc, struct fddi_addr *dest, |
964 | int len) |
965 | { |
966 | smc->sm.pend[SMT_TID_ECF] = smt_get_tid(smc) ; |
967 | smt_send_ecf(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_ECF], |
968 | SMT_REQUEST,len) ; |
969 | } |
970 | #endif |
971 | |
972 | /* |
973 | * echo test |
974 | */ |
975 | static void smt_echo_test(struct s_smc *smc, int dna) |
976 | { |
977 | u_long tid ; |
978 | |
979 | smc->sm.pend[dna ? SMT_TID_ECF_DNA : SMT_TID_ECF_UNA] = |
980 | tid = smt_get_tid(smc) ; |
981 | smt_send_ecf(smc, dest: dna ? |
982 | &smc->mib.m[MAC0].fddiMACDownstreamNbr : |
983 | &smc->mib.m[MAC0].fddiMACUpstreamNbr, |
984 | FC_SMT_INFO,tid, SMT_REQUEST, len: (SMT_TEST_ECHO_LEN & ~3)-8) ; |
985 | } |
986 | |
987 | /* |
988 | * generate and send ECF |
989 | */ |
990 | static void smt_send_ecf(struct s_smc *smc, struct fddi_addr *dest, int fc, |
991 | u_long tid, int type, int len) |
992 | /* struct fddi_addr *dest; dest address */ |
993 | /* int fc; frame control */ |
994 | /* u_long tid; transaction id */ |
995 | /* int type; frame type */ |
996 | /* int len; frame length */ |
997 | { |
998 | struct smt_ecf *ecf ; |
999 | SMbuf *mb ; |
1000 | |
1001 | if (!(mb = smt_build_frame(smc,SMT_ECF,type,SMT_ECF_LEN + len))) |
1002 | return ; |
1003 | ecf = smtod(mb, struct smt_ecf *) ; |
1004 | |
1005 | smt_fill_echo(smc,echo: &ecf->ec_echo,seed: tid,len) ; /* set ECHO */ |
1006 | ecf->smt.smt_dest = *dest ; /* destination address */ |
1007 | ecf->smt.smt_tid = tid ; /* transaction ID */ |
1008 | smc->mib.priv.fddiPRIVECF_Req_Tx++ ; |
1009 | smt_send_frame(smc,mb,fc,local: 0) ; |
1010 | } |
1011 | |
1012 | /* |
1013 | * generate and send SIF config response |
1014 | */ |
1015 | |
1016 | static void smt_send_sif_config(struct s_smc *smc, struct fddi_addr *dest, |
1017 | u_long tid, int local) |
1018 | /* struct fddi_addr *dest; dest address */ |
1019 | /* u_long tid; transaction id */ |
1020 | { |
1021 | struct smt_sif_config *sif ; |
1022 | SMbuf *mb ; |
1023 | int len ; |
1024 | if (!(mb = smt_build_frame(smc,SMT_SIF_CONFIG,SMT_REPLY, |
1025 | SIZEOF_SMT_SIF_CONFIG))) |
1026 | return ; |
1027 | |
1028 | sif = smtod(mb, struct smt_sif_config *) ; |
1029 | smt_fill_timestamp(smc,ts: &sif->ts) ; /* set time stamp */ |
1030 | smt_fill_sde(smc,sde: &sif->sde) ; /* set station descriptor */ |
1031 | smt_fill_version(smc,vers: &sif->version) ; /* set version information */ |
1032 | smt_fill_state(smc,state: &sif->state) ; /* set state information */ |
1033 | smt_fill_policy(smc,policy: &sif->policy) ; /* set station policy */ |
1034 | smt_fill_latency(smc,latency: &sif->latency); /* set station latency */ |
1035 | smt_fill_neighbor(smc,neighbor: &sif->neighbor); /* set station neighbor */ |
1036 | smt_fill_setcount(smc,setcount: &sif->setcount) ; /* set count */ |
1037 | len = smt_fill_path(smc,path: &sif->path); /* set station path descriptor*/ |
1038 | sif->smt.smt_dest = *dest ; /* destination address */ |
1039 | sif->smt.smt_tid = tid ; /* transaction ID */ |
1040 | smt_add_frame_len(mb,len) ; /* adjust length fields */ |
1041 | dump_smt(smc,(struct smt_header *)sif,"SIF Configuration Reply" ) ; |
1042 | smt_send_frame(smc,mb,FC_SMT_INFO,local) ; |
1043 | } |
1044 | |
1045 | /* |
1046 | * generate and send SIF operation response |
1047 | */ |
1048 | |
1049 | static void smt_send_sif_operation(struct s_smc *smc, struct fddi_addr *dest, |
1050 | u_long tid, int local) |
1051 | /* struct fddi_addr *dest; dest address */ |
1052 | /* u_long tid; transaction id */ |
1053 | { |
1054 | struct smt_sif_operation *sif ; |
1055 | SMbuf *mb ; |
1056 | int ports ; |
1057 | int i ; |
1058 | |
1059 | ports = NUMPHYS ; |
1060 | #ifndef CONCENTRATOR |
1061 | if (smc->s.sas == SMT_SAS) |
1062 | ports = 1 ; |
1063 | #endif |
1064 | |
1065 | if (!(mb = smt_build_frame(smc,SMT_SIF_OPER,SMT_REPLY, |
1066 | struct_size(sif, lem, ports)))) |
1067 | return ; |
1068 | sif = smtod(mb, typeof(sif)); |
1069 | smt_fill_timestamp(smc,ts: &sif->ts) ; /* set time stamp */ |
1070 | smt_fill_mac_status(smc,st: &sif->status) ; /* set mac status */ |
1071 | smt_fill_mac_counter(smc,mc: &sif->mc) ; /* set mac counter field */ |
1072 | smt_fill_mac_fnc(smc,fnc: &sif->fnc) ; /* set frame not copied counter */ |
1073 | smt_fill_manufacturer(smc,man: &sif->man) ; /* set manufacturer field */ |
1074 | smt_fill_user(smc,user: &sif->user) ; /* set user field */ |
1075 | smt_fill_setcount(smc,setcount: &sif->setcount) ; /* set count */ |
1076 | /* |
1077 | * set link error mon information |
1078 | */ |
1079 | if (ports == 1) { |
1080 | smt_fill_lem(smc,lem: sif->lem,PS) ; |
1081 | } |
1082 | else { |
1083 | for (i = 0 ; i < ports ; i++) { |
1084 | smt_fill_lem(smc,lem: &sif->lem[i],phy: i) ; |
1085 | } |
1086 | } |
1087 | |
1088 | sif->smt.smt_dest = *dest ; /* destination address */ |
1089 | sif->smt.smt_tid = tid ; /* transaction ID */ |
1090 | dump_smt(smc,(struct smt_header *)sif,"SIF Operation Reply" ) ; |
1091 | smt_send_frame(smc,mb,FC_SMT_INFO,local) ; |
1092 | } |
1093 | |
1094 | /* |
1095 | * get and initialize SMT frame |
1096 | */ |
1097 | SMbuf *smt_build_frame(struct s_smc *smc, int class, int type, |
1098 | int length) |
1099 | { |
1100 | SMbuf *mb ; |
1101 | struct smt_header *smt ; |
1102 | |
1103 | #if 0 |
1104 | if (!smc->r.sm_ma_avail) { |
1105 | return 0; |
1106 | } |
1107 | #endif |
1108 | if (!(mb = smt_get_mbuf(smc))) |
1109 | return mb; |
1110 | |
1111 | mb->sm_len = length ; |
1112 | smt = smtod(mb, struct smt_header *) ; |
1113 | smt->smt_dest = fddi_broadcast ; /* set dest = broadcast */ |
1114 | smt->smt_class = class ; |
1115 | smt->smt_type = type ; |
1116 | switch (class) { |
1117 | case SMT_NIF : |
1118 | case SMT_SIF_CONFIG : |
1119 | case SMT_SIF_OPER : |
1120 | case SMT_ECF : |
1121 | smt->smt_version = SMT_VID ; |
1122 | break ; |
1123 | default : |
1124 | smt->smt_version = SMT_VID_2 ; |
1125 | break ; |
1126 | } |
1127 | smt->smt_tid = smt_get_tid(smc) ; /* set transaction ID */ |
1128 | smt->smt_pad = 0 ; |
1129 | smt->smt_len = length - sizeof(struct smt_header) ; |
1130 | return mb; |
1131 | } |
1132 | |
1133 | static void smt_add_frame_len(SMbuf *mb, int len) |
1134 | { |
1135 | struct smt_header *smt ; |
1136 | |
1137 | smt = smtod(mb, struct smt_header *) ; |
1138 | smt->smt_len += len ; |
1139 | mb->sm_len += len ; |
1140 | } |
1141 | |
1142 | |
1143 | |
1144 | /* |
1145 | * fill values in UNA parameter |
1146 | */ |
1147 | static void smt_fill_una(struct s_smc *smc, struct smt_p_una *una) |
1148 | { |
1149 | SMTSETPARA(una,SMT_P_UNA) ; |
1150 | una->una_pad = 0 ; |
1151 | una->una_node = smc->mib.m[MAC0].fddiMACUpstreamNbr ; |
1152 | } |
1153 | |
1154 | /* |
1155 | * fill values in SDE parameter |
1156 | */ |
1157 | static void smt_fill_sde(struct s_smc *smc, struct smt_p_sde *sde) |
1158 | { |
1159 | SMTSETPARA(sde,SMT_P_SDE) ; |
1160 | sde->sde_non_master = smc->mib.fddiSMTNonMaster_Ct ; |
1161 | sde->sde_master = smc->mib.fddiSMTMaster_Ct ; |
1162 | sde->sde_mac_count = NUMMACS ; /* only 1 MAC */ |
1163 | #ifdef CONCENTRATOR |
1164 | sde->sde_type = SMT_SDE_CONCENTRATOR ; |
1165 | #else |
1166 | sde->sde_type = SMT_SDE_STATION ; |
1167 | #endif |
1168 | } |
1169 | |
1170 | /* |
1171 | * fill in values in station state parameter |
1172 | */ |
1173 | static void smt_fill_state(struct s_smc *smc, struct smt_p_state *state) |
1174 | { |
1175 | int top ; |
1176 | int twist ; |
1177 | |
1178 | SMTSETPARA(state,SMT_P_STATE) ; |
1179 | state->st_pad = 0 ; |
1180 | |
1181 | /* determine topology */ |
1182 | top = 0 ; |
1183 | if (smc->mib.fddiSMTPeerWrapFlag) { |
1184 | top |= SMT_ST_WRAPPED ; /* state wrapped */ |
1185 | } |
1186 | #ifdef CONCENTRATOR |
1187 | if (cfm_status_unattached(smc)) { |
1188 | top |= SMT_ST_UNATTACHED ; /* unattached concentrator */ |
1189 | } |
1190 | #endif |
1191 | if ((twist = pcm_status_twisted(smc)) & 1) { |
1192 | top |= SMT_ST_TWISTED_A ; /* twisted cable */ |
1193 | } |
1194 | if (twist & 2) { |
1195 | top |= SMT_ST_TWISTED_B ; /* twisted cable */ |
1196 | } |
1197 | #ifdef OPT_SRF |
1198 | top |= SMT_ST_SRF ; |
1199 | #endif |
1200 | if (pcm_rooted_station(smc)) |
1201 | top |= SMT_ST_ROOTED_S ; |
1202 | if (smc->mib.a[0].fddiPATHSbaPayload != 0) |
1203 | top |= SMT_ST_SYNC_SERVICE ; |
1204 | state->st_topology = top ; |
1205 | state->st_dupl_addr = |
1206 | ((smc->mib.m[MAC0].fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0 ) | |
1207 | (smc->mib.m[MAC0].fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0)) ; |
1208 | } |
1209 | |
1210 | /* |
1211 | * fill values in timestamp parameter |
1212 | */ |
1213 | static void smt_fill_timestamp(struct s_smc *smc, struct smt_p_timestamp *ts) |
1214 | { |
1215 | |
1216 | SMTSETPARA(ts,SMT_P_TIMESTAMP) ; |
1217 | smt_set_timestamp(smc,p: ts->ts_time) ; |
1218 | } |
1219 | |
1220 | void smt_set_timestamp(struct s_smc *smc, u_char *p) |
1221 | { |
1222 | u_long time ; |
1223 | u_long utime ; |
1224 | |
1225 | /* |
1226 | * timestamp is 64 bits long ; resolution is 80 nS |
1227 | * our clock resolution is 10mS |
1228 | * 10mS/80ns = 125000 ~ 2^17 = 131072 |
1229 | */ |
1230 | utime = smt_get_time() ; |
1231 | time = utime * 100 ; |
1232 | time /= TICKS_PER_SECOND ; |
1233 | p[0] = 0 ; |
1234 | p[1] = (u_char)((time>>(8+8+8+8-1)) & 1) ; |
1235 | p[2] = (u_char)(time>>(8+8+8-1)) ; |
1236 | p[3] = (u_char)(time>>(8+8-1)) ; |
1237 | p[4] = (u_char)(time>>(8-1)) ; |
1238 | p[5] = (u_char)(time<<1) ; |
1239 | p[6] = (u_char)(smc->sm.uniq_ticks>>8) ; |
1240 | p[7] = (u_char)smc->sm.uniq_ticks ; |
1241 | /* |
1242 | * make sure we don't wrap: restart whenever the upper digits change |
1243 | */ |
1244 | if (utime != smc->sm.uniq_time) { |
1245 | smc->sm.uniq_ticks = 0 ; |
1246 | } |
1247 | smc->sm.uniq_ticks++ ; |
1248 | smc->sm.uniq_time = utime ; |
1249 | } |
1250 | |
1251 | /* |
1252 | * fill values in station policy parameter |
1253 | */ |
1254 | static void smt_fill_policy(struct s_smc *smc, struct smt_p_policy *policy) |
1255 | { |
1256 | int i ; |
1257 | const u_char *map ; |
1258 | u_short in ; |
1259 | u_short out ; |
1260 | |
1261 | /* |
1262 | * MIB para 101b (fddiSMTConnectionPolicy) coding |
1263 | * is different from 0005 coding |
1264 | */ |
1265 | static const u_char ansi_weirdness[16] = { |
1266 | 0,7,5,3,8,1,6,4,9,10,2,11,12,13,14,15 |
1267 | } ; |
1268 | SMTSETPARA(policy,SMT_P_POLICY) ; |
1269 | |
1270 | out = 0 ; |
1271 | in = smc->mib.fddiSMTConnectionPolicy ; |
1272 | for (i = 0, map = ansi_weirdness ; i < 16 ; i++) { |
1273 | if (in & 1) |
1274 | out |= (1<<*map) ; |
1275 | in >>= 1 ; |
1276 | map++ ; |
1277 | } |
1278 | policy->pl_config = smc->mib.fddiSMTConfigPolicy ; |
1279 | policy->pl_connect = out ; |
1280 | } |
1281 | |
1282 | /* |
1283 | * fill values in latency equivalent parameter |
1284 | */ |
1285 | static void smt_fill_latency(struct s_smc *smc, struct smt_p_latency *latency) |
1286 | { |
1287 | SMTSETPARA(latency,SMT_P_LATENCY) ; |
1288 | |
1289 | latency->lt_phyout_idx1 = phy_index(smc,phy: 0) ; |
1290 | latency->lt_latency1 = 10 ; /* in octets (byte clock) */ |
1291 | /* |
1292 | * note: latency has two phy entries by definition |
1293 | * for a SAS, the 2nd one is null |
1294 | */ |
1295 | if (smc->s.sas == SMT_DAS) { |
1296 | latency->lt_phyout_idx2 = phy_index(smc,phy: 1) ; |
1297 | latency->lt_latency2 = 10 ; /* in octets (byte clock) */ |
1298 | } |
1299 | else { |
1300 | latency->lt_phyout_idx2 = 0 ; |
1301 | latency->lt_latency2 = 0 ; |
1302 | } |
1303 | } |
1304 | |
1305 | /* |
1306 | * fill values in MAC neighbors parameter |
1307 | */ |
1308 | static void smt_fill_neighbor(struct s_smc *smc, struct smt_p_neighbor *neighbor) |
1309 | { |
1310 | SMTSETPARA(neighbor,SMT_P_NEIGHBORS) ; |
1311 | |
1312 | neighbor->nb_mib_index = INDEX_MAC ; |
1313 | neighbor->nb_mac_index = mac_index(smc,mac: 1) ; |
1314 | neighbor->nb_una = smc->mib.m[MAC0].fddiMACUpstreamNbr ; |
1315 | neighbor->nb_dna = smc->mib.m[MAC0].fddiMACDownstreamNbr ; |
1316 | } |
1317 | |
1318 | /* |
1319 | * fill values in path descriptor |
1320 | */ |
1321 | #ifdef CONCENTRATOR |
1322 | #define ALLPHYS NUMPHYS |
1323 | #else |
1324 | #define ALLPHYS ((smc->s.sas == SMT_SAS) ? 1 : 2) |
1325 | #endif |
1326 | |
1327 | static int smt_fill_path(struct s_smc *smc, struct smt_p_path *path) |
1328 | { |
1329 | SK_LOC_DECL(int,type) ; |
1330 | SK_LOC_DECL(int,state) ; |
1331 | SK_LOC_DECL(int,remote) ; |
1332 | SK_LOC_DECL(int,mac) ; |
1333 | int len ; |
1334 | int p ; |
1335 | int physp ; |
1336 | struct smt_phy_rec *phy ; |
1337 | struct smt_mac_rec *pd_mac ; |
1338 | |
1339 | len = PARA_LEN + |
1340 | sizeof(struct smt_mac_rec) * NUMMACS + |
1341 | sizeof(struct smt_phy_rec) * ALLPHYS ; |
1342 | path->para.p_type = SMT_P_PATH ; |
1343 | path->para.p_len = len - PARA_LEN ; |
1344 | |
1345 | /* PHYs */ |
1346 | for (p = 0,phy = path->pd_phy ; p < ALLPHYS ; p++, phy++) { |
1347 | physp = p ; |
1348 | #ifndef CONCENTRATOR |
1349 | if (smc->s.sas == SMT_SAS) |
1350 | physp = PS ; |
1351 | #endif |
1352 | pcm_status_state(smc,np: physp,type: &type,state: &state,remote: &remote,mac: &mac) ; |
1353 | #ifdef LITTLE_ENDIAN |
1354 | phy->phy_mib_index = smt_swap_short(s: (u_short)p+INDEX_PORT) ; |
1355 | #else |
1356 | phy->phy_mib_index = p+INDEX_PORT ; |
1357 | #endif |
1358 | phy->phy_type = type ; |
1359 | phy->phy_connect_state = state ; |
1360 | phy->phy_remote_type = remote ; |
1361 | phy->phy_remote_mac = mac ; |
1362 | phy->phy_resource_idx = phy_con_resource_index(smc,phy: p) ; |
1363 | } |
1364 | |
1365 | /* MAC */ |
1366 | pd_mac = (struct smt_mac_rec *) phy ; |
1367 | pd_mac->mac_addr = smc->mib.m[MAC0].fddiMACSMTAddress ; |
1368 | pd_mac->mac_resource_idx = mac_con_resource_index(smc,mac: 1) ; |
1369 | return len; |
1370 | } |
1371 | |
1372 | /* |
1373 | * fill values in mac status |
1374 | */ |
1375 | static void smt_fill_mac_status(struct s_smc *smc, struct smt_p_mac_status *st) |
1376 | { |
1377 | SMTSETPARA(st,SMT_P_MAC_STATUS) ; |
1378 | |
1379 | st->st_mib_index = INDEX_MAC ; |
1380 | st->st_mac_index = mac_index(smc,mac: 1) ; |
1381 | |
1382 | mac_update_counter(smc) ; |
1383 | /* |
1384 | * timer values are represented in SMT as 2's complement numbers |
1385 | * units : internal : 2's complement BCLK |
1386 | */ |
1387 | st->st_t_req = smc->mib.m[MAC0].fddiMACT_Req ; |
1388 | st->st_t_neg = smc->mib.m[MAC0].fddiMACT_Neg ; |
1389 | st->st_t_max = smc->mib.m[MAC0].fddiMACT_Max ; |
1390 | st->st_tvx_value = smc->mib.m[MAC0].fddiMACTvxValue ; |
1391 | st->st_t_min = smc->mib.m[MAC0].fddiMACT_Min ; |
1392 | |
1393 | st->st_sba = smc->mib.a[PATH0].fddiPATHSbaPayload ; |
1394 | st->st_frame_ct = smc->mib.m[MAC0].fddiMACFrame_Ct ; |
1395 | st->st_error_ct = smc->mib.m[MAC0].fddiMACError_Ct ; |
1396 | st->st_lost_ct = smc->mib.m[MAC0].fddiMACLost_Ct ; |
1397 | } |
1398 | |
1399 | /* |
1400 | * fill values in LEM status |
1401 | */ |
1402 | static void smt_fill_lem(struct s_smc *smc, struct smt_p_lem *lem, int phy) |
1403 | { |
1404 | struct fddi_mib_p *mib ; |
1405 | |
1406 | mib = smc->y[phy].mib ; |
1407 | |
1408 | SMTSETPARA(lem,SMT_P_LEM) ; |
1409 | lem->lem_mib_index = phy+INDEX_PORT ; |
1410 | lem->lem_phy_index = phy_index(smc,phy) ; |
1411 | lem->lem_pad2 = 0 ; |
1412 | lem->lem_cutoff = mib->fddiPORTLer_Cutoff ; |
1413 | lem->lem_alarm = mib->fddiPORTLer_Alarm ; |
1414 | /* long term bit error rate */ |
1415 | lem->lem_estimate = mib->fddiPORTLer_Estimate ; |
1416 | /* # of rejected connections */ |
1417 | lem->lem_reject_ct = mib->fddiPORTLem_Reject_Ct ; |
1418 | lem->lem_ct = mib->fddiPORTLem_Ct ; /* total number of errors */ |
1419 | } |
1420 | |
1421 | /* |
1422 | * fill version parameter |
1423 | */ |
1424 | static void smt_fill_version(struct s_smc *smc, struct smt_p_version *vers) |
1425 | { |
1426 | SK_UNUSED(smc) ; |
1427 | SMTSETPARA(vers,SMT_P_VERSION) ; |
1428 | vers->v_pad = 0 ; |
1429 | vers->v_n = 1 ; /* one version is enough .. */ |
1430 | vers->v_index = 1 ; |
1431 | vers->v_version[0] = SMT_VID_2 ; |
1432 | vers->v_pad2 = 0 ; |
1433 | } |
1434 | |
1435 | #ifdef SMT6_10 |
1436 | /* |
1437 | * fill frame status capabilities |
1438 | */ |
1439 | /* |
1440 | * note: this para 200B is NOT in swap table, because it's also set in |
1441 | * PMF add_para |
1442 | */ |
1443 | static void smt_fill_fsc(struct s_smc *smc, struct smt_p_fsc *fsc) |
1444 | { |
1445 | SK_UNUSED(smc) ; |
1446 | SMTSETPARA(fsc,SMT_P_FSC) ; |
1447 | fsc->fsc_pad0 = 0 ; |
1448 | fsc->fsc_mac_index = INDEX_MAC ; /* this is MIB ; MIB is NOT |
1449 | * mac_index ()i ! |
1450 | */ |
1451 | fsc->fsc_pad1 = 0 ; |
1452 | fsc->fsc_value = FSC_TYPE0 ; /* "normal" node */ |
1453 | #ifdef LITTLE_ENDIAN |
1454 | fsc->fsc_mac_index = smt_swap_short(INDEX_MAC) ; |
1455 | fsc->fsc_value = smt_swap_short(FSC_TYPE0) ; |
1456 | #endif |
1457 | } |
1458 | #endif |
1459 | |
1460 | /* |
1461 | * fill mac counter field |
1462 | */ |
1463 | static void smt_fill_mac_counter(struct s_smc *smc, struct smt_p_mac_counter *mc) |
1464 | { |
1465 | SMTSETPARA(mc,SMT_P_MAC_COUNTER) ; |
1466 | mc->mc_mib_index = INDEX_MAC ; |
1467 | mc->mc_index = mac_index(smc,mac: 1) ; |
1468 | mc->mc_receive_ct = smc->mib.m[MAC0].fddiMACCopied_Ct ; |
1469 | mc->mc_transmit_ct = smc->mib.m[MAC0].fddiMACTransmit_Ct ; |
1470 | } |
1471 | |
1472 | /* |
1473 | * fill mac frame not copied counter |
1474 | */ |
1475 | static void smt_fill_mac_fnc(struct s_smc *smc, struct smt_p_mac_fnc *fnc) |
1476 | { |
1477 | SMTSETPARA(fnc,SMT_P_MAC_FNC) ; |
1478 | fnc->nc_mib_index = INDEX_MAC ; |
1479 | fnc->nc_index = mac_index(smc,mac: 1) ; |
1480 | fnc->nc_counter = smc->mib.m[MAC0].fddiMACNotCopied_Ct ; |
1481 | } |
1482 | |
1483 | |
1484 | /* |
1485 | * fill manufacturer field |
1486 | */ |
1487 | static void smt_fill_manufacturer(struct s_smc *smc, |
1488 | struct smp_p_manufacturer *man) |
1489 | { |
1490 | SMTSETPARA(man,SMT_P_MANUFACTURER) ; |
1491 | memcpy((char *) man->mf_data, |
1492 | (char *) smc->mib.fddiSMTManufacturerData, |
1493 | sizeof(man->mf_data)) ; |
1494 | } |
1495 | |
1496 | /* |
1497 | * fill user field |
1498 | */ |
1499 | static void smt_fill_user(struct s_smc *smc, struct smp_p_user *user) |
1500 | { |
1501 | SMTSETPARA(user,SMT_P_USER) ; |
1502 | memcpy((char *) user->us_data, |
1503 | (char *) smc->mib.fddiSMTUserData, |
1504 | sizeof(user->us_data)) ; |
1505 | } |
1506 | |
1507 | /* |
1508 | * fill set count |
1509 | */ |
1510 | static void smt_fill_setcount(struct s_smc *smc, struct smt_p_setcount *setcount) |
1511 | { |
1512 | SK_UNUSED(smc) ; |
1513 | SMTSETPARA(setcount,SMT_P_SETCOUNT) ; |
1514 | setcount->count = smc->mib.fddiSMTSetCount.count ; |
1515 | memcpy((char *)setcount->timestamp, |
1516 | (char *)smc->mib.fddiSMTSetCount.timestamp,8) ; |
1517 | } |
1518 | |
1519 | /* |
1520 | * fill echo data |
1521 | */ |
1522 | static void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long seed, |
1523 | int len) |
1524 | { |
1525 | u_char *p ; |
1526 | |
1527 | SK_UNUSED(smc) ; |
1528 | SMTSETPARA(echo,SMT_P_ECHODATA) ; |
1529 | echo->para.p_len = len ; |
1530 | for (p = echo->ec_data ; len ; len--) { |
1531 | *p++ = (u_char) seed ; |
1532 | seed += 13 ; |
1533 | } |
1534 | } |
1535 | |
1536 | /* |
1537 | * clear DNA and UNA |
1538 | * called from CFM if configuration changes |
1539 | */ |
1540 | static void smt_clear_una_dna(struct s_smc *smc) |
1541 | { |
1542 | smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ; |
1543 | smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ; |
1544 | } |
1545 | |
1546 | static void smt_clear_old_una_dna(struct s_smc *smc) |
1547 | { |
1548 | smc->mib.m[MAC0].fddiMACOldUpstreamNbr = SMT_Unknown ; |
1549 | smc->mib.m[MAC0].fddiMACOldDownstreamNbr = SMT_Unknown ; |
1550 | } |
1551 | |
1552 | u_long smt_get_tid(struct s_smc *smc) |
1553 | { |
1554 | u_long tid ; |
1555 | while ((tid = ++(smc->sm.smt_tid) ^ SMT_TID_MAGIC) == 0) |
1556 | ; |
1557 | return tid & 0x3fffffffL; |
1558 | } |
1559 | |
1560 | #ifdef LITTLE_ENDIAN |
1561 | /* |
1562 | * table of parameter lengths |
1563 | */ |
1564 | static const struct smt_pdef { |
1565 | int ptype ; |
1566 | int plen ; |
1567 | const char *pswap ; |
1568 | } smt_pdef[] = { |
1569 | { SMT_P_UNA, sizeof(struct smt_p_una) , |
1570 | SWAP_SMT_P_UNA } , |
1571 | { SMT_P_SDE, sizeof(struct smt_p_sde) , |
1572 | SWAP_SMT_P_SDE } , |
1573 | { SMT_P_STATE, sizeof(struct smt_p_state) , |
1574 | SWAP_SMT_P_STATE } , |
1575 | { SMT_P_TIMESTAMP,sizeof(struct smt_p_timestamp) , |
1576 | SWAP_SMT_P_TIMESTAMP } , |
1577 | { SMT_P_POLICY, sizeof(struct smt_p_policy) , |
1578 | SWAP_SMT_P_POLICY } , |
1579 | { SMT_P_LATENCY, sizeof(struct smt_p_latency) , |
1580 | SWAP_SMT_P_LATENCY } , |
1581 | { SMT_P_NEIGHBORS,sizeof(struct smt_p_neighbor) , |
1582 | SWAP_SMT_P_NEIGHBORS } , |
1583 | { SMT_P_PATH, sizeof(struct smt_p_path) , |
1584 | SWAP_SMT_P_PATH } , |
1585 | { SMT_P_MAC_STATUS,sizeof(struct smt_p_mac_status) , |
1586 | SWAP_SMT_P_MAC_STATUS } , |
1587 | { SMT_P_LEM, sizeof(struct smt_p_lem) , |
1588 | SWAP_SMT_P_LEM } , |
1589 | { SMT_P_MAC_COUNTER,sizeof(struct smt_p_mac_counter) , |
1590 | SWAP_SMT_P_MAC_COUNTER } , |
1591 | { SMT_P_MAC_FNC,sizeof(struct smt_p_mac_fnc) , |
1592 | SWAP_SMT_P_MAC_FNC } , |
1593 | { SMT_P_PRIORITY,sizeof(struct smt_p_priority) , |
1594 | SWAP_SMT_P_PRIORITY } , |
1595 | { SMT_P_EB,sizeof(struct smt_p_eb) , |
1596 | SWAP_SMT_P_EB } , |
1597 | { SMT_P_MANUFACTURER,sizeof(struct smp_p_manufacturer) , |
1598 | SWAP_SMT_P_MANUFACTURER } , |
1599 | { SMT_P_REASON, sizeof(struct smt_p_reason) , |
1600 | SWAP_SMT_P_REASON } , |
1601 | { SMT_P_REFUSED, sizeof(struct smt_p_refused) , |
1602 | SWAP_SMT_P_REFUSED } , |
1603 | { SMT_P_VERSION, sizeof(struct smt_p_version) , |
1604 | SWAP_SMT_P_VERSION } , |
1605 | #ifdef ESS |
1606 | { SMT_P0015, sizeof(struct smt_p_0015) , SWAP_SMT_P0015 } , |
1607 | { SMT_P0016, sizeof(struct smt_p_0016) , SWAP_SMT_P0016 } , |
1608 | { SMT_P0017, sizeof(struct smt_p_0017) , SWAP_SMT_P0017 } , |
1609 | { SMT_P0018, sizeof(struct smt_p_0018) , SWAP_SMT_P0018 } , |
1610 | { SMT_P0019, sizeof(struct smt_p_0019) , SWAP_SMT_P0019 } , |
1611 | { SMT_P001A, sizeof(struct smt_p_001a) , SWAP_SMT_P001A } , |
1612 | { SMT_P001B, sizeof(struct smt_p_001b) , SWAP_SMT_P001B } , |
1613 | { SMT_P001C, sizeof(struct smt_p_001c) , SWAP_SMT_P001C } , |
1614 | { SMT_P001D, sizeof(struct smt_p_001d) , SWAP_SMT_P001D } , |
1615 | #endif |
1616 | #if 0 |
1617 | { SMT_P_FSC, sizeof(struct smt_p_fsc) , |
1618 | SWAP_SMT_P_FSC } , |
1619 | #endif |
1620 | |
1621 | { SMT_P_SETCOUNT,0, SWAP_SMT_P_SETCOUNT } , |
1622 | { SMT_P1048, 0, SWAP_SMT_P1048 } , |
1623 | { SMT_P208C, 0, SWAP_SMT_P208C } , |
1624 | { SMT_P208D, 0, SWAP_SMT_P208D } , |
1625 | { SMT_P208E, 0, SWAP_SMT_P208E } , |
1626 | { SMT_P208F, 0, SWAP_SMT_P208F } , |
1627 | { SMT_P2090, 0, SWAP_SMT_P2090 } , |
1628 | #ifdef ESS |
1629 | { SMT_P320B, sizeof(struct smt_p_320b) , SWAP_SMT_P320B } , |
1630 | { SMT_P320F, sizeof(struct smt_p_320f) , SWAP_SMT_P320F } , |
1631 | { SMT_P3210, sizeof(struct smt_p_3210) , SWAP_SMT_P3210 } , |
1632 | #endif |
1633 | { SMT_P4050, 0, SWAP_SMT_P4050 } , |
1634 | { SMT_P4051, 0, SWAP_SMT_P4051 } , |
1635 | { SMT_P4052, 0, SWAP_SMT_P4052 } , |
1636 | { SMT_P4053, 0, SWAP_SMT_P4053 } , |
1637 | } ; |
1638 | |
1639 | #define N_SMT_PLEN ARRAY_SIZE(smt_pdef) |
1640 | #endif |
1641 | |
1642 | int smt_check_para(struct s_smc *smc, struct smt_header *sm, |
1643 | const u_short list[]) |
1644 | { |
1645 | const u_short *p = list ; |
1646 | while (*p) { |
1647 | if (!sm_to_para(smc,sm,para: (int) *p)) { |
1648 | DB_SMT("SMT: smt_check_para - missing para %hx" , *p); |
1649 | return -1; |
1650 | } |
1651 | p++ ; |
1652 | } |
1653 | return 0; |
1654 | } |
1655 | |
1656 | void *sm_to_para(struct s_smc *smc, struct smt_header *sm, int para) |
1657 | { |
1658 | char *p ; |
1659 | int len ; |
1660 | int plen ; |
1661 | void *found = NULL; |
1662 | |
1663 | SK_UNUSED(smc) ; |
1664 | |
1665 | len = sm->smt_len ; |
1666 | p = (char *)(sm+1) ; /* pointer to info */ |
1667 | while (len > 0 ) { |
1668 | if (((struct smt_para *)p)->p_type == para) |
1669 | found = (void *) p ; |
1670 | plen = ((struct smt_para *)p)->p_len + PARA_LEN ; |
1671 | p += plen ; |
1672 | len -= plen ; |
1673 | if (len < 0) { |
1674 | DB_SMT("SMT : sm_to_para - length error %d" , plen); |
1675 | return NULL; |
1676 | } |
1677 | if ((plen & 3) && (para != SMT_P_ECHODATA)) { |
1678 | DB_SMT("SMT : sm_to_para - odd length %d" , plen); |
1679 | return NULL; |
1680 | } |
1681 | if (found) |
1682 | return found; |
1683 | } |
1684 | return NULL; |
1685 | } |
1686 | |
1687 | #if 0 |
1688 | /* |
1689 | * send ANTC data test frame |
1690 | */ |
1691 | void fddi_send_antc(struct s_smc *smc, struct fddi_addr *dest) |
1692 | { |
1693 | SK_UNUSED(smc) ; |
1694 | SK_UNUSED(dest) ; |
1695 | #if 0 |
1696 | SMbuf *mb ; |
1697 | struct smt_header *smt ; |
1698 | int i ; |
1699 | char *p ; |
1700 | |
1701 | mb = smt_get_mbuf() ; |
1702 | mb->sm_len = 3000+12 ; |
1703 | p = smtod(mb, char *) + 12 ; |
1704 | for (i = 0 ; i < 3000 ; i++) |
1705 | *p++ = 1 << (i&7) ; |
1706 | |
1707 | smt = smtod(mb, struct smt_header *) ; |
1708 | smt->smt_dest = *dest ; |
1709 | smt->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ; |
1710 | smt_send_mbuf(smc,mb,FC_ASYNC_LLC) ; |
1711 | #endif |
1712 | } |
1713 | #endif |
1714 | |
1715 | /* |
1716 | * return static mac index |
1717 | */ |
1718 | static int mac_index(struct s_smc *smc, int mac) |
1719 | { |
1720 | SK_UNUSED(mac) ; |
1721 | #ifdef CONCENTRATOR |
1722 | SK_UNUSED(smc) ; |
1723 | return NUMPHYS + 1; |
1724 | #else |
1725 | return (smc->s.sas == SMT_SAS) ? 2 : 3; |
1726 | #endif |
1727 | } |
1728 | |
1729 | /* |
1730 | * return static phy index |
1731 | */ |
1732 | static int phy_index(struct s_smc *smc, int phy) |
1733 | { |
1734 | SK_UNUSED(smc) ; |
1735 | return phy + 1; |
1736 | } |
1737 | |
1738 | /* |
1739 | * return dynamic mac connection resource index |
1740 | */ |
1741 | static int mac_con_resource_index(struct s_smc *smc, int mac) |
1742 | { |
1743 | #ifdef CONCENTRATOR |
1744 | SK_UNUSED(smc) ; |
1745 | SK_UNUSED(mac) ; |
1746 | return entity_to_index(smc, cem_get_downstream(smc, ENTITY_MAC)); |
1747 | #else |
1748 | SK_UNUSED(mac) ; |
1749 | switch (smc->mib.fddiSMTCF_State) { |
1750 | case SC9_C_WRAP_A : |
1751 | case SC5_THRU_B : |
1752 | case SC11_C_WRAP_S : |
1753 | return 1; |
1754 | case SC10_C_WRAP_B : |
1755 | case SC4_THRU_A : |
1756 | return 2; |
1757 | } |
1758 | return smc->s.sas == SMT_SAS ? 2 : 3; |
1759 | #endif |
1760 | } |
1761 | |
1762 | /* |
1763 | * return dynamic phy connection resource index |
1764 | */ |
1765 | static int phy_con_resource_index(struct s_smc *smc, int phy) |
1766 | { |
1767 | #ifdef CONCENTRATOR |
1768 | return entity_to_index(smc, cem_get_downstream(smc, ENTITY_PHY(phy))) ; |
1769 | #else |
1770 | switch (smc->mib.fddiSMTCF_State) { |
1771 | case SC9_C_WRAP_A : |
1772 | return phy == PA ? 3 : 2; |
1773 | case SC10_C_WRAP_B : |
1774 | return phy == PA ? 1 : 3; |
1775 | case SC4_THRU_A : |
1776 | return phy == PA ? 3 : 1; |
1777 | case SC5_THRU_B : |
1778 | return phy == PA ? 2 : 3; |
1779 | case SC11_C_WRAP_S : |
1780 | return 2; |
1781 | } |
1782 | return phy; |
1783 | #endif |
1784 | } |
1785 | |
1786 | #ifdef CONCENTRATOR |
1787 | static int entity_to_index(struct s_smc *smc, int e) |
1788 | { |
1789 | if (e == ENTITY_MAC) |
1790 | return mac_index(smc, 1); |
1791 | else |
1792 | return phy_index(smc, e - ENTITY_PHY(0)); |
1793 | } |
1794 | #endif |
1795 | |
1796 | #ifdef LITTLE_ENDIAN |
1797 | static int smt_swap_short(u_short s) |
1798 | { |
1799 | return ((s>>8)&0xff) | ((s&0xff)<<8); |
1800 | } |
1801 | |
1802 | void smt_swap_para(struct smt_header *sm, int len, int direction) |
1803 | /* int direction; 0 encode 1 decode */ |
1804 | { |
1805 | struct smt_para *pa ; |
1806 | const struct smt_pdef *pd ; |
1807 | char *p ; |
1808 | int plen ; |
1809 | int type ; |
1810 | int i ; |
1811 | |
1812 | /* printf("smt_swap_para sm %x len %d dir %d\n", |
1813 | sm,len,direction) ; |
1814 | */ |
1815 | smt_string_swap(data: (char *)sm,SWAP_SMTHEADER,len) ; |
1816 | |
1817 | /* swap args */ |
1818 | len -= sizeof(struct smt_header) ; |
1819 | |
1820 | p = (char *) (sm + 1) ; |
1821 | while (len > 0) { |
1822 | pa = (struct smt_para *) p ; |
1823 | plen = pa->p_len ; |
1824 | type = pa->p_type ; |
1825 | pa->p_type = smt_swap_short(s: pa->p_type) ; |
1826 | pa->p_len = smt_swap_short(s: pa->p_len) ; |
1827 | if (direction) { |
1828 | plen = pa->p_len ; |
1829 | type = pa->p_type ; |
1830 | } |
1831 | /* |
1832 | * note: paras can have 0 length ! |
1833 | */ |
1834 | if (plen < 0) |
1835 | break ; |
1836 | plen += PARA_LEN ; |
1837 | for (i = N_SMT_PLEN, pd = smt_pdef; i ; i--,pd++) { |
1838 | if (pd->ptype == type) |
1839 | break ; |
1840 | } |
1841 | if (i && pd->pswap) { |
1842 | smt_string_swap(data: p+PARA_LEN,format: pd->pswap,len) ; |
1843 | } |
1844 | len -= plen ; |
1845 | p += plen ; |
1846 | } |
1847 | } |
1848 | |
1849 | |
1850 | static void smt_string_swap(char *data, const char *format, int len) |
1851 | { |
1852 | const char *open_paren = NULL ; |
1853 | |
1854 | while (len > 0 && *format) { |
1855 | switch (*format) { |
1856 | case '[' : |
1857 | open_paren = format ; |
1858 | break ; |
1859 | case ']' : |
1860 | format = open_paren ; |
1861 | break ; |
1862 | case '1' : |
1863 | case '2' : |
1864 | case '3' : |
1865 | case '4' : |
1866 | case '5' : |
1867 | case '6' : |
1868 | case '7' : |
1869 | case '8' : |
1870 | case '9' : |
1871 | data += *format - '0' ; |
1872 | len -= *format - '0' ; |
1873 | break ; |
1874 | case 'c': |
1875 | data++ ; |
1876 | len-- ; |
1877 | break ; |
1878 | case 's' : |
1879 | swap(data[0], data[1]) ; |
1880 | data += 2 ; |
1881 | len -= 2 ; |
1882 | break ; |
1883 | case 'l' : |
1884 | swap(data[0], data[3]) ; |
1885 | swap(data[1], data[2]) ; |
1886 | data += 4 ; |
1887 | len -= 4 ; |
1888 | break ; |
1889 | } |
1890 | format++ ; |
1891 | } |
1892 | } |
1893 | #else |
1894 | void smt_swap_para(struct smt_header *sm, int len, int direction) |
1895 | /* int direction; 0 encode 1 decode */ |
1896 | { |
1897 | SK_UNUSED(sm) ; |
1898 | SK_UNUSED(len) ; |
1899 | SK_UNUSED(direction) ; |
1900 | } |
1901 | #endif |
1902 | |
1903 | /* |
1904 | * PMF actions |
1905 | */ |
1906 | int smt_action(struct s_smc *smc, int class, int code, int index) |
1907 | { |
1908 | int event ; |
1909 | int port ; |
1910 | DB_SMT("SMT: action %d code %d" , class, code); |
1911 | switch(class) { |
1912 | case SMT_STATION_ACTION : |
1913 | switch(code) { |
1914 | case SMT_STATION_ACTION_CONNECT : |
1915 | smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ; |
1916 | queue_event(smc,EVENT_ECM,EC_CONNECT) ; |
1917 | break ; |
1918 | case SMT_STATION_ACTION_DISCONNECT : |
1919 | queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; |
1920 | smc->mib.fddiSMTRemoteDisconnectFlag = TRUE ; |
1921 | RS_SET(smc,RS_DISCONNECT) ; |
1922 | AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) |
1923 | FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_DISCONNECT, |
1924 | smt_get_event_word(smc)); |
1925 | break ; |
1926 | case SMT_STATION_ACTION_PATHTEST : |
1927 | AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) |
1928 | FDDI_SMT_EVENT, (u_long) FDDI_PATH_TEST, |
1929 | smt_get_event_word(smc)); |
1930 | break ; |
1931 | case SMT_STATION_ACTION_SELFTEST : |
1932 | AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) |
1933 | FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_SELF_TEST, |
1934 | smt_get_event_word(smc)); |
1935 | break ; |
1936 | case SMT_STATION_ACTION_DISABLE_A : |
1937 | if (smc->y[PA].pc_mode == PM_PEER) { |
1938 | RS_SET(smc,RS_EVENT) ; |
1939 | queue_event(smc,EVENT_PCM+PA,PC_DISABLE) ; |
1940 | } |
1941 | break ; |
1942 | case SMT_STATION_ACTION_DISABLE_B : |
1943 | if (smc->y[PB].pc_mode == PM_PEER) { |
1944 | RS_SET(smc,RS_EVENT) ; |
1945 | queue_event(smc,EVENT_PCM+PB,PC_DISABLE) ; |
1946 | } |
1947 | break ; |
1948 | case SMT_STATION_ACTION_DISABLE_M : |
1949 | for (port = 0 ; port < NUMPHYS ; port++) { |
1950 | if (smc->mib.p[port].fddiPORTMy_Type != TM) |
1951 | continue ; |
1952 | RS_SET(smc,RS_EVENT) ; |
1953 | queue_event(smc,EVENT_PCM+port,PC_DISABLE) ; |
1954 | } |
1955 | break ; |
1956 | default : |
1957 | return 1; |
1958 | } |
1959 | break ; |
1960 | case SMT_PORT_ACTION : |
1961 | switch(code) { |
1962 | case SMT_PORT_ACTION_ENABLE : |
1963 | event = PC_ENABLE ; |
1964 | break ; |
1965 | case SMT_PORT_ACTION_DISABLE : |
1966 | event = PC_DISABLE ; |
1967 | break ; |
1968 | case SMT_PORT_ACTION_MAINT : |
1969 | event = PC_MAINT ; |
1970 | break ; |
1971 | case SMT_PORT_ACTION_START : |
1972 | event = PC_START ; |
1973 | break ; |
1974 | case SMT_PORT_ACTION_STOP : |
1975 | event = PC_STOP ; |
1976 | break ; |
1977 | default : |
1978 | return 1; |
1979 | } |
1980 | queue_event(smc,EVENT_PCM+index,event) ; |
1981 | break ; |
1982 | default : |
1983 | return 1; |
1984 | } |
1985 | return 0; |
1986 | } |
1987 | |
1988 | /* |
1989 | * canonical conversion of <len> bytes beginning form *data |
1990 | */ |
1991 | #ifdef USE_CAN_ADDR |
1992 | static void hwm_conv_can(struct s_smc *smc, char *data, int len) |
1993 | { |
1994 | int i ; |
1995 | |
1996 | SK_UNUSED(smc) ; |
1997 | |
1998 | for (i = len; i ; i--, data++) |
1999 | *data = bitrev8(*data); |
2000 | } |
2001 | #endif |
2002 | |
2003 | #endif /* no SLIM_SMT */ |
2004 | |
2005 | |