xref: /csrg-svn/sys/netccitt/llc_subr.c (revision 63216)
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