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