1 /* 2 * Copyright (C) Dirk Husemann, Computer Science Department IV, 3 * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Dirk Husemann and the Computer Science Department (IV) of 9 * the University of Erlangen-Nuremberg, Germany. 10 * 11 * %sccs.include.redist.c% 12 * 13 * @(#)llc_subr.c 8.1 (Berkeley) 06/10/93 14 */ 15 16 #include <sys/param.h> 17 #include <sys/systm.h> 18 #include <sys/mbuf.h> 19 #include <sys/domain.h> 20 #include <sys/socket.h> 21 #include <sys/protosw.h> 22 #include <sys/socketvar.h> 23 #include <sys/errno.h> 24 #include <sys/time.h> 25 #include <sys/kernel.h> 26 27 #include <net/if.h> 28 #include <net/if_dl.h> 29 #include <net/if_llc.h> 30 #include <net/route.h> 31 32 #include <netccitt/dll.h> 33 #include <netccitt/llc_var.h> 34 35 /* 36 * Frame names for diagnostic messages 37 */ 38 char *frame_names[] = { "INFO", "RR", "RNR", "REJ", "DM", "SABME", "DISC", 39 "UA", "FRMR", "UI", "XID", "TEST", "ILLEGAL", "TIMER", "N2xT1"}; 40 41 42 /* 43 * Trace level 44 */ 45 int llc_tracelevel = LLCTR_URGENT; 46 47 /* 48 * Values for accessing various bitfields 49 */ 50 struct bitslice llc_bitslice[] = { 51 /* mask, shift value */ 52 { 0x1, 0x0 }, 53 { 0xfe, 0x1 }, 54 { 0x3, 0x0 }, 55 { 0xc, 0x2 }, 56 { 0x10, 0x4 }, 57 { 0xe0, 0x5 }, 58 { 0x1f, 0x0 } 59 }; 60 61 /* 62 * We keep the link control blocks on a doubly linked list - 63 * primarily for checking in llc_time() 64 */ 65 66 struct llccb_q llccb_q = { &llccb_q, &llccb_q }; 67 68 /* 69 * Flag for signalling wether route tree for AF_LINK has been 70 * initialized yet. 71 */ 72 73 int af_link_rts_init_done = 0; 74 75 76 /* 77 * Functions dealing with struct sockaddr_dl */ 78 79 /* Compare sdl_a w/ sdl_b */ 80 81 sdl_cmp(struct sockaddr_dl *sdl_a, struct sockaddr_dl *sdl_b) 82 { 83 if (LLADDRLEN(sdl_a) != LLADDRLEN(sdl_b)) 84 return(1); 85 return(bcmp((caddr_t) sdl_a->sdl_data, (caddr_t) sdl_b->sdl_data, 86 LLADDRLEN(sdl_a))); 87 } 88 89 /* Copy sdl_f to sdl_t */ 90 91 sdl_copy(struct sockaddr_dl *sdl_f, struct sockaddr_dl *sdl_t) 92 { 93 bcopy((caddr_t) sdl_f, (caddr_t) sdl_t, sdl_f->sdl_len); 94 } 95 96 /* Swap sdl_a w/ sdl_b */ 97 98 sdl_swapaddr(struct sockaddr_dl *sdl_a, struct sockaddr_dl *sdl_b) 99 { 100 struct sockaddr_dl sdl_tmp; 101 102 sdl_copy(sdl_a, &sdl_tmp); 103 sdl_copy(sdl_b, sdl_a); 104 sdl_copy(&sdl_tmp, sdl_b); 105 } 106 107 /* Fetch the sdl of the associated if */ 108 109 struct sockaddr_dl * 110 sdl_getaddrif(struct ifnet *ifp) 111 { 112 register struct ifaddr *ifa; 113 114 for(ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 115 if (ifa->ifa_addr->sa_family == AF_LINK ) 116 return((struct sockaddr_dl *)(ifa->ifa_addr)); 117 118 return((struct sockaddr_dl *)0); 119 } 120 121 /* Check addr of interface with the one given */ 122 123 sdl_checkaddrif(struct ifnet *ifp, struct sockaddr_dl *sdl_c) 124 { 125 register struct ifaddr *ifa; 126 127 for(ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 128 if ((ifa->ifa_addr->sa_family == AF_LINK ) && 129 !sdl_cmp((struct sockaddr_dl *)(ifa->ifa_addr), sdl_c)) 130 return(1); 131 132 return(0); 133 } 134 135 /* Build an sdl from MAC addr, DLSAP addr, and interface */ 136 137 sdl_setaddrif(struct ifnet *ifp, u_char *mac_addr, u_char dlsap_addr, 138 u_char mac_len, struct sockaddr_dl *sdl_to) 139 { 140 register struct sockaddr_dl *sdl_tmp; 141 142 if ((sdl_tmp = sdl_getaddrif(ifp)) ) { 143 sdl_copy(sdl_tmp, sdl_to); 144 bcopy((caddr_t) mac_addr, (caddr_t) LLADDR(sdl_to), mac_len); 145 *(LLADDR(sdl_to)+mac_len) = dlsap_addr; 146 sdl_to->sdl_alen = mac_len+1; 147 return(1); 148 } else return(0); 149 } 150 151 /* Fill out the sdl header aggregate */ 152 153 sdl_sethdrif(struct ifnet *ifp, u_char *mac_src, u_char dlsap_src, u_char *mac_dst, 154 u_char dlsap_dst, u_char mac_len, struct sdl_hdr *sdlhdr_to) 155 { 156 if ( !sdl_setaddrif(ifp, mac_src, dlsap_src, mac_len, 157 &sdlhdr_to->sdlhdr_src) || 158 !sdl_setaddrif(ifp, mac_dst, dlsap_dst, mac_len, 159 &sdlhdr_to->sdlhdr_dst) ) 160 return(0); 161 else return(1); 162 } 163 164 static struct sockaddr_dl sap_saddr; 165 static struct sockaddr_dl sap_sgate = { 166 sizeof(struct sockaddr_dl), /* _len */ 167 AF_LINK /* _af */ 168 }; 169 170 /* 171 * Set sapinfo for SAP address, llcconfig, af, and interface 172 */ 173 struct npaidbentry * 174 llc_setsapinfo(struct ifnet *ifp, u_char af, u_char sap, struct dllconfig *llconf) 175 { 176 struct protosw *pp; 177 struct sockaddr_dl *ifdl_addr; 178 struct rtentry *sirt = (struct rtentry *)0; 179 struct npaidbentry *sapinfo; 180 u_char saploc; 181 int size = sizeof(struct npaidbentry); 182 183 USES_AF_LINK_RTS; 184 185 /* 186 * We rely/assume that only STREAM protocols will make use of 187 * connection oriented LLC2. If this will one day not be the 188 * case this will obviously fail. 189 */ 190 pp = pffindtype (af, SOCK_STREAM); 191 if (pp == 0 || pp->pr_input == 0 || pp->pr_ctlinput == 0) { 192 printf("network level protosw error"); 193 return 0; 194 } 195 196 /* 197 * We need a way to jot down the LLC2 configuration for 198 * a certain LSAP address. To do this we enter 199 * a "route" for the SAP. 200 */ 201 ifdl_addr = sdl_getaddrif(ifp); 202 sdl_copy(ifdl_addr, &sap_saddr); 203 sdl_copy(ifdl_addr, &sap_sgate); 204 saploc = LLSAPLOC(&sap_saddr, ifp); 205 sap_saddr.sdl_data[saploc] = sap; 206 sap_saddr.sdl_alen++; 207 208 /* now enter it */ 209 rtrequest(RTM_ADD, (struct sockaddr *)&sap_saddr, 210 (struct sockaddr *)&sap_sgate, 0, 0, &sirt); 211 if (sirt == 0) 212 return 0; 213 214 /* Plug in config information in rt->rt_llinfo */ 215 216 sirt->rt_llinfo = malloc(size , M_PCB, M_WAITOK); 217 sapinfo = (struct npaidbentry *) sirt->rt_llinfo; 218 if (sapinfo) { 219 bzero ((caddr_t)sapinfo, size); 220 /* 221 * For the time being we support LLC CLASS II here 222 * only 223 */ 224 sapinfo->si_class = LLC_CLASS_II; 225 sapinfo->si_window = llconf->dllcfg_window; 226 sapinfo->si_trace = llconf->dllcfg_trace; 227 if (sapinfo->si_trace) 228 llc_tracelevel--; 229 else llc_tracelevel++; 230 sapinfo->si_input = pp->pr_input; 231 sapinfo->si_ctlinput = (caddr_t (*)())pp->pr_ctlinput; 232 233 return (sapinfo); 234 } 235 236 return 0; 237 } 238 239 /* 240 * Get sapinfo for SAP address and interface 241 */ 242 struct npaidbentry * 243 llc_getsapinfo(u_char sap, struct ifnet *ifp) 244 { 245 struct sockaddr_dl *ifdl_addr; 246 struct sockaddr_dl si_addr; 247 struct rtentry *sirt; 248 u_char saploc; 249 250 USES_AF_LINK_RTS; 251 252 ifdl_addr = sdl_getaddrif(ifp); 253 sdl_copy(ifdl_addr, &si_addr); 254 saploc = LLSAPLOC(&si_addr, ifp); 255 si_addr.sdl_data[saploc] = sap; 256 si_addr.sdl_alen++; 257 258 if ((sirt = rtalloc1((struct sockaddr *)&si_addr, 0))) 259 sirt->rt_refcnt--; 260 else return(0); 261 262 return((struct npaidbentry *)sirt->rt_llinfo); 263 } 264 265 /* 266 * llc_seq2slot() --- We only allocate enough memory to hold the window. This 267 * introduces the necessity to keep track of two ``pointers'' 268 * 269 * o llcl_freeslot the next free slot to be used 270 * this one advances modulo llcl_window 271 * o llcl_projvs the V(S) associated with the next frame 272 * to be set via llcl_freeslot 273 * this one advances modulo LLC_MAX_SEQUENCE 274 * 275 * A new frame is inserted at llcl_output_buffers[llcl_freeslot], after 276 * which both llcl_freeslot and llcl_projvs are incremented. 277 * 278 * The slot sl(sn) for any given sequence number sn is given by 279 * 280 * sl(sn) = (llcl_freeslot + llcl_window - 1 - (llcl_projvs + 281 * LLC_MAX_SEQUENCE- sn) % LLC_MAX_SEQUENCE) % 282 * llcl_window 283 * 284 * i.e. we first calculate the number of frames we need to ``go back'' 285 * from the current one (really the next one, but that doesn't matter as 286 * llcl_projvs is likewise of by plus one) and subtract that from the 287 * pointer to the most recently taken frame (llcl_freeslot - 1). 288 */ 289 290 short 291 llc_seq2slot(struct llc_linkcb *linkp, short seqn) 292 { 293 register sn = 0; 294 295 sn = (linkp->llcl_freeslot + linkp->llcl_window - 296 (linkp->llcl_projvs + LLC_MAX_SEQUENCE - seqn) % 297 LLC_MAX_SEQUENCE) % linkp->llcl_window; 298 299 return sn; 300 } 301 302 /* 303 * LLC2 link state handler 304 * 305 * There is in most cases one function per LLC2 state. The LLC2 standard 306 * ISO 8802-2 allows in some cases for ambiguities, i.e. we have the choice 307 * to do one thing or the other. Right now I have just chosen one but have also 308 * indicated the spot by "multiple possibilities". One could make the behavior 309 * in those cases configurable, allowing the superuser to enter a profile word 310 * (32/64 bits, whatever is needed) that would suit her needs [I quite like 311 * that idea, perhaps I'll get around to it]. 312 * 313 * [Preceeding each state handler function is the description as taken from 314 * ISO 8802-2, section 7.9.2.1] 315 */ 316 317 /* 318 * ADM --- The connection component is in the asynchronous disconnected mode. 319 * It can accept an SABME PDU from a remote LLC SSAP or, at the request 320 * of the service access point user, can initiate an SABME PDU 321 * transmission to a remote LLC DSAP, to establish a data link 322 * connection. It also responds to a DISC command PDU and to any 323 * command PDU with the P bit set to ``1''. 324 */ 325 int 326 llc_state_ADM(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 327 int cmdrsp, int pollfinal) 328 { 329 int action = 0; 330 331 switch(frame_kind + cmdrsp) { 332 case NL_CONNECT_REQUEST: 333 llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); 334 LLC_SETFLAG(linkp, P, pollfinal); 335 LLC_SETFLAG(linkp, S, 0); 336 linkp->llcl_retry = 0; 337 LLC_NEWSTATE(linkp, SETUP); 338 break; 339 case LLCFT_SABME + LLC_CMD: 340 /* 341 * ISO 8802-2, table 7-1, ADM state says to set 342 * the P flag, yet this will cause an SABME [P] to be 343 * answered with an UA only, not an UA [F], all 344 * other `disconnected' states set the F flag, so ... 345 */ 346 LLC_SETFLAG(linkp, F, pollfinal); 347 LLC_NEWSTATE(linkp, CONN); 348 action = LLC_CONNECT_INDICATION; 349 break; 350 case LLCFT_DISC + LLC_CMD: 351 llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); 352 break; 353 default: 354 if (cmdrsp == LLC_CMD && pollfinal == 1) 355 llc_send(linkp, LLCFT_DM, LLC_RSP, 1); 356 /* remain in ADM state */ 357 } 358 359 return action; 360 } 361 362 /* 363 * CONN --- The local connection component has received an SABME PDU from a 364 * remote LLC SSAP, and it is waiting for the local user to accept or 365 * refuse the connection. 366 */ 367 int 368 llc_state_CONN(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 369 int cmdrsp, int pollfinal) 370 { 371 int action = 0; 372 373 switch(frame_kind + cmdrsp) { 374 case NL_CONNECT_RESPONSE: 375 llc_send(linkp, LLCFT_UA, LLC_RSP, LLC_GETFLAG(linkp, F)); 376 LLC_RESETCOUNTER(linkp); 377 LLC_SETFLAG(linkp, P, 0); 378 LLC_SETFLAG(linkp, REMOTE_BUSY, 0); 379 LLC_NEWSTATE(linkp, NORMAL); 380 break; 381 case NL_DISCONNECT_REQUEST: 382 llc_send(linkp, LLCFT_DM, LLC_RSP, LLC_GETFLAG(linkp, F)); 383 LLC_NEWSTATE(linkp, ADM); 384 break; 385 case LLCFT_SABME + LLC_CMD: 386 LLC_SETFLAG(linkp, F, pollfinal); 387 break; 388 case LLCFT_DM + LLC_RSP: 389 LLC_NEWSTATE(linkp, ADM); 390 action = LLC_DISCONNECT_INDICATION; 391 break; 392 /* all other frames effect nothing here */ 393 } 394 395 return action; 396 } 397 398 /* 399 * RESET_WAIT --- The local connection component is waiting for the local user 400 * to indicate a RESET_REQUEST or a DISCONNECT_REQUEST. 401 */ 402 int 403 llc_state_RESET_WAIT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 404 int cmdrsp, int pollfinal) 405 { 406 int action = 0; 407 408 switch(frame_kind + cmdrsp) { 409 case NL_RESET_REQUEST: 410 if (LLC_GETFLAG(linkp, S) == 0) { 411 llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); 412 LLC_SETFLAG(linkp, P, pollfinal); 413 LLC_START_ACK_TIMER(linkp); 414 linkp->llcl_retry = 0; 415 LLC_NEWSTATE(linkp, RESET); 416 } else { 417 llc_send(linkp, LLCFT_UA, LLC_RSP, 418 LLC_GETFLAG(linkp, F)); 419 LLC_RESETCOUNTER(linkp); 420 LLC_SETFLAG(linkp, P, 0); 421 LLC_SETFLAG(linkp, REMOTE_BUSY, 0); 422 LLC_NEWSTATE(linkp, NORMAL); 423 action = LLC_RESET_CONFIRM; 424 } 425 break; 426 case NL_DISCONNECT_REQUEST: 427 if (LLC_GETFLAG(linkp, S) == 0) { 428 llc_send(linkp, LLCFT_DISC, LLC_CMD, pollfinal); 429 LLC_SETFLAG(linkp, P, pollfinal); 430 LLC_START_ACK_TIMER(linkp); 431 linkp->llcl_retry = 0; 432 LLC_NEWSTATE(linkp, D_CONN); 433 } else { 434 llc_send(linkp, LLCFT_DM, LLC_RSP, 435 LLC_GETFLAG(linkp, F)); 436 LLC_NEWSTATE(linkp, ADM); 437 } 438 break; 439 case LLCFT_DM + LLC_RSP: 440 LLC_NEWSTATE(linkp, ADM); 441 action = LLC_DISCONNECT_INDICATION; 442 break; 443 case LLCFT_SABME + LLC_CMD: 444 LLC_SETFLAG(linkp, S, 1); 445 LLC_SETFLAG(linkp, F, pollfinal); 446 break; 447 case LLCFT_DISC + LLC_CMD: 448 llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); 449 LLC_NEWSTATE(linkp, ADM); 450 action = LLC_DISCONNECT_INDICATION; 451 break; 452 } 453 454 return action; 455 } 456 457 /* 458 * RESET_CHECK --- The local connection component is waiting for the local user 459 * to accept or refuse a remote reset request. 460 */ 461 int 462 llc_state_RESET_CHECK(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 463 int cmdrsp, int pollfinal) 464 { 465 int action = 0; 466 467 switch(frame_kind + cmdrsp) { 468 case NL_RESET_RESPONSE: 469 llc_send(linkp, LLCFT_UA, LLC_RSP, LLC_GETFLAG(linkp, F)); 470 LLC_RESETCOUNTER(linkp); 471 LLC_SETFLAG(linkp, P, 0); 472 LLC_SETFLAG(linkp, REMOTE_BUSY, 0); 473 LLC_NEWSTATE(linkp, NORMAL); 474 break; 475 case NL_DISCONNECT_REQUEST: 476 llc_send(linkp, LLCFT_DM, LLC_RSP, LLC_GETFLAG(linkp, F)); 477 LLC_NEWSTATE(linkp, ADM); 478 break; 479 case LLCFT_DM + LLC_RSP: 480 action = LLC_DISCONNECT_INDICATION; 481 break; 482 case LLCFT_SABME + LLC_CMD: 483 LLC_SETFLAG(linkp, F, pollfinal); 484 break; 485 case LLCFT_DISC + LLC_CMD: 486 llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); 487 LLC_NEWSTATE(linkp, ADM); 488 action = LLC_DISCONNECT_INDICATION; 489 break; 490 } 491 492 return action; 493 } 494 495 /* 496 * SETUP --- The connection component has transmitted an SABME command PDU to a 497 * remote LLC DSAP and is waiting for a reply. 498 */ 499 int 500 llc_state_SETUP(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 501 int cmdrsp, int pollfinal) 502 { 503 int action = 0; 504 505 switch(frame_kind + cmdrsp) { 506 case LLCFT_SABME + LLC_CMD: 507 LLC_RESETCOUNTER(linkp); 508 llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal); 509 LLC_SETFLAG(linkp, S, 1); 510 break; 511 case LLCFT_UA + LLC_RSP: 512 if (LLC_GETFLAG(linkp, P) == pollfinal) { 513 LLC_STOP_ACK_TIMER(linkp); 514 LLC_RESETCOUNTER(linkp); 515 LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 516 LLC_SETFLAG(linkp, REMOTE_BUSY, 0); 517 LLC_NEWSTATE(linkp, NORMAL); 518 action = LLC_CONNECT_CONFIRM; 519 } 520 break; 521 case LLC_ACK_TIMER_EXPIRED: 522 if (LLC_GETFLAG(linkp, S) == 1) { 523 LLC_SETFLAG(linkp, P, 0); 524 LLC_SETFLAG(linkp, REMOTE_BUSY, 0), 525 LLC_NEWSTATE(linkp, NORMAL); 526 action = LLC_CONNECT_CONFIRM; 527 } else if (linkp->llcl_retry < llc_n2) { 528 llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); 529 LLC_SETFLAG(linkp, P, pollfinal); 530 LLC_START_ACK_TIMER(linkp); 531 linkp->llcl_retry++; 532 } else { 533 LLC_NEWSTATE(linkp, ADM); 534 action = LLC_DISCONNECT_INDICATION; 535 } 536 break; 537 case LLCFT_DISC + LLC_CMD: 538 llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); 539 LLC_STOP_ACK_TIMER(linkp); 540 LLC_NEWSTATE(linkp, ADM); 541 action = LLC_DISCONNECT_INDICATION; 542 break; 543 case LLCFT_DM + LLC_RSP: 544 LLC_STOP_ACK_TIMER(linkp); 545 LLC_NEWSTATE(linkp, ADM); 546 action = LLC_DISCONNECT_INDICATION; 547 break; 548 } 549 550 return action; 551 } 552 553 /* 554 * RESET --- As a result of a service access point user request or the receipt 555 * of a FRMR response PDU, the local connection component has sent an 556 * SABME command PDU to the remote LLC DSAP to reset the data link 557 * connection and is waiting for a reply. 558 */ 559 int 560 llc_state_RESET(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 561 int cmdrsp, int pollfinal) 562 { 563 int action = 0; 564 565 switch(frame_kind + cmdrsp) { 566 case LLCFT_SABME + LLC_CMD: 567 LLC_RESETCOUNTER(linkp); 568 LLC_SETFLAG(linkp, S, 1); 569 llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal); 570 break; 571 case LLCFT_UA + LLC_RSP: 572 if (LLC_GETFLAG(linkp, P) == pollfinal) { 573 LLC_STOP_ACK_TIMER(linkp); 574 LLC_RESETCOUNTER(linkp); 575 LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 576 LLC_SETFLAG(linkp, REMOTE_BUSY, 0); 577 LLC_NEWSTATE(linkp, NORMAL); 578 action = LLC_RESET_CONFIRM; 579 } 580 break; 581 case LLC_ACK_TIMER_EXPIRED: 582 if (LLC_GETFLAG(linkp, S) == 1) { 583 LLC_SETFLAG(linkp, P, 0); 584 LLC_SETFLAG(linkp, REMOTE_BUSY, 0); 585 LLC_NEWSTATE(linkp, NORMAL); 586 action = LLC_RESET_CONFIRM; 587 } else if (linkp->llcl_retry < llc_n2) { 588 llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); 589 LLC_SETFLAG(linkp, P, pollfinal); 590 LLC_START_ACK_TIMER(linkp); 591 linkp->llcl_retry++; 592 } else { 593 LLC_NEWSTATE(linkp, ADM); 594 action = LLC_DISCONNECT_INDICATION; 595 } 596 break; 597 case LLCFT_DISC + LLC_CMD: 598 llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); 599 LLC_STOP_ACK_TIMER(linkp); 600 LLC_NEWSTATE(linkp, ADM); 601 action = LLC_DISCONNECT_INDICATION; 602 break; 603 case LLCFT_DM + LLC_RSP: 604 LLC_STOP_ACK_TIMER(linkp); 605 LLC_NEWSTATE(linkp, ADM); 606 action = LLC_DISCONNECT_INDICATION; 607 break; 608 } 609 610 return action; 611 } 612 613 /* 614 * D_CONN --- At the request of the service access point user, the local LLC 615 * has sent a DISC command PDU to the remote LLC DSAP and is waiting 616 * for a reply. 617 */ 618 int 619 llc_state_D_CONN(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 620 int cmdrsp, int pollfinal) 621 { 622 int action = 0; 623 624 switch(frame_kind + cmdrsp) { 625 case LLCFT_SABME + LLC_CMD: 626 llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); 627 LLC_STOP_ACK_TIMER(linkp); 628 LLC_NEWSTATE(linkp, ADM); 629 break; 630 case LLCFT_UA + LLC_RSP: 631 if (LLC_GETFLAG(linkp, P) == pollfinal) { 632 LLC_STOP_ACK_TIMER(linkp); 633 LLC_NEWSTATE(linkp, ADM); 634 } 635 break; 636 case LLCFT_DISC + LLC_CMD: 637 llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal); 638 break; 639 case LLCFT_DM + LLC_RSP: 640 LLC_STOP_ACK_TIMER(linkp); 641 LLC_NEWSTATE(linkp, ADM); 642 break; 643 case LLC_ACK_TIMER_EXPIRED: 644 if (linkp->llcl_retry < llc_n2) { 645 llc_send(linkp, LLCFT_DISC, LLC_CMD, pollfinal); 646 LLC_SETFLAG(linkp, P, pollfinal); 647 LLC_START_ACK_TIMER(linkp); 648 linkp->llcl_retry++; 649 } else LLC_NEWSTATE(linkp, ADM); 650 break; 651 } 652 653 return action; 654 } 655 656 /* 657 * ERROR --- The local connection component has detected an error in a received 658 * PDU and has sent a FRMR response PDU. It is waiting for a reply from 659 * the remote connection component. 660 */ 661 int 662 llc_state_ERROR(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 663 int cmdrsp, int pollfinal) 664 { 665 int action = 0; 666 667 switch(frame_kind + cmdrsp) { 668 case LLCFT_SABME + LLC_CMD: 669 LLC_STOP_ACK_TIMER(linkp); 670 LLC_NEWSTATE(linkp, RESET_CHECK); 671 action = LLC_RESET_INDICATION_REMOTE; 672 break; 673 case LLCFT_DISC + LLC_CMD: 674 llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal); 675 LLC_STOP_ACK_TIMER(linkp); 676 LLC_NEWSTATE(linkp, ADM); 677 action = LLC_DISCONNECT_INDICATION; 678 break; 679 case LLCFT_DM + LLC_RSP: 680 LLC_STOP_ACK_TIMER(linkp); 681 LLC_NEWSTATE(linkp, ADM); 682 action = LLC_DISCONNECT_INDICATION; 683 break; 684 case LLCFT_FRMR + LLC_RSP: 685 LLC_STOP_ACK_TIMER(linkp); 686 LLC_SETFLAG(linkp, S, 0); 687 LLC_NEWSTATE(linkp, RESET_WAIT); 688 action = LLC_FRMR_RECEIVED; 689 break; 690 case LLC_ACK_TIMER_EXPIRED: 691 if (linkp->llcl_retry < llc_n2) { 692 llc_send(linkp, LLCFT_FRMR, LLC_RSP, 0); 693 LLC_START_ACK_TIMER(linkp); 694 linkp->llcl_retry++; 695 } else { 696 LLC_SETFLAG(linkp, S, 0); 697 LLC_NEWSTATE(linkp, RESET_WAIT); 698 action = LLC_RESET_INDICATION_LOCAL; 699 } 700 break; 701 default: 702 if (cmdrsp == LLC_CMD){ 703 llc_send(linkp, LLCFT_FRMR, LLC_RSP, pollfinal); 704 LLC_START_ACK_TIMER(linkp); 705 } 706 break; 707 708 } 709 710 return action; 711 } 712 713 /* 714 * NORMAL, BUSY, REJECT, AWAIT, AWAIT_BUSY, and AWAIT_REJECT all share 715 * a common core state handler. 716 */ 717 int 718 llc_state_NBRAcore(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 719 int cmdrsp, int pollfinal) 720 { 721 int action = 0; 722 723 switch(frame_kind + cmdrsp) { 724 case NL_DISCONNECT_REQUEST: 725 llc_send(linkp, LLCFT_DISC, LLC_CMD, pollfinal); 726 LLC_SETFLAG(linkp, P, pollfinal); 727 LLC_STOP_ALL_TIMERS(linkp); 728 LLC_START_ACK_TIMER(linkp); 729 linkp->llcl_retry = 0; 730 LLC_NEWSTATE(linkp, D_CONN); 731 break; 732 case NL_RESET_REQUEST: 733 llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); 734 LLC_SETFLAG(linkp, P, pollfinal); 735 LLC_STOP_ALL_TIMERS(linkp); 736 LLC_START_ACK_TIMER(linkp); 737 linkp->llcl_retry = 0; 738 LLC_SETFLAG(linkp, S, 0); 739 LLC_NEWSTATE(linkp, RESET); 740 break; 741 case LLCFT_SABME + LLC_CMD: 742 LLC_SETFLAG(linkp, F, pollfinal); 743 LLC_STOP_ALL_TIMERS(linkp); 744 LLC_NEWSTATE(linkp, RESET_CHECK); 745 action = LLC_RESET_INDICATION_REMOTE; 746 break; 747 case LLCFT_DISC + LLC_CMD: 748 llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal); 749 LLC_STOP_ALL_TIMERS(linkp); 750 LLC_NEWSTATE(linkp, ADM); 751 action = LLC_DISCONNECT_INDICATION; 752 break; 753 case LLCFT_FRMR + LLC_RSP: 754 LLC_STOP_ALL_TIMERS(linkp); 755 LLC_SETFLAG(linkp, S, 0); 756 LLC_NEWSTATE(linkp, RESET_WAIT); 757 action = LLC_FRMR_RECEIVED; 758 break; 759 case LLCFT_DM + LLC_RSP: 760 LLC_STOP_ALL_TIMERS(linkp); 761 LLC_NEWSTATE(linkp, ADM); 762 action = LLC_DISCONNECT_INDICATION; 763 break; 764 case LLC_INVALID_NR + LLC_CMD: 765 case LLC_INVALID_NS + LLC_CMD: 766 LLC_SETFRMR(linkp, frame, cmdrsp, 767 (frame_kind == LLC_INVALID_NR ? LLC_FRMR_Z : 768 (LLC_FRMR_V | LLC_FRMR_W))); 769 llc_send(linkp, LLCFT_FRMR, LLC_RSP, pollfinal); 770 LLC_STOP_ALL_TIMERS(linkp); 771 LLC_START_ACK_TIMER(linkp); 772 linkp->llcl_retry = 0; 773 LLC_NEWSTATE(linkp, ERROR); 774 action = LLC_FRMR_SENT; 775 break; 776 case LLC_INVALID_NR + LLC_RSP: 777 case LLC_INVALID_NS + LLC_RSP: 778 case LLCFT_UA + LLC_RSP: 779 case LLC_BAD_PDU: { 780 char frmrcause = 0; 781 782 switch (frame_kind) { 783 case LLC_INVALID_NR: frmrcause = LLC_FRMR_Z; break; 784 case LLC_INVALID_NS: frmrcause = LLC_FRMR_V | LLC_FRMR_W; break; 785 default: frmrcause = LLC_FRMR_W; 786 } 787 LLC_SETFRMR(linkp, frame, cmdrsp, frmrcause); 788 llc_send(linkp, LLCFT_FRMR, LLC_RSP, 0); 789 LLC_STOP_ALL_TIMERS(linkp); 790 LLC_START_ACK_TIMER(linkp); 791 linkp->llcl_retry = 0; 792 LLC_NEWSTATE(linkp, ERROR); 793 action = LLC_FRMR_SENT; 794 break; 795 } 796 default: 797 if (cmdrsp == LLC_RSP && pollfinal == 1 && 798 LLC_GETFLAG(linkp, P) == 0) { 799 LLC_SETFRMR(linkp, frame, cmdrsp, LLC_FRMR_W); 800 LLC_STOP_ALL_TIMERS(linkp); 801 LLC_START_ACK_TIMER(linkp); 802 linkp->llcl_retry = 0; 803 LLC_NEWSTATE(linkp, ERROR); 804 action = LLC_FRMR_SENT; 805 } 806 break; 807 case LLC_P_TIMER_EXPIRED: 808 case LLC_ACK_TIMER_EXPIRED: 809 case LLC_REJ_TIMER_EXPIRED: 810 case LLC_BUSY_TIMER_EXPIRED: 811 if (linkp->llcl_retry >= llc_n2) { 812 LLC_STOP_ALL_TIMERS(linkp); 813 LLC_SETFLAG(linkp, S, 0); 814 LLC_NEWSTATE(linkp, RESET_WAIT); 815 action = LLC_RESET_INDICATION_LOCAL; 816 } 817 break; 818 } 819 820 return action; 821 } 822 823 /* 824 * NORMAL --- A data link connection exists between the local LLC service access 825 * point and the remote LLC service access point. Sending and 826 * reception of information and supervisory PDUs can be performed. 827 */ 828 int 829 llc_state_NORMAL(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 830 int cmdrsp, int pollfinal) 831 { 832 int action = LLC_PASSITON; 833 834 switch(frame_kind + cmdrsp) { 835 case NL_DATA_REQUEST: 836 if (LLC_GETFLAG(linkp, REMOTE_BUSY) == 0) { 837 #ifdef not_now 838 if (LLC_GETFLAG(linkp, P) == 0) { 839 /* multiple possibilities */ 840 llc_send(linkp, LLCFT_INFO, LLC_CMD, 1); 841 LLC_START_P_TIMER(linkp); 842 if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) 843 LLC_START_ACK_TIMER(linkp); 844 } else { 845 #endif 846 /* multiple possibilities */ 847 llc_send(linkp, LLCFT_INFO, LLC_CMD, 0); 848 if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) 849 LLC_START_ACK_TIMER(linkp); 850 #ifdef not_now 851 } 852 #endif 853 action = 0; 854 } 855 break; 856 case LLC_LOCAL_BUSY_DETECTED: 857 if (LLC_GETFLAG(linkp, P) == 0) { 858 /* multiple possibilities --- action-wise */ 859 /* multiple possibilities --- CMD/RSP-wise */ 860 llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 861 LLC_START_P_TIMER(linkp); 862 LLC_SETFLAG(linkp, DATA, 0); 863 LLC_NEWSTATE(linkp, BUSY); 864 action = 0; 865 } else { 866 /* multiple possibilities --- CMD/RSP-wise */ 867 llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 868 LLC_SETFLAG(linkp, DATA, 0); 869 LLC_NEWSTATE(linkp, BUSY); 870 action = 0; 871 } 872 break; 873 case LLC_INVALID_NS + LLC_CMD: 874 case LLC_INVALID_NS + LLC_RSP: { 875 register int p = LLC_GETFLAG(linkp, P); 876 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 877 878 if (cmdrsp == LLC_CMD && pollfinal == 1) { 879 llc_send(linkp, LLCFT_REJ, LLC_RSP, 1); 880 LLC_UPDATE_NR_RECEIVED(linkp, nr); 881 LLC_START_REJ_TIMER(linkp); 882 LLC_NEWSTATE(linkp, REJECT); 883 action = 0; 884 } else if (pollfinal == 0 && p == 1) { 885 llc_send(linkp, LLCFT_REJ, LLC_CMD, 0); 886 LLC_UPDATE_NR_RECEIVED(linkp, nr); 887 LLC_START_REJ_TIMER(linkp); 888 LLC_NEWSTATE(linkp, REJECT); 889 action = 0; 890 } else if ((pollfinal == 0 && p == 0) || 891 (pollfinal == 1 && p == 1 && cmdrsp == LLC_RSP)) { 892 llc_send(linkp, LLCFT_REJ, LLC_CMD, 1); 893 LLC_UPDATE_NR_RECEIVED(linkp, nr); 894 LLC_START_P_TIMER(linkp); 895 LLC_START_REJ_TIMER(linkp); 896 if (cmdrsp == LLC_RSP && pollfinal == 1) { 897 LLC_CLEAR_REMOTE_BUSY(linkp, action); 898 } else action = 0; 899 LLC_NEWSTATE(linkp, REJECT); 900 } 901 break; 902 } 903 case LLCFT_INFO + LLC_CMD: 904 case LLCFT_INFO + LLC_RSP: { 905 register int p = LLC_GETFLAG(linkp, P); 906 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 907 908 if (cmdrsp == LLC_CMD && pollfinal == 1) { 909 LLC_INC(linkp->llcl_vr); 910 LLC_SENDACKNOWLEDGE(linkp, LLC_RSP, 1); 911 LLC_UPDATE_NR_RECEIVED(linkp, nr); 912 action = LLC_DATA_INDICATION; 913 } else if (pollfinal == 0 && p == 1) { 914 LLC_INC(linkp->llcl_vr); 915 LLC_SENDACKNOWLEDGE(linkp, LLC_CMD, 0); 916 LLC_UPDATE_NR_RECEIVED(linkp, nr); 917 action = LLC_DATA_INDICATION; 918 } else if ((pollfinal == 0 && p == 0 && cmdrsp == LLC_CMD) || 919 (pollfinal == p && cmdrsp == LLC_RSP)) { 920 LLC_INC(linkp->llcl_vr); 921 LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 922 LLC_SENDACKNOWLEDGE(linkp, LLC_CMD, 0); 923 LLC_UPDATE_NR_RECEIVED(linkp, nr); 924 if (cmdrsp == LLC_RSP && pollfinal == 1) 925 LLC_CLEAR_REMOTE_BUSY(linkp, action); 926 action = LLC_DATA_INDICATION; 927 } 928 break; 929 } 930 case LLCFT_RR + LLC_CMD: 931 case LLCFT_RR + LLC_RSP: { 932 register int p = LLC_GETFLAG(linkp, P); 933 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 934 935 if (cmdrsp == LLC_CMD && pollfinal == 1) { 936 LLC_SENDACKNOWLEDGE(linkp, LLC_RSP, 1); 937 LLC_UPDATE_NR_RECEIVED(linkp, nr); 938 LLC_CLEAR_REMOTE_BUSY(linkp, action); 939 } else if ((pollfinal == 0) || 940 (cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) { 941 LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 942 LLC_UPDATE_NR_RECEIVED(linkp, nr); 943 LLC_CLEAR_REMOTE_BUSY(linkp, action); 944 } 945 break; 946 } 947 case LLCFT_RNR + LLC_CMD: 948 case LLCFT_RNR + LLC_RSP: { 949 register int p = LLC_GETFLAG(linkp, P); 950 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 951 952 if (cmdrsp == LLC_CMD && pollfinal == 1) { 953 llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 954 LLC_UPDATE_NR_RECEIVED(linkp, nr); 955 LLC_SET_REMOTE_BUSY(linkp, action); 956 } else if ((pollfinal == 0) || 957 (cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) { 958 LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 959 LLC_UPDATE_NR_RECEIVED(linkp, nr); 960 LLC_SET_REMOTE_BUSY(linkp, action); 961 } 962 break; 963 } 964 case LLCFT_REJ + LLC_CMD: 965 case LLCFT_REJ + LLC_RSP: { 966 register int p = LLC_GETFLAG(linkp, P); 967 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 968 969 if (cmdrsp == LLC_CMD && pollfinal == 1) { 970 linkp->llcl_vs = nr; 971 LLC_UPDATE_NR_RECEIVED(linkp, nr); 972 llc_resend(linkp, LLC_RSP, 1); 973 LLC_CLEAR_REMOTE_BUSY(linkp, action); 974 } else if (pollfinal == 0 && p == 1) { 975 linkp->llcl_vs = nr; 976 LLC_UPDATE_NR_RECEIVED(linkp, nr); 977 llc_resend(linkp, LLC_CMD, 0); 978 LLC_CLEAR_REMOTE_BUSY(linkp, action); 979 } else if ((pollfinal == 0 && p == 0 && cmdrsp == LLC_CMD) || 980 (pollfinal == p && cmdrsp == LLC_RSP)) { 981 linkp->llcl_vs = nr; 982 LLC_UPDATE_NR_RECEIVED(linkp, nr); 983 LLC_START_P_TIMER(linkp); 984 llc_resend(linkp, LLC_CMD, 1); 985 LLC_CLEAR_REMOTE_BUSY(linkp, action); 986 } 987 break; 988 } 989 case NL_INITIATE_PF_CYCLE: 990 if (LLC_GETFLAG(linkp, P) == 0) { 991 llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 992 LLC_START_P_TIMER(linkp); 993 action = 0; 994 } 995 break; 996 case LLC_P_TIMER_EXPIRED: 997 if (linkp->llcl_retry < llc_n2) { 998 llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 999 LLC_START_P_TIMER(linkp); 1000 linkp->llcl_retry++; 1001 LLC_NEWSTATE(linkp, AWAIT); 1002 action = 0; 1003 } 1004 break; 1005 case LLC_ACK_TIMER_EXPIRED: 1006 case LLC_BUSY_TIMER_EXPIRED: 1007 if ((LLC_GETFLAG(linkp, P) == 0) 1008 && (linkp->llcl_retry < llc_n2)) { 1009 llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 1010 LLC_START_P_TIMER(linkp); 1011 linkp->llcl_retry++; 1012 LLC_NEWSTATE(linkp, AWAIT); 1013 action = 0; 1014 } 1015 break; 1016 } 1017 if (action == LLC_PASSITON) 1018 action = llc_state_NBRAcore(linkp, frame, frame_kind, 1019 cmdrsp, pollfinal); 1020 1021 return action; 1022 } 1023 1024 /* 1025 * BUSY --- A data link connection exists between the local LLC service access 1026 * point and the remote LLC service access point. I PDUs may be sent. 1027 * Local conditions make it likely that the information feld of 1028 * received I PDUs will be ignored. Supervisory PDUs may be both sent 1029 * and received. 1030 */ 1031 int 1032 llc_state_BUSY(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 1033 int cmdrsp, int pollfinal) 1034 { 1035 int action = LLC_PASSITON; 1036 1037 switch(frame_kind + cmdrsp) { 1038 case NL_DATA_REQUEST: 1039 if (LLC_GETFLAG(linkp, REMOTE_BUSY) == 0) 1040 if (LLC_GETFLAG(linkp, P) == 0) { 1041 llc_send(linkp, LLCFT_INFO, LLC_CMD, 1); 1042 LLC_START_P_TIMER(linkp); 1043 if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) 1044 LLC_START_ACK_TIMER(linkp); 1045 action = 0; 1046 } else { 1047 llc_send(linkp, LLCFT_INFO, LLC_CMD, 0); 1048 if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) 1049 LLC_START_ACK_TIMER(linkp); 1050 action = 0; 1051 } 1052 break; 1053 case LLC_LOCAL_BUSY_CLEARED: { 1054 register int p = LLC_GETFLAG(linkp, P); 1055 register int df = LLC_GETFLAG(linkp, DATA); 1056 1057 switch (df) { 1058 case 1: 1059 if (p == 0) { 1060 /* multiple possibilities */ 1061 llc_send(linkp, LLCFT_REJ, LLC_CMD, 1); 1062 LLC_START_REJ_TIMER(linkp); 1063 LLC_START_P_TIMER(linkp); 1064 LLC_NEWSTATE(linkp, REJECT); 1065 action = 0; 1066 } else { 1067 llc_send(linkp, LLCFT_REJ, LLC_CMD, 0); 1068 LLC_START_REJ_TIMER(linkp); 1069 LLC_NEWSTATE(linkp, REJECT); 1070 action = 0; 1071 } 1072 break; 1073 case 0: 1074 if (p == 0) { 1075 /* multiple possibilities */ 1076 llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 1077 LLC_START_P_TIMER(linkp); 1078 LLC_NEWSTATE(linkp, NORMAL); 1079 action = 0; 1080 } else { 1081 llc_send(linkp, LLCFT_RR, LLC_CMD, 0); 1082 LLC_NEWSTATE(linkp, NORMAL); 1083 action = 0; 1084 } 1085 break; 1086 case 2: 1087 if (p == 0) { 1088 /* multiple possibilities */ 1089 llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 1090 LLC_START_P_TIMER(linkp); 1091 LLC_NEWSTATE(linkp, REJECT); 1092 action = 0; 1093 } else { 1094 llc_send(linkp, LLCFT_RR, LLC_CMD, 0); 1095 LLC_NEWSTATE(linkp, REJECT); 1096 action =0; 1097 } 1098 break; 1099 } 1100 break; 1101 } 1102 case LLC_INVALID_NS + LLC_CMD: 1103 case LLC_INVALID_NS + LLC_RSP: { 1104 register int p = LLC_GETFLAG(linkp, P); 1105 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1106 1107 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1108 llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 1109 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1110 if (LLC_GETFLAG(linkp, DATA) == 0) 1111 LLC_SETFLAG(linkp, DATA, 1); 1112 action = 0; 1113 } else if ((cmdrsp == LLC_CMD && pollfinal == 0 && p == 0) || 1114 (cmdrsp == LLC_RSP && pollfinal == p)) { 1115 llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 1116 LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 1117 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1118 if (LLC_GETFLAG(linkp, DATA) == 0) 1119 LLC_SETFLAG(linkp, DATA, 1); 1120 if (cmdrsp == LLC_RSP && pollfinal == 1) { 1121 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1122 } else action = 0; 1123 } else if (pollfinal == 0 && p == 1) { 1124 llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 1125 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1126 if (LLC_GETFLAG(linkp, DATA) == 0) 1127 LLC_SETFLAG(linkp, DATA, 1); 1128 action = 0; 1129 } 1130 break; 1131 } 1132 case LLCFT_INFO + LLC_CMD: 1133 case LLCFT_INFO + LLC_RSP: { 1134 register int p = LLC_GETFLAG(linkp, P); 1135 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1136 1137 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1138 LLC_INC(linkp->llcl_vr); 1139 llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 1140 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1141 if (LLC_GETFLAG(linkp, DATA) == 2) 1142 LLC_STOP_REJ_TIMER(linkp); 1143 LLC_SETFLAG(linkp, DATA, 0); 1144 action = LLC_DATA_INDICATION; 1145 } else if ((cmdrsp == LLC_CMD && pollfinal == 0 && p == 0) || 1146 (cmdrsp == LLC_RSP && pollfinal == p)) { 1147 LLC_INC(linkp->llcl_vr); 1148 llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); 1149 LLC_START_P_TIMER(linkp); 1150 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1151 if (LLC_GETFLAG(linkp, DATA) == 2) 1152 LLC_STOP_REJ_TIMER(linkp); 1153 if (cmdrsp == LLC_RSP && pollfinal == 1) 1154 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1155 action = LLC_DATA_INDICATION; 1156 } else if (pollfinal == 0 && p == 1) { 1157 LLC_INC(linkp->llcl_vr); 1158 llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 1159 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1160 if (LLC_GETFLAG(linkp, DATA) == 2) 1161 LLC_STOP_REJ_TIMER(linkp); 1162 LLC_SETFLAG(linkp, DATA, 0); 1163 action = LLC_DATA_INDICATION; 1164 } 1165 break; 1166 } 1167 case LLCFT_RR + LLC_CMD: 1168 case LLCFT_RR + LLC_RSP: 1169 case LLCFT_RNR + LLC_CMD: 1170 case LLCFT_RNR + LLC_RSP: { 1171 register int p = LLC_GETFLAG(linkp, P); 1172 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1173 1174 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1175 llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 1176 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1177 if (frame_kind == LLCFT_RR) { 1178 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1179 } else { 1180 LLC_SET_REMOTE_BUSY(linkp, action); 1181 } 1182 } else if (pollfinal = 0 || 1183 (cmdrsp == LLC_RSP && pollfinal == 1)) { 1184 LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 1185 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1186 if (frame_kind == LLCFT_RR) { 1187 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1188 } else { 1189 LLC_SET_REMOTE_BUSY(linkp, action); 1190 } 1191 } 1192 break; 1193 } 1194 case LLCFT_REJ + LLC_CMD: 1195 case LLCFT_REJ + LLC_RSP: { 1196 register int p = LLC_GETFLAG(linkp, P); 1197 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1198 1199 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1200 linkp->llcl_vs = nr; 1201 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1202 llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 1203 llc_resend(linkp, LLC_CMD, 0); 1204 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1205 } else if ((cmdrsp == LLC_CMD && pollfinal == 0 && p == 0) || 1206 (cmdrsp == LLC_RSP && pollfinal == p)) { 1207 linkp->llcl_vs = nr; 1208 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1209 LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 1210 llc_resend(linkp, LLC_CMD, 0); 1211 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1212 } else if (pollfinal == 0 && p == 1) { 1213 linkp->llcl_vs = nr; 1214 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1215 llc_resend(linkp, LLC_CMD, 0); 1216 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1217 } 1218 break; 1219 } 1220 case NL_INITIATE_PF_CYCLE: 1221 if (LLC_GETFLAG(linkp, P) == 0) { 1222 llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); 1223 LLC_START_P_TIMER(linkp); 1224 action = 0; 1225 } 1226 break; 1227 case LLC_P_TIMER_EXPIRED: 1228 /* multiple possibilities */ 1229 if (linkp->llcl_retry < llc_n2) { 1230 llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); 1231 LLC_START_P_TIMER(linkp); 1232 linkp->llcl_retry++; 1233 LLC_NEWSTATE(linkp, AWAIT_BUSY); 1234 action = 0; 1235 } 1236 break; 1237 case LLC_ACK_TIMER_EXPIRED: 1238 case LLC_BUSY_TIMER_EXPIRED: 1239 if (LLC_GETFLAG(linkp, P) == 0 && linkp->llcl_retry < llc_n2) { 1240 llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); 1241 LLC_START_P_TIMER(linkp); 1242 linkp->llcl_retry++; 1243 LLC_NEWSTATE(linkp, AWAIT_BUSY); 1244 action = 0; 1245 } 1246 break; 1247 case LLC_REJ_TIMER_EXPIRED: 1248 if (linkp->llcl_retry < llc_n2) 1249 if (LLC_GETFLAG(linkp, P) == 0) { 1250 /* multiple possibilities */ 1251 llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); 1252 LLC_START_P_TIMER(linkp); 1253 linkp->llcl_retry++; 1254 LLC_SETFLAG(linkp, DATA, 1); 1255 LLC_NEWSTATE(linkp, AWAIT_BUSY); 1256 action = 0; 1257 } else{ 1258 LLC_SETFLAG(linkp, DATA, 1); 1259 LLC_NEWSTATE(linkp, BUSY); 1260 action = 0; 1261 } 1262 1263 break; 1264 } 1265 if (action == LLC_PASSITON) 1266 action = llc_state_NBRAcore(linkp, frame, frame_kind, 1267 cmdrsp, pollfinal); 1268 1269 return action; 1270 } 1271 1272 /* 1273 * REJECT --- A data link connection exists between the local LLC service 1274 * access point and the remote LLC service access point. The local 1275 * connection component has requested that the remote connection 1276 * component resend a specific I PDU that the local connection 1277 * componnent has detected as being out of sequence. Both I PDUs and 1278 * supervisory PDUs may be sent and received. 1279 */ 1280 int 1281 llc_state_REJECT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 1282 int cmdrsp, int pollfinal) 1283 { 1284 int action = LLC_PASSITON; 1285 1286 switch(frame_kind + cmdrsp) { 1287 case NL_DATA_REQUEST: 1288 if (LLC_GETFLAG(linkp, P) == 0) { 1289 llc_send(linkp, LLCFT_INFO, LLC_CMD, 1); 1290 LLC_START_P_TIMER(linkp); 1291 if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) 1292 LLC_START_ACK_TIMER(linkp); 1293 LLC_NEWSTATE(linkp, REJECT); 1294 action = 0; 1295 } else { 1296 llc_send(linkp, LLCFT_INFO, LLC_CMD, 0); 1297 if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) 1298 LLC_START_ACK_TIMER(linkp); 1299 LLC_NEWSTATE(linkp, REJECT); 1300 action = 0; 1301 } 1302 break; 1303 case NL_LOCAL_BUSY_DETECTED: 1304 if (LLC_GETFLAG(linkp, P) == 0) { 1305 llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); 1306 LLC_START_P_TIMER(linkp); 1307 LLC_SETFLAG(linkp, DATA, 2); 1308 LLC_NEWSTATE(linkp, BUSY); 1309 action = 0; 1310 } else { 1311 llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 1312 LLC_SETFLAG(linkp, DATA, 2); 1313 LLC_NEWSTATE(linkp, BUSY); 1314 action = 0; 1315 } 1316 break; 1317 case LLC_INVALID_NS + LLC_CMD: 1318 case LLC_INVALID_NS + LLC_RSP: { 1319 register int p = LLC_GETFLAG(linkp, P); 1320 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1321 1322 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1323 llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 1324 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1325 action = 0; 1326 } else if (pollfinal == 0 || 1327 (cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) { 1328 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1329 LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 1330 if (cmdrsp == LLC_RSP && pollfinal == 1) { 1331 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1332 } else action = 0; 1333 } 1334 break; 1335 } 1336 case LLCFT_INFO + LLC_CMD: 1337 case LLCFT_INFO + LLC_RSP: { 1338 register int p = LLC_GETFLAG(linkp, P); 1339 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1340 1341 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1342 LLC_INC(linkp->llcl_vr); 1343 LLC_SENDACKNOWLEDGE(linkp, LLC_RSP, 1); 1344 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1345 LLC_STOP_REJ_TIMER(linkp); 1346 LLC_NEWSTATE(linkp, NORMAL); 1347 action = LLC_DATA_INDICATION; 1348 } else if ((cmdrsp = LLC_RSP && pollfinal == p) || 1349 (cmdrsp == LLC_CMD && pollfinal == 0 && p == 0)) { 1350 LLC_INC(linkp->llcl_vr); 1351 LLC_SENDACKNOWLEDGE(linkp, LLC_CMD, 1); 1352 LLC_START_P_TIMER(linkp); 1353 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1354 if (cmdrsp == LLC_RSP && pollfinal == 1) 1355 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1356 LLC_STOP_REJ_TIMER(linkp); 1357 LLC_NEWSTATE(linkp, NORMAL); 1358 action = LLC_DATA_INDICATION; 1359 } else if (pollfinal == 0 && p == 1) { 1360 LLC_INC(linkp->llcl_vr); 1361 LLC_SENDACKNOWLEDGE(linkp, LLC_CMD, 0); 1362 LLC_STOP_REJ_TIMER(linkp); 1363 LLC_NEWSTATE(linkp, NORMAL); 1364 action = LLC_DATA_INDICATION; 1365 } 1366 break; 1367 } 1368 case LLCFT_RR + LLC_CMD: 1369 case LLCFT_RR + LLC_RSP: { 1370 register int p = LLC_GETFLAG(linkp, P); 1371 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1372 1373 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1374 LLC_SENDACKNOWLEDGE(linkp, LLC_RSP, 1); 1375 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1376 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1377 } else if (pollfinal == 0 || 1378 (cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) { 1379 LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 1380 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1381 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1382 } 1383 break; 1384 } 1385 case LLCFT_RNR + LLC_CMD: 1386 case LLCFT_RNR + LLC_RSP: { 1387 register int p = LLC_GETFLAG(linkp, P); 1388 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1389 1390 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1391 llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 1392 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1393 LLC_SET_REMOTE_BUSY(linkp, action); 1394 } else if (pollfinal == 0 || 1395 (cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) { 1396 LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 1397 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1398 action = 0; 1399 } 1400 break; 1401 } 1402 case LLCFT_REJ + LLC_CMD: 1403 case LLCFT_REJ + LLC_RSP: { 1404 register int p = LLC_GETFLAG(linkp, P); 1405 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1406 1407 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1408 linkp->llcl_vs = nr; 1409 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1410 llc_resend(linkp, LLC_RSP, 1); 1411 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1412 } else if ((cmdrsp == LLC_CMD && pollfinal == 0 && p == 0) || 1413 (cmdrsp == LLC_RSP && pollfinal == p)) { 1414 linkp->llcl_vs = nr; 1415 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1416 LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 1417 llc_resend(linkp, LLC_CMD, 0); 1418 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1419 } else if (pollfinal == 0 && p == 1) { 1420 linkp->llcl_vs = nr; 1421 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1422 llc_resend(linkp, LLC_CMD, 0); 1423 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1424 } 1425 break; 1426 } 1427 case NL_INITIATE_PF_CYCLE: 1428 if (LLC_GETFLAG(linkp, P) == 0) { 1429 llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 1430 LLC_START_P_TIMER(linkp); 1431 action = 0; 1432 } 1433 break; 1434 case LLC_REJ_TIMER_EXPIRED: 1435 if (LLC_GETFLAG(linkp, P) == 0 && linkp->llcl_retry < llc_n2) { 1436 llc_send(linkp, LLCFT_REJ, LLC_CMD, 1); 1437 LLC_START_P_TIMER(linkp); 1438 LLC_START_REJ_TIMER(linkp); 1439 linkp->llcl_retry++; 1440 action = 0; 1441 } 1442 case LLC_P_TIMER_EXPIRED: 1443 if (linkp->llcl_retry < llc_n2) { 1444 llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 1445 LLC_START_P_TIMER(linkp); 1446 LLC_START_REJ_TIMER(linkp); 1447 linkp->llcl_retry++; 1448 LLC_NEWSTATE(linkp, AWAIT_REJECT); 1449 action = 0; 1450 } 1451 break; 1452 case LLC_ACK_TIMER_EXPIRED: 1453 case LLC_BUSY_TIMER_EXPIRED: 1454 if (LLC_GETFLAG(linkp, P) == 0 && linkp->llcl_retry < llc_n2) { 1455 llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 1456 LLC_START_P_TIMER(linkp); 1457 LLC_START_REJ_TIMER(linkp); 1458 linkp->llcl_retry++; 1459 /* 1460 * I cannot locate the description of RESET_V(S) 1461 * in ISO 8802-2, table 7-1, state REJECT, last event, 1462 * and assume they meant to set V(S) to 0 ... 1463 */ 1464 linkp->llcl_vs = 0; /* XXX */ 1465 LLC_NEWSTATE(linkp, AWAIT_REJECT); 1466 action = 0; 1467 } 1468 1469 break; 1470 } 1471 if (action == LLC_PASSITON) 1472 action = llc_state_NBRAcore(linkp, frame, frame_kind, 1473 cmdrsp, pollfinal); 1474 1475 return action; 1476 } 1477 1478 /* 1479 * AWAIT --- A data link connection exists between the local LLC service access 1480 * point and the remote LLC service access point. The local LLC is 1481 * performing a timer recovery operation and has sent a command PDU 1482 * with the P bit set to ``1'', and is awaiting an acknowledgement 1483 * from the remote LLC. I PDUs may be received but not sent. 1484 * Supervisory PDUs may be both sent and received. 1485 */ 1486 int 1487 llc_state_AWAIT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 1488 int cmdrsp, int pollfinal) 1489 { 1490 int action = LLC_PASSITON; 1491 1492 switch(frame_kind + cmdrsp) { 1493 case LLC_LOCAL_BUSY_DETECTED: 1494 llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 1495 LLC_SETFLAG(linkp, DATA, 0); 1496 LLC_NEWSTATE(linkp, AWAIT_BUSY); 1497 action = 0; 1498 break; 1499 case LLC_INVALID_NS + LLC_CMD: 1500 case LLC_INVALID_NS + LLC_RSP: { 1501 register int p = LLC_GETFLAG(linkp, P); 1502 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1503 1504 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1505 llc_send(linkp, LLCFT_REJ, LLC_RSP, 1); 1506 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1507 LLC_START_REJ_TIMER(linkp); 1508 LLC_NEWSTATE(linkp, AWAIT_REJECT); 1509 action = 0; 1510 } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 1511 llc_send(linkp, LLCFT_REJ, LLC_CMD, 0); 1512 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1513 linkp->llcl_vs = nr; 1514 LLC_STOP_P_TIMER(linkp); 1515 llc_resend(linkp, LLC_CMD, 0); 1516 LLC_START_REJ_TIMER(linkp); 1517 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1518 LLC_NEWSTATE(linkp, REJECT); 1519 } else if (pollfinal == 0) { 1520 llc_send(linkp, LLCFT_REJ, LLC_CMD, 0); 1521 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1522 LLC_START_REJ_TIMER(linkp); 1523 LLC_NEWSTATE(linkp, AWAIT_REJECT); 1524 action = 0; 1525 } 1526 break; 1527 } 1528 case LLCFT_INFO + LLC_RSP: 1529 case LLCFT_INFO + LLC_CMD: { 1530 register int p = LLC_GETFLAG(linkp, P); 1531 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1532 1533 LLC_INC(linkp->llcl_vr); 1534 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1535 llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 1536 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1537 action = LLC_DATA_INDICATION; 1538 } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 1539 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1540 linkp->llcl_vs = nr; 1541 llc_resend(linkp, LLC_CMD, 1); 1542 LLC_START_P_TIMER(linkp); 1543 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1544 LLC_NEWSTATE(linkp, NORMAL); 1545 action = LLC_DATA_INDICATION; 1546 } else if (pollfinal == 0) { 1547 llc_send(linkp, LLCFT_RR, LLC_CMD, 0); 1548 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1549 action = LLC_DATA_INDICATION; 1550 } 1551 break; 1552 } 1553 case LLCFT_RR + LLC_CMD: 1554 case LLCFT_RR + LLC_RSP: 1555 case LLCFT_REJ + LLC_CMD: 1556 case LLCFT_REJ + LLC_RSP: { 1557 register int p = LLC_GETFLAG(linkp, P); 1558 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1559 1560 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1561 llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 1562 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1563 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1564 } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 1565 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1566 linkp->llcl_vs = nr; 1567 LLC_STOP_P_TIMER(linkp); 1568 llc_resend(linkp, LLC_CMD, 0); 1569 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1570 LLC_NEWSTATE(linkp, NORMAL); 1571 } else if (pollfinal == 0) { 1572 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1573 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1574 } 1575 break; 1576 } 1577 case LLCFT_RNR + LLC_CMD: 1578 case LLCFT_RNR + LLC_RSP: { 1579 register int p = LLC_GETFLAG(linkp, P); 1580 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1581 1582 if (pollfinal == 1 && cmdrsp == LLC_CMD) { 1583 llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 1584 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1585 LLC_SET_REMOTE_BUSY(linkp, action); 1586 } else if (pollfinal == 1 && cmdrsp == LLC_RSP) { 1587 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1588 linkp->llcl_vs = nr; 1589 LLC_STOP_P_TIMER(linkp); 1590 LLC_SET_REMOTE_BUSY(linkp, action); 1591 LLC_NEWSTATE(linkp, NORMAL); 1592 } else if (pollfinal == 0) { 1593 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1594 LLC_SET_REMOTE_BUSY(linkp, action); 1595 } 1596 break; 1597 } 1598 case LLC_P_TIMER_EXPIRED: 1599 if (linkp->llcl_retry < llc_n2) { 1600 llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 1601 LLC_START_P_TIMER(linkp); 1602 linkp->llcl_retry++; 1603 action = 0; 1604 } 1605 break; 1606 } 1607 if (action == LLC_PASSITON) 1608 action = llc_state_NBRAcore(linkp, frame, frame_kind, 1609 cmdrsp, pollfinal); 1610 1611 return action; 1612 } 1613 1614 /* 1615 * AWAIT_BUSY --- A data link connection exists between the local LLC service 1616 * access point and the remote LLC service access point. The 1617 * local LLC is performing a timer recovery operation and has 1618 * sent a command PDU with the P bit set to ``1'', and is 1619 * awaiting an acknowledgement from the remote LLC. I PDUs may 1620 * not be sent. Local conditions make it likely that the 1621 * information feld of receoved I PDUs will be ignored. 1622 * Supervisory PDUs may be both sent and received. 1623 */ 1624 int 1625 llc_state_AWAIT_BUSY(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 1626 int cmdrsp, int pollfinal) 1627 { 1628 int action = LLC_PASSITON; 1629 1630 switch(frame_kind + cmdrsp) { 1631 case LLC_LOCAL_BUSY_CLEARED: 1632 switch (LLC_GETFLAG(linkp, DATA)) { 1633 case 1: 1634 llc_send(linkp, LLCFT_REJ, LLC_CMD, 0); 1635 LLC_START_REJ_TIMER(linkp); 1636 LLC_NEWSTATE(linkp, AWAIT_REJECT); 1637 action = 0; 1638 break; 1639 case 0: 1640 llc_send(linkp, LLCFT_RR, LLC_CMD, 0); 1641 LLC_NEWSTATE(linkp, AWAIT); 1642 action = 0; 1643 break; 1644 case 2: 1645 llc_send(linkp, LLCFT_RR, LLC_CMD, 0); 1646 LLC_NEWSTATE(linkp, AWAIT_REJECT); 1647 action = 0; 1648 break; 1649 } 1650 break; 1651 case LLC_INVALID_NS + LLC_CMD: 1652 case LLC_INVALID_NS + LLC_RSP: { 1653 register int p = LLC_GETFLAG(linkp, P); 1654 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1655 1656 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1657 llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 1658 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1659 LLC_SETFLAG(linkp, DATA, 1); 1660 action = 0; 1661 } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 1662 /* optionally */ 1663 llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 1664 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1665 linkp->llcl_vs = nr; 1666 LLC_STOP_P_TIMER(linkp); 1667 LLC_SETFLAG(linkp, DATA, 1); 1668 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1669 llc_resend(linkp, LLC_CMD, 0); 1670 LLC_NEWSTATE(linkp, BUSY); 1671 } else if (pollfinal == 0) { 1672 /* optionally */ 1673 llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 1674 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1675 LLC_SETFLAG(linkp, DATA, 1); 1676 action = 0; 1677 } 1678 } 1679 case LLCFT_INFO + LLC_CMD: 1680 case LLCFT_INFO + LLC_RSP: { 1681 register int p = LLC_GETFLAG(linkp, P); 1682 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1683 1684 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1685 llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 1686 LLC_INC(linkp->llcl_vr); 1687 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1688 LLC_SETFLAG(linkp, DATA, 0); 1689 action = LLC_DATA_INDICATION; 1690 } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 1691 llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); 1692 LLC_INC(linkp->llcl_vr); 1693 LLC_START_P_TIMER(linkp); 1694 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1695 linkp->llcl_vs = nr; 1696 LLC_SETFLAG(linkp, DATA, 0); 1697 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1698 llc_resend(linkp, LLC_CMD, 0); 1699 LLC_NEWSTATE(linkp, BUSY); 1700 action = LLC_DATA_INDICATION; 1701 } else if (pollfinal == 0) { 1702 llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 1703 LLC_INC(linkp->llcl_vr); 1704 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1705 LLC_SETFLAG(linkp, DATA, 0); 1706 action = LLC_DATA_INDICATION; 1707 } 1708 break; 1709 } 1710 case LLCFT_RR + LLC_CMD: 1711 case LLCFT_REJ + LLC_CMD: 1712 case LLCFT_RR + LLC_RSP: 1713 case LLCFT_REJ + LLC_RSP: { 1714 register int p = LLC_GETFLAG(linkp, P); 1715 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1716 1717 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1718 llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 1719 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1720 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1721 } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 1722 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1723 linkp->llcl_vs = nr; 1724 LLC_STOP_P_TIMER(linkp); 1725 llc_resend(linkp, LLC_CMD, 0); 1726 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1727 LLC_NEWSTATE(linkp, BUSY); 1728 } else if (pollfinal == 0) { 1729 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1730 linkp->llcl_vs = nr; 1731 LLC_STOP_P_TIMER(linkp); 1732 llc_resend(linkp, LLC_CMD, 0); 1733 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1734 } 1735 break; 1736 } 1737 case LLCFT_RNR + LLC_CMD: 1738 case LLCFT_RNR + LLC_RSP: { 1739 register int p = LLC_GETFLAG(linkp, P); 1740 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1741 1742 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1743 llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 1744 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1745 LLC_SET_REMOTE_BUSY(linkp, action); 1746 } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 1747 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1748 linkp->llcl_vs = nr; 1749 LLC_STOP_P_TIMER(linkp); 1750 LLC_SET_REMOTE_BUSY(linkp, action); 1751 LLC_NEWSTATE(linkp, BUSY); 1752 } else if (pollfinal == 0) { 1753 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1754 LLC_SET_REMOTE_BUSY(linkp, action); 1755 } 1756 break; 1757 } 1758 case LLC_P_TIMER_EXPIRED: 1759 if (linkp->llcl_retry < llc_n2) { 1760 llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); 1761 LLC_START_P_TIMER(linkp); 1762 linkp->llcl_retry++; 1763 action = 0; 1764 } 1765 break; 1766 } 1767 if (action == LLC_PASSITON) 1768 action = llc_state_NBRAcore(linkp, frame, frame_kind, 1769 cmdrsp, pollfinal); 1770 1771 return action; 1772 } 1773 1774 /* 1775 * AWAIT_REJECT --- A data link connection exists between the local LLC service 1776 * access point and the remote LLC service access point. The 1777 * local connection component has requested that the remote 1778 * connection component re-transmit a specific I PDU that the 1779 * local connection component has detected as being out of 1780 * sequence. Before the local LLC entered this state it was 1781 * performing a timer recovery operation and had sent a 1782 * command PDU with the P bit set to ``1'', and is still 1783 * awaiting an acknowledgment from the remote LLC. I PDUs may 1784 * be received but not transmitted. Supervisory PDUs may be 1785 * both transmitted and received. 1786 */ 1787 int 1788 llc_state_AWAIT_REJECT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 1789 int cmdrsp, int pollfinal) 1790 { 1791 int action = LLC_PASSITON; 1792 1793 switch(frame_kind + cmdrsp) { 1794 case LLC_LOCAL_BUSY_DETECTED: 1795 llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 1796 LLC_SETFLAG(linkp, DATA, 2); 1797 LLC_NEWSTATE(linkp, AWAIT_BUSY); 1798 action = 0; 1799 break; 1800 case LLC_INVALID_NS + LLC_CMD: 1801 case LLC_INVALID_NS + LLC_RSP: { 1802 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1803 1804 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1805 llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 1806 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1807 action = 0; 1808 } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 1809 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1810 linkp->llcl_vs = nr; 1811 llc_resend(linkp, LLC_CMD, 1); 1812 LLC_START_P_TIMER(linkp); 1813 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1814 LLC_NEWSTATE(linkp, REJECT); 1815 } else if (pollfinal == 0) { 1816 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1817 action = 0; 1818 } 1819 break; 1820 } 1821 case LLCFT_INFO + LLC_CMD: 1822 case LLCFT_INFO + LLC_RSP: { 1823 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1824 1825 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1826 LLC_INC(linkp->llcl_vr); 1827 llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 1828 LLC_STOP_REJ_TIMER(linkp); 1829 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1830 LLC_NEWSTATE(linkp, AWAIT); 1831 action = LLC_DATA_INDICATION; 1832 } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 1833 LLC_INC(linkp->llcl_vr); 1834 LLC_STOP_P_TIMER(linkp); 1835 LLC_STOP_REJ_TIMER(linkp); 1836 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1837 linkp->llcl_vs = nr; 1838 llc_resend(linkp, LLC_CMD, 0); 1839 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1840 LLC_NEWSTATE(linkp, NORMAL); 1841 action = LLC_DATA_INDICATION; 1842 } else if (pollfinal == 0) { 1843 LLC_INC(linkp->llcl_vr); 1844 llc_send(linkp, LLCFT_RR, LLC_CMD, 0); 1845 LLC_STOP_REJ_TIMER(linkp); 1846 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1847 LLC_NEWSTATE(linkp, AWAIT); 1848 action = LLC_DATA_INDICATION; 1849 } 1850 break; 1851 } 1852 case LLCFT_RR + LLC_CMD: 1853 case LLCFT_REJ + LLC_CMD: 1854 case LLCFT_RR + LLC_RSP: 1855 case LLCFT_REJ + LLC_RSP: { 1856 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1857 1858 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1859 llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 1860 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1861 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1862 } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 1863 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1864 linkp->llcl_vs = nr; 1865 llc_resend(linkp, LLC_CMD, 1); 1866 LLC_START_P_TIMER(linkp); 1867 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1868 LLC_NEWSTATE(linkp, REJECT); 1869 } else if (pollfinal == 0) { 1870 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1871 LLC_CLEAR_REMOTE_BUSY(linkp, action); 1872 } 1873 break; 1874 } 1875 case LLCFT_RNR + LLC_CMD: 1876 case LLCFT_RNR + LLC_RSP: { 1877 register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 1878 1879 if (cmdrsp == LLC_CMD && pollfinal == 1) { 1880 llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 1881 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1882 LLC_SET_REMOTE_BUSY(linkp, action); 1883 } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 1884 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1885 linkp->llcl_vs = nr; 1886 LLC_STOP_P_TIMER(linkp); 1887 LLC_SET_REMOTE_BUSY(linkp, action); 1888 LLC_NEWSTATE(linkp, REJECT); 1889 } else if (pollfinal == 0) { 1890 LLC_UPDATE_NR_RECEIVED(linkp, nr); 1891 LLC_SET_REMOTE_BUSY(linkp, action); 1892 } 1893 break; 1894 } 1895 case LLC_P_TIMER_EXPIRED: 1896 if (linkp->llcl_retry < llc_n2) { 1897 llc_send(linkp, LLCFT_REJ, LLC_CMD, 1); 1898 LLC_START_P_TIMER(linkp); 1899 linkp->llcl_retry++; 1900 action = 0; 1901 } 1902 break; 1903 } 1904 if (action == LLC_PASSITON) 1905 action = llc_state_NBRAcore(linkp, frame, frame_kind, 1906 cmdrsp, pollfinal); 1907 1908 return action; 1909 } 1910 1911 1912 /* 1913 * llc_statehandler() --- Wrapper for llc_state_*() functions. 1914 * Deals with action codes and checks for 1915 * ``stuck'' links. 1916 */ 1917 1918 int 1919 llc_statehandler(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 1920 int cmdrsp, int pollfinal) 1921 { 1922 register int action = 0; 1923 1924 /* 1925 * To check for ``zombie'' links each time llc_statehandler() gets called 1926 * the AGE timer of linkp is reset. If it expires llc_timer() will 1927 * take care of the link --- i.e. kill it 8=) 1928 */ 1929 LLC_STARTTIMER(linkp, AGE); 1930 1931 /* 1932 * Now call the current statehandler function. 1933 */ 1934 action = (*linkp->llcl_statehandler)(linkp, frame, frame_kind, 1935 cmdrsp, pollfinal); 1936 once_more_and_again: 1937 switch (action) { 1938 case LLC_CONNECT_INDICATION: { 1939 int naction; 1940 1941 LLC_TRACE(linkp, LLCTR_INTERESTING, "CONNECT INDICATION"); 1942 linkp->llcl_nlnext = 1943 (*linkp->llcl_sapinfo->si_ctlinput) 1944 (PRC_CONNECT_INDICATION, 1945 (struct sockaddr *) &linkp->llcl_addr, (caddr_t) linkp); 1946 if (linkp->llcl_nlnext == 0) 1947 naction = NL_DISCONNECT_REQUEST; 1948 else naction = NL_CONNECT_RESPONSE; 1949 action = (*linkp->llcl_statehandler)(linkp, frame, naction, 0, 0); 1950 goto once_more_and_again; 1951 } 1952 case LLC_CONNECT_CONFIRM: 1953 /* llc_resend(linkp, LLC_CMD, 0); */ 1954 llc_start(linkp); 1955 break; 1956 case LLC_DISCONNECT_INDICATION: 1957 LLC_TRACE(linkp, LLCTR_INTERESTING, "DISCONNECT INDICATION"); 1958 (*linkp->llcl_sapinfo->si_ctlinput) 1959 (PRC_DISCONNECT_INDICATION, 1960 (struct sockaddr *) &linkp->llcl_addr, linkp->llcl_nlnext); 1961 break; 1962 /* internally visible only */ 1963 case LLC_RESET_CONFIRM: 1964 case LLC_RESET_INDICATION_LOCAL: 1965 /* 1966 * not much we can do here, the state machine either makes it or 1967 * brakes it ... 1968 */ 1969 break; 1970 case LLC_RESET_INDICATION_REMOTE: 1971 LLC_TRACE(linkp, LLCTR_SHOULDKNOW, "RESET INDICATION (REMOTE)"); 1972 action = (*linkp->llcl_statehandler)(linkp, frame, 1973 NL_RESET_RESPONSE, 0, 0); 1974 goto once_more_and_again; 1975 case LLC_FRMR_SENT: 1976 LLC_TRACE(linkp, LLCTR_URGENT, "FRMR SENT"); 1977 break; 1978 case LLC_FRMR_RECEIVED: 1979 LLC_TRACE(linkp, LLCTR_URGEN, "FRMR RECEIVED"); 1980 action = (*linkp->llcl_statehandler)(linkp, frame, 1981 NL_RESET_REQUEST, 0, 0); 1982 1983 goto once_more_and_again; 1984 case LLC_REMOTE_BUSY: 1985 LLC_TRACE(linkp, LLCTR_SHOULDKNOW, "REMOTE BUSY"); 1986 break; 1987 case LLC_REMOTE_NOT_BUSY: 1988 LLC_TRACE(linkp, LLCTR_SHOULDKNOW, "REMOTE BUSY CLEARED"); 1989 /* 1990 * try to get queued frames out 1991 */ 1992 llc_start(linkp); 1993 break; 1994 } 1995 1996 /* 1997 * Only LLC_DATA_INDICATION is for the time being 1998 * passed up to the network layer entity. 1999 * The remaining action codes are for the time 2000 * being visible internally only. 2001 * However, this can/may be changed if necessary. 2002 */ 2003 2004 return action; 2005 } 2006 2007 2008 /* 2009 * Core LLC2 routines 2010 */ 2011 2012 /* 2013 * The INIT call. This routine is called once after the system is booted. 2014 */ 2015 2016 llc_init() 2017 { 2018 llcintrq.ifq_maxlen = IFQ_MAXLEN; 2019 } 2020 2021 2022 /* 2023 * In case of a link reset we need to shuffle the frames queued inside the 2024 * LLC2 window. 2025 */ 2026 2027 void 2028 llc_resetwindow(struct llc_linkcb *linkp) 2029 { 2030 register struct mbuf *mptr = (struct mbuf *) 0; 2031 register struct mbuf *anchor = (struct mbuf *)0; 2032 register short i; 2033 2034 /* Pick up all queued frames and collect them in a linked mbuf list */ 2035 if (linkp->llcl_slotsfree != linkp->llcl_window) { 2036 i = llc_seq2slot(linkp, linkp->llcl_nr_received); 2037 anchor = mptr = linkp->llcl_output_buffers[i]; 2038 for (; i != linkp->llcl_freeslot; 2039 i = llc_seq2slot(linkp, i+1)) { 2040 if (linkp->llcl_output_buffers[i]) { 2041 mptr->m_nextpkt = linkp->llcl_output_buffers[i]; 2042 mptr = mptr->m_nextpkt; 2043 } else panic("LLC2 window broken"); 2044 } 2045 } 2046 /* clean closure */ 2047 if (mptr) 2048 mptr->m_nextpkt = (struct mbuf *) 0; 2049 2050 /* Now --- plug 'em in again */ 2051 if (anchor != (struct mbuf *)0) { 2052 for (i = 0, mptr = anchor; mptr != (struct mbuf *) 0; i++) { 2053 linkp->llcl_output_buffers[i] = mptr; 2054 mptr = mptr->m_nextpkt; 2055 linkp->llcl_output_buffers[i]->m_nextpkt = (struct mbuf *)0; 2056 } 2057 linkp->llcl_freeslot = i; 2058 } else linkp->llcl_freeslot = 0; 2059 2060 /* We're resetting the link, the next frame to be acknowledged is 0 */ 2061 linkp->llcl_nr_received = 0; 2062 2063 /* set distance between LLC2 sequence number and the top of window to 0 */ 2064 linkp->llcl_projvs = linkp->llcl_freeslot; 2065 2066 return; 2067 } 2068 2069 /* 2070 * llc_newlink() --- We allocate enough memory to contain a link control block 2071 * and initialize it properly. We don't intiate the actual setup 2072 * of the LLC2 link here. 2073 */ 2074 struct llc_linkcb * 2075 llc_newlink(struct sockaddr_dl *dst, struct ifnet *ifp, struct rtentry *nlrt, 2076 caddr_t nlnext, struct rtentry *llrt) 2077 { 2078 struct llc_linkcb *nlinkp; 2079 u_char sap = LLSAPADDR(dst); 2080 short llcwindow; 2081 2082 2083 /* allocate memory for link control block */ 2084 MALLOC(nlinkp, struct llc_linkcb *, sizeof(struct llc_linkcb), 2085 M_PCB, M_DONTWAIT); 2086 if (nlinkp == 0) 2087 return (NULL); 2088 bzero((caddr_t)nlinkp, sizeof(struct llc_linkcb)); 2089 2090 /* copy link address */ 2091 sdl_copy(dst, &nlinkp->llcl_addr); 2092 2093 /* hold on to the network layer route entry */ 2094 nlinkp->llcl_nlrt = nlrt; 2095 2096 /* likewise the network layer control block */ 2097 nlinkp->llcl_nlnext = nlnext; 2098 2099 /* jot down the link layer route entry */ 2100 nlinkp->llcl_llrt = llrt; 2101 2102 /* reset writeq */ 2103 nlinkp->llcl_writeqh = nlinkp->llcl_writeqt = NULL; 2104 2105 /* setup initial state handler function */ 2106 nlinkp->llcl_statehandler = llc_state_ADM; 2107 2108 /* hold on to interface pointer */ 2109 nlinkp->llcl_if = ifp; 2110 2111 /* get service access point information */ 2112 nlinkp->llcl_sapinfo = llc_getsapinfo(sap, ifp); 2113 2114 /* get window size from SAP info block */ 2115 if ((llcwindow = nlinkp->llcl_sapinfo->si_window) == 0) 2116 llcwindow = LLC_MAX_WINDOW; 2117 2118 /* allocate memory for window buffer */ 2119 MALLOC(nlinkp->llcl_output_buffers, struct mbuf **, 2120 llcwindow*sizeof(struct mbuf *), M_PCB, M_DONTWAIT); 2121 if (nlinkp->llcl_output_buffers == 0) { 2122 FREE(nlinkp, M_PCB); 2123 return(NULL); 2124 } 2125 bzero((caddr_t)nlinkp->llcl_output_buffers, 2126 llcwindow*sizeof(struct mbuf *)); 2127 2128 /* set window size & slotsfree */ 2129 nlinkp->llcl_slotsfree = nlinkp->llcl_window = llcwindow; 2130 2131 /* enter into linked listed of link control blocks */ 2132 insque(nlinkp, &llccb_q); 2133 2134 return(nlinkp); 2135 } 2136 2137 /* 2138 * llc_dellink() --- farewell to link control block 2139 */ 2140 llc_dellink(struct llc_linkcb *linkp) 2141 { 2142 register struct mbuf *m; 2143 register struct mbuf *n; 2144 register struct npaidbentry *sapinfo = linkp->llcl_sapinfo; 2145 register i; 2146 2147 /* notify upper layer of imminent death */ 2148 if (linkp->llcl_nlnext && sapinfo->si_ctlinput) 2149 (*sapinfo->si_ctlinput) 2150 (PRC_DISCONNECT_INDICATION, 2151 (struct sockaddr *)&linkp->llcl_addr, linkp->llcl_nlnext); 2152 2153 /* pull the plug */ 2154 if (linkp->llcl_llrt) 2155 ((struct npaidbentry *)(linkp->llcl_llrt->rt_llinfo))->np_link 2156 = (struct llc_linkcb *) 0; 2157 2158 /* leave link control block queue */ 2159 remque(linkp); 2160 2161 /* drop queued packets */ 2162 for (m = linkp->llcl_writeqh; m;) { 2163 n = m->m_act; 2164 m_freem(m); 2165 m = n; 2166 } 2167 2168 /* drop packets in the window */ 2169 for(i = 0; i < linkp->llcl_window; i++) 2170 if (linkp->llcl_output_buffers[i]) 2171 m_freem(linkp->llcl_output_buffers[i]); 2172 2173 /* return the window space */ 2174 FREE((caddr_t)linkp->llcl_output_buffers, M_PCB); 2175 2176 /* return the control block space --- now it's gone ... */ 2177 FREE((caddr_t)linkp, M_PCB); 2178 } 2179 2180 llc_decode(struct llc* frame, struct llc_linkcb * linkp) 2181 { 2182 register int ft = LLC_BAD_PDU; 2183 2184 if ((frame->llc_control & 01) == 0) { 2185 ft = LLCFT_INFO; 2186 /* S or U frame ? */ 2187 } else switch (frame->llc_control) { 2188 2189 /* U frames */ 2190 case LLC_UI: 2191 case LLC_UI_P: ft = LLC_UI; break; 2192 case LLC_DM: 2193 case LLC_DM_P: ft =LLCFT_DM; break; 2194 case LLC_DISC: 2195 case LLC_DISC_P: ft = LLCFT_DISC; break; 2196 case LLC_UA: 2197 case LLC_UA_P: ft = LLCFT_UA; break; 2198 case LLC_SABME: 2199 case LLC_SABME_P: ft = LLCFT_SABME; break; 2200 case LLC_FRMR: 2201 case LLC_FRMR_P: ft = LLCFT_FRMR; break; 2202 case LLC_XID: 2203 case LLC_XID_P: ft = LLCFT_XID; break; 2204 case LLC_TEST: 2205 case LLC_TEST_P: ft = LLCFT_TEST; break; 2206 2207 /* S frames */ 2208 case LLC_RR: ft = LLCFT_RR; break; 2209 case LLC_RNR: ft = LLCFT_RNR; break; 2210 case LLC_REJ: ft = LLCFT_REJ; break; 2211 } /* switch */ 2212 2213 if (linkp) { 2214 switch (ft) { 2215 case LLCFT_INFO: 2216 if (LLCGBITS(frame->llc_control, i_ns) != linkp->llcl_vr) { 2217 ft = LLC_INVALID_NS; 2218 break; 2219 } 2220 /* fall thru --- yeeeeeee */ 2221 case LLCFT_RR: 2222 case LLCFT_RNR: 2223 case LLCFT_REJ: 2224 /* splash! */ 2225 if (LLC_NR_VALID(linkp, LLCGBITS(frame->llc_control_ext, 2226 s_nr)) == 0) 2227 ft = LLC_INVALID_NR; 2228 break; 2229 } 2230 } 2231 2232 return ft; 2233 } 2234 2235 /* 2236 * llc_anytimersup() --- Checks if at least one timer is still up and running. 2237 */ 2238 int 2239 llc_anytimersup(struct llc_linkcb * linkp) 2240 { 2241 register int i; 2242 2243 FOR_ALL_LLC_TIMERS(i) 2244 if (linkp->llcl_timers[i] > 0) 2245 break; 2246 if (i == LLC_AGE_SHIFT) 2247 return 0; 2248 else return 1; 2249 } 2250 2251 /* 2252 * llc_link_dump() - dump link info 2253 */ 2254 2255 #define SAL(s) ((struct sockaddr_dl *)&(s)->llcl_addr) 2256 #define CHECK(l, s) if (LLC_STATEEQ(l, s)) return #s 2257 2258 char *timer_names[] = {"ACK", "P", "BUSY", "REJ", "AGE"}; 2259 2260 char * 2261 llc_getstatename(struct llc_linkcb *linkp) 2262 { 2263 CHECK(linkp, ADM); 2264 CHECK(linkp, CONN); 2265 CHECK(linkp, RESET_WAIT); 2266 CHECK(linkp, RESET_CHECK); 2267 CHECK(linkp, SETUP); 2268 CHECK(linkp, RESET); 2269 CHECK(linkp, D_CONN); 2270 CHECK(linkp, ERROR); 2271 CHECK(linkp, NORMAL); 2272 CHECK(linkp, BUSY); 2273 CHECK(linkp, REJECT); 2274 CHECK(linkp, AWAIT); 2275 CHECK(linkp, AWAIT_BUSY); 2276 CHECK(linkp, AWAIT_REJECT); 2277 2278 return "UNKNOWN - eh?"; 2279 } 2280 2281 void 2282 llc_link_dump(struct llc_linkcb* linkp, const char *message) 2283 { 2284 register int i; 2285 register char *state; 2286 2287 /* print interface */ 2288 printf("if %s%d\n", linkp->llcl_if->if_name, linkp->llcl_if->if_unit); 2289 2290 /* print message */ 2291 printf(">> %s <<\n", message); 2292 2293 /* print MAC and LSAP */ 2294 printf("llc addr "); 2295 for (i = 0; i < (SAL(linkp)->sdl_alen)-2; i++) 2296 printf("%x:", (char)*(LLADDR(SAL(linkp))+i) & 0xff); 2297 printf("%x,", (char)*(LLADDR(SAL(linkp))+i) & 0xff); 2298 printf("%x\n", (char)*(LLADDR(SAL(linkp))+i+1) & 0xff); 2299 2300 /* print state we're in and timers */ 2301 printf("state %s, ", llc_getstatename(linkp)); 2302 for (i = LLC_ACK_SHIFT; i < LLC_AGE_SHIFT; i++) 2303 printf("%s-%c %d/", timer_names[i], 2304 (linkp->llcl_timerflags & (1<<i) ? 'R' : 'S'), 2305 linkp->llcl_timers[i]); 2306 printf("%s-%c %d\n", timer_names[i], (linkp->llcl_timerflags & (1<<i) ? 2307 'R' : 'S'), linkp->llcl_timers[i]); 2308 2309 /* print flag values */ 2310 printf("flags P %d/F %d/S %d/DATA %d/REMOTE_BUSY %d\n", 2311 LLC_GETFLAG(linkp, P), LLC_GETFLAG(linkp, S), 2312 LLC_GETFLAG(linkp, DATA), LLC_GETFLAG(linkp, REMOTE_BUSY)); 2313 2314 /* print send and receive state variables, ack, and window */ 2315 printf("V(R) %d/V(S) %d/N(R) received %d/window %d/freeslot %d\n", 2316 linkp->llcl_vs, linkp->llcl_vr, linkp->llcl_nr_received, 2317 linkp->llcl_window, linkp->llcl_freeslot); 2318 2319 /* further expansions can follow here */ 2320 2321 } 2322 2323 void 2324 llc_trace(struct llc_linkcb *linkp, int level, const char *message) 2325 { 2326 if (linkp->llcl_sapinfo->si_trace && level > llc_tracelevel) 2327 llc_link_dump(linkp, message); 2328 2329 return; 2330 } 2331