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