157027Ssklower /*
257027Ssklower * Copyright (C) Dirk Husemann, Computer Science Department IV,
357027Ssklower * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992
4*63216Sbostic * Copyright (c) 1992, 1993
5*63216Sbostic * The Regents of the University of California. 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*63216Sbostic * @(#)llc_subr.c 8.1 (Berkeley) 06/10/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
sdl_cmp(struct sockaddr_dl * sdl_a,struct sockaddr_dl * sdl_b)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
sdl_copy(struct sockaddr_dl * sdl_f,struct sockaddr_dl * sdl_t)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
sdl_swapaddr(struct sockaddr_dl * sdl_a,struct sockaddr_dl * sdl_b)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 *
sdl_getaddrif(struct ifnet * ifp)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
sdl_checkaddrif(struct ifnet * ifp,struct sockaddr_dl * sdl_c)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
sdl_setaddrif(struct ifnet * ifp,u_char * mac_addr,u_char dlsap_addr,u_char mac_len,struct sockaddr_dl * sdl_to)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
sdl_sethdrif(struct ifnet * ifp,u_char * mac_src,u_char dlsap_src,u_char * mac_dst,u_char dlsap_dst,u_char mac_len,struct sdl_hdr * sdlhdr_to)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 *
llc_setsapinfo(struct ifnet * ifp,u_char af,u_char sap,struct dllconfig * llconf)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 */
20961656Ssklower rtrequest(RTM_ADD, (struct sockaddr *)&sap_saddr,
21061656Ssklower (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 *
llc_getsapinfo(u_char sap,struct ifnet * ifp)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
25861656Ssklower 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
llc_seq2slot(struct llc_linkcb * linkp,short seqn)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
llc_state_ADM(struct llc_linkcb * linkp,struct llc * frame,int frame_kind,int cmdrsp,int pollfinal)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
llc_state_CONN(struct llc_linkcb * linkp,struct llc * frame,int frame_kind,int cmdrsp,int pollfinal)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
llc_state_RESET_WAIT(struct llc_linkcb * linkp,struct llc * frame,int frame_kind,int cmdrsp,int pollfinal)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
llc_state_RESET_CHECK(struct llc_linkcb * linkp,struct llc * frame,int frame_kind,int cmdrsp,int pollfinal)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
llc_state_SETUP(struct llc_linkcb * linkp,struct llc * frame,int frame_kind,int cmdrsp,int pollfinal)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
llc_state_RESET(struct llc_linkcb * linkp,struct llc * frame,int frame_kind,int cmdrsp,int pollfinal)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
llc_state_D_CONN(struct llc_linkcb * linkp,struct llc * frame,int frame_kind,int cmdrsp,int pollfinal)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
llc_state_ERROR(struct llc_linkcb * linkp,struct llc * frame,int frame_kind,int cmdrsp,int pollfinal)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
llc_state_NBRAcore(struct llc_linkcb * linkp,struct llc * frame,int frame_kind,int cmdrsp,int pollfinal)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
llc_state_NORMAL(struct llc_linkcb * linkp,struct llc * frame,int frame_kind,int cmdrsp,int pollfinal)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
llc_state_BUSY(struct llc_linkcb * linkp,struct llc * frame,int frame_kind,int cmdrsp,int pollfinal)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
llc_state_REJECT(struct llc_linkcb * linkp,struct llc * frame,int frame_kind,int cmdrsp,int pollfinal)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
llc_state_AWAIT(struct llc_linkcb * linkp,struct llc * frame,int frame_kind,int cmdrsp,int pollfinal)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
llc_state_AWAIT_BUSY(struct llc_linkcb * linkp,struct llc * frame,int frame_kind,int cmdrsp,int pollfinal)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
llc_state_AWAIT_REJECT(struct llc_linkcb * linkp,struct llc * frame,int frame_kind,int cmdrsp,int pollfinal)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
llc_statehandler(struct llc_linkcb * linkp,struct llc * frame,int frame_kind,int cmdrsp,int pollfinal)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
llc_init()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
llc_resetwindow(struct llc_linkcb * linkp)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 *
llc_newlink(struct sockaddr_dl * dst,struct ifnet * ifp,struct rtentry * nlrt,caddr_t nlnext,struct rtentry * llrt)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 */
llc_dellink(struct llc_linkcb * linkp)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
llc_decode(struct llc * frame,struct llc_linkcb * linkp)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
llc_anytimersup(struct llc_linkcb * linkp)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 *
llc_getstatename(struct llc_linkcb * linkp)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
llc_link_dump(struct llc_linkcb * linkp,const char * message)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
llc_trace(struct llc_linkcb * linkp,int level,const char * message)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