Annotation of kernel/bsd/netccitt/llc_subr.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.