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