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