1/* 2 * Copyright (c) 1996-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * Author: Hartmut Brandt <harti@freebsd.org> 28 * 29 * $Begemot: libunimsg/netnatm/saal/saal_sscfu.c,v 1.4 2004/07/08 08:22:10 brandt Exp $ 30 * 31 * SSCF on the UNI 32 */ 33 34#include <netnatm/saal/sscfu.h> 35#include <netnatm/saal/sscfupriv.h> 36 37#define MKSTR(S) #S 38 39static const char *const sscf_sigs[] = { 40 MKSTR(SAAL_ESTABLISH_request), 41 MKSTR(SAAL_ESTABLISH_indication), 42 MKSTR(SAAL_ESTABLISH_confirm), 43 MKSTR(SAAL_RELEASE_request), 44 MKSTR(SAAL_RELEASE_confirm), 45 MKSTR(SAAL_RELEASE_indication), 46 MKSTR(SAAL_DATA_request), 47 MKSTR(SAAL_DATA_indication), 48 MKSTR(SAAL_UDATA_request), 49 MKSTR(SAAL_UDATA_indication), 50}; 51 52static const char *const sscf_states[] = { 53 MKSTR(SSCF_RELEASED), 54 MKSTR(SSCF_AWAITING_ESTABLISH), 55 MKSTR(SSCF_AWAITING_RELEASE), 56 MKSTR(SSCF_ESTABLISHED), 57 MKSTR(SSCF_RESYNC), 58}; 59 60#define AA_SIG(S,G,M) \ 61 ((S)->funcs->send_upper((S), (S)->aarg, (G), (M))) 62 63#define SSCOP_AASIG(S,G,M,P) \ 64 ((S)->funcs->send_lower((S), (S)->aarg, (G), (M), (P))) 65 66MEMINIT(); 67 68static void sscfu_unqueue(struct sscfu *sscf); 69 70/************************************************************/ 71/* 72 * INSTANCE AND CLASS MANAGEMENT 73 */ 74 75/* 76 * Initialize SSCF. 77 */ 78struct sscfu * 79sscfu_create(void *a, const struct sscfu_funcs *funcs) 80{ 81 struct sscfu *sscf; 82 83 MEMZALLOC(sscf, struct sscfu *, sizeof(struct sscfu)); 84 if (sscf == NULL) 85 return (NULL); 86 87 sscf->funcs = funcs; 88 sscf->aarg = a; 89 sscf->state = SSCFU_RELEASED; 90 sscf->inhand = 0; 91 SIGQ_INIT(&sscf->sigs); 92 sscf->debug = 0; 93 94 return (sscf); 95} 96 97/* 98 * Reset the instance. Call only if you know, what you're doing. 99 */ 100void 101sscfu_reset(struct sscfu *sscf) 102{ 103 sscf->state = SSCFU_RELEASED; 104 sscf->inhand = 0; 105 SIGQ_CLEAR(&sscf->sigs); 106} 107 108/* 109 * Destroy SSCF 110 */ 111void 112sscfu_destroy(struct sscfu *sscf) 113{ 114 SIGQ_CLEAR(&sscf->sigs); 115 MEMFREE(sscf); 116} 117 118enum sscfu_state 119sscfu_getstate(const struct sscfu *sscf) 120{ 121 return (sscf->state); 122} 123 124u_int 125sscfu_getdefparam(struct sscop_param *p) 126{ 127 memset(p, 0, sizeof(*p)); 128 129 p->timer_cc = 1000; 130 p->timer_poll = 750; 131 p->timer_keep_alive = 2000; 132 p->timer_no_response = 7000; 133 p->timer_idle = 15000; 134 p->maxk = 4096; 135 p->maxj = 4096; 136 p->maxcc = 4; 137 p->maxpd = 25; 138 139 return (SSCOP_SET_TCC | SSCOP_SET_TPOLL | SSCOP_SET_TKA | 140 SSCOP_SET_TNR | SSCOP_SET_TIDLE | SSCOP_SET_MAXK | 141 SSCOP_SET_MAXJ | SSCOP_SET_MAXCC | SSCOP_SET_MAXPD); 142} 143 144const char * 145sscfu_signame(enum saal_sig sig) 146{ 147 static char str[40]; 148 149 if (sig >= sizeof(sscf_sigs)/sizeof(sscf_sigs[0])) { 150 sprintf(str, "BAD SAAL_SIGNAL %u", sig); 151 return (str); 152 } else { 153 return (sscf_sigs[sig]); 154 } 155} 156 157const char * 158sscfu_statename(enum sscfu_state s) 159{ 160 static char str[40]; 161 162 if (s >= sizeof(sscf_states)/sizeof(sscf_states[0])) { 163 sprintf(str, "BAD SSCFU state %u", s); 164 return (str); 165 } else { 166 return (sscf_states[s]); 167 } 168} 169 170/************************************************************/ 171/* 172 * EXTERNAL INPUT SIGNAL MAPPING 173 */ 174static __inline void 175set_state(struct sscfu *sscf, enum sscfu_state state) 176{ 177 VERBOSE(sscf, SSCFU_DBG_STATE, (sscf, sscf->aarg, 178 "change state from %s to %s", 179 sscf_states[sscf->state], sscf_states[state])); 180 sscf->state = state; 181} 182 183/* 184 * signal from SSCOP to SSCF 185 * Message must be freed by the user specified handler, if 186 * it is passed. 187 */ 188void 189sscfu_input(struct sscfu *sscf, enum sscop_aasig sig, 190 struct SSCFU_MBUF_T *m, u_int arg __unused) 191{ 192 sscf->inhand = 1; 193 194 VERBOSE(sscf, SSCFU_DBG_LSIG, (sscf, sscf->aarg, 195 "SSCF got signal %d. in state %s", sig, sscf_states[sscf->state])); 196 197 switch (sig) { 198 199 case SSCOP_RELEASE_indication: 200 /* arg is: UU, SRC */ 201 switch (sscf->state) { 202 203 case SSCFU_RELEASED: 204 if (m) 205 MBUF_FREE(m); 206 goto badsig; 207 208 case SSCFU_AWAITING_ESTABLISH: 209 set_state(sscf, SSCFU_RELEASED); 210 AA_SIG(sscf, SAAL_RELEASE_indication, m); 211 break; 212 213 case SSCFU_AWAITING_RELEASE: 214 if (m) 215 MBUF_FREE(m); 216 goto badsig; 217 218 case SSCFU_ESTABLISHED: 219 set_state(sscf, SSCFU_RELEASED); 220 AA_SIG(sscf, SAAL_RELEASE_indication, m); 221 break; 222 223 case SSCFU_RESYNC: 224 set_state(sscf, SSCFU_RELEASED); 225 AA_SIG(sscf, SAAL_RELEASE_indication, m); 226 break; 227 } 228 break; 229 230 case SSCOP_ESTABLISH_indication: 231 /* arg is: UU */ 232 switch (sscf->state) { 233 234 case SSCFU_RELEASED: 235 set_state(sscf, SSCFU_ESTABLISHED); 236 SSCOP_AASIG(sscf, SSCOP_ESTABLISH_response, NULL, 1); 237 AA_SIG(sscf, SAAL_ESTABLISH_indication, m); 238 break; 239 240 case SSCFU_AWAITING_ESTABLISH: 241 case SSCFU_AWAITING_RELEASE: 242 case SSCFU_ESTABLISHED: 243 case SSCFU_RESYNC: 244 if (m) 245 MBUF_FREE(m); 246 goto badsig; 247 } 248 break; 249 250 case SSCOP_ESTABLISH_confirm: 251 /* arg is: UU */ 252 switch (sscf->state) { 253 254 case SSCFU_RELEASED: 255 if (m) 256 MBUF_FREE(m); 257 goto badsig; 258 259 case SSCFU_AWAITING_ESTABLISH: 260 set_state(sscf, SSCFU_ESTABLISHED); 261 AA_SIG(sscf, SAAL_ESTABLISH_confirm, m); 262 break; 263 264 case SSCFU_AWAITING_RELEASE: 265 case SSCFU_ESTABLISHED: 266 case SSCFU_RESYNC: 267 if (m) 268 MBUF_FREE(m); 269 goto badsig; 270 } 271 break; 272 273 case SSCOP_RELEASE_confirm: 274 /* arg is: */ 275 switch (sscf->state) { 276 277 case SSCFU_RELEASED: 278 case SSCFU_AWAITING_ESTABLISH: 279 goto badsig; 280 281 case SSCFU_AWAITING_RELEASE: 282 set_state(sscf, SSCFU_RELEASED); 283 AA_SIG(sscf, SAAL_RELEASE_confirm, NULL); 284 break; 285 286 case SSCFU_ESTABLISHED: 287 case SSCFU_RESYNC: 288 goto badsig; 289 } 290 break; 291 292 case SSCOP_DATA_indication: 293 /* arg is: MU */ 294 sscf->funcs->window(sscf, sscf->aarg, 1); 295 switch (sscf->state) { 296 297 case SSCFU_RELEASED: 298 case SSCFU_AWAITING_ESTABLISH: 299 case SSCFU_AWAITING_RELEASE: 300 MBUF_FREE(m); 301 goto badsig; 302 303 case SSCFU_ESTABLISHED: 304 AA_SIG(sscf, SAAL_DATA_indication, m); 305 break; 306 307 case SSCFU_RESYNC: 308 MBUF_FREE(m); 309 goto badsig; 310 } 311 break; 312 313 case SSCOP_RECOVER_indication: 314 /* arg is: */ 315 switch (sscf->state) { 316 317 case SSCFU_RELEASED: 318 case SSCFU_AWAITING_ESTABLISH: 319 case SSCFU_AWAITING_RELEASE: 320 goto badsig; 321 322 case SSCFU_ESTABLISHED: 323 SSCOP_AASIG(sscf, SSCOP_RECOVER_response, NULL, 0); 324 AA_SIG(sscf, SAAL_ESTABLISH_indication, NULL); 325 break; 326 327 case SSCFU_RESYNC: 328 goto badsig; 329 } 330 break; 331 332 case SSCOP_RESYNC_indication: 333 /* arg is: UU */ 334 switch (sscf->state) { 335 336 case SSCFU_RELEASED: 337 case SSCFU_AWAITING_ESTABLISH: 338 case SSCFU_AWAITING_RELEASE: 339 if (m) 340 MBUF_FREE(m); 341 goto badsig; 342 343 case SSCFU_ESTABLISHED: 344 SSCOP_AASIG(sscf, SSCOP_RESYNC_response, NULL, 0); 345 AA_SIG(sscf, SAAL_ESTABLISH_indication, m); 346 break; 347 348 case SSCFU_RESYNC: 349 if (m) 350 MBUF_FREE(m); 351 goto badsig; 352 } 353 break; 354 355 case SSCOP_RESYNC_confirm: 356 /* arg is: */ 357 switch (sscf->state) { 358 359 case SSCFU_RELEASED: 360 case SSCFU_AWAITING_ESTABLISH: 361 case SSCFU_AWAITING_RELEASE: 362 case SSCFU_ESTABLISHED: 363 364 case SSCFU_RESYNC: 365 set_state(sscf, SSCFU_ESTABLISHED); 366 AA_SIG(sscf, SAAL_ESTABLISH_confirm, NULL); 367 break; 368 } 369 break; 370 371 case SSCOP_UDATA_indication: 372 /* arg is: MD */ 373 AA_SIG(sscf, SAAL_UDATA_indication, m); 374 break; 375 376 377 case SSCOP_RETRIEVE_indication: 378 if (m) 379 MBUF_FREE(m); 380 goto badsig; 381 382 case SSCOP_RETRIEVE_COMPL_indication: 383 goto badsig; 384 385 case SSCOP_ESTABLISH_request: 386 case SSCOP_RELEASE_request: 387 case SSCOP_ESTABLISH_response: 388 case SSCOP_DATA_request: 389 case SSCOP_RECOVER_response: 390 case SSCOP_RESYNC_request: 391 case SSCOP_RESYNC_response: 392 case SSCOP_UDATA_request: 393 case SSCOP_RETRIEVE_request: 394 ASSERT(0); 395 break; 396 } 397 398 sscfu_unqueue(sscf); 399 return; 400 401 badsig: 402 VERBOSE(sscf, SSCFU_DBG_ERR, (sscf, sscf->aarg, 403 "bad signal %d. in state %s", sig, sscf_states[sscf->state])); 404 sscfu_unqueue(sscf); 405} 406 407 408/* 409 * Handle signals from the user 410 */ 411static void 412sscfu_dosig(struct sscfu *sscf, enum saal_sig sig, struct SSCFU_MBUF_T *m) 413{ 414 VERBOSE(sscf, SSCFU_DBG_EXEC, (sscf, sscf->aarg, 415 "executing signal %s(%s)", 416 sscf_sigs[sig], sscf_states[sscf->state])); 417 418 switch (sig) { 419 420 case SAAL_ESTABLISH_request: 421 /* arg is opt UU */ 422 switch (sscf->state) { 423 424 case SSCFU_RELEASED: 425 set_state(sscf, SSCFU_AWAITING_ESTABLISH); 426 SSCOP_AASIG(sscf, SSCOP_ESTABLISH_request, m, 1); 427 break; 428 429 case SSCFU_AWAITING_ESTABLISH: 430 if (m) 431 MBUF_FREE(m); 432 goto badsig; 433 434 case SSCFU_AWAITING_RELEASE: 435 set_state(sscf, SSCFU_AWAITING_ESTABLISH); 436 SSCOP_AASIG(sscf, SSCOP_ESTABLISH_request, m, 1); 437 break; 438 439 case SSCFU_ESTABLISHED: 440 set_state(sscf, SSCFU_RESYNC); 441 SSCOP_AASIG(sscf, SSCOP_RESYNC_request, m, 0); 442 break; 443 444 case SSCFU_RESYNC: 445 if (m) 446 MBUF_FREE(m); 447 goto badsig; 448 } 449 break; 450 451 case SAAL_RELEASE_request: 452 /* arg is opt UU */ 453 switch(sscf->state) { 454 455 case SSCFU_RELEASED: 456 if (m) 457 MBUF_FREE(m); 458 AA_SIG(sscf, SAAL_RELEASE_confirm, NULL); 459 break; 460 461 case SSCFU_AWAITING_ESTABLISH: 462 set_state(sscf, SSCFU_AWAITING_RELEASE); 463 SSCOP_AASIG(sscf, SSCOP_RELEASE_request, m, 0); 464 break; 465 466 case SSCFU_AWAITING_RELEASE: 467 if (m) 468 MBUF_FREE(m); 469 goto badsig; 470 471 case SSCFU_ESTABLISHED: 472 set_state(sscf, SSCFU_AWAITING_RELEASE); 473 SSCOP_AASIG(sscf, SSCOP_RELEASE_request, m, 0); 474 break; 475 476 case SSCFU_RESYNC: 477 set_state(sscf, SSCFU_AWAITING_RELEASE); 478 SSCOP_AASIG(sscf, SSCOP_RELEASE_request, m, 0); 479 break; 480 } 481 break; 482 483 case SAAL_DATA_request: 484 /* arg is DATA */ 485 switch (sscf->state) { 486 487 case SSCFU_RELEASED: 488 case SSCFU_AWAITING_ESTABLISH: 489 case SSCFU_AWAITING_RELEASE: 490 MBUF_FREE(m); 491 goto badsig; 492 493 case SSCFU_ESTABLISHED: 494 SSCOP_AASIG(sscf, SSCOP_DATA_request, m, 0); 495 break; 496 497 case SSCFU_RESYNC: 498 MBUF_FREE(m); 499 goto badsig; 500 } 501 break; 502 503 case SAAL_UDATA_request: 504 /* arg is UDATA */ 505 SSCOP_AASIG(sscf, SSCOP_UDATA_request, m, 0); 506 break; 507 508 case SAAL_ESTABLISH_indication: 509 case SAAL_ESTABLISH_confirm: 510 case SAAL_RELEASE_confirm: 511 case SAAL_RELEASE_indication: 512 case SAAL_DATA_indication: 513 case SAAL_UDATA_indication: 514 ASSERT(0); 515 break; 516 } 517 return; 518 519 badsig: 520 VERBOSE(sscf, SSCFU_DBG_ERR, (sscf, sscf->aarg, 521 "bad signal %s in state %s", sscf_sigs[sig], 522 sscf_states[sscf->state])); 523} 524 525/* 526 * Handle user signal. 527 */ 528int 529sscfu_saalsig(struct sscfu *sscf, enum saal_sig sig, struct SSCFU_MBUF_T *m) 530{ 531 struct sscfu_sig *s; 532 533 if (sscf->inhand) { 534 VERBOSE(sscf, SSCFU_DBG_EXEC, (sscf, sscf->aarg, 535 "queuing user signal %s(%s)", 536 sscf_sigs[sig], sscf_states[sscf->state])); 537 SIG_ALLOC(s); 538 if (s == NULL) 539 return (ENOMEM); 540 s->sig = sig; 541 s->m = m; 542 SIGQ_APPEND(&sscf->sigs, s); 543 return (0); 544 } 545 546 sscf->inhand = 1; 547 sscfu_dosig(sscf, sig, m); 548 sscfu_unqueue(sscf); 549 return (0); 550} 551 552/* 553 * Unqueue all qeueued signals. Must be called with inhand==1. 554 */ 555static void 556sscfu_unqueue(struct sscfu *sscf) 557{ 558 struct sscfu_sig *s; 559 560 while ((s = SIGQ_GET(&sscf->sigs)) != NULL) { 561 sscfu_dosig(sscf, s->sig, s->m); 562 SIG_FREE(s); 563 } 564 sscf->inhand = 0; 565} 566 567void 568sscfu_setdebug(struct sscfu *sscf, u_int n) 569{ 570 sscf->debug = n; 571} 572 573u_int 574sscfu_getdebug(const struct sscfu *sscf) 575{ 576 return (sscf->debug); 577} 578