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