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