157027Ssklower /* 257027Ssklower * Copyright (C) Dirk Husemann, Computer Science Department IV, 357027Ssklower * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992 457027Ssklower * Copyright (c) 1992 Regents of the University of California. 557027Ssklower * All rights reserved. 657027Ssklower * 757027Ssklower * This code is derived from software contributed to Berkeley by 857027Ssklower * Dirk Husemann and the Computer Science Department (IV) of 957027Ssklower * the University of Erlangen-Nuremberg, Germany. 1057027Ssklower * 1157027Ssklower * %sccs.include.redist.c% 1257027Ssklower * 13*61656Ssklower * @(#)llc_subr.c 7.3 (Berkeley) 06/05/93 1457027Ssklower */ 1557027Ssklower 1657027Ssklower #include <sys/param.h> 1757027Ssklower #include <sys/systm.h> 1857027Ssklower #include <sys/mbuf.h> 1957027Ssklower #include <sys/domain.h> 2057027Ssklower #include <sys/socket.h> 2157027Ssklower #include <sys/protosw.h> 2257027Ssklower #include <sys/socketvar.h> 2357027Ssklower #include <sys/errno.h> 2457027Ssklower #include <sys/time.h> 2557027Ssklower #include <sys/kernel.h> 2657027Ssklower 2757027Ssklower #include <net/if.h> 2857027Ssklower #include <net/if_dl.h> 2957027Ssklower #include <net/if_llc.h> 3057027Ssklower #include <net/route.h> 3157027Ssklower 3257027Ssklower #include <netccitt/dll.h> 3357027Ssklower #include <netccitt/llc_var.h> 3457027Ssklower 3557027Ssklower /* 3657027Ssklower * Frame names for diagnostic messages 3757027Ssklower */ 3857027Ssklower char *frame_names[] = { "INFO", "RR", "RNR", "REJ", "DM", "SABME", "DISC", 3957027Ssklower "UA", "FRMR", "UI", "XID", "TEST", "ILLEGAL", "TIMER", "N2xT1"}; 4057027Ssklower 4157027Ssklower 4257027Ssklower /* 4357027Ssklower * Trace level 4457027Ssklower */ 4557027Ssklower int llc_tracelevel = LLCTR_URGENT; 4657027Ssklower 4757027Ssklower /* 4857027Ssklower * Values for accessing various bitfields 4957027Ssklower */ 5057027Ssklower struct bitslice llc_bitslice[] = { 5157027Ssklower /* mask, shift value */ 5257027Ssklower { 0x1, 0x0 }, 5357027Ssklower { 0xfe, 0x1 }, 5457027Ssklower { 0x3, 0x0 }, 5557027Ssklower { 0xc, 0x2 }, 5657027Ssklower { 0x10, 0x4 }, 5757027Ssklower { 0xe0, 0x5 }, 5857027Ssklower { 0x1f, 0x0 } 5957027Ssklower }; 6057027Ssklower 6157027Ssklower /* 6257027Ssklower * We keep the link control blocks on a doubly linked list - 6357027Ssklower * primarily for checking in llc_time() 6457027Ssklower */ 6557027Ssklower 6657027Ssklower struct llccb_q llccb_q = { &llccb_q, &llccb_q }; 6757027Ssklower 6857027Ssklower /* 6958150Sdkhusema * Flag for signalling wether route tree for AF_LINK has been 7058150Sdkhusema * initialized yet. 7158150Sdkhusema */ 7258150Sdkhusema 7358150Sdkhusema int af_link_rts_init_done = 0; 7458150Sdkhusema 7558150Sdkhusema 7658150Sdkhusema /* 7757027Ssklower * Functions dealing with struct sockaddr_dl */ 7857027Ssklower 7957027Ssklower /* Compare sdl_a w/ sdl_b */ 8057027Ssklower 8157027Ssklower sdl_cmp(struct sockaddr_dl *sdl_a, struct sockaddr_dl *sdl_b) 8257027Ssklower { 8357027Ssklower if (LLADDRLEN(sdl_a) != LLADDRLEN(sdl_b)) 8457027Ssklower return(1); 8557027Ssklower return(bcmp((caddr_t) sdl_a->sdl_data, (caddr_t) sdl_b->sdl_data, 8657027Ssklower LLADDRLEN(sdl_a))); 8757027Ssklower } 8857027Ssklower 8957027Ssklower /* Copy sdl_f to sdl_t */ 9057027Ssklower 9157027Ssklower sdl_copy(struct sockaddr_dl *sdl_f, struct sockaddr_dl *sdl_t) 9257027Ssklower { 9357027Ssklower bcopy((caddr_t) sdl_f, (caddr_t) sdl_t, sdl_f->sdl_len); 9457027Ssklower } 9557027Ssklower 9657027Ssklower /* Swap sdl_a w/ sdl_b */ 9757027Ssklower 9857027Ssklower sdl_swapaddr(struct sockaddr_dl *sdl_a, struct sockaddr_dl *sdl_b) 9957027Ssklower { 10057027Ssklower struct sockaddr_dl sdl_tmp; 10157027Ssklower 10257027Ssklower sdl_copy(sdl_a, &sdl_tmp); 10357027Ssklower sdl_copy(sdl_b, sdl_a); 10457027Ssklower sdl_copy(&sdl_tmp, sdl_b); 10557027Ssklower } 10657027Ssklower 10757027Ssklower /* Fetch the sdl of the associated if */ 10857027Ssklower 10957027Ssklower struct sockaddr_dl * 11057027Ssklower sdl_getaddrif(struct ifnet *ifp) 11157027Ssklower { 11257027Ssklower register struct ifaddr *ifa; 11357027Ssklower 11457027Ssklower for(ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 11557027Ssklower if (ifa->ifa_addr->sa_family == AF_LINK ) 11657027Ssklower return((struct sockaddr_dl *)(ifa->ifa_addr)); 11757027Ssklower 11857027Ssklower return((struct sockaddr_dl *)0); 11957027Ssklower } 12057027Ssklower 12157027Ssklower /* Check addr of interface with the one given */ 12257027Ssklower 12357027Ssklower sdl_checkaddrif(struct ifnet *ifp, struct sockaddr_dl *sdl_c) 12457027Ssklower { 12557027Ssklower register struct ifaddr *ifa; 12657027Ssklower 12757027Ssklower for(ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 12857027Ssklower if ((ifa->ifa_addr->sa_family == AF_LINK ) && 12957027Ssklower !sdl_cmp((struct sockaddr_dl *)(ifa->ifa_addr), sdl_c)) 13057027Ssklower return(1); 13157027Ssklower 13257027Ssklower return(0); 13357027Ssklower } 13457027Ssklower 13557027Ssklower /* Build an sdl from MAC addr, DLSAP addr, and interface */ 13657027Ssklower 13757027Ssklower sdl_setaddrif(struct ifnet *ifp, u_char *mac_addr, u_char dlsap_addr, 13857027Ssklower u_char mac_len, struct sockaddr_dl *sdl_to) 13957027Ssklower { 14057027Ssklower register struct sockaddr_dl *sdl_tmp; 14157027Ssklower 14257027Ssklower if ((sdl_tmp = sdl_getaddrif(ifp)) ) { 14357027Ssklower sdl_copy(sdl_tmp, sdl_to); 14457027Ssklower bcopy((caddr_t) mac_addr, (caddr_t) LLADDR(sdl_to), mac_len); 14557027Ssklower *(LLADDR(sdl_to)+mac_len) = dlsap_addr; 14657027Ssklower sdl_to->sdl_alen = mac_len+1; 14757027Ssklower return(1); 14857027Ssklower } else return(0); 14957027Ssklower } 15057027Ssklower 15157027Ssklower /* Fill out the sdl header aggregate */ 15257027Ssklower 15357027Ssklower sdl_sethdrif(struct ifnet *ifp, u_char *mac_src, u_char dlsap_src, u_char *mac_dst, 15457027Ssklower u_char dlsap_dst, u_char mac_len, struct sdl_hdr *sdlhdr_to) 15557027Ssklower { 15657027Ssklower if ( !sdl_setaddrif(ifp, mac_src, dlsap_src, mac_len, 15757027Ssklower &sdlhdr_to->sdlhdr_src) || 15857027Ssklower !sdl_setaddrif(ifp, mac_dst, dlsap_dst, mac_len, 15957027Ssklower &sdlhdr_to->sdlhdr_dst) ) 16057027Ssklower return(0); 16157027Ssklower else return(1); 16257027Ssklower } 16357027Ssklower 16457027Ssklower static struct sockaddr_dl sap_saddr; 16557027Ssklower static struct sockaddr_dl sap_sgate = { 16657027Ssklower sizeof(struct sockaddr_dl), /* _len */ 16757027Ssklower AF_LINK /* _af */ 16857027Ssklower }; 16957027Ssklower 17057027Ssklower /* 17157027Ssklower * Set sapinfo for SAP address, llcconfig, af, and interface 17257027Ssklower */ 17357027Ssklower struct npaidbentry * 17457027Ssklower llc_setsapinfo(struct ifnet *ifp, u_char af, u_char sap, struct dllconfig *llconf) 17557027Ssklower { 17657027Ssklower struct protosw *pp; 17757027Ssklower struct sockaddr_dl *ifdl_addr; 17857027Ssklower struct rtentry *sirt = (struct rtentry *)0; 17957027Ssklower struct npaidbentry *sapinfo; 18057027Ssklower u_char saploc; 18157027Ssklower int size = sizeof(struct npaidbentry); 18257027Ssklower 18357027Ssklower USES_AF_LINK_RTS; 18457027Ssklower 18557027Ssklower /* 18657027Ssklower * We rely/assume that only STREAM protocols will make use of 18757027Ssklower * connection oriented LLC2. If this will one day not be the 18857027Ssklower * case this will obviously fail. 18957027Ssklower */ 19057027Ssklower pp = pffindtype (af, SOCK_STREAM); 19157027Ssklower if (pp == 0 || pp->pr_input == 0 || pp->pr_ctlinput == 0) { 19257027Ssklower printf("network level protosw error"); 19357027Ssklower return 0; 19457027Ssklower } 19557027Ssklower 19657027Ssklower /* 19757027Ssklower * We need a way to jot down the LLC2 configuration for 19857027Ssklower * a certain LSAP address. To do this we enter 19957027Ssklower * a "route" for the SAP. 20057027Ssklower */ 20157027Ssklower ifdl_addr = sdl_getaddrif(ifp); 20257027Ssklower sdl_copy(ifdl_addr, &sap_saddr); 20357027Ssklower sdl_copy(ifdl_addr, &sap_sgate); 20457027Ssklower saploc = LLSAPLOC(&sap_saddr, ifp); 20557027Ssklower sap_saddr.sdl_data[saploc] = sap; 20657027Ssklower sap_saddr.sdl_alen++; 20757027Ssklower 20857027Ssklower /* now enter it */ 209*61656Ssklower rtrequest(RTM_ADD, (struct sockaddr *)&sap_saddr, 210*61656Ssklower (struct sockaddr *)&sap_sgate, 0, 0, &sirt); 21157027Ssklower if (sirt == 0) 21257027Ssklower return 0; 21357027Ssklower 21457027Ssklower /* Plug in config information in rt->rt_llinfo */ 21557027Ssklower 21657027Ssklower sirt->rt_llinfo = malloc(size , M_PCB, M_WAITOK); 21757027Ssklower sapinfo = (struct npaidbentry *) sirt->rt_llinfo; 21857027Ssklower if (sapinfo) { 21957027Ssklower bzero ((caddr_t)sapinfo, size); 22057027Ssklower /* 22157027Ssklower * For the time being we support LLC CLASS II here 22257027Ssklower * only 22357027Ssklower */ 22457027Ssklower sapinfo->si_class = LLC_CLASS_II; 22557027Ssklower sapinfo->si_window = llconf->dllcfg_window; 22657027Ssklower sapinfo->si_trace = llconf->dllcfg_trace; 22757027Ssklower if (sapinfo->si_trace) 22857027Ssklower llc_tracelevel--; 22957027Ssklower else llc_tracelevel++; 23057027Ssklower sapinfo->si_input = pp->pr_input; 23157027Ssklower sapinfo->si_ctlinput = (caddr_t (*)())pp->pr_ctlinput; 23257027Ssklower 23357027Ssklower return (sapinfo); 23457027Ssklower } 23557027Ssklower 23657027Ssklower return 0; 23757027Ssklower } 23857027Ssklower 23957027Ssklower /* 24057027Ssklower * Get sapinfo for SAP address and interface 24157027Ssklower */ 24257027Ssklower struct npaidbentry * 24357027Ssklower llc_getsapinfo(u_char sap, struct ifnet *ifp) 24457027Ssklower { 24557027Ssklower struct sockaddr_dl *ifdl_addr; 24657027Ssklower struct sockaddr_dl si_addr; 24757027Ssklower struct rtentry *sirt; 24857027Ssklower u_char saploc; 24957027Ssklower 25057027Ssklower USES_AF_LINK_RTS; 25157027Ssklower 25257027Ssklower ifdl_addr = sdl_getaddrif(ifp); 25357027Ssklower sdl_copy(ifdl_addr, &si_addr); 25457027Ssklower saploc = LLSAPLOC(&si_addr, ifp); 25557027Ssklower si_addr.sdl_data[saploc] = sap; 25657027Ssklower si_addr.sdl_alen++; 25757027Ssklower 258*61656Ssklower if ((sirt = rtalloc1((struct sockaddr *)&si_addr, 0))) 25957027Ssklower sirt->rt_refcnt--; 26057027Ssklower else return(0); 26157027Ssklower 26257027Ssklower return((struct npaidbentry *)sirt->rt_llinfo); 26357027Ssklower } 26457027Ssklower 26557027Ssklower /* 26657027Ssklower * llc_seq2slot() --- We only allocate enough memory to hold the window. This 26757027Ssklower * introduces the necessity to keep track of two ``pointers'' 26857027Ssklower * 26957027Ssklower * o llcl_freeslot the next free slot to be used 27057027Ssklower * this one advances modulo llcl_window 27157027Ssklower * o llcl_projvs the V(S) associated with the next frame 27257027Ssklower * to be set via llcl_freeslot 27357027Ssklower * this one advances modulo LLC_MAX_SEQUENCE 27457027Ssklower * 27557027Ssklower * A new frame is inserted at llcl_output_buffers[llcl_freeslot], after 27657027Ssklower * which both llcl_freeslot and llcl_projvs are incremented. 27757027Ssklower * 27857027Ssklower * The slot sl(sn) for any given sequence number sn is given by 27957027Ssklower * 28057027Ssklower * sl(sn) = (llcl_freeslot + llcl_window - 1 - (llcl_projvs + 28157027Ssklower * LLC_MAX_SEQUENCE- sn) % LLC_MAX_SEQUENCE) % 28257027Ssklower * llcl_window 28357027Ssklower * 28457027Ssklower * i.e. we first calculate the number of frames we need to ``go back'' 28557027Ssklower * from the current one (really the next one, but that doesn't matter as 28657027Ssklower * llcl_projvs is likewise of by plus one) and subtract that from the 28757027Ssklower * pointer to the most recently taken frame (llcl_freeslot - 1). 28857027Ssklower */ 28957027Ssklower 29057027Ssklower short 29157027Ssklower llc_seq2slot(struct llc_linkcb *linkp, short seqn) 29257027Ssklower { 29357027Ssklower register sn = 0; 29457027Ssklower 29557027Ssklower sn = (linkp->llcl_freeslot + linkp->llcl_window - 29657027Ssklower (linkp->llcl_projvs + LLC_MAX_SEQUENCE - seqn) % 29757027Ssklower LLC_MAX_SEQUENCE) % linkp->llcl_window; 29857027Ssklower 29957027Ssklower return sn; 30057027Ssklower } 30157027Ssklower 30257027Ssklower /* 30357027Ssklower * LLC2 link state handler 30457027Ssklower * 30557027Ssklower * There is in most cases one function per LLC2 state. The LLC2 standard 30657027Ssklower * ISO 8802-2 allows in some cases for ambiguities, i.e. we have the choice 30757027Ssklower * to do one thing or the other. Right now I have just chosen one but have also 30857027Ssklower * indicated the spot by "multiple possibilities". One could make the behavior 30957027Ssklower * in those cases configurable, allowing the superuser to enter a profile word 31057027Ssklower * (32/64 bits, whatever is needed) that would suit her needs [I quite like 31157027Ssklower * that idea, perhaps I'll get around to it]. 31257027Ssklower * 31357027Ssklower * [Preceeding each state handler function is the description as taken from 31457027Ssklower * ISO 8802-2, section 7.9.2.1] 31557027Ssklower */ 31657027Ssklower 31757027Ssklower /* 31857027Ssklower * ADM --- The connection component is in the asynchronous disconnected mode. 31957027Ssklower * It can accept an SABME PDU from a remote LLC SSAP or, at the request 32057027Ssklower * of the service access point user, can initiate an SABME PDU 32157027Ssklower * transmission to a remote LLC DSAP, to establish a data link 32257027Ssklower * connection. It also responds to a DISC command PDU and to any 32357027Ssklower * command PDU with the P bit set to ``1''. 32457027Ssklower */ 32557027Ssklower int 32657027Ssklower llc_state_ADM(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 32757027Ssklower int cmdrsp, int pollfinal) 32857027Ssklower { 32957027Ssklower int action = 0; 33057027Ssklower 33157027Ssklower switch(frame_kind + cmdrsp) { 33257027Ssklower case NL_CONNECT_REQUEST: 33357027Ssklower llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); 33457027Ssklower LLC_SETFLAG(linkp, P, pollfinal); 33557027Ssklower LLC_SETFLAG(linkp, S, 0); 33657027Ssklower linkp->llcl_retry = 0; 33757027Ssklower LLC_NEWSTATE(linkp, SETUP); 33857027Ssklower break; 33957027Ssklower case LLCFT_SABME + LLC_CMD: 34057027Ssklower /* 34157027Ssklower * ISO 8802-2, table 7-1, ADM state says to set 34257027Ssklower * the P flag, yet this will cause an SABME [P] to be 34357027Ssklower * answered with an UA only, not an UA [F], all 34457027Ssklower * other `disconnected' states set the F flag, so ... 34557027Ssklower */ 34657027Ssklower LLC_SETFLAG(linkp, F, pollfinal); 34757027Ssklower LLC_NEWSTATE(linkp, CONN); 34857027Ssklower action = LLC_CONNECT_INDICATION; 34957027Ssklower break; 35057027Ssklower case LLCFT_DISC + LLC_CMD: 35157027Ssklower llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); 35257027Ssklower break; 35357027Ssklower default: 35457027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) 35557027Ssklower llc_send(linkp, LLCFT_DM, LLC_RSP, 1); 35657027Ssklower /* remain in ADM state */ 35757027Ssklower } 35857027Ssklower 35957027Ssklower return action; 36057027Ssklower } 36157027Ssklower 36257027Ssklower /* 36357027Ssklower * CONN --- The local connection component has received an SABME PDU from a 36457027Ssklower * remote LLC SSAP, and it is waiting for the local user to accept or 36557027Ssklower * refuse the connection. 36657027Ssklower */ 36757027Ssklower int 36857027Ssklower llc_state_CONN(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 36957027Ssklower int cmdrsp, int pollfinal) 37057027Ssklower { 37157027Ssklower int action = 0; 37257027Ssklower 37357027Ssklower switch(frame_kind + cmdrsp) { 37457027Ssklower case NL_CONNECT_RESPONSE: 37557027Ssklower llc_send(linkp, LLCFT_UA, LLC_RSP, LLC_GETFLAG(linkp, F)); 37657027Ssklower LLC_RESETCOUNTER(linkp); 37757027Ssklower LLC_SETFLAG(linkp, P, 0); 37857027Ssklower LLC_SETFLAG(linkp, REMOTE_BUSY, 0); 37957027Ssklower LLC_NEWSTATE(linkp, NORMAL); 38057027Ssklower break; 38157027Ssklower case NL_DISCONNECT_REQUEST: 38257027Ssklower llc_send(linkp, LLCFT_DM, LLC_RSP, LLC_GETFLAG(linkp, F)); 38357027Ssklower LLC_NEWSTATE(linkp, ADM); 38457027Ssklower break; 38557027Ssklower case LLCFT_SABME + LLC_CMD: 38657027Ssklower LLC_SETFLAG(linkp, F, pollfinal); 38757027Ssklower break; 38857027Ssklower case LLCFT_DM + LLC_RSP: 38957027Ssklower LLC_NEWSTATE(linkp, ADM); 39057027Ssklower action = LLC_DISCONNECT_INDICATION; 39157027Ssklower break; 39257027Ssklower /* all other frames effect nothing here */ 39357027Ssklower } 39457027Ssklower 39557027Ssklower return action; 39657027Ssklower } 39757027Ssklower 39857027Ssklower /* 39957027Ssklower * RESET_WAIT --- The local connection component is waiting for the local user 40057027Ssklower * to indicate a RESET_REQUEST or a DISCONNECT_REQUEST. 40157027Ssklower */ 40257027Ssklower int 40357027Ssklower llc_state_RESET_WAIT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 40457027Ssklower int cmdrsp, int pollfinal) 40557027Ssklower { 40657027Ssklower int action = 0; 40757027Ssklower 40857027Ssklower switch(frame_kind + cmdrsp) { 40957027Ssklower case NL_RESET_REQUEST: 41057027Ssklower if (LLC_GETFLAG(linkp, S) == 0) { 41157027Ssklower llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); 41257027Ssklower LLC_SETFLAG(linkp, P, pollfinal); 41357027Ssklower LLC_START_ACK_TIMER(linkp); 41457027Ssklower linkp->llcl_retry = 0; 41557027Ssklower LLC_NEWSTATE(linkp, RESET); 41657027Ssklower } else { 41757027Ssklower llc_send(linkp, LLCFT_UA, LLC_RSP, 41857027Ssklower LLC_GETFLAG(linkp, F)); 41957027Ssklower LLC_RESETCOUNTER(linkp); 42057027Ssklower LLC_SETFLAG(linkp, P, 0); 42157027Ssklower LLC_SETFLAG(linkp, REMOTE_BUSY, 0); 42257027Ssklower LLC_NEWSTATE(linkp, NORMAL); 42357027Ssklower action = LLC_RESET_CONFIRM; 42457027Ssklower } 42557027Ssklower break; 42657027Ssklower case NL_DISCONNECT_REQUEST: 42757027Ssklower if (LLC_GETFLAG(linkp, S) == 0) { 42857027Ssklower llc_send(linkp, LLCFT_DISC, LLC_CMD, pollfinal); 42957027Ssklower LLC_SETFLAG(linkp, P, pollfinal); 43057027Ssklower LLC_START_ACK_TIMER(linkp); 43157027Ssklower linkp->llcl_retry = 0; 43257027Ssklower LLC_NEWSTATE(linkp, D_CONN); 43357027Ssklower } else { 43457027Ssklower llc_send(linkp, LLCFT_DM, LLC_RSP, 43557027Ssklower LLC_GETFLAG(linkp, F)); 43657027Ssklower LLC_NEWSTATE(linkp, ADM); 43757027Ssklower } 43857027Ssklower break; 43957027Ssklower case LLCFT_DM + LLC_RSP: 44057027Ssklower LLC_NEWSTATE(linkp, ADM); 44157027Ssklower action = LLC_DISCONNECT_INDICATION; 44257027Ssklower break; 44357027Ssklower case LLCFT_SABME + LLC_CMD: 44457027Ssklower LLC_SETFLAG(linkp, S, 1); 44557027Ssklower LLC_SETFLAG(linkp, F, pollfinal); 44657027Ssklower break; 44757027Ssklower case LLCFT_DISC + LLC_CMD: 44857027Ssklower llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); 44957027Ssklower LLC_NEWSTATE(linkp, ADM); 45057027Ssklower action = LLC_DISCONNECT_INDICATION; 45157027Ssklower break; 45257027Ssklower } 45357027Ssklower 45457027Ssklower return action; 45557027Ssklower } 45657027Ssklower 45757027Ssklower /* 45857027Ssklower * RESET_CHECK --- The local connection component is waiting for the local user 45957027Ssklower * to accept or refuse a remote reset request. 46057027Ssklower */ 46157027Ssklower int 46257027Ssklower llc_state_RESET_CHECK(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 46357027Ssklower int cmdrsp, int pollfinal) 46457027Ssklower { 46557027Ssklower int action = 0; 46657027Ssklower 46757027Ssklower switch(frame_kind + cmdrsp) { 46857027Ssklower case NL_RESET_RESPONSE: 46957027Ssklower llc_send(linkp, LLCFT_UA, LLC_RSP, LLC_GETFLAG(linkp, F)); 47057027Ssklower LLC_RESETCOUNTER(linkp); 47157027Ssklower LLC_SETFLAG(linkp, P, 0); 47257027Ssklower LLC_SETFLAG(linkp, REMOTE_BUSY, 0); 47357027Ssklower LLC_NEWSTATE(linkp, NORMAL); 47457027Ssklower break; 47557027Ssklower case NL_DISCONNECT_REQUEST: 47657027Ssklower llc_send(linkp, LLCFT_DM, LLC_RSP, LLC_GETFLAG(linkp, F)); 47757027Ssklower LLC_NEWSTATE(linkp, ADM); 47857027Ssklower break; 47957027Ssklower case LLCFT_DM + LLC_RSP: 48057027Ssklower action = LLC_DISCONNECT_INDICATION; 48157027Ssklower break; 48257027Ssklower case LLCFT_SABME + LLC_CMD: 48357027Ssklower LLC_SETFLAG(linkp, F, pollfinal); 48457027Ssklower break; 48557027Ssklower case LLCFT_DISC + LLC_CMD: 48657027Ssklower llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); 48757027Ssklower LLC_NEWSTATE(linkp, ADM); 48857027Ssklower action = LLC_DISCONNECT_INDICATION; 48957027Ssklower break; 49057027Ssklower } 49157027Ssklower 49257027Ssklower return action; 49357027Ssklower } 49457027Ssklower 49557027Ssklower /* 49657027Ssklower * SETUP --- The connection component has transmitted an SABME command PDU to a 49757027Ssklower * remote LLC DSAP and is waiting for a reply. 49857027Ssklower */ 49957027Ssklower int 50057027Ssklower llc_state_SETUP(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 50157027Ssklower int cmdrsp, int pollfinal) 50257027Ssklower { 50357027Ssklower int action = 0; 50457027Ssklower 50557027Ssklower switch(frame_kind + cmdrsp) { 50657027Ssklower case LLCFT_SABME + LLC_CMD: 50757027Ssklower LLC_RESETCOUNTER(linkp); 50857027Ssklower llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal); 50957027Ssklower LLC_SETFLAG(linkp, S, 1); 51057027Ssklower break; 51157027Ssklower case LLCFT_UA + LLC_RSP: 51257027Ssklower if (LLC_GETFLAG(linkp, P) == pollfinal) { 51357027Ssklower LLC_STOP_ACK_TIMER(linkp); 51457027Ssklower LLC_RESETCOUNTER(linkp); 51557027Ssklower LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 51657027Ssklower LLC_SETFLAG(linkp, REMOTE_BUSY, 0); 51757027Ssklower LLC_NEWSTATE(linkp, NORMAL); 51857027Ssklower action = LLC_CONNECT_CONFIRM; 51957027Ssklower } 52057027Ssklower break; 52157027Ssklower case LLC_ACK_TIMER_EXPIRED: 52257027Ssklower if (LLC_GETFLAG(linkp, S) == 1) { 52357027Ssklower LLC_SETFLAG(linkp, P, 0); 52457027Ssklower LLC_SETFLAG(linkp, REMOTE_BUSY, 0), 52557027Ssklower LLC_NEWSTATE(linkp, NORMAL); 52657027Ssklower action = LLC_CONNECT_CONFIRM; 52757027Ssklower } else if (linkp->llcl_retry < llc_n2) { 52857027Ssklower llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); 52957027Ssklower LLC_SETFLAG(linkp, P, pollfinal); 53057027Ssklower LLC_START_ACK_TIMER(linkp); 53157027Ssklower linkp->llcl_retry++; 53257027Ssklower } else { 53357027Ssklower LLC_NEWSTATE(linkp, ADM); 53457027Ssklower action = LLC_DISCONNECT_INDICATION; 53557027Ssklower } 53657027Ssklower break; 53757027Ssklower case LLCFT_DISC + LLC_CMD: 53857027Ssklower llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); 53957027Ssklower LLC_STOP_ACK_TIMER(linkp); 54057027Ssklower LLC_NEWSTATE(linkp, ADM); 54157027Ssklower action = LLC_DISCONNECT_INDICATION; 54257027Ssklower break; 54357027Ssklower case LLCFT_DM + LLC_RSP: 54457027Ssklower LLC_STOP_ACK_TIMER(linkp); 54557027Ssklower LLC_NEWSTATE(linkp, ADM); 54657027Ssklower action = LLC_DISCONNECT_INDICATION; 54757027Ssklower break; 54857027Ssklower } 54957027Ssklower 55057027Ssklower return action; 55157027Ssklower } 55257027Ssklower 55357027Ssklower /* 55457027Ssklower * RESET --- As a result of a service access point user request or the receipt 55557027Ssklower * of a FRMR response PDU, the local connection component has sent an 55657027Ssklower * SABME command PDU to the remote LLC DSAP to reset the data link 55757027Ssklower * connection and is waiting for a reply. 55857027Ssklower */ 55957027Ssklower int 56057027Ssklower llc_state_RESET(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 56157027Ssklower int cmdrsp, int pollfinal) 56257027Ssklower { 56357027Ssklower int action = 0; 56457027Ssklower 56557027Ssklower switch(frame_kind + cmdrsp) { 56657027Ssklower case LLCFT_SABME + LLC_CMD: 56757027Ssklower LLC_RESETCOUNTER(linkp); 56857027Ssklower LLC_SETFLAG(linkp, S, 1); 56957027Ssklower llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal); 57057027Ssklower break; 57157027Ssklower case LLCFT_UA + LLC_RSP: 57257027Ssklower if (LLC_GETFLAG(linkp, P) == pollfinal) { 57357027Ssklower LLC_STOP_ACK_TIMER(linkp); 57457027Ssklower LLC_RESETCOUNTER(linkp); 57557027Ssklower LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 57657027Ssklower LLC_SETFLAG(linkp, REMOTE_BUSY, 0); 57757027Ssklower LLC_NEWSTATE(linkp, NORMAL); 57857027Ssklower action = LLC_RESET_CONFIRM; 57957027Ssklower } 58057027Ssklower break; 58157027Ssklower case LLC_ACK_TIMER_EXPIRED: 58257027Ssklower if (LLC_GETFLAG(linkp, S) == 1) { 58357027Ssklower LLC_SETFLAG(linkp, P, 0); 58457027Ssklower LLC_SETFLAG(linkp, REMOTE_BUSY, 0); 58557027Ssklower LLC_NEWSTATE(linkp, NORMAL); 58657027Ssklower action = LLC_RESET_CONFIRM; 58757027Ssklower } else if (linkp->llcl_retry < llc_n2) { 58857027Ssklower llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); 58957027Ssklower LLC_SETFLAG(linkp, P, pollfinal); 59057027Ssklower LLC_START_ACK_TIMER(linkp); 59157027Ssklower linkp->llcl_retry++; 59257027Ssklower } else { 59357027Ssklower LLC_NEWSTATE(linkp, ADM); 59457027Ssklower action = LLC_DISCONNECT_INDICATION; 59557027Ssklower } 59657027Ssklower break; 59757027Ssklower case LLCFT_DISC + LLC_CMD: 59857027Ssklower llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); 59957027Ssklower LLC_STOP_ACK_TIMER(linkp); 60057027Ssklower LLC_NEWSTATE(linkp, ADM); 60157027Ssklower action = LLC_DISCONNECT_INDICATION; 60257027Ssklower break; 60357027Ssklower case LLCFT_DM + LLC_RSP: 60457027Ssklower LLC_STOP_ACK_TIMER(linkp); 60557027Ssklower LLC_NEWSTATE(linkp, ADM); 60657027Ssklower action = LLC_DISCONNECT_INDICATION; 60757027Ssklower break; 60857027Ssklower } 60957027Ssklower 61057027Ssklower return action; 61157027Ssklower } 61257027Ssklower 61357027Ssklower /* 61457027Ssklower * D_CONN --- At the request of the service access point user, the local LLC 61557027Ssklower * has sent a DISC command PDU to the remote LLC DSAP and is waiting 61657027Ssklower * for a reply. 61757027Ssklower */ 61857027Ssklower int 61957027Ssklower llc_state_D_CONN(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 62057027Ssklower int cmdrsp, int pollfinal) 62157027Ssklower { 62257027Ssklower int action = 0; 62357027Ssklower 62457027Ssklower switch(frame_kind + cmdrsp) { 62557027Ssklower case LLCFT_SABME + LLC_CMD: 62657027Ssklower llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); 62757027Ssklower LLC_STOP_ACK_TIMER(linkp); 62857027Ssklower LLC_NEWSTATE(linkp, ADM); 62957027Ssklower break; 63057027Ssklower case LLCFT_UA + LLC_RSP: 63157027Ssklower if (LLC_GETFLAG(linkp, P) == pollfinal) { 63257027Ssklower LLC_STOP_ACK_TIMER(linkp); 63357027Ssklower LLC_NEWSTATE(linkp, ADM); 63457027Ssklower } 63557027Ssklower break; 63657027Ssklower case LLCFT_DISC + LLC_CMD: 63757027Ssklower llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal); 63857027Ssklower break; 63957027Ssklower case LLCFT_DM + LLC_RSP: 64057027Ssklower LLC_STOP_ACK_TIMER(linkp); 64157027Ssklower LLC_NEWSTATE(linkp, ADM); 64257027Ssklower break; 64357027Ssklower case LLC_ACK_TIMER_EXPIRED: 64457027Ssklower if (linkp->llcl_retry < llc_n2) { 64557027Ssklower llc_send(linkp, LLCFT_DISC, LLC_CMD, pollfinal); 64657027Ssklower LLC_SETFLAG(linkp, P, pollfinal); 64757027Ssklower LLC_START_ACK_TIMER(linkp); 64857027Ssklower linkp->llcl_retry++; 64957027Ssklower } else LLC_NEWSTATE(linkp, ADM); 65057027Ssklower break; 65157027Ssklower } 65257027Ssklower 65357027Ssklower return action; 65457027Ssklower } 65557027Ssklower 65657027Ssklower /* 65757027Ssklower * ERROR --- The local connection component has detected an error in a received 65857027Ssklower * PDU and has sent a FRMR response PDU. It is waiting for a reply from 65957027Ssklower * the remote connection component. 66057027Ssklower */ 66157027Ssklower int 66257027Ssklower llc_state_ERROR(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 66357027Ssklower int cmdrsp, int pollfinal) 66457027Ssklower { 66557027Ssklower int action = 0; 66657027Ssklower 66757027Ssklower switch(frame_kind + cmdrsp) { 66857027Ssklower case LLCFT_SABME + LLC_CMD: 66957027Ssklower LLC_STOP_ACK_TIMER(linkp); 67057027Ssklower LLC_NEWSTATE(linkp, RESET_CHECK); 67157027Ssklower action = LLC_RESET_INDICATION_REMOTE; 67257027Ssklower break; 67357027Ssklower case LLCFT_DISC + LLC_CMD: 67457027Ssklower llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal); 67557027Ssklower LLC_STOP_ACK_TIMER(linkp); 67657027Ssklower LLC_NEWSTATE(linkp, ADM); 67757027Ssklower action = LLC_DISCONNECT_INDICATION; 67857027Ssklower break; 67957027Ssklower case LLCFT_DM + LLC_RSP: 68057027Ssklower LLC_STOP_ACK_TIMER(linkp); 68157027Ssklower LLC_NEWSTATE(linkp, ADM); 68257027Ssklower action = LLC_DISCONNECT_INDICATION; 68357027Ssklower break; 68457027Ssklower case LLCFT_FRMR + LLC_RSP: 68557027Ssklower LLC_STOP_ACK_TIMER(linkp); 68657027Ssklower LLC_SETFLAG(linkp, S, 0); 68757027Ssklower LLC_NEWSTATE(linkp, RESET_WAIT); 68857027Ssklower action = LLC_FRMR_RECEIVED; 68957027Ssklower break; 69057027Ssklower case LLC_ACK_TIMER_EXPIRED: 69157027Ssklower if (linkp->llcl_retry < llc_n2) { 69257027Ssklower llc_send(linkp, LLCFT_FRMR, LLC_RSP, 0); 69357027Ssklower LLC_START_ACK_TIMER(linkp); 69457027Ssklower linkp->llcl_retry++; 69557027Ssklower } else { 69657027Ssklower LLC_SETFLAG(linkp, S, 0); 69757027Ssklower LLC_NEWSTATE(linkp, RESET_WAIT); 69857027Ssklower action = LLC_RESET_INDICATION_LOCAL; 69957027Ssklower } 70057027Ssklower break; 70157027Ssklower default: 70257027Ssklower if (cmdrsp == LLC_CMD){ 70357027Ssklower llc_send(linkp, LLCFT_FRMR, LLC_RSP, pollfinal); 70457027Ssklower LLC_START_ACK_TIMER(linkp); 70557027Ssklower } 70657027Ssklower break; 70757027Ssklower 70857027Ssklower } 70957027Ssklower 71057027Ssklower return action; 71157027Ssklower } 71257027Ssklower 71357027Ssklower /* 71457027Ssklower * NORMAL, BUSY, REJECT, AWAIT, AWAIT_BUSY, and AWAIT_REJECT all share 71557027Ssklower * a common core state handler. 71657027Ssklower */ 71757027Ssklower int 71857027Ssklower llc_state_NBRAcore(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 71957027Ssklower int cmdrsp, int pollfinal) 72057027Ssklower { 72157027Ssklower int action = 0; 72257027Ssklower 72357027Ssklower switch(frame_kind + cmdrsp) { 72457027Ssklower case NL_DISCONNECT_REQUEST: 72557027Ssklower llc_send(linkp, LLCFT_DISC, LLC_CMD, pollfinal); 72657027Ssklower LLC_SETFLAG(linkp, P, pollfinal); 72757027Ssklower LLC_STOP_ALL_TIMERS(linkp); 72857027Ssklower LLC_START_ACK_TIMER(linkp); 72957027Ssklower linkp->llcl_retry = 0; 73057027Ssklower LLC_NEWSTATE(linkp, D_CONN); 73157027Ssklower break; 73257027Ssklower case NL_RESET_REQUEST: 73357027Ssklower llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); 73457027Ssklower LLC_SETFLAG(linkp, P, pollfinal); 73557027Ssklower LLC_STOP_ALL_TIMERS(linkp); 73657027Ssklower LLC_START_ACK_TIMER(linkp); 73757027Ssklower linkp->llcl_retry = 0; 73857027Ssklower LLC_SETFLAG(linkp, S, 0); 73957027Ssklower LLC_NEWSTATE(linkp, RESET); 74057027Ssklower break; 74157027Ssklower case LLCFT_SABME + LLC_CMD: 74257027Ssklower LLC_SETFLAG(linkp, F, pollfinal); 74357027Ssklower LLC_STOP_ALL_TIMERS(linkp); 74457027Ssklower LLC_NEWSTATE(linkp, RESET_CHECK); 74557027Ssklower action = LLC_RESET_INDICATION_REMOTE; 74657027Ssklower break; 74757027Ssklower case LLCFT_DISC + LLC_CMD: 74857027Ssklower llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal); 74957027Ssklower LLC_STOP_ALL_TIMERS(linkp); 75057027Ssklower LLC_NEWSTATE(linkp, ADM); 75157027Ssklower action = LLC_DISCONNECT_INDICATION; 75257027Ssklower break; 75357027Ssklower case LLCFT_FRMR + LLC_RSP: 75457027Ssklower LLC_STOP_ALL_TIMERS(linkp); 75557027Ssklower LLC_SETFLAG(linkp, S, 0); 75657027Ssklower LLC_NEWSTATE(linkp, RESET_WAIT); 75757027Ssklower action = LLC_FRMR_RECEIVED; 75857027Ssklower break; 75957027Ssklower case LLCFT_DM + LLC_RSP: 76057027Ssklower LLC_STOP_ALL_TIMERS(linkp); 76157027Ssklower LLC_NEWSTATE(linkp, ADM); 76257027Ssklower action = LLC_DISCONNECT_INDICATION; 76357027Ssklower break; 76457027Ssklower case LLC_INVALID_NR + LLC_CMD: 76557027Ssklower case LLC_INVALID_NS + LLC_CMD: 76657027Ssklower LLC_SETFRMR(linkp, frame, cmdrsp, 76757027Ssklower (frame_kind == LLC_INVALID_NR ? LLC_FRMR_Z : 76857027Ssklower (LLC_FRMR_V | LLC_FRMR_W))); 76957027Ssklower llc_send(linkp, LLCFT_FRMR, LLC_RSP, pollfinal); 77057027Ssklower LLC_STOP_ALL_TIMERS(linkp); 77157027Ssklower LLC_START_ACK_TIMER(linkp); 77257027Ssklower linkp->llcl_retry = 0; 77357027Ssklower LLC_NEWSTATE(linkp, ERROR); 77457027Ssklower action = LLC_FRMR_SENT; 77557027Ssklower break; 77657027Ssklower case LLC_INVALID_NR + LLC_RSP: 77757027Ssklower case LLC_INVALID_NS + LLC_RSP: 77857027Ssklower case LLCFT_UA + LLC_RSP: 77957027Ssklower case LLC_BAD_PDU: { 78057027Ssklower char frmrcause = 0; 78157027Ssklower 78257027Ssklower switch (frame_kind) { 78357027Ssklower case LLC_INVALID_NR: frmrcause = LLC_FRMR_Z; break; 78457027Ssklower case LLC_INVALID_NS: frmrcause = LLC_FRMR_V | LLC_FRMR_W; break; 78557027Ssklower default: frmrcause = LLC_FRMR_W; 78657027Ssklower } 78757027Ssklower LLC_SETFRMR(linkp, frame, cmdrsp, frmrcause); 78857027Ssklower llc_send(linkp, LLCFT_FRMR, LLC_RSP, 0); 78957027Ssklower LLC_STOP_ALL_TIMERS(linkp); 79057027Ssklower LLC_START_ACK_TIMER(linkp); 79157027Ssklower linkp->llcl_retry = 0; 79257027Ssklower LLC_NEWSTATE(linkp, ERROR); 79357027Ssklower action = LLC_FRMR_SENT; 79457027Ssklower break; 79557027Ssklower } 79657027Ssklower default: 79757027Ssklower if (cmdrsp == LLC_RSP && pollfinal == 1 && 79857027Ssklower LLC_GETFLAG(linkp, P) == 0) { 79957027Ssklower LLC_SETFRMR(linkp, frame, cmdrsp, LLC_FRMR_W); 80057027Ssklower LLC_STOP_ALL_TIMERS(linkp); 80157027Ssklower LLC_START_ACK_TIMER(linkp); 80257027Ssklower linkp->llcl_retry = 0; 80357027Ssklower LLC_NEWSTATE(linkp, ERROR); 80457027Ssklower action = LLC_FRMR_SENT; 80557027Ssklower } 80657027Ssklower break; 80757027Ssklower case LLC_P_TIMER_EXPIRED: 80857027Ssklower case LLC_ACK_TIMER_EXPIRED: 80957027Ssklower case LLC_REJ_TIMER_EXPIRED: 81057027Ssklower case LLC_BUSY_TIMER_EXPIRED: 81157027Ssklower if (linkp->llcl_retry >= llc_n2) { 81257027Ssklower LLC_STOP_ALL_TIMERS(linkp); 81357027Ssklower LLC_SETFLAG(linkp, S, 0); 81457027Ssklower LLC_NEWSTATE(linkp, RESET_WAIT); 81557027Ssklower action = LLC_RESET_INDICATION_LOCAL; 81657027Ssklower } 81757027Ssklower break; 81857027Ssklower } 81957027Ssklower 82057027Ssklower return action; 82157027Ssklower } 82257027Ssklower 82357027Ssklower /* 82457027Ssklower * NORMAL --- A data link connection exists between the local LLC service access 82557027Ssklower * point and the remote LLC service access point. Sending and 82657027Ssklower * reception of information and supervisory PDUs can be performed. 82757027Ssklower */ 82857027Ssklower int 82957027Ssklower llc_state_NORMAL(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 83057027Ssklower int cmdrsp, int pollfinal) 83157027Ssklower { 83257027Ssklower int action = LLC_PASSITON; 83357027Ssklower 83457027Ssklower switch(frame_kind + cmdrsp) { 83557027Ssklower case NL_DATA_REQUEST: 83657027Ssklower if (LLC_GETFLAG(linkp, REMOTE_BUSY) == 0) { 83757027Ssklower #ifdef not_now 83857027Ssklower if (LLC_GETFLAG(linkp, P) == 0) { 83957027Ssklower /* multiple possibilities */ 84057027Ssklower llc_send(linkp, LLCFT_INFO, LLC_CMD, 1); 84157027Ssklower LLC_START_P_TIMER(linkp); 84257027Ssklower if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) 84357027Ssklower LLC_START_ACK_TIMER(linkp); 84457027Ssklower } else { 84557027Ssklower #endif 84657027Ssklower /* multiple possibilities */ 84757027Ssklower llc_send(linkp, LLCFT_INFO, LLC_CMD, 0); 84857027Ssklower if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) 84957027Ssklower LLC_START_ACK_TIMER(linkp); 85057027Ssklower #ifdef not_now 85157027Ssklower } 85257027Ssklower #endif 85357027Ssklower action = 0; 85457027Ssklower } 85557027Ssklower break; 85657027Ssklower case LLC_LOCAL_BUSY_DETECTED: 85757027Ssklower if (LLC_GETFLAG(linkp, P) == 0) { 85857027Ssklower /* multiple possibilities --- action-wise */ 85957027Ssklower /* multiple possibilities --- CMD/RSP-wise */ 86057027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 86157027Ssklower LLC_START_P_TIMER(linkp); 86257027Ssklower LLC_SETFLAG(linkp, DATA, 0); 86357027Ssklower LLC_NEWSTATE(linkp, BUSY); 86457027Ssklower action = 0; 86557027Ssklower } else { 86657027Ssklower /* multiple possibilities --- CMD/RSP-wise */ 86757027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 86857027Ssklower LLC_SETFLAG(linkp, DATA, 0); 86957027Ssklower LLC_NEWSTATE(linkp, BUSY); 87057027Ssklower action = 0; 87157027Ssklower } 87257027Ssklower break; 87357027Ssklower case LLC_INVALID_NS + LLC_CMD: 87457027Ssklower case LLC_INVALID_NS + LLC_RSP: { 87557027Ssklower register int p = LLC_GETFLAG(linkp, P); 87657027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 87757027Ssklower 87857027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 87957027Ssklower llc_send(linkp, LLCFT_REJ, LLC_RSP, 1); 88057027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 88157027Ssklower LLC_START_REJ_TIMER(linkp); 88257027Ssklower LLC_NEWSTATE(linkp, REJECT); 88357027Ssklower action = 0; 88457027Ssklower } else if (pollfinal == 0 && p == 1) { 88557027Ssklower llc_send(linkp, LLCFT_REJ, LLC_CMD, 0); 88657027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 88757027Ssklower LLC_START_REJ_TIMER(linkp); 88857027Ssklower LLC_NEWSTATE(linkp, REJECT); 88957027Ssklower action = 0; 89057027Ssklower } else if ((pollfinal == 0 && p == 0) || 89157027Ssklower (pollfinal == 1 && p == 1 && cmdrsp == LLC_RSP)) { 89257027Ssklower llc_send(linkp, LLCFT_REJ, LLC_CMD, 1); 89357027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 89457027Ssklower LLC_START_P_TIMER(linkp); 89557027Ssklower LLC_START_REJ_TIMER(linkp); 89657027Ssklower if (cmdrsp == LLC_RSP && pollfinal == 1) { 89757027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 89857027Ssklower } else action = 0; 89957027Ssklower LLC_NEWSTATE(linkp, REJECT); 90057027Ssklower } 90157027Ssklower break; 90257027Ssklower } 90357027Ssklower case LLCFT_INFO + LLC_CMD: 90457027Ssklower case LLCFT_INFO + LLC_RSP: { 90557027Ssklower register int p = LLC_GETFLAG(linkp, P); 90657027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 90757027Ssklower 90857027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 90957027Ssklower LLC_INC(linkp->llcl_vr); 91057027Ssklower LLC_SENDACKNOWLEDGE(linkp, LLC_RSP, 1); 91157027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 91257027Ssklower action = LLC_DATA_INDICATION; 91357027Ssklower } else if (pollfinal == 0 && p == 1) { 91457027Ssklower LLC_INC(linkp->llcl_vr); 91557027Ssklower LLC_SENDACKNOWLEDGE(linkp, LLC_CMD, 0); 91657027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 91757027Ssklower action = LLC_DATA_INDICATION; 91857027Ssklower } else if ((pollfinal == 0 && p == 0 && cmdrsp == LLC_CMD) || 91957027Ssklower (pollfinal == p && cmdrsp == LLC_RSP)) { 92057027Ssklower LLC_INC(linkp->llcl_vr); 92157027Ssklower LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 92257027Ssklower LLC_SENDACKNOWLEDGE(linkp, LLC_CMD, 0); 92357027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 92457027Ssklower if (cmdrsp == LLC_RSP && pollfinal == 1) 92557027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 92657027Ssklower action = LLC_DATA_INDICATION; 92757027Ssklower } 92857027Ssklower break; 92957027Ssklower } 93057027Ssklower case LLCFT_RR + LLC_CMD: 93157027Ssklower case LLCFT_RR + LLC_RSP: { 93257027Ssklower register int p = LLC_GETFLAG(linkp, P); 93357027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 93457027Ssklower 93557027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 93657027Ssklower LLC_SENDACKNOWLEDGE(linkp, LLC_RSP, 1); 93757027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 93857027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 93957027Ssklower } else if ((pollfinal == 0) || 94057027Ssklower (cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) { 94157027Ssklower LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 94257027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 94357027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 94457027Ssklower } 94557027Ssklower break; 94657027Ssklower } 94757027Ssklower case LLCFT_RNR + LLC_CMD: 94857027Ssklower case LLCFT_RNR + LLC_RSP: { 94957027Ssklower register int p = LLC_GETFLAG(linkp, P); 95057027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 95157027Ssklower 95257027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 95357027Ssklower llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 95457027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 95557027Ssklower LLC_SET_REMOTE_BUSY(linkp, action); 95657027Ssklower } else if ((pollfinal == 0) || 95757027Ssklower (cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) { 95857027Ssklower LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 95957027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 96057027Ssklower LLC_SET_REMOTE_BUSY(linkp, action); 96157027Ssklower } 96257027Ssklower break; 96357027Ssklower } 96457027Ssklower case LLCFT_REJ + LLC_CMD: 96557027Ssklower case LLCFT_REJ + LLC_RSP: { 96657027Ssklower register int p = LLC_GETFLAG(linkp, P); 96757027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 96857027Ssklower 96957027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 97057027Ssklower linkp->llcl_vs = nr; 97157027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 97257027Ssklower llc_resend(linkp, LLC_RSP, 1); 97357027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 97457027Ssklower } else if (pollfinal == 0 && p == 1) { 97557027Ssklower linkp->llcl_vs = nr; 97657027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 97757027Ssklower llc_resend(linkp, LLC_CMD, 0); 97857027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 97957027Ssklower } else if ((pollfinal == 0 && p == 0 && cmdrsp == LLC_CMD) || 98057027Ssklower (pollfinal == p && cmdrsp == LLC_RSP)) { 98157027Ssklower linkp->llcl_vs = nr; 98257027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 98357027Ssklower LLC_START_P_TIMER(linkp); 98457027Ssklower llc_resend(linkp, LLC_CMD, 1); 98557027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 98657027Ssklower } 98757027Ssklower break; 98857027Ssklower } 98957027Ssklower case NL_INITIATE_PF_CYCLE: 99057027Ssklower if (LLC_GETFLAG(linkp, P) == 0) { 99157027Ssklower llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 99257027Ssklower LLC_START_P_TIMER(linkp); 99357027Ssklower action = 0; 99457027Ssklower } 99557027Ssklower break; 99657027Ssklower case LLC_P_TIMER_EXPIRED: 99757027Ssklower if (linkp->llcl_retry < llc_n2) { 99857027Ssklower llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 99957027Ssklower LLC_START_P_TIMER(linkp); 100057027Ssklower linkp->llcl_retry++; 100157027Ssklower LLC_NEWSTATE(linkp, AWAIT); 100257027Ssklower action = 0; 100357027Ssklower } 100457027Ssklower break; 100557027Ssklower case LLC_ACK_TIMER_EXPIRED: 100657027Ssklower case LLC_BUSY_TIMER_EXPIRED: 100757027Ssklower if ((LLC_GETFLAG(linkp, P) == 0) 100857027Ssklower && (linkp->llcl_retry < llc_n2)) { 100957027Ssklower llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 101057027Ssklower LLC_START_P_TIMER(linkp); 101157027Ssklower linkp->llcl_retry++; 101257027Ssklower LLC_NEWSTATE(linkp, AWAIT); 101357027Ssklower action = 0; 101457027Ssklower } 101557027Ssklower break; 101657027Ssklower } 101757027Ssklower if (action == LLC_PASSITON) 101857027Ssklower action = llc_state_NBRAcore(linkp, frame, frame_kind, 101957027Ssklower cmdrsp, pollfinal); 102057027Ssklower 102157027Ssklower return action; 102257027Ssklower } 102357027Ssklower 102457027Ssklower /* 102557027Ssklower * BUSY --- A data link connection exists between the local LLC service access 102657027Ssklower * point and the remote LLC service access point. I PDUs may be sent. 102757027Ssklower * Local conditions make it likely that the information feld of 102857027Ssklower * received I PDUs will be ignored. Supervisory PDUs may be both sent 102957027Ssklower * and received. 103057027Ssklower */ 103157027Ssklower int 103257027Ssklower llc_state_BUSY(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 103357027Ssklower int cmdrsp, int pollfinal) 103457027Ssklower { 103557027Ssklower int action = LLC_PASSITON; 103657027Ssklower 103757027Ssklower switch(frame_kind + cmdrsp) { 103857027Ssklower case NL_DATA_REQUEST: 103957027Ssklower if (LLC_GETFLAG(linkp, REMOTE_BUSY) == 0) 104057027Ssklower if (LLC_GETFLAG(linkp, P) == 0) { 104157027Ssklower llc_send(linkp, LLCFT_INFO, LLC_CMD, 1); 104257027Ssklower LLC_START_P_TIMER(linkp); 104357027Ssklower if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) 104457027Ssklower LLC_START_ACK_TIMER(linkp); 104557027Ssklower action = 0; 104657027Ssklower } else { 104757027Ssklower llc_send(linkp, LLCFT_INFO, LLC_CMD, 0); 104857027Ssklower if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) 104957027Ssklower LLC_START_ACK_TIMER(linkp); 105057027Ssklower action = 0; 105157027Ssklower } 105257027Ssklower break; 105357027Ssklower case LLC_LOCAL_BUSY_CLEARED: { 105457027Ssklower register int p = LLC_GETFLAG(linkp, P); 105557027Ssklower register int df = LLC_GETFLAG(linkp, DATA); 105657027Ssklower 105757027Ssklower switch (df) { 105857027Ssklower case 1: 105957027Ssklower if (p == 0) { 106057027Ssklower /* multiple possibilities */ 106157027Ssklower llc_send(linkp, LLCFT_REJ, LLC_CMD, 1); 106257027Ssklower LLC_START_REJ_TIMER(linkp); 106357027Ssklower LLC_START_P_TIMER(linkp); 106457027Ssklower LLC_NEWSTATE(linkp, REJECT); 106557027Ssklower action = 0; 106657027Ssklower } else { 106757027Ssklower llc_send(linkp, LLCFT_REJ, LLC_CMD, 0); 106857027Ssklower LLC_START_REJ_TIMER(linkp); 106957027Ssklower LLC_NEWSTATE(linkp, REJECT); 107057027Ssklower action = 0; 107157027Ssklower } 107257027Ssklower break; 107357027Ssklower case 0: 107457027Ssklower if (p == 0) { 107557027Ssklower /* multiple possibilities */ 107657027Ssklower llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 107757027Ssklower LLC_START_P_TIMER(linkp); 107857027Ssklower LLC_NEWSTATE(linkp, NORMAL); 107957027Ssklower action = 0; 108057027Ssklower } else { 108157027Ssklower llc_send(linkp, LLCFT_RR, LLC_CMD, 0); 108257027Ssklower LLC_NEWSTATE(linkp, NORMAL); 108357027Ssklower action = 0; 108457027Ssklower } 108557027Ssklower break; 108657027Ssklower case 2: 108757027Ssklower if (p == 0) { 108857027Ssklower /* multiple possibilities */ 108957027Ssklower llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 109057027Ssklower LLC_START_P_TIMER(linkp); 109157027Ssklower LLC_NEWSTATE(linkp, REJECT); 109257027Ssklower action = 0; 109357027Ssklower } else { 109457027Ssklower llc_send(linkp, LLCFT_RR, LLC_CMD, 0); 109557027Ssklower LLC_NEWSTATE(linkp, REJECT); 109657027Ssklower action =0; 109757027Ssklower } 109857027Ssklower break; 109957027Ssklower } 110057027Ssklower break; 110157027Ssklower } 110257027Ssklower case LLC_INVALID_NS + LLC_CMD: 110357027Ssklower case LLC_INVALID_NS + LLC_RSP: { 110457027Ssklower register int p = LLC_GETFLAG(linkp, P); 110557027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 110657027Ssklower 110757027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 110857027Ssklower llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 110957027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 111057027Ssklower if (LLC_GETFLAG(linkp, DATA) == 0) 111157027Ssklower LLC_SETFLAG(linkp, DATA, 1); 111257027Ssklower action = 0; 111357027Ssklower } else if ((cmdrsp == LLC_CMD && pollfinal == 0 && p == 0) || 111457027Ssklower (cmdrsp == LLC_RSP && pollfinal == p)) { 111557027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 111657027Ssklower LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 111757027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 111857027Ssklower if (LLC_GETFLAG(linkp, DATA) == 0) 111957027Ssklower LLC_SETFLAG(linkp, DATA, 1); 112057027Ssklower if (cmdrsp == LLC_RSP && pollfinal == 1) { 112157027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 112257027Ssklower } else action = 0; 112357027Ssklower } else if (pollfinal == 0 && p == 1) { 112457027Ssklower llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 112557027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 112657027Ssklower if (LLC_GETFLAG(linkp, DATA) == 0) 112757027Ssklower LLC_SETFLAG(linkp, DATA, 1); 112857027Ssklower action = 0; 112957027Ssklower } 113057027Ssklower break; 113157027Ssklower } 113257027Ssklower case LLCFT_INFO + LLC_CMD: 113357027Ssklower case LLCFT_INFO + LLC_RSP: { 113457027Ssklower register int p = LLC_GETFLAG(linkp, P); 113557027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 113657027Ssklower 113757027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 113857027Ssklower LLC_INC(linkp->llcl_vr); 113957027Ssklower llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 114057027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 114157027Ssklower if (LLC_GETFLAG(linkp, DATA) == 2) 114257027Ssklower LLC_STOP_REJ_TIMER(linkp); 114357027Ssklower LLC_SETFLAG(linkp, DATA, 0); 114457027Ssklower action = LLC_DATA_INDICATION; 114557027Ssklower } else if ((cmdrsp == LLC_CMD && pollfinal == 0 && p == 0) || 114657027Ssklower (cmdrsp == LLC_RSP && pollfinal == p)) { 114757027Ssklower LLC_INC(linkp->llcl_vr); 114857027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); 114957027Ssklower LLC_START_P_TIMER(linkp); 115057027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 115157027Ssklower if (LLC_GETFLAG(linkp, DATA) == 2) 115257027Ssklower LLC_STOP_REJ_TIMER(linkp); 115357027Ssklower if (cmdrsp == LLC_RSP && pollfinal == 1) 115457027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 115557027Ssklower action = LLC_DATA_INDICATION; 115657027Ssklower } else if (pollfinal == 0 && p == 1) { 115757027Ssklower LLC_INC(linkp->llcl_vr); 115857027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 115957027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 116057027Ssklower if (LLC_GETFLAG(linkp, DATA) == 2) 116157027Ssklower LLC_STOP_REJ_TIMER(linkp); 116257027Ssklower LLC_SETFLAG(linkp, DATA, 0); 116357027Ssklower action = LLC_DATA_INDICATION; 116457027Ssklower } 116557027Ssklower break; 116657027Ssklower } 116757027Ssklower case LLCFT_RR + LLC_CMD: 116857027Ssklower case LLCFT_RR + LLC_RSP: 116957027Ssklower case LLCFT_RNR + LLC_CMD: 117057027Ssklower case LLCFT_RNR + LLC_RSP: { 117157027Ssklower register int p = LLC_GETFLAG(linkp, P); 117257027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 117357027Ssklower 117457027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 117557027Ssklower llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 117657027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 117757027Ssklower if (frame_kind == LLCFT_RR) { 117857027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 117957027Ssklower } else { 118057027Ssklower LLC_SET_REMOTE_BUSY(linkp, action); 118157027Ssklower } 118257027Ssklower } else if (pollfinal = 0 || 118357027Ssklower (cmdrsp == LLC_RSP && pollfinal == 1)) { 118457027Ssklower LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 118557027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 118657027Ssklower if (frame_kind == LLCFT_RR) { 118757027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 118857027Ssklower } else { 118957027Ssklower LLC_SET_REMOTE_BUSY(linkp, action); 119057027Ssklower } 119157027Ssklower } 119257027Ssklower break; 119357027Ssklower } 119457027Ssklower case LLCFT_REJ + LLC_CMD: 119557027Ssklower case LLCFT_REJ + LLC_RSP: { 119657027Ssklower register int p = LLC_GETFLAG(linkp, P); 119757027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 119857027Ssklower 119957027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 120057027Ssklower linkp->llcl_vs = nr; 120157027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 120257027Ssklower llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 120357027Ssklower llc_resend(linkp, LLC_CMD, 0); 120457027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 120557027Ssklower } else if ((cmdrsp == LLC_CMD && pollfinal == 0 && p == 0) || 120657027Ssklower (cmdrsp == LLC_RSP && pollfinal == p)) { 120757027Ssklower linkp->llcl_vs = nr; 120857027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 120957027Ssklower LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 121057027Ssklower llc_resend(linkp, LLC_CMD, 0); 121157027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 121257027Ssklower } else if (pollfinal == 0 && p == 1) { 121357027Ssklower linkp->llcl_vs = nr; 121457027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 121557027Ssklower llc_resend(linkp, LLC_CMD, 0); 121657027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 121757027Ssklower } 121857027Ssklower break; 121957027Ssklower } 122057027Ssklower case NL_INITIATE_PF_CYCLE: 122157027Ssklower if (LLC_GETFLAG(linkp, P) == 0) { 122257027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); 122357027Ssklower LLC_START_P_TIMER(linkp); 122457027Ssklower action = 0; 122557027Ssklower } 122657027Ssklower break; 122757027Ssklower case LLC_P_TIMER_EXPIRED: 122857027Ssklower /* multiple possibilities */ 122957027Ssklower if (linkp->llcl_retry < llc_n2) { 123057027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); 123157027Ssklower LLC_START_P_TIMER(linkp); 123257027Ssklower linkp->llcl_retry++; 123357027Ssklower LLC_NEWSTATE(linkp, AWAIT_BUSY); 123457027Ssklower action = 0; 123557027Ssklower } 123657027Ssklower break; 123757027Ssklower case LLC_ACK_TIMER_EXPIRED: 123857027Ssklower case LLC_BUSY_TIMER_EXPIRED: 123957027Ssklower if (LLC_GETFLAG(linkp, P) == 0 && linkp->llcl_retry < llc_n2) { 124057027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); 124157027Ssklower LLC_START_P_TIMER(linkp); 124257027Ssklower linkp->llcl_retry++; 124357027Ssklower LLC_NEWSTATE(linkp, AWAIT_BUSY); 124457027Ssklower action = 0; 124557027Ssklower } 124657027Ssklower break; 124757027Ssklower case LLC_REJ_TIMER_EXPIRED: 124857027Ssklower if (linkp->llcl_retry < llc_n2) 124957027Ssklower if (LLC_GETFLAG(linkp, P) == 0) { 125057027Ssklower /* multiple possibilities */ 125157027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); 125257027Ssklower LLC_START_P_TIMER(linkp); 125357027Ssklower linkp->llcl_retry++; 125457027Ssklower LLC_SETFLAG(linkp, DATA, 1); 125557027Ssklower LLC_NEWSTATE(linkp, AWAIT_BUSY); 125657027Ssklower action = 0; 125757027Ssklower } else{ 125857027Ssklower LLC_SETFLAG(linkp, DATA, 1); 125957027Ssklower LLC_NEWSTATE(linkp, BUSY); 126057027Ssklower action = 0; 126157027Ssklower } 126257027Ssklower 126357027Ssklower break; 126457027Ssklower } 126557027Ssklower if (action == LLC_PASSITON) 126657027Ssklower action = llc_state_NBRAcore(linkp, frame, frame_kind, 126757027Ssklower cmdrsp, pollfinal); 126857027Ssklower 126957027Ssklower return action; 127057027Ssklower } 127157027Ssklower 127257027Ssklower /* 127357027Ssklower * REJECT --- A data link connection exists between the local LLC service 127457027Ssklower * access point and the remote LLC service access point. The local 127557027Ssklower * connection component has requested that the remote connection 127657027Ssklower * component resend a specific I PDU that the local connection 127757027Ssklower * componnent has detected as being out of sequence. Both I PDUs and 127857027Ssklower * supervisory PDUs may be sent and received. 127957027Ssklower */ 128057027Ssklower int 128157027Ssklower llc_state_REJECT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 128257027Ssklower int cmdrsp, int pollfinal) 128357027Ssklower { 128457027Ssklower int action = LLC_PASSITON; 128557027Ssklower 128657027Ssklower switch(frame_kind + cmdrsp) { 128757027Ssklower case NL_DATA_REQUEST: 128857027Ssklower if (LLC_GETFLAG(linkp, P) == 0) { 128957027Ssklower llc_send(linkp, LLCFT_INFO, LLC_CMD, 1); 129057027Ssklower LLC_START_P_TIMER(linkp); 129157027Ssklower if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) 129257027Ssklower LLC_START_ACK_TIMER(linkp); 129357027Ssklower LLC_NEWSTATE(linkp, REJECT); 129457027Ssklower action = 0; 129557027Ssklower } else { 129657027Ssklower llc_send(linkp, LLCFT_INFO, LLC_CMD, 0); 129757027Ssklower if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) 129857027Ssklower LLC_START_ACK_TIMER(linkp); 129957027Ssklower LLC_NEWSTATE(linkp, REJECT); 130057027Ssklower action = 0; 130157027Ssklower } 130257027Ssklower break; 130357027Ssklower case NL_LOCAL_BUSY_DETECTED: 130457027Ssklower if (LLC_GETFLAG(linkp, P) == 0) { 130557027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); 130657027Ssklower LLC_START_P_TIMER(linkp); 130757027Ssklower LLC_SETFLAG(linkp, DATA, 2); 130857027Ssklower LLC_NEWSTATE(linkp, BUSY); 130957027Ssklower action = 0; 131057027Ssklower } else { 131157027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 131257027Ssklower LLC_SETFLAG(linkp, DATA, 2); 131357027Ssklower LLC_NEWSTATE(linkp, BUSY); 131457027Ssklower action = 0; 131557027Ssklower } 131657027Ssklower break; 131757027Ssklower case LLC_INVALID_NS + LLC_CMD: 131857027Ssklower case LLC_INVALID_NS + LLC_RSP: { 131957027Ssklower register int p = LLC_GETFLAG(linkp, P); 132057027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 132157027Ssklower 132257027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 132357027Ssklower llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 132457027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 132557027Ssklower action = 0; 132657027Ssklower } else if (pollfinal == 0 || 132757027Ssklower (cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) { 132857027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 132957027Ssklower LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 133057027Ssklower if (cmdrsp == LLC_RSP && pollfinal == 1) { 133157027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 133257027Ssklower } else action = 0; 133357027Ssklower } 133457027Ssklower break; 133557027Ssklower } 133657027Ssklower case LLCFT_INFO + LLC_CMD: 133757027Ssklower case LLCFT_INFO + LLC_RSP: { 133857027Ssklower register int p = LLC_GETFLAG(linkp, P); 133957027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 134057027Ssklower 134157027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 134257027Ssklower LLC_INC(linkp->llcl_vr); 134357027Ssklower LLC_SENDACKNOWLEDGE(linkp, LLC_RSP, 1); 134457027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 134557027Ssklower LLC_STOP_REJ_TIMER(linkp); 134657027Ssklower LLC_NEWSTATE(linkp, NORMAL); 134757027Ssklower action = LLC_DATA_INDICATION; 134857027Ssklower } else if ((cmdrsp = LLC_RSP && pollfinal == p) || 134957027Ssklower (cmdrsp == LLC_CMD && pollfinal == 0 && p == 0)) { 135057027Ssklower LLC_INC(linkp->llcl_vr); 135157027Ssklower LLC_SENDACKNOWLEDGE(linkp, LLC_CMD, 1); 135257027Ssklower LLC_START_P_TIMER(linkp); 135357027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 135457027Ssklower if (cmdrsp == LLC_RSP && pollfinal == 1) 135557027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 135657027Ssklower LLC_STOP_REJ_TIMER(linkp); 135757027Ssklower LLC_NEWSTATE(linkp, NORMAL); 135857027Ssklower action = LLC_DATA_INDICATION; 135957027Ssklower } else if (pollfinal == 0 && p == 1) { 136057027Ssklower LLC_INC(linkp->llcl_vr); 136157027Ssklower LLC_SENDACKNOWLEDGE(linkp, LLC_CMD, 0); 136257027Ssklower LLC_STOP_REJ_TIMER(linkp); 136357027Ssklower LLC_NEWSTATE(linkp, NORMAL); 136457027Ssklower action = LLC_DATA_INDICATION; 136557027Ssklower } 136657027Ssklower break; 136757027Ssklower } 136857027Ssklower case LLCFT_RR + LLC_CMD: 136957027Ssklower case LLCFT_RR + LLC_RSP: { 137057027Ssklower register int p = LLC_GETFLAG(linkp, P); 137157027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 137257027Ssklower 137357027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 137457027Ssklower LLC_SENDACKNOWLEDGE(linkp, LLC_RSP, 1); 137557027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 137657027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 137757027Ssklower } else if (pollfinal == 0 || 137857027Ssklower (cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) { 137957027Ssklower LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 138057027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 138157027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 138257027Ssklower } 138357027Ssklower break; 138457027Ssklower } 138557027Ssklower case LLCFT_RNR + LLC_CMD: 138657027Ssklower case LLCFT_RNR + LLC_RSP: { 138757027Ssklower register int p = LLC_GETFLAG(linkp, P); 138857027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 138957027Ssklower 139057027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 139157027Ssklower llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 139257027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 139357027Ssklower LLC_SET_REMOTE_BUSY(linkp, action); 139457027Ssklower } else if (pollfinal == 0 || 139557027Ssklower (cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) { 139657027Ssklower LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 139757027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 139857027Ssklower action = 0; 139957027Ssklower } 140057027Ssklower break; 140157027Ssklower } 140257027Ssklower case LLCFT_REJ + LLC_CMD: 140357027Ssklower case LLCFT_REJ + LLC_RSP: { 140457027Ssklower register int p = LLC_GETFLAG(linkp, P); 140557027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 140657027Ssklower 140757027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 140857027Ssklower linkp->llcl_vs = nr; 140957027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 141057027Ssklower llc_resend(linkp, LLC_RSP, 1); 141157027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 141257027Ssklower } else if ((cmdrsp == LLC_CMD && pollfinal == 0 && p == 0) || 141357027Ssklower (cmdrsp == LLC_RSP && pollfinal == p)) { 141457027Ssklower linkp->llcl_vs = nr; 141557027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 141657027Ssklower LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); 141757027Ssklower llc_resend(linkp, LLC_CMD, 0); 141857027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 141957027Ssklower } else if (pollfinal == 0 && p == 1) { 142057027Ssklower linkp->llcl_vs = nr; 142157027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 142257027Ssklower llc_resend(linkp, LLC_CMD, 0); 142357027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 142457027Ssklower } 142557027Ssklower break; 142657027Ssklower } 142757027Ssklower case NL_INITIATE_PF_CYCLE: 142857027Ssklower if (LLC_GETFLAG(linkp, P) == 0) { 142957027Ssklower llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 143057027Ssklower LLC_START_P_TIMER(linkp); 143157027Ssklower action = 0; 143257027Ssklower } 143357027Ssklower break; 143457027Ssklower case LLC_REJ_TIMER_EXPIRED: 143557027Ssklower if (LLC_GETFLAG(linkp, P) == 0 && linkp->llcl_retry < llc_n2) { 143657027Ssklower llc_send(linkp, LLCFT_REJ, LLC_CMD, 1); 143757027Ssklower LLC_START_P_TIMER(linkp); 143857027Ssklower LLC_START_REJ_TIMER(linkp); 143957027Ssklower linkp->llcl_retry++; 144057027Ssklower action = 0; 144157027Ssklower } 144257027Ssklower case LLC_P_TIMER_EXPIRED: 144357027Ssklower if (linkp->llcl_retry < llc_n2) { 144457027Ssklower llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 144557027Ssklower LLC_START_P_TIMER(linkp); 144657027Ssklower LLC_START_REJ_TIMER(linkp); 144757027Ssklower linkp->llcl_retry++; 144857027Ssklower LLC_NEWSTATE(linkp, AWAIT_REJECT); 144957027Ssklower action = 0; 145057027Ssklower } 145157027Ssklower break; 145257027Ssklower case LLC_ACK_TIMER_EXPIRED: 145357027Ssklower case LLC_BUSY_TIMER_EXPIRED: 145457027Ssklower if (LLC_GETFLAG(linkp, P) == 0 && linkp->llcl_retry < llc_n2) { 145557027Ssklower llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 145657027Ssklower LLC_START_P_TIMER(linkp); 145757027Ssklower LLC_START_REJ_TIMER(linkp); 145857027Ssklower linkp->llcl_retry++; 145957027Ssklower /* 146057027Ssklower * I cannot locate the description of RESET_V(S) 146157027Ssklower * in ISO 8802-2, table 7-1, state REJECT, last event, 146257027Ssklower * and assume they meant to set V(S) to 0 ... 146357027Ssklower */ 146457027Ssklower linkp->llcl_vs = 0; /* XXX */ 146557027Ssklower LLC_NEWSTATE(linkp, AWAIT_REJECT); 146657027Ssklower action = 0; 146757027Ssklower } 146857027Ssklower 146957027Ssklower break; 147057027Ssklower } 147157027Ssklower if (action == LLC_PASSITON) 147257027Ssklower action = llc_state_NBRAcore(linkp, frame, frame_kind, 147357027Ssklower cmdrsp, pollfinal); 147457027Ssklower 147557027Ssklower return action; 147657027Ssklower } 147757027Ssklower 147857027Ssklower /* 147957027Ssklower * AWAIT --- A data link connection exists between the local LLC service access 148057027Ssklower * point and the remote LLC service access point. The local LLC is 148157027Ssklower * performing a timer recovery operation and has sent a command PDU 148257027Ssklower * with the P bit set to ``1'', and is awaiting an acknowledgement 148357027Ssklower * from the remote LLC. I PDUs may be received but not sent. 148457027Ssklower * Supervisory PDUs may be both sent and received. 148557027Ssklower */ 148657027Ssklower int 148757027Ssklower llc_state_AWAIT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 148857027Ssklower int cmdrsp, int pollfinal) 148957027Ssklower { 149057027Ssklower int action = LLC_PASSITON; 149157027Ssklower 149257027Ssklower switch(frame_kind + cmdrsp) { 149357027Ssklower case LLC_LOCAL_BUSY_DETECTED: 149457027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 149557027Ssklower LLC_SETFLAG(linkp, DATA, 0); 149657027Ssklower LLC_NEWSTATE(linkp, AWAIT_BUSY); 149757027Ssklower action = 0; 149857027Ssklower break; 149957027Ssklower case LLC_INVALID_NS + LLC_CMD: 150057027Ssklower case LLC_INVALID_NS + LLC_RSP: { 150157027Ssklower register int p = LLC_GETFLAG(linkp, P); 150257027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 150357027Ssklower 150457027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 150557027Ssklower llc_send(linkp, LLCFT_REJ, LLC_RSP, 1); 150657027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 150757027Ssklower LLC_START_REJ_TIMER(linkp); 150857027Ssklower LLC_NEWSTATE(linkp, AWAIT_REJECT); 150957027Ssklower action = 0; 151057027Ssklower } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 151157027Ssklower llc_send(linkp, LLCFT_REJ, LLC_CMD, 0); 151257027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 151357027Ssklower linkp->llcl_vs = nr; 151457027Ssklower LLC_STOP_P_TIMER(linkp); 151557027Ssklower llc_resend(linkp, LLC_CMD, 0); 151657027Ssklower LLC_START_REJ_TIMER(linkp); 151757027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 151857027Ssklower LLC_NEWSTATE(linkp, REJECT); 151957027Ssklower } else if (pollfinal == 0) { 152057027Ssklower llc_send(linkp, LLCFT_REJ, LLC_CMD, 0); 152157027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 152257027Ssklower LLC_START_REJ_TIMER(linkp); 152357027Ssklower LLC_NEWSTATE(linkp, AWAIT_REJECT); 152457027Ssklower action = 0; 152557027Ssklower } 152657027Ssklower break; 152757027Ssklower } 152857027Ssklower case LLCFT_INFO + LLC_RSP: 152957027Ssklower case LLCFT_INFO + LLC_CMD: { 153057027Ssklower register int p = LLC_GETFLAG(linkp, P); 153157027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 153257027Ssklower 153357027Ssklower LLC_INC(linkp->llcl_vr); 153457027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 153557027Ssklower llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 153657027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 153757027Ssklower action = LLC_DATA_INDICATION; 153857027Ssklower } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 153957027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 154057027Ssklower linkp->llcl_vs = nr; 154157027Ssklower llc_resend(linkp, LLC_CMD, 1); 154257027Ssklower LLC_START_P_TIMER(linkp); 154357027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 154457027Ssklower LLC_NEWSTATE(linkp, NORMAL); 154557027Ssklower action = LLC_DATA_INDICATION; 154657027Ssklower } else if (pollfinal == 0) { 154757027Ssklower llc_send(linkp, LLCFT_RR, LLC_CMD, 0); 154857027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 154957027Ssklower action = LLC_DATA_INDICATION; 155057027Ssklower } 155157027Ssklower break; 155257027Ssklower } 155357027Ssklower case LLCFT_RR + LLC_CMD: 155457027Ssklower case LLCFT_RR + LLC_RSP: 155557027Ssklower case LLCFT_REJ + LLC_CMD: 155657027Ssklower case LLCFT_REJ + LLC_RSP: { 155757027Ssklower register int p = LLC_GETFLAG(linkp, P); 155857027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 155957027Ssklower 156057027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 156157027Ssklower llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 156257027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 156357027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 156457027Ssklower } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 156557027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 156657027Ssklower linkp->llcl_vs = nr; 156757027Ssklower LLC_STOP_P_TIMER(linkp); 156857027Ssklower llc_resend(linkp, LLC_CMD, 0); 156957027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 157057027Ssklower LLC_NEWSTATE(linkp, NORMAL); 157157027Ssklower } else if (pollfinal == 0) { 157257027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 157357027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 157457027Ssklower } 157557027Ssklower break; 157657027Ssklower } 157757027Ssklower case LLCFT_RNR + LLC_CMD: 157857027Ssklower case LLCFT_RNR + LLC_RSP: { 157957027Ssklower register int p = LLC_GETFLAG(linkp, P); 158057027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 158157027Ssklower 158257027Ssklower if (pollfinal == 1 && cmdrsp == LLC_CMD) { 158357027Ssklower llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 158457027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 158557027Ssklower LLC_SET_REMOTE_BUSY(linkp, action); 158657027Ssklower } else if (pollfinal == 1 && cmdrsp == LLC_RSP) { 158757027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 158857027Ssklower linkp->llcl_vs = nr; 158957027Ssklower LLC_STOP_P_TIMER(linkp); 159057027Ssklower LLC_SET_REMOTE_BUSY(linkp, action); 159157027Ssklower LLC_NEWSTATE(linkp, NORMAL); 159257027Ssklower } else if (pollfinal == 0) { 159357027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 159457027Ssklower LLC_SET_REMOTE_BUSY(linkp, action); 159557027Ssklower } 159657027Ssklower break; 159757027Ssklower } 159857027Ssklower case LLC_P_TIMER_EXPIRED: 159957027Ssklower if (linkp->llcl_retry < llc_n2) { 160057027Ssklower llc_send(linkp, LLCFT_RR, LLC_CMD, 1); 160157027Ssklower LLC_START_P_TIMER(linkp); 160257027Ssklower linkp->llcl_retry++; 160357027Ssklower action = 0; 160457027Ssklower } 160557027Ssklower break; 160657027Ssklower } 160757027Ssklower if (action == LLC_PASSITON) 160857027Ssklower action = llc_state_NBRAcore(linkp, frame, frame_kind, 160957027Ssklower cmdrsp, pollfinal); 161057027Ssklower 161157027Ssklower return action; 161257027Ssklower } 161357027Ssklower 161457027Ssklower /* 161557027Ssklower * AWAIT_BUSY --- A data link connection exists between the local LLC service 161657027Ssklower * access point and the remote LLC service access point. The 161757027Ssklower * local LLC is performing a timer recovery operation and has 161857027Ssklower * sent a command PDU with the P bit set to ``1'', and is 161957027Ssklower * awaiting an acknowledgement from the remote LLC. I PDUs may 162057027Ssklower * not be sent. Local conditions make it likely that the 162157027Ssklower * information feld of receoved I PDUs will be ignored. 162257027Ssklower * Supervisory PDUs may be both sent and received. 162357027Ssklower */ 162457027Ssklower int 162557027Ssklower llc_state_AWAIT_BUSY(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 162657027Ssklower int cmdrsp, int pollfinal) 162757027Ssklower { 162857027Ssklower int action = LLC_PASSITON; 162957027Ssklower 163057027Ssklower switch(frame_kind + cmdrsp) { 163157027Ssklower case LLC_LOCAL_BUSY_CLEARED: 163257027Ssklower switch (LLC_GETFLAG(linkp, DATA)) { 163357027Ssklower case 1: 163457027Ssklower llc_send(linkp, LLCFT_REJ, LLC_CMD, 0); 163557027Ssklower LLC_START_REJ_TIMER(linkp); 163657027Ssklower LLC_NEWSTATE(linkp, AWAIT_REJECT); 163757027Ssklower action = 0; 163857027Ssklower break; 163957027Ssklower case 0: 164057027Ssklower llc_send(linkp, LLCFT_RR, LLC_CMD, 0); 164157027Ssklower LLC_NEWSTATE(linkp, AWAIT); 164257027Ssklower action = 0; 164357027Ssklower break; 164457027Ssklower case 2: 164557027Ssklower llc_send(linkp, LLCFT_RR, LLC_CMD, 0); 164657027Ssklower LLC_NEWSTATE(linkp, AWAIT_REJECT); 164757027Ssklower action = 0; 164857027Ssklower break; 164957027Ssklower } 165057027Ssklower break; 165157027Ssklower case LLC_INVALID_NS + LLC_CMD: 165257027Ssklower case LLC_INVALID_NS + LLC_RSP: { 165357027Ssklower register int p = LLC_GETFLAG(linkp, P); 165457027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 165557027Ssklower 165657027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 165757027Ssklower llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 165857027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 165957027Ssklower LLC_SETFLAG(linkp, DATA, 1); 166057027Ssklower action = 0; 166157027Ssklower } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 166257027Ssklower /* optionally */ 166357027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 166457027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 166557027Ssklower linkp->llcl_vs = nr; 166657027Ssklower LLC_STOP_P_TIMER(linkp); 166757027Ssklower LLC_SETFLAG(linkp, DATA, 1); 166857027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 166957027Ssklower llc_resend(linkp, LLC_CMD, 0); 167057027Ssklower LLC_NEWSTATE(linkp, BUSY); 167157027Ssklower } else if (pollfinal == 0) { 167257027Ssklower /* optionally */ 167357027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 167457027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 167557027Ssklower LLC_SETFLAG(linkp, DATA, 1); 167657027Ssklower action = 0; 167757027Ssklower } 167857027Ssklower } 167957027Ssklower case LLCFT_INFO + LLC_CMD: 168057027Ssklower case LLCFT_INFO + LLC_RSP: { 168157027Ssklower register int p = LLC_GETFLAG(linkp, P); 168257027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 168357027Ssklower 168457027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 168557027Ssklower llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 168657027Ssklower LLC_INC(linkp->llcl_vr); 168757027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 168857027Ssklower LLC_SETFLAG(linkp, DATA, 0); 168957027Ssklower action = LLC_DATA_INDICATION; 169057027Ssklower } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 169157027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); 169257027Ssklower LLC_INC(linkp->llcl_vr); 169357027Ssklower LLC_START_P_TIMER(linkp); 169457027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 169557027Ssklower linkp->llcl_vs = nr; 169657027Ssklower LLC_SETFLAG(linkp, DATA, 0); 169757027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 169857027Ssklower llc_resend(linkp, LLC_CMD, 0); 169957027Ssklower LLC_NEWSTATE(linkp, BUSY); 170057027Ssklower action = LLC_DATA_INDICATION; 170157027Ssklower } else if (pollfinal == 0) { 170257027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 170357027Ssklower LLC_INC(linkp->llcl_vr); 170457027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 170557027Ssklower LLC_SETFLAG(linkp, DATA, 0); 170657027Ssklower action = LLC_DATA_INDICATION; 170757027Ssklower } 170857027Ssklower break; 170957027Ssklower } 171057027Ssklower case LLCFT_RR + LLC_CMD: 171157027Ssklower case LLCFT_REJ + LLC_CMD: 171257027Ssklower case LLCFT_RR + LLC_RSP: 171357027Ssklower case LLCFT_REJ + LLC_RSP: { 171457027Ssklower register int p = LLC_GETFLAG(linkp, P); 171557027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 171657027Ssklower 171757027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 171857027Ssklower llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 171957027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 172057027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 172157027Ssklower } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 172257027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 172357027Ssklower linkp->llcl_vs = nr; 172457027Ssklower LLC_STOP_P_TIMER(linkp); 172557027Ssklower llc_resend(linkp, LLC_CMD, 0); 172657027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 172757027Ssklower LLC_NEWSTATE(linkp, BUSY); 172857027Ssklower } else if (pollfinal == 0) { 172957027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 173057027Ssklower linkp->llcl_vs = nr; 173157027Ssklower LLC_STOP_P_TIMER(linkp); 173257027Ssklower llc_resend(linkp, LLC_CMD, 0); 173357027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 173457027Ssklower } 173557027Ssklower break; 173657027Ssklower } 173757027Ssklower case LLCFT_RNR + LLC_CMD: 173857027Ssklower case LLCFT_RNR + LLC_RSP: { 173957027Ssklower register int p = LLC_GETFLAG(linkp, P); 174057027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 174157027Ssklower 174257027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 174357027Ssklower llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); 174457027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 174557027Ssklower LLC_SET_REMOTE_BUSY(linkp, action); 174657027Ssklower } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 174757027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 174857027Ssklower linkp->llcl_vs = nr; 174957027Ssklower LLC_STOP_P_TIMER(linkp); 175057027Ssklower LLC_SET_REMOTE_BUSY(linkp, action); 175157027Ssklower LLC_NEWSTATE(linkp, BUSY); 175257027Ssklower } else if (pollfinal == 0) { 175357027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 175457027Ssklower LLC_SET_REMOTE_BUSY(linkp, action); 175557027Ssklower } 175657027Ssklower break; 175757027Ssklower } 175857027Ssklower case LLC_P_TIMER_EXPIRED: 175957027Ssklower if (linkp->llcl_retry < llc_n2) { 176057027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); 176157027Ssklower LLC_START_P_TIMER(linkp); 176257027Ssklower linkp->llcl_retry++; 176357027Ssklower action = 0; 176457027Ssklower } 176557027Ssklower break; 176657027Ssklower } 176757027Ssklower if (action == LLC_PASSITON) 176857027Ssklower action = llc_state_NBRAcore(linkp, frame, frame_kind, 176957027Ssklower cmdrsp, pollfinal); 177057027Ssklower 177157027Ssklower return action; 177257027Ssklower } 177357027Ssklower 177457027Ssklower /* 177557027Ssklower * AWAIT_REJECT --- A data link connection exists between the local LLC service 177657027Ssklower * access point and the remote LLC service access point. The 177757027Ssklower * local connection component has requested that the remote 177857027Ssklower * connection component re-transmit a specific I PDU that the 177957027Ssklower * local connection component has detected as being out of 178057027Ssklower * sequence. Before the local LLC entered this state it was 178157027Ssklower * performing a timer recovery operation and had sent a 178257027Ssklower * command PDU with the P bit set to ``1'', and is still 178357027Ssklower * awaiting an acknowledgment from the remote LLC. I PDUs may 178457027Ssklower * be received but not transmitted. Supervisory PDUs may be 178557027Ssklower * both transmitted and received. 178657027Ssklower */ 178757027Ssklower int 178857027Ssklower llc_state_AWAIT_REJECT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 178957027Ssklower int cmdrsp, int pollfinal) 179057027Ssklower { 179157027Ssklower int action = LLC_PASSITON; 179257027Ssklower 179357027Ssklower switch(frame_kind + cmdrsp) { 179457027Ssklower case LLC_LOCAL_BUSY_DETECTED: 179557027Ssklower llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); 179657027Ssklower LLC_SETFLAG(linkp, DATA, 2); 179757027Ssklower LLC_NEWSTATE(linkp, AWAIT_BUSY); 179857027Ssklower action = 0; 179957027Ssklower break; 180057027Ssklower case LLC_INVALID_NS + LLC_CMD: 180157027Ssklower case LLC_INVALID_NS + LLC_RSP: { 180257027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 180357027Ssklower 180457027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 180557027Ssklower llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 180657027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 180757027Ssklower action = 0; 180857027Ssklower } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 180957027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 181057027Ssklower linkp->llcl_vs = nr; 181157027Ssklower llc_resend(linkp, LLC_CMD, 1); 181257027Ssklower LLC_START_P_TIMER(linkp); 181357027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 181457027Ssklower LLC_NEWSTATE(linkp, REJECT); 181557027Ssklower } else if (pollfinal == 0) { 181657027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 181757027Ssklower action = 0; 181857027Ssklower } 181957027Ssklower break; 182057027Ssklower } 182157027Ssklower case LLCFT_INFO + LLC_CMD: 182257027Ssklower case LLCFT_INFO + LLC_RSP: { 182357027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 182457027Ssklower 182557027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 182657027Ssklower LLC_INC(linkp->llcl_vr); 182757027Ssklower llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 182857027Ssklower LLC_STOP_REJ_TIMER(linkp); 182957027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 183057027Ssklower LLC_NEWSTATE(linkp, AWAIT); 183157027Ssklower action = LLC_DATA_INDICATION; 183257027Ssklower } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 183357027Ssklower LLC_INC(linkp->llcl_vr); 183457027Ssklower LLC_STOP_P_TIMER(linkp); 183557027Ssklower LLC_STOP_REJ_TIMER(linkp); 183657027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 183757027Ssklower linkp->llcl_vs = nr; 183857027Ssklower llc_resend(linkp, LLC_CMD, 0); 183957027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 184057027Ssklower LLC_NEWSTATE(linkp, NORMAL); 184157027Ssklower action = LLC_DATA_INDICATION; 184257027Ssklower } else if (pollfinal == 0) { 184357027Ssklower LLC_INC(linkp->llcl_vr); 184457027Ssklower llc_send(linkp, LLCFT_RR, LLC_CMD, 0); 184557027Ssklower LLC_STOP_REJ_TIMER(linkp); 184657027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 184757027Ssklower LLC_NEWSTATE(linkp, AWAIT); 184857027Ssklower action = LLC_DATA_INDICATION; 184957027Ssklower } 185057027Ssklower break; 185157027Ssklower } 185257027Ssklower case LLCFT_RR + LLC_CMD: 185357027Ssklower case LLCFT_REJ + LLC_CMD: 185457027Ssklower case LLCFT_RR + LLC_RSP: 185557027Ssklower case LLCFT_REJ + LLC_RSP: { 185657027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 185757027Ssklower 185857027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 185957027Ssklower llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 186057027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 186157027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 186257027Ssklower } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 186357027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 186457027Ssklower linkp->llcl_vs = nr; 186557027Ssklower llc_resend(linkp, LLC_CMD, 1); 186657027Ssklower LLC_START_P_TIMER(linkp); 186757027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 186857027Ssklower LLC_NEWSTATE(linkp, REJECT); 186957027Ssklower } else if (pollfinal == 0) { 187057027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 187157027Ssklower LLC_CLEAR_REMOTE_BUSY(linkp, action); 187257027Ssklower } 187357027Ssklower break; 187457027Ssklower } 187557027Ssklower case LLCFT_RNR + LLC_CMD: 187657027Ssklower case LLCFT_RNR + LLC_RSP: { 187757027Ssklower register int nr = LLCGBITS(frame->llc_control_ext, s_nr); 187857027Ssklower 187957027Ssklower if (cmdrsp == LLC_CMD && pollfinal == 1) { 188057027Ssklower llc_send(linkp, LLCFT_RR, LLC_RSP, 1); 188157027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 188257027Ssklower LLC_SET_REMOTE_BUSY(linkp, action); 188357027Ssklower } else if (cmdrsp == LLC_RSP && pollfinal == 1) { 188457027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 188557027Ssklower linkp->llcl_vs = nr; 188657027Ssklower LLC_STOP_P_TIMER(linkp); 188757027Ssklower LLC_SET_REMOTE_BUSY(linkp, action); 188857027Ssklower LLC_NEWSTATE(linkp, REJECT); 188957027Ssklower } else if (pollfinal == 0) { 189057027Ssklower LLC_UPDATE_NR_RECEIVED(linkp, nr); 189157027Ssklower LLC_SET_REMOTE_BUSY(linkp, action); 189257027Ssklower } 189357027Ssklower break; 189457027Ssklower } 189557027Ssklower case LLC_P_TIMER_EXPIRED: 189657027Ssklower if (linkp->llcl_retry < llc_n2) { 189757027Ssklower llc_send(linkp, LLCFT_REJ, LLC_CMD, 1); 189857027Ssklower LLC_START_P_TIMER(linkp); 189957027Ssklower linkp->llcl_retry++; 190057027Ssklower action = 0; 190157027Ssklower } 190257027Ssklower break; 190357027Ssklower } 190457027Ssklower if (action == LLC_PASSITON) 190557027Ssklower action = llc_state_NBRAcore(linkp, frame, frame_kind, 190657027Ssklower cmdrsp, pollfinal); 190757027Ssklower 190857027Ssklower return action; 190957027Ssklower } 191057027Ssklower 191157027Ssklower 191257027Ssklower /* 191357027Ssklower * llc_statehandler() --- Wrapper for llc_state_*() functions. 191457027Ssklower * Deals with action codes and checks for 191557027Ssklower * ``stuck'' links. 191657027Ssklower */ 191757027Ssklower 191857027Ssklower int 191957027Ssklower llc_statehandler(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, 192057027Ssklower int cmdrsp, int pollfinal) 192157027Ssklower { 192257027Ssklower register int action = 0; 192357027Ssklower 192457027Ssklower /* 192557027Ssklower * To check for ``zombie'' links each time llc_statehandler() gets called 192657027Ssklower * the AGE timer of linkp is reset. If it expires llc_timer() will 192757027Ssklower * take care of the link --- i.e. kill it 8=) 192857027Ssklower */ 192957027Ssklower LLC_STARTTIMER(linkp, AGE); 193057027Ssklower 193157027Ssklower /* 193257027Ssklower * Now call the current statehandler function. 193357027Ssklower */ 193457027Ssklower action = (*linkp->llcl_statehandler)(linkp, frame, frame_kind, 193557027Ssklower cmdrsp, pollfinal); 193657027Ssklower once_more_and_again: 193757027Ssklower switch (action) { 193857027Ssklower case LLC_CONNECT_INDICATION: { 193957027Ssklower int naction; 194057027Ssklower 194157027Ssklower LLC_TRACE(linkp, LLCTR_INTERESTING, "CONNECT INDICATION"); 194257027Ssklower linkp->llcl_nlnext = 194357027Ssklower (*linkp->llcl_sapinfo->si_ctlinput) 194457027Ssklower (PRC_CONNECT_INDICATION, 194557027Ssklower (struct sockaddr *) &linkp->llcl_addr, (caddr_t) linkp); 194657027Ssklower if (linkp->llcl_nlnext == 0) 194757027Ssklower naction = NL_DISCONNECT_REQUEST; 194857027Ssklower else naction = NL_CONNECT_RESPONSE; 194957027Ssklower action = (*linkp->llcl_statehandler)(linkp, frame, naction, 0, 0); 195057027Ssklower goto once_more_and_again; 195157027Ssklower } 195257027Ssklower case LLC_CONNECT_CONFIRM: 195357027Ssklower /* llc_resend(linkp, LLC_CMD, 0); */ 195457027Ssklower llc_start(linkp); 195557027Ssklower break; 195657027Ssklower case LLC_DISCONNECT_INDICATION: 195757027Ssklower LLC_TRACE(linkp, LLCTR_INTERESTING, "DISCONNECT INDICATION"); 195857027Ssklower (*linkp->llcl_sapinfo->si_ctlinput) 195957027Ssklower (PRC_DISCONNECT_INDICATION, 196057027Ssklower (struct sockaddr *) &linkp->llcl_addr, linkp->llcl_nlnext); 196157027Ssklower break; 196257027Ssklower /* internally visible only */ 196357027Ssklower case LLC_RESET_CONFIRM: 196457027Ssklower case LLC_RESET_INDICATION_LOCAL: 196557027Ssklower /* 196657027Ssklower * not much we can do here, the state machine either makes it or 196757027Ssklower * brakes it ... 196857027Ssklower */ 196957027Ssklower break; 197057027Ssklower case LLC_RESET_INDICATION_REMOTE: 197157027Ssklower LLC_TRACE(linkp, LLCTR_SHOULDKNOW, "RESET INDICATION (REMOTE)"); 197257027Ssklower action = (*linkp->llcl_statehandler)(linkp, frame, 197357027Ssklower NL_RESET_RESPONSE, 0, 0); 197457027Ssklower goto once_more_and_again; 197557027Ssklower case LLC_FRMR_SENT: 197657027Ssklower LLC_TRACE(linkp, LLCTR_URGENT, "FRMR SENT"); 197757027Ssklower break; 197857027Ssklower case LLC_FRMR_RECEIVED: 197957027Ssklower LLC_TRACE(linkp, LLCTR_URGEN, "FRMR RECEIVED"); 198057027Ssklower action = (*linkp->llcl_statehandler)(linkp, frame, 198157027Ssklower NL_RESET_REQUEST, 0, 0); 198257027Ssklower 198357027Ssklower goto once_more_and_again; 198457027Ssklower case LLC_REMOTE_BUSY: 198557027Ssklower LLC_TRACE(linkp, LLCTR_SHOULDKNOW, "REMOTE BUSY"); 198657027Ssklower break; 198757027Ssklower case LLC_REMOTE_NOT_BUSY: 198857027Ssklower LLC_TRACE(linkp, LLCTR_SHOULDKNOW, "REMOTE BUSY CLEARED"); 198957027Ssklower /* 199057027Ssklower * try to get queued frames out 199157027Ssklower */ 199257027Ssklower llc_start(linkp); 199357027Ssklower break; 199457027Ssklower } 199557027Ssklower 199657027Ssklower /* 199757027Ssklower * Only LLC_DATA_INDICATION is for the time being 199857027Ssklower * passed up to the network layer entity. 199957027Ssklower * The remaining action codes are for the time 200057027Ssklower * being visible internally only. 200157027Ssklower * However, this can/may be changed if necessary. 200257027Ssklower */ 200357027Ssklower 200457027Ssklower return action; 200557027Ssklower } 200657027Ssklower 200757027Ssklower 200857027Ssklower /* 200957027Ssklower * Core LLC2 routines 201057027Ssklower */ 201157027Ssklower 201257027Ssklower /* 201357027Ssklower * The INIT call. This routine is called once after the system is booted. 201457027Ssklower */ 201557027Ssklower 201657027Ssklower llc_init() 201757027Ssklower { 201857027Ssklower llcintrq.ifq_maxlen = IFQ_MAXLEN; 201957027Ssklower } 202057027Ssklower 202157027Ssklower 202257027Ssklower /* 202357027Ssklower * In case of a link reset we need to shuffle the frames queued inside the 202457027Ssklower * LLC2 window. 202557027Ssklower */ 202657027Ssklower 202757027Ssklower void 202857027Ssklower llc_resetwindow(struct llc_linkcb *linkp) 202957027Ssklower { 203057027Ssklower register struct mbuf *mptr = (struct mbuf *) 0; 203157027Ssklower register struct mbuf *anchor = (struct mbuf *)0; 203257027Ssklower register short i; 203357027Ssklower 203457027Ssklower /* Pick up all queued frames and collect them in a linked mbuf list */ 203557027Ssklower if (linkp->llcl_slotsfree != linkp->llcl_window) { 203657027Ssklower i = llc_seq2slot(linkp, linkp->llcl_nr_received); 203757027Ssklower anchor = mptr = linkp->llcl_output_buffers[i]; 203857027Ssklower for (; i != linkp->llcl_freeslot; 203957027Ssklower i = llc_seq2slot(linkp, i+1)) { 204057027Ssklower if (linkp->llcl_output_buffers[i]) { 204157027Ssklower mptr->m_nextpkt = linkp->llcl_output_buffers[i]; 204257027Ssklower mptr = mptr->m_nextpkt; 204357027Ssklower } else panic("LLC2 window broken"); 204457027Ssklower } 204557027Ssklower } 204657027Ssklower /* clean closure */ 204757027Ssklower if (mptr) 204857027Ssklower mptr->m_nextpkt = (struct mbuf *) 0; 204957027Ssklower 205057027Ssklower /* Now --- plug 'em in again */ 205157027Ssklower if (anchor != (struct mbuf *)0) { 205257027Ssklower for (i = 0, mptr = anchor; mptr != (struct mbuf *) 0; i++) { 205357027Ssklower linkp->llcl_output_buffers[i] = mptr; 205457027Ssklower mptr = mptr->m_nextpkt; 205557027Ssklower linkp->llcl_output_buffers[i]->m_nextpkt = (struct mbuf *)0; 205657027Ssklower } 205757027Ssklower linkp->llcl_freeslot = i; 205857027Ssklower } else linkp->llcl_freeslot = 0; 205957027Ssklower 206057027Ssklower /* We're resetting the link, the next frame to be acknowledged is 0 */ 206157027Ssklower linkp->llcl_nr_received = 0; 206257027Ssklower 206357027Ssklower /* set distance between LLC2 sequence number and the top of window to 0 */ 206457027Ssklower linkp->llcl_projvs = linkp->llcl_freeslot; 206557027Ssklower 206657027Ssklower return; 206757027Ssklower } 206857027Ssklower 206957027Ssklower /* 207057027Ssklower * llc_newlink() --- We allocate enough memory to contain a link control block 207157027Ssklower * and initialize it properly. We don't intiate the actual setup 207257027Ssklower * of the LLC2 link here. 207357027Ssklower */ 207457027Ssklower struct llc_linkcb * 207557027Ssklower llc_newlink(struct sockaddr_dl *dst, struct ifnet *ifp, struct rtentry *nlrt, 207657027Ssklower caddr_t nlnext, struct rtentry *llrt) 207757027Ssklower { 207857027Ssklower struct llc_linkcb *nlinkp; 207957027Ssklower u_char sap = LLSAPADDR(dst); 208057027Ssklower short llcwindow; 208157027Ssklower 208257027Ssklower 208357027Ssklower /* allocate memory for link control block */ 208457027Ssklower MALLOC(nlinkp, struct llc_linkcb *, sizeof(struct llc_linkcb), 208557027Ssklower M_PCB, M_DONTWAIT); 208657027Ssklower if (nlinkp == 0) 208757027Ssklower return (NULL); 208857027Ssklower bzero((caddr_t)nlinkp, sizeof(struct llc_linkcb)); 208957027Ssklower 209057027Ssklower /* copy link address */ 209157027Ssklower sdl_copy(dst, &nlinkp->llcl_addr); 209257027Ssklower 209357027Ssklower /* hold on to the network layer route entry */ 209457027Ssklower nlinkp->llcl_nlrt = nlrt; 209557027Ssklower 209657027Ssklower /* likewise the network layer control block */ 209757027Ssklower nlinkp->llcl_nlnext = nlnext; 209857027Ssklower 209957027Ssklower /* jot down the link layer route entry */ 210057027Ssklower nlinkp->llcl_llrt = llrt; 210157027Ssklower 210257027Ssklower /* reset writeq */ 210357027Ssklower nlinkp->llcl_writeqh = nlinkp->llcl_writeqt = NULL; 210457027Ssklower 210557027Ssklower /* setup initial state handler function */ 210657027Ssklower nlinkp->llcl_statehandler = llc_state_ADM; 210757027Ssklower 210857027Ssklower /* hold on to interface pointer */ 210957027Ssklower nlinkp->llcl_if = ifp; 211057027Ssklower 211157027Ssklower /* get service access point information */ 211257027Ssklower nlinkp->llcl_sapinfo = llc_getsapinfo(sap, ifp); 211357027Ssklower 211457027Ssklower /* get window size from SAP info block */ 211557027Ssklower if ((llcwindow = nlinkp->llcl_sapinfo->si_window) == 0) 211657027Ssklower llcwindow = LLC_MAX_WINDOW; 211757027Ssklower 211857027Ssklower /* allocate memory for window buffer */ 211957027Ssklower MALLOC(nlinkp->llcl_output_buffers, struct mbuf **, 212057027Ssklower llcwindow*sizeof(struct mbuf *), M_PCB, M_DONTWAIT); 212157027Ssklower if (nlinkp->llcl_output_buffers == 0) { 212257027Ssklower FREE(nlinkp, M_PCB); 212357027Ssklower return(NULL); 212457027Ssklower } 212557027Ssklower bzero((caddr_t)nlinkp->llcl_output_buffers, 212657027Ssklower llcwindow*sizeof(struct mbuf *)); 212757027Ssklower 212857027Ssklower /* set window size & slotsfree */ 212957027Ssklower nlinkp->llcl_slotsfree = nlinkp->llcl_window = llcwindow; 213057027Ssklower 213157027Ssklower /* enter into linked listed of link control blocks */ 213257027Ssklower insque(nlinkp, &llccb_q); 213357027Ssklower 213457027Ssklower return(nlinkp); 213557027Ssklower } 213657027Ssklower 213757027Ssklower /* 213857027Ssklower * llc_dellink() --- farewell to link control block 213957027Ssklower */ 214057027Ssklower llc_dellink(struct llc_linkcb *linkp) 214157027Ssklower { 214257027Ssklower register struct mbuf *m; 214357027Ssklower register struct mbuf *n; 214457027Ssklower register struct npaidbentry *sapinfo = linkp->llcl_sapinfo; 214557027Ssklower register i; 214657027Ssklower 214757027Ssklower /* notify upper layer of imminent death */ 214857027Ssklower if (linkp->llcl_nlnext && sapinfo->si_ctlinput) 214957027Ssklower (*sapinfo->si_ctlinput) 215057027Ssklower (PRC_DISCONNECT_INDICATION, 215157027Ssklower (struct sockaddr *)&linkp->llcl_addr, linkp->llcl_nlnext); 215257027Ssklower 215357027Ssklower /* pull the plug */ 215457027Ssklower if (linkp->llcl_llrt) 215557027Ssklower ((struct npaidbentry *)(linkp->llcl_llrt->rt_llinfo))->np_link 215657027Ssklower = (struct llc_linkcb *) 0; 215757027Ssklower 215857027Ssklower /* leave link control block queue */ 215957027Ssklower remque(linkp); 216057027Ssklower 216157027Ssklower /* drop queued packets */ 216257027Ssklower for (m = linkp->llcl_writeqh; m;) { 216357027Ssklower n = m->m_act; 216457027Ssklower m_freem(m); 216557027Ssklower m = n; 216657027Ssklower } 216757027Ssklower 216857027Ssklower /* drop packets in the window */ 216957027Ssklower for(i = 0; i < linkp->llcl_window; i++) 217057027Ssklower if (linkp->llcl_output_buffers[i]) 217157027Ssklower m_freem(linkp->llcl_output_buffers[i]); 217257027Ssklower 217357027Ssklower /* return the window space */ 217457027Ssklower FREE((caddr_t)linkp->llcl_output_buffers, M_PCB); 217557027Ssklower 217657027Ssklower /* return the control block space --- now it's gone ... */ 217757027Ssklower FREE((caddr_t)linkp, M_PCB); 217857027Ssklower } 217957027Ssklower 218057027Ssklower llc_decode(struct llc* frame, struct llc_linkcb * linkp) 218157027Ssklower { 218257027Ssklower register int ft = LLC_BAD_PDU; 218357027Ssklower 218457027Ssklower if ((frame->llc_control & 01) == 0) { 218557027Ssklower ft = LLCFT_INFO; 218657027Ssklower /* S or U frame ? */ 218757027Ssklower } else switch (frame->llc_control) { 218857027Ssklower 218957027Ssklower /* U frames */ 219057027Ssklower case LLC_UI: 219157027Ssklower case LLC_UI_P: ft = LLC_UI; break; 219257027Ssklower case LLC_DM: 219357027Ssklower case LLC_DM_P: ft =LLCFT_DM; break; 219457027Ssklower case LLC_DISC: 219557027Ssklower case LLC_DISC_P: ft = LLCFT_DISC; break; 219657027Ssklower case LLC_UA: 219757027Ssklower case LLC_UA_P: ft = LLCFT_UA; break; 219857027Ssklower case LLC_SABME: 219957027Ssklower case LLC_SABME_P: ft = LLCFT_SABME; break; 220057027Ssklower case LLC_FRMR: 220157027Ssklower case LLC_FRMR_P: ft = LLCFT_FRMR; break; 220257027Ssklower case LLC_XID: 220357027Ssklower case LLC_XID_P: ft = LLCFT_XID; break; 220457027Ssklower case LLC_TEST: 220557027Ssklower case LLC_TEST_P: ft = LLCFT_TEST; break; 220657027Ssklower 220757027Ssklower /* S frames */ 220857027Ssklower case LLC_RR: ft = LLCFT_RR; break; 220957027Ssklower case LLC_RNR: ft = LLCFT_RNR; break; 221057027Ssklower case LLC_REJ: ft = LLCFT_REJ; break; 221157027Ssklower } /* switch */ 221257027Ssklower 221357027Ssklower if (linkp) { 221457027Ssklower switch (ft) { 221557027Ssklower case LLCFT_INFO: 221657027Ssklower if (LLCGBITS(frame->llc_control, i_ns) != linkp->llcl_vr) { 221757027Ssklower ft = LLC_INVALID_NS; 221857027Ssklower break; 221957027Ssklower } 222057027Ssklower /* fall thru --- yeeeeeee */ 222157027Ssklower case LLCFT_RR: 222257027Ssklower case LLCFT_RNR: 222357027Ssklower case LLCFT_REJ: 222457027Ssklower /* splash! */ 222557027Ssklower if (LLC_NR_VALID(linkp, LLCGBITS(frame->llc_control_ext, 222657027Ssklower s_nr)) == 0) 222757027Ssklower ft = LLC_INVALID_NR; 222857027Ssklower break; 222957027Ssklower } 223057027Ssklower } 223157027Ssklower 223257027Ssklower return ft; 223357027Ssklower } 223457027Ssklower 223557027Ssklower /* 223657027Ssklower * llc_anytimersup() --- Checks if at least one timer is still up and running. 223757027Ssklower */ 223857027Ssklower int 223957027Ssklower llc_anytimersup(struct llc_linkcb * linkp) 224057027Ssklower { 224157027Ssklower register int i; 224257027Ssklower 224357027Ssklower FOR_ALL_LLC_TIMERS(i) 224457027Ssklower if (linkp->llcl_timers[i] > 0) 224557027Ssklower break; 224657027Ssklower if (i == LLC_AGE_SHIFT) 224757027Ssklower return 0; 224857027Ssklower else return 1; 224957027Ssklower } 225057027Ssklower 225157027Ssklower /* 225257027Ssklower * llc_link_dump() - dump link info 225357027Ssklower */ 225457027Ssklower 225557027Ssklower #define SAL(s) ((struct sockaddr_dl *)&(s)->llcl_addr) 225657027Ssklower #define CHECK(l, s) if (LLC_STATEEQ(l, s)) return #s 225757027Ssklower 225857027Ssklower char *timer_names[] = {"ACK", "P", "BUSY", "REJ", "AGE"}; 225957027Ssklower 226057027Ssklower char * 226157027Ssklower llc_getstatename(struct llc_linkcb *linkp) 226257027Ssklower { 226357027Ssklower CHECK(linkp, ADM); 226457027Ssklower CHECK(linkp, CONN); 226557027Ssklower CHECK(linkp, RESET_WAIT); 226657027Ssklower CHECK(linkp, RESET_CHECK); 226757027Ssklower CHECK(linkp, SETUP); 226857027Ssklower CHECK(linkp, RESET); 226957027Ssklower CHECK(linkp, D_CONN); 227057027Ssklower CHECK(linkp, ERROR); 227157027Ssklower CHECK(linkp, NORMAL); 227257027Ssklower CHECK(linkp, BUSY); 227357027Ssklower CHECK(linkp, REJECT); 227457027Ssklower CHECK(linkp, AWAIT); 227557027Ssklower CHECK(linkp, AWAIT_BUSY); 227657027Ssklower CHECK(linkp, AWAIT_REJECT); 227757027Ssklower 227857027Ssklower return "UNKNOWN - eh?"; 227957027Ssklower } 228057027Ssklower 228157027Ssklower void 228257027Ssklower llc_link_dump(struct llc_linkcb* linkp, const char *message) 228357027Ssklower { 228457027Ssklower register int i; 228557027Ssklower register char *state; 228657027Ssklower 228757027Ssklower /* print interface */ 228857027Ssklower printf("if %s%d\n", linkp->llcl_if->if_name, linkp->llcl_if->if_unit); 228957027Ssklower 229057027Ssklower /* print message */ 229157027Ssklower printf(">> %s <<\n", message); 229257027Ssklower 229357027Ssklower /* print MAC and LSAP */ 229457027Ssklower printf("llc addr "); 229557027Ssklower for (i = 0; i < (SAL(linkp)->sdl_alen)-2; i++) 229657027Ssklower printf("%x:", (char)*(LLADDR(SAL(linkp))+i) & 0xff); 229757027Ssklower printf("%x,", (char)*(LLADDR(SAL(linkp))+i) & 0xff); 229857027Ssklower printf("%x\n", (char)*(LLADDR(SAL(linkp))+i+1) & 0xff); 229957027Ssklower 230057027Ssklower /* print state we're in and timers */ 230157027Ssklower printf("state %s, ", llc_getstatename(linkp)); 230257027Ssklower for (i = LLC_ACK_SHIFT; i < LLC_AGE_SHIFT; i++) 230357027Ssklower printf("%s-%c %d/", timer_names[i], 230457027Ssklower (linkp->llcl_timerflags & (1<<i) ? 'R' : 'S'), 230557027Ssklower linkp->llcl_timers[i]); 230657027Ssklower printf("%s-%c %d\n", timer_names[i], (linkp->llcl_timerflags & (1<<i) ? 230757027Ssklower 'R' : 'S'), linkp->llcl_timers[i]); 230857027Ssklower 230957027Ssklower /* print flag values */ 231057027Ssklower printf("flags P %d/F %d/S %d/DATA %d/REMOTE_BUSY %d\n", 231157027Ssklower LLC_GETFLAG(linkp, P), LLC_GETFLAG(linkp, S), 231257027Ssklower LLC_GETFLAG(linkp, DATA), LLC_GETFLAG(linkp, REMOTE_BUSY)); 231357027Ssklower 231457027Ssklower /* print send and receive state variables, ack, and window */ 231557027Ssklower printf("V(R) %d/V(S) %d/N(R) received %d/window %d/freeslot %d\n", 231657027Ssklower linkp->llcl_vs, linkp->llcl_vr, linkp->llcl_nr_received, 231757027Ssklower linkp->llcl_window, linkp->llcl_freeslot); 231857027Ssklower 231957027Ssklower /* further expansions can follow here */ 232057027Ssklower 232157027Ssklower } 232257027Ssklower 232357027Ssklower void 232457027Ssklower llc_trace(struct llc_linkcb *linkp, int level, const char *message) 232557027Ssklower { 232657027Ssklower if (linkp->llcl_sapinfo->si_trace && level > llc_tracelevel) 232757027Ssklower llc_link_dump(linkp, message); 232857027Ssklower 232957027Ssklower return; 233057027Ssklower } 2331