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