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