2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (C) Dirk Husemann, Computer Science Department IV,
24 * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992
25 * Copyright (c) 1992, 1993
26 * The Regents of the University of California. All rights reserved.
28 * This code is derived from software contributed to Berkeley by
29 * Dirk Husemann and the Computer Science Department (IV) of
30 * the University of Erlangen-Nuremberg, Germany.
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * @(#)llc_subr.c 8.1 (Berkeley) 6/10/93
63 #include <sys/param.h>
64 #include <sys/systm.h>
66 #include <sys/domain.h>
67 #include <sys/socket.h>
68 #include <sys/protosw.h>
69 #include <sys/socketvar.h>
70 #include <sys/errno.h>
72 #include <sys/kernel.h>
73 #include <sys/malloc.h>
76 #include <net/if_dl.h>
77 #include <net/if_llc.h>
78 #include <net/route.h>
80 #include <netccitt/dll.h>
81 #include <netccitt/llc_var.h>
84 * Frame names for diagnostic messages
86 char *frame_names
[] = { "INFO", "RR", "RNR", "REJ", "DM", "SABME", "DISC",
87 "UA", "FRMR", "UI", "XID", "TEST", "ILLEGAL", "TIMER", "N2xT1"};
93 int llc_tracelevel
= LLCTR_URGENT
;
96 * Values for accessing various bitfields
98 struct bitslice llc_bitslice
[] = {
99 /* mask, shift value */
110 * We keep the link control blocks on a doubly linked list -
111 * primarily for checking in llc_time()
114 struct llccb_q llccb_q
= { &llccb_q
, &llccb_q
};
117 * Flag for signalling wether route tree for AF_LINK has been
121 int af_link_rts_init_done
= 0;
125 * Functions dealing with struct sockaddr_dl */
127 /* Compare sdl_a w/ sdl_b */
129 sdl_cmp(struct sockaddr_dl
*sdl_a
, struct sockaddr_dl
*sdl_b
)
131 if (LLADDRLEN(sdl_a
) != LLADDRLEN(sdl_b
))
133 return(bcmp((caddr_t
) sdl_a
->sdl_data
, (caddr_t
) sdl_b
->sdl_data
,
137 /* Copy sdl_f to sdl_t */
139 sdl_copy(struct sockaddr_dl
*sdl_f
, struct sockaddr_dl
*sdl_t
)
141 bcopy((caddr_t
) sdl_f
, (caddr_t
) sdl_t
, sdl_f
->sdl_len
);
144 /* Swap sdl_a w/ sdl_b */
146 sdl_swapaddr(struct sockaddr_dl
*sdl_a
, struct sockaddr_dl
*sdl_b
)
148 struct sockaddr_dl sdl_tmp
;
150 sdl_copy(sdl_a
, &sdl_tmp
);
151 sdl_copy(sdl_b
, sdl_a
);
152 sdl_copy(&sdl_tmp
, sdl_b
);
155 /* Fetch the sdl of the associated if */
158 sdl_getaddrif(struct ifnet
*ifp
)
160 register struct ifaddr
*ifa
;
162 for(ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
163 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
164 return((struct sockaddr_dl
*)(ifa
->ifa_addr
));
166 return((struct sockaddr_dl
*)0);
169 /* Check addr of interface with the one given */
171 sdl_checkaddrif(struct ifnet
*ifp
, struct sockaddr_dl
*sdl_c
)
173 register struct ifaddr
*ifa
;
175 for(ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
176 if ((ifa
->ifa_addr
->sa_family
== AF_LINK
) &&
177 !sdl_cmp((struct sockaddr_dl
*)(ifa
->ifa_addr
), sdl_c
))
183 /* Build an sdl from MAC addr, DLSAP addr, and interface */
185 sdl_setaddrif(struct ifnet
*ifp
, u_char
*mac_addr
, u_char dlsap_addr
,
186 u_char mac_len
, struct sockaddr_dl
*sdl_to
)
188 register struct sockaddr_dl
*sdl_tmp
;
190 if ((sdl_tmp
= sdl_getaddrif(ifp
)) ) {
191 sdl_copy(sdl_tmp
, sdl_to
);
192 bcopy((caddr_t
) mac_addr
, (caddr_t
) LLADDR(sdl_to
), mac_len
);
193 *(LLADDR(sdl_to
)+mac_len
) = dlsap_addr
;
194 sdl_to
->sdl_alen
= mac_len
+1;
199 /* Fill out the sdl header aggregate */
201 sdl_sethdrif(struct ifnet
*ifp
, u_char
*mac_src
, u_char dlsap_src
, u_char
*mac_dst
,
202 u_char dlsap_dst
, u_char mac_len
, struct sdl_hdr
*sdlhdr_to
)
204 if ( !sdl_setaddrif(ifp
, mac_src
, dlsap_src
, mac_len
,
205 &sdlhdr_to
->sdlhdr_src
) ||
206 !sdl_setaddrif(ifp
, mac_dst
, dlsap_dst
, mac_len
,
207 &sdlhdr_to
->sdlhdr_dst
) )
212 static struct sockaddr_dl sap_saddr
;
213 static struct sockaddr_dl sap_sgate
= {
214 sizeof(struct sockaddr_dl
), /* _len */
219 * Set sapinfo for SAP address, llcconfig, af, and interface
222 llc_setsapinfo(struct ifnet
*ifp
, u_char af
, u_char sap
, struct dllconfig
*llconf
)
225 struct sockaddr_dl
*ifdl_addr
;
226 struct rtentry
*sirt
= (struct rtentry
*)0;
227 struct npaidbentry
*sapinfo
;
229 int size
= sizeof(struct npaidbentry
);
234 * We rely/assume that only STREAM protocols will make use of
235 * connection oriented LLC2. If this will one day not be the
236 * case this will obviously fail.
238 pp
= pffindtype (af
, SOCK_STREAM
);
239 if (pp
== 0 || pp
->pr_input
== 0 || pp
->pr_ctlinput
== 0) {
240 printf("network level protosw error");
245 * We need a way to jot down the LLC2 configuration for
246 * a certain LSAP address. To do this we enter
247 * a "route" for the SAP.
249 ifdl_addr
= sdl_getaddrif(ifp
);
250 sdl_copy(ifdl_addr
, &sap_saddr
);
251 sdl_copy(ifdl_addr
, &sap_sgate
);
252 saploc
= LLSAPLOC(&sap_saddr
, ifp
);
253 sap_saddr
.sdl_data
[saploc
] = sap
;
254 sap_saddr
.sdl_alen
++;
257 rtrequest(RTM_ADD
, (struct sockaddr
*)&sap_saddr
,
258 (struct sockaddr
*)&sap_sgate
, 0, 0, &sirt
);
262 /* Plug in config information in rt->rt_llinfo */
264 // sirt->rt_llinfo = malloc(size , M_PCB, M_WAITOK);
265 MALLOC(sirt
->rt_llinfo
, caddr_t
, size
, M_PCB
, M_WAITOK
);
266 sapinfo
= (struct npaidbentry
*) sirt
->rt_llinfo
;
268 bzero ((caddr_t
)sapinfo
, size
);
270 * For the time being we support LLC CLASS II here
273 sapinfo
->si_class
= LLC_CLASS_II
;
274 sapinfo
->si_window
= llconf
->dllcfg_window
;
275 sapinfo
->si_trace
= llconf
->dllcfg_trace
;
276 if (sapinfo
->si_trace
)
278 else llc_tracelevel
++;
279 sapinfo
->si_input
= pp
->pr_input
;
280 sapinfo
->si_ctlinput
= (caddr_t (*)())pp
->pr_ctlinput
;
289 * Get sapinfo for SAP address and interface
292 llc_getsapinfo(u_char sap
, struct ifnet
*ifp
)
294 struct sockaddr_dl
*ifdl_addr
;
295 struct sockaddr_dl si_addr
;
296 struct rtentry
*sirt
;
301 ifdl_addr
= sdl_getaddrif(ifp
);
302 sdl_copy(ifdl_addr
, &si_addr
);
303 saploc
= LLSAPLOC(&si_addr
, ifp
);
304 si_addr
.sdl_data
[saploc
] = sap
;
307 if ((sirt
= rtalloc1((struct sockaddr
*)&si_addr
, 0)))
311 return((struct npaidbentry
*)sirt
->rt_llinfo
);
315 * llc_seq2slot() --- We only allocate enough memory to hold the window. This
316 * introduces the necessity to keep track of two ``pointers''
318 * o llcl_freeslot the next free slot to be used
319 * this one advances modulo llcl_window
320 * o llcl_projvs the V(S) associated with the next frame
321 * to be set via llcl_freeslot
322 * this one advances modulo LLC_MAX_SEQUENCE
324 * A new frame is inserted at llcl_output_buffers[llcl_freeslot], after
325 * which both llcl_freeslot and llcl_projvs are incremented.
327 * The slot sl(sn) for any given sequence number sn is given by
329 * sl(sn) = (llcl_freeslot + llcl_window - 1 - (llcl_projvs +
330 * LLC_MAX_SEQUENCE- sn) % LLC_MAX_SEQUENCE) %
333 * i.e. we first calculate the number of frames we need to ``go back''
334 * from the current one (really the next one, but that doesn't matter as
335 * llcl_projvs is likewise of by plus one) and subtract that from the
336 * pointer to the most recently taken frame (llcl_freeslot - 1).
340 llc_seq2slot(struct llc_linkcb
*linkp
, short seqn
)
344 sn
= (linkp
->llcl_freeslot
+ linkp
->llcl_window
-
345 (linkp
->llcl_projvs
+ LLC_MAX_SEQUENCE
- seqn
) %
346 LLC_MAX_SEQUENCE
) % linkp
->llcl_window
;
352 * LLC2 link state handler
354 * There is in most cases one function per LLC2 state. The LLC2 standard
355 * ISO 8802-2 allows in some cases for ambiguities, i.e. we have the choice
356 * to do one thing or the other. Right now I have just chosen one but have also
357 * indicated the spot by "multiple possibilities". One could make the behavior
358 * in those cases configurable, allowing the superuser to enter a profile word
359 * (32/64 bits, whatever is needed) that would suit her needs [I quite like
360 * that idea, perhaps I'll get around to it].
362 * [Preceeding each state handler function is the description as taken from
363 * ISO 8802-2, section 7.9.2.1]
367 * ADM --- The connection component is in the asynchronous disconnected mode.
368 * It can accept an SABME PDU from a remote LLC SSAP or, at the request
369 * of the service access point user, can initiate an SABME PDU
370 * transmission to a remote LLC DSAP, to establish a data link
371 * connection. It also responds to a DISC command PDU and to any
372 * command PDU with the P bit set to ``1''.
375 llc_state_ADM(struct llc_linkcb
*linkp
, struct llc
*frame
, int frame_kind
,
376 int cmdrsp
, int pollfinal
)
380 switch(frame_kind
+ cmdrsp
) {
381 case NL_CONNECT_REQUEST
:
382 llc_send(linkp
, LLCFT_SABME
, LLC_CMD
, pollfinal
);
383 LLC_SETFLAG(linkp
, P
, pollfinal
);
384 LLC_SETFLAG(linkp
, S
, 0);
385 linkp
->llcl_retry
= 0;
386 LLC_NEWSTATE(linkp
, SETUP
);
388 case LLCFT_SABME
+ LLC_CMD
:
390 * ISO 8802-2, table 7-1, ADM state says to set
391 * the P flag, yet this will cause an SABME [P] to be
392 * answered with an UA only, not an UA [F], all
393 * other `disconnected' states set the F flag, so ...
395 LLC_SETFLAG(linkp
, F
, pollfinal
);
396 LLC_NEWSTATE(linkp
, CONN
);
397 action
= LLC_CONNECT_INDICATION
;
399 case LLCFT_DISC
+ LLC_CMD
:
400 llc_send(linkp
, LLCFT_DM
, LLC_RSP
, pollfinal
);
403 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1)
404 llc_send(linkp
, LLCFT_DM
, LLC_RSP
, 1);
405 /* remain in ADM state */
412 * CONN --- The local connection component has received an SABME PDU from a
413 * remote LLC SSAP, and it is waiting for the local user to accept or
414 * refuse the connection.
417 llc_state_CONN(struct llc_linkcb
*linkp
, struct llc
*frame
, int frame_kind
,
418 int cmdrsp
, int pollfinal
)
422 switch(frame_kind
+ cmdrsp
) {
423 case NL_CONNECT_RESPONSE
:
424 llc_send(linkp
, LLCFT_UA
, LLC_RSP
, LLC_GETFLAG(linkp
, F
));
425 LLC_RESETCOUNTER(linkp
);
426 LLC_SETFLAG(linkp
, P
, 0);
427 LLC_SETFLAG(linkp
, REMOTE_BUSY
, 0);
428 LLC_NEWSTATE(linkp
, NORMAL
);
430 case NL_DISCONNECT_REQUEST
:
431 llc_send(linkp
, LLCFT_DM
, LLC_RSP
, LLC_GETFLAG(linkp
, F
));
432 LLC_NEWSTATE(linkp
, ADM
);
434 case LLCFT_SABME
+ LLC_CMD
:
435 LLC_SETFLAG(linkp
, F
, pollfinal
);
437 case LLCFT_DM
+ LLC_RSP
:
438 LLC_NEWSTATE(linkp
, ADM
);
439 action
= LLC_DISCONNECT_INDICATION
;
441 /* all other frames effect nothing here */
448 * RESET_WAIT --- The local connection component is waiting for the local user
449 * to indicate a RESET_REQUEST or a DISCONNECT_REQUEST.
452 llc_state_RESET_WAIT(struct llc_linkcb
*linkp
, struct llc
*frame
, int frame_kind
,
453 int cmdrsp
, int pollfinal
)
457 switch(frame_kind
+ cmdrsp
) {
458 case NL_RESET_REQUEST
:
459 if (LLC_GETFLAG(linkp
, S
) == 0) {
460 llc_send(linkp
, LLCFT_SABME
, LLC_CMD
, pollfinal
);
461 LLC_SETFLAG(linkp
, P
, pollfinal
);
462 LLC_START_ACK_TIMER(linkp
);
463 linkp
->llcl_retry
= 0;
464 LLC_NEWSTATE(linkp
, RESET
);
466 llc_send(linkp
, LLCFT_UA
, LLC_RSP
,
467 LLC_GETFLAG(linkp
, F
));
468 LLC_RESETCOUNTER(linkp
);
469 LLC_SETFLAG(linkp
, P
, 0);
470 LLC_SETFLAG(linkp
, REMOTE_BUSY
, 0);
471 LLC_NEWSTATE(linkp
, NORMAL
);
472 action
= LLC_RESET_CONFIRM
;
475 case NL_DISCONNECT_REQUEST
:
476 if (LLC_GETFLAG(linkp
, S
) == 0) {
477 llc_send(linkp
, LLCFT_DISC
, LLC_CMD
, pollfinal
);
478 LLC_SETFLAG(linkp
, P
, pollfinal
);
479 LLC_START_ACK_TIMER(linkp
);
480 linkp
->llcl_retry
= 0;
481 LLC_NEWSTATE(linkp
, D_CONN
);
483 llc_send(linkp
, LLCFT_DM
, LLC_RSP
,
484 LLC_GETFLAG(linkp
, F
));
485 LLC_NEWSTATE(linkp
, ADM
);
488 case LLCFT_DM
+ LLC_RSP
:
489 LLC_NEWSTATE(linkp
, ADM
);
490 action
= LLC_DISCONNECT_INDICATION
;
492 case LLCFT_SABME
+ LLC_CMD
:
493 LLC_SETFLAG(linkp
, S
, 1);
494 LLC_SETFLAG(linkp
, F
, pollfinal
);
496 case LLCFT_DISC
+ LLC_CMD
:
497 llc_send(linkp
, LLCFT_DM
, LLC_RSP
, pollfinal
);
498 LLC_NEWSTATE(linkp
, ADM
);
499 action
= LLC_DISCONNECT_INDICATION
;
507 * RESET_CHECK --- The local connection component is waiting for the local user
508 * to accept or refuse a remote reset request.
511 llc_state_RESET_CHECK(struct llc_linkcb
*linkp
, struct llc
*frame
, int frame_kind
,
512 int cmdrsp
, int pollfinal
)
516 switch(frame_kind
+ cmdrsp
) {
517 case NL_RESET_RESPONSE
:
518 llc_send(linkp
, LLCFT_UA
, LLC_RSP
, LLC_GETFLAG(linkp
, F
));
519 LLC_RESETCOUNTER(linkp
);
520 LLC_SETFLAG(linkp
, P
, 0);
521 LLC_SETFLAG(linkp
, REMOTE_BUSY
, 0);
522 LLC_NEWSTATE(linkp
, NORMAL
);
524 case NL_DISCONNECT_REQUEST
:
525 llc_send(linkp
, LLCFT_DM
, LLC_RSP
, LLC_GETFLAG(linkp
, F
));
526 LLC_NEWSTATE(linkp
, ADM
);
528 case LLCFT_DM
+ LLC_RSP
:
529 action
= LLC_DISCONNECT_INDICATION
;
531 case LLCFT_SABME
+ LLC_CMD
:
532 LLC_SETFLAG(linkp
, F
, pollfinal
);
534 case LLCFT_DISC
+ LLC_CMD
:
535 llc_send(linkp
, LLCFT_DM
, LLC_RSP
, pollfinal
);
536 LLC_NEWSTATE(linkp
, ADM
);
537 action
= LLC_DISCONNECT_INDICATION
;
545 * SETUP --- The connection component has transmitted an SABME command PDU to a
546 * remote LLC DSAP and is waiting for a reply.
549 llc_state_SETUP(struct llc_linkcb
*linkp
, struct llc
*frame
, int frame_kind
,
550 int cmdrsp
, int pollfinal
)
554 switch(frame_kind
+ cmdrsp
) {
555 case LLCFT_SABME
+ LLC_CMD
:
556 LLC_RESETCOUNTER(linkp
);
557 llc_send(linkp
, LLCFT_UA
, LLC_RSP
, pollfinal
);
558 LLC_SETFLAG(linkp
, S
, 1);
560 case LLCFT_UA
+ LLC_RSP
:
561 if (LLC_GETFLAG(linkp
, P
) == pollfinal
) {
562 LLC_STOP_ACK_TIMER(linkp
);
563 LLC_RESETCOUNTER(linkp
);
564 LLC_UPDATE_P_FLAG(linkp
, cmdrsp
, pollfinal
);
565 LLC_SETFLAG(linkp
, REMOTE_BUSY
, 0);
566 LLC_NEWSTATE(linkp
, NORMAL
);
567 action
= LLC_CONNECT_CONFIRM
;
570 case LLC_ACK_TIMER_EXPIRED
:
571 if (LLC_GETFLAG(linkp
, S
) == 1) {
572 LLC_SETFLAG(linkp
, P
, 0);
573 LLC_SETFLAG(linkp
, REMOTE_BUSY
, 0),
574 LLC_NEWSTATE(linkp
, NORMAL
);
575 action
= LLC_CONNECT_CONFIRM
;
576 } else if (linkp
->llcl_retry
< llc_n2
) {
577 llc_send(linkp
, LLCFT_SABME
, LLC_CMD
, pollfinal
);
578 LLC_SETFLAG(linkp
, P
, pollfinal
);
579 LLC_START_ACK_TIMER(linkp
);
582 LLC_NEWSTATE(linkp
, ADM
);
583 action
= LLC_DISCONNECT_INDICATION
;
586 case LLCFT_DISC
+ LLC_CMD
:
587 llc_send(linkp
, LLCFT_DM
, LLC_RSP
, pollfinal
);
588 LLC_STOP_ACK_TIMER(linkp
);
589 LLC_NEWSTATE(linkp
, ADM
);
590 action
= LLC_DISCONNECT_INDICATION
;
592 case LLCFT_DM
+ LLC_RSP
:
593 LLC_STOP_ACK_TIMER(linkp
);
594 LLC_NEWSTATE(linkp
, ADM
);
595 action
= LLC_DISCONNECT_INDICATION
;
603 * RESET --- As a result of a service access point user request or the receipt
604 * of a FRMR response PDU, the local connection component has sent an
605 * SABME command PDU to the remote LLC DSAP to reset the data link
606 * connection and is waiting for a reply.
609 llc_state_RESET(struct llc_linkcb
*linkp
, struct llc
*frame
, int frame_kind
,
610 int cmdrsp
, int pollfinal
)
614 switch(frame_kind
+ cmdrsp
) {
615 case LLCFT_SABME
+ LLC_CMD
:
616 LLC_RESETCOUNTER(linkp
);
617 LLC_SETFLAG(linkp
, S
, 1);
618 llc_send(linkp
, LLCFT_UA
, LLC_RSP
, pollfinal
);
620 case LLCFT_UA
+ LLC_RSP
:
621 if (LLC_GETFLAG(linkp
, P
) == pollfinal
) {
622 LLC_STOP_ACK_TIMER(linkp
);
623 LLC_RESETCOUNTER(linkp
);
624 LLC_UPDATE_P_FLAG(linkp
, cmdrsp
, pollfinal
);
625 LLC_SETFLAG(linkp
, REMOTE_BUSY
, 0);
626 LLC_NEWSTATE(linkp
, NORMAL
);
627 action
= LLC_RESET_CONFIRM
;
630 case LLC_ACK_TIMER_EXPIRED
:
631 if (LLC_GETFLAG(linkp
, S
) == 1) {
632 LLC_SETFLAG(linkp
, P
, 0);
633 LLC_SETFLAG(linkp
, REMOTE_BUSY
, 0);
634 LLC_NEWSTATE(linkp
, NORMAL
);
635 action
= LLC_RESET_CONFIRM
;
636 } else if (linkp
->llcl_retry
< llc_n2
) {
637 llc_send(linkp
, LLCFT_SABME
, LLC_CMD
, pollfinal
);
638 LLC_SETFLAG(linkp
, P
, pollfinal
);
639 LLC_START_ACK_TIMER(linkp
);
642 LLC_NEWSTATE(linkp
, ADM
);
643 action
= LLC_DISCONNECT_INDICATION
;
646 case LLCFT_DISC
+ LLC_CMD
:
647 llc_send(linkp
, LLCFT_DM
, LLC_RSP
, pollfinal
);
648 LLC_STOP_ACK_TIMER(linkp
);
649 LLC_NEWSTATE(linkp
, ADM
);
650 action
= LLC_DISCONNECT_INDICATION
;
652 case LLCFT_DM
+ LLC_RSP
:
653 LLC_STOP_ACK_TIMER(linkp
);
654 LLC_NEWSTATE(linkp
, ADM
);
655 action
= LLC_DISCONNECT_INDICATION
;
663 * D_CONN --- At the request of the service access point user, the local LLC
664 * has sent a DISC command PDU to the remote LLC DSAP and is waiting
668 llc_state_D_CONN(struct llc_linkcb
*linkp
, struct llc
*frame
, int frame_kind
,
669 int cmdrsp
, int pollfinal
)
673 switch(frame_kind
+ cmdrsp
) {
674 case LLCFT_SABME
+ LLC_CMD
:
675 llc_send(linkp
, LLCFT_DM
, LLC_RSP
, pollfinal
);
676 LLC_STOP_ACK_TIMER(linkp
);
677 LLC_NEWSTATE(linkp
, ADM
);
679 case LLCFT_UA
+ LLC_RSP
:
680 if (LLC_GETFLAG(linkp
, P
) == pollfinal
) {
681 LLC_STOP_ACK_TIMER(linkp
);
682 LLC_NEWSTATE(linkp
, ADM
);
685 case LLCFT_DISC
+ LLC_CMD
:
686 llc_send(linkp
, LLCFT_UA
, LLC_RSP
, pollfinal
);
688 case LLCFT_DM
+ LLC_RSP
:
689 LLC_STOP_ACK_TIMER(linkp
);
690 LLC_NEWSTATE(linkp
, ADM
);
692 case LLC_ACK_TIMER_EXPIRED
:
693 if (linkp
->llcl_retry
< llc_n2
) {
694 llc_send(linkp
, LLCFT_DISC
, LLC_CMD
, pollfinal
);
695 LLC_SETFLAG(linkp
, P
, pollfinal
);
696 LLC_START_ACK_TIMER(linkp
);
698 } else LLC_NEWSTATE(linkp
, ADM
);
706 * ERROR --- The local connection component has detected an error in a received
707 * PDU and has sent a FRMR response PDU. It is waiting for a reply from
708 * the remote connection component.
711 llc_state_ERROR(struct llc_linkcb
*linkp
, struct llc
*frame
, int frame_kind
,
712 int cmdrsp
, int pollfinal
)
716 switch(frame_kind
+ cmdrsp
) {
717 case LLCFT_SABME
+ LLC_CMD
:
718 LLC_STOP_ACK_TIMER(linkp
);
719 LLC_NEWSTATE(linkp
, RESET_CHECK
);
720 action
= LLC_RESET_INDICATION_REMOTE
;
722 case LLCFT_DISC
+ LLC_CMD
:
723 llc_send(linkp
, LLCFT_UA
, LLC_RSP
, pollfinal
);
724 LLC_STOP_ACK_TIMER(linkp
);
725 LLC_NEWSTATE(linkp
, ADM
);
726 action
= LLC_DISCONNECT_INDICATION
;
728 case LLCFT_DM
+ LLC_RSP
:
729 LLC_STOP_ACK_TIMER(linkp
);
730 LLC_NEWSTATE(linkp
, ADM
);
731 action
= LLC_DISCONNECT_INDICATION
;
733 case LLCFT_FRMR
+ LLC_RSP
:
734 LLC_STOP_ACK_TIMER(linkp
);
735 LLC_SETFLAG(linkp
, S
, 0);
736 LLC_NEWSTATE(linkp
, RESET_WAIT
);
737 action
= LLC_FRMR_RECEIVED
;
739 case LLC_ACK_TIMER_EXPIRED
:
740 if (linkp
->llcl_retry
< llc_n2
) {
741 llc_send(linkp
, LLCFT_FRMR
, LLC_RSP
, 0);
742 LLC_START_ACK_TIMER(linkp
);
745 LLC_SETFLAG(linkp
, S
, 0);
746 LLC_NEWSTATE(linkp
, RESET_WAIT
);
747 action
= LLC_RESET_INDICATION_LOCAL
;
751 if (cmdrsp
== LLC_CMD
){
752 llc_send(linkp
, LLCFT_FRMR
, LLC_RSP
, pollfinal
);
753 LLC_START_ACK_TIMER(linkp
);
763 * NORMAL, BUSY, REJECT, AWAIT, AWAIT_BUSY, and AWAIT_REJECT all share
764 * a common core state handler.
767 llc_state_NBRAcore(struct llc_linkcb
*linkp
, struct llc
*frame
, int frame_kind
,
768 int cmdrsp
, int pollfinal
)
772 switch(frame_kind
+ cmdrsp
) {
773 case NL_DISCONNECT_REQUEST
:
774 llc_send(linkp
, LLCFT_DISC
, LLC_CMD
, pollfinal
);
775 LLC_SETFLAG(linkp
, P
, pollfinal
);
776 LLC_STOP_ALL_TIMERS(linkp
);
777 LLC_START_ACK_TIMER(linkp
);
778 linkp
->llcl_retry
= 0;
779 LLC_NEWSTATE(linkp
, D_CONN
);
781 case NL_RESET_REQUEST
:
782 llc_send(linkp
, LLCFT_SABME
, LLC_CMD
, pollfinal
);
783 LLC_SETFLAG(linkp
, P
, pollfinal
);
784 LLC_STOP_ALL_TIMERS(linkp
);
785 LLC_START_ACK_TIMER(linkp
);
786 linkp
->llcl_retry
= 0;
787 LLC_SETFLAG(linkp
, S
, 0);
788 LLC_NEWSTATE(linkp
, RESET
);
790 case LLCFT_SABME
+ LLC_CMD
:
791 LLC_SETFLAG(linkp
, F
, pollfinal
);
792 LLC_STOP_ALL_TIMERS(linkp
);
793 LLC_NEWSTATE(linkp
, RESET_CHECK
);
794 action
= LLC_RESET_INDICATION_REMOTE
;
796 case LLCFT_DISC
+ LLC_CMD
:
797 llc_send(linkp
, LLCFT_UA
, LLC_RSP
, pollfinal
);
798 LLC_STOP_ALL_TIMERS(linkp
);
799 LLC_NEWSTATE(linkp
, ADM
);
800 action
= LLC_DISCONNECT_INDICATION
;
802 case LLCFT_FRMR
+ LLC_RSP
:
803 LLC_STOP_ALL_TIMERS(linkp
);
804 LLC_SETFLAG(linkp
, S
, 0);
805 LLC_NEWSTATE(linkp
, RESET_WAIT
);
806 action
= LLC_FRMR_RECEIVED
;
808 case LLCFT_DM
+ LLC_RSP
:
809 LLC_STOP_ALL_TIMERS(linkp
);
810 LLC_NEWSTATE(linkp
, ADM
);
811 action
= LLC_DISCONNECT_INDICATION
;
813 case LLC_INVALID_NR
+ LLC_CMD
:
814 case LLC_INVALID_NS
+ LLC_CMD
:
815 LLC_SETFRMR(linkp
, frame
, cmdrsp
,
816 (frame_kind
== LLC_INVALID_NR
? LLC_FRMR_Z
:
817 (LLC_FRMR_V
| LLC_FRMR_W
)));
818 llc_send(linkp
, LLCFT_FRMR
, LLC_RSP
, pollfinal
);
819 LLC_STOP_ALL_TIMERS(linkp
);
820 LLC_START_ACK_TIMER(linkp
);
821 linkp
->llcl_retry
= 0;
822 LLC_NEWSTATE(linkp
, ERROR
);
823 action
= LLC_FRMR_SENT
;
825 case LLC_INVALID_NR
+ LLC_RSP
:
826 case LLC_INVALID_NS
+ LLC_RSP
:
827 case LLCFT_UA
+ LLC_RSP
:
831 switch (frame_kind
) {
832 case LLC_INVALID_NR
: frmrcause
= LLC_FRMR_Z
; break;
833 case LLC_INVALID_NS
: frmrcause
= LLC_FRMR_V
| LLC_FRMR_W
; break;
834 default: frmrcause
= LLC_FRMR_W
;
836 LLC_SETFRMR(linkp
, frame
, cmdrsp
, frmrcause
);
837 llc_send(linkp
, LLCFT_FRMR
, LLC_RSP
, 0);
838 LLC_STOP_ALL_TIMERS(linkp
);
839 LLC_START_ACK_TIMER(linkp
);
840 linkp
->llcl_retry
= 0;
841 LLC_NEWSTATE(linkp
, ERROR
);
842 action
= LLC_FRMR_SENT
;
846 if (cmdrsp
== LLC_RSP
&& pollfinal
== 1 &&
847 LLC_GETFLAG(linkp
, P
) == 0) {
848 LLC_SETFRMR(linkp
, frame
, cmdrsp
, LLC_FRMR_W
);
849 LLC_STOP_ALL_TIMERS(linkp
);
850 LLC_START_ACK_TIMER(linkp
);
851 linkp
->llcl_retry
= 0;
852 LLC_NEWSTATE(linkp
, ERROR
);
853 action
= LLC_FRMR_SENT
;
856 case LLC_P_TIMER_EXPIRED
:
857 case LLC_ACK_TIMER_EXPIRED
:
858 case LLC_REJ_TIMER_EXPIRED
:
859 case LLC_BUSY_TIMER_EXPIRED
:
860 if (linkp
->llcl_retry
>= llc_n2
) {
861 LLC_STOP_ALL_TIMERS(linkp
);
862 LLC_SETFLAG(linkp
, S
, 0);
863 LLC_NEWSTATE(linkp
, RESET_WAIT
);
864 action
= LLC_RESET_INDICATION_LOCAL
;
873 * NORMAL --- A data link connection exists between the local LLC service access
874 * point and the remote LLC service access point. Sending and
875 * reception of information and supervisory PDUs can be performed.
878 llc_state_NORMAL(struct llc_linkcb
*linkp
, struct llc
*frame
, int frame_kind
,
879 int cmdrsp
, int pollfinal
)
881 int action
= LLC_PASSITON
;
883 switch(frame_kind
+ cmdrsp
) {
884 case NL_DATA_REQUEST
:
885 if (LLC_GETFLAG(linkp
, REMOTE_BUSY
) == 0) {
887 if (LLC_GETFLAG(linkp
, P
) == 0) {
888 /* multiple possibilities */
889 llc_send(linkp
, LLCFT_INFO
, LLC_CMD
, 1);
890 LLC_START_P_TIMER(linkp
);
891 if (LLC_TIMERXPIRED(linkp
, ACK
) != LLC_TIMER_RUNNING
)
892 LLC_START_ACK_TIMER(linkp
);
895 /* multiple possibilities */
896 llc_send(linkp
, LLCFT_INFO
, LLC_CMD
, 0);
897 if (LLC_TIMERXPIRED(linkp
, ACK
) != LLC_TIMER_RUNNING
)
898 LLC_START_ACK_TIMER(linkp
);
905 case LLC_LOCAL_BUSY_DETECTED
:
906 if (LLC_GETFLAG(linkp
, P
) == 0) {
907 /* multiple possibilities --- action-wise */
908 /* multiple possibilities --- CMD/RSP-wise */
909 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 0);
910 LLC_START_P_TIMER(linkp
);
911 LLC_SETFLAG(linkp
, DATA
, 0);
912 LLC_NEWSTATE(linkp
, BUSY
);
915 /* multiple possibilities --- CMD/RSP-wise */
916 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 0);
917 LLC_SETFLAG(linkp
, DATA
, 0);
918 LLC_NEWSTATE(linkp
, BUSY
);
922 case LLC_INVALID_NS
+ LLC_CMD
:
923 case LLC_INVALID_NS
+ LLC_RSP
: {
924 register int p
= LLC_GETFLAG(linkp
, P
);
925 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
927 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
928 llc_send(linkp
, LLCFT_REJ
, LLC_RSP
, 1);
929 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
930 LLC_START_REJ_TIMER(linkp
);
931 LLC_NEWSTATE(linkp
, REJECT
);
933 } else if (pollfinal
== 0 && p
== 1) {
934 llc_send(linkp
, LLCFT_REJ
, LLC_CMD
, 0);
935 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
936 LLC_START_REJ_TIMER(linkp
);
937 LLC_NEWSTATE(linkp
, REJECT
);
939 } else if ((pollfinal
== 0 && p
== 0) ||
940 (pollfinal
== 1 && p
== 1 && cmdrsp
== LLC_RSP
)) {
941 llc_send(linkp
, LLCFT_REJ
, LLC_CMD
, 1);
942 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
943 LLC_START_P_TIMER(linkp
);
944 LLC_START_REJ_TIMER(linkp
);
945 if (cmdrsp
== LLC_RSP
&& pollfinal
== 1) {
946 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
948 LLC_NEWSTATE(linkp
, REJECT
);
952 case LLCFT_INFO
+ LLC_CMD
:
953 case LLCFT_INFO
+ LLC_RSP
: {
954 register int p
= LLC_GETFLAG(linkp
, P
);
955 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
957 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
958 LLC_INC(linkp
->llcl_vr
);
959 LLC_SENDACKNOWLEDGE(linkp
, LLC_RSP
, 1);
960 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
961 action
= LLC_DATA_INDICATION
;
962 } else if (pollfinal
== 0 && p
== 1) {
963 LLC_INC(linkp
->llcl_vr
);
964 LLC_SENDACKNOWLEDGE(linkp
, LLC_CMD
, 0);
965 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
966 action
= LLC_DATA_INDICATION
;
967 } else if ((pollfinal
== 0 && p
== 0 && cmdrsp
== LLC_CMD
) ||
968 (pollfinal
== p
&& cmdrsp
== LLC_RSP
)) {
969 LLC_INC(linkp
->llcl_vr
);
970 LLC_UPDATE_P_FLAG(linkp
, cmdrsp
, pollfinal
);
971 LLC_SENDACKNOWLEDGE(linkp
, LLC_CMD
, 0);
972 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
973 if (cmdrsp
== LLC_RSP
&& pollfinal
== 1)
974 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
975 action
= LLC_DATA_INDICATION
;
979 case LLCFT_RR
+ LLC_CMD
:
980 case LLCFT_RR
+ LLC_RSP
: {
981 register int p
= LLC_GETFLAG(linkp
, P
);
982 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
984 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
985 LLC_SENDACKNOWLEDGE(linkp
, LLC_RSP
, 1);
986 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
987 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
988 } else if ((pollfinal
== 0) ||
989 (cmdrsp
== LLC_RSP
&& pollfinal
== 1 && p
== 1)) {
990 LLC_UPDATE_P_FLAG(linkp
, cmdrsp
, pollfinal
);
991 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
992 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
996 case LLCFT_RNR
+ LLC_CMD
:
997 case LLCFT_RNR
+ LLC_RSP
: {
998 register int p
= LLC_GETFLAG(linkp
, P
);
999 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1001 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1002 llc_send(linkp
, LLCFT_RR
, LLC_RSP
, 1);
1003 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1004 LLC_SET_REMOTE_BUSY(linkp
, action
);
1005 } else if ((pollfinal
== 0) ||
1006 (cmdrsp
== LLC_RSP
&& pollfinal
== 1 && p
== 1)) {
1007 LLC_UPDATE_P_FLAG(linkp
, cmdrsp
, pollfinal
);
1008 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1009 LLC_SET_REMOTE_BUSY(linkp
, action
);
1013 case LLCFT_REJ
+ LLC_CMD
:
1014 case LLCFT_REJ
+ LLC_RSP
: {
1015 register int p
= LLC_GETFLAG(linkp
, P
);
1016 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1018 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1019 linkp
->llcl_vs
= nr
;
1020 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1021 llc_resend(linkp
, LLC_RSP
, 1);
1022 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1023 } else if (pollfinal
== 0 && p
== 1) {
1024 linkp
->llcl_vs
= nr
;
1025 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1026 llc_resend(linkp
, LLC_CMD
, 0);
1027 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1028 } else if ((pollfinal
== 0 && p
== 0 && cmdrsp
== LLC_CMD
) ||
1029 (pollfinal
== p
&& cmdrsp
== LLC_RSP
)) {
1030 linkp
->llcl_vs
= nr
;
1031 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1032 LLC_START_P_TIMER(linkp
);
1033 llc_resend(linkp
, LLC_CMD
, 1);
1034 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1038 case NL_INITIATE_PF_CYCLE
:
1039 if (LLC_GETFLAG(linkp
, P
) == 0) {
1040 llc_send(linkp
, LLCFT_RR
, LLC_CMD
, 1);
1041 LLC_START_P_TIMER(linkp
);
1045 case LLC_P_TIMER_EXPIRED
:
1046 if (linkp
->llcl_retry
< llc_n2
) {
1047 llc_send(linkp
, LLCFT_RR
, LLC_CMD
, 1);
1048 LLC_START_P_TIMER(linkp
);
1049 linkp
->llcl_retry
++;
1050 LLC_NEWSTATE(linkp
, AWAIT
);
1054 case LLC_ACK_TIMER_EXPIRED
:
1055 case LLC_BUSY_TIMER_EXPIRED
:
1056 if ((LLC_GETFLAG(linkp
, P
) == 0)
1057 && (linkp
->llcl_retry
< llc_n2
)) {
1058 llc_send(linkp
, LLCFT_RR
, LLC_CMD
, 1);
1059 LLC_START_P_TIMER(linkp
);
1060 linkp
->llcl_retry
++;
1061 LLC_NEWSTATE(linkp
, AWAIT
);
1066 if (action
== LLC_PASSITON
)
1067 action
= llc_state_NBRAcore(linkp
, frame
, frame_kind
,
1074 * BUSY --- A data link connection exists between the local LLC service access
1075 * point and the remote LLC service access point. I PDUs may be sent.
1076 * Local conditions make it likely that the information feld of
1077 * received I PDUs will be ignored. Supervisory PDUs may be both sent
1081 llc_state_BUSY(struct llc_linkcb
*linkp
, struct llc
*frame
, int frame_kind
,
1082 int cmdrsp
, int pollfinal
)
1084 int action
= LLC_PASSITON
;
1086 switch(frame_kind
+ cmdrsp
) {
1087 case NL_DATA_REQUEST
:
1088 if (LLC_GETFLAG(linkp
, REMOTE_BUSY
) == 0)
1089 if (LLC_GETFLAG(linkp
, P
) == 0) {
1090 llc_send(linkp
, LLCFT_INFO
, LLC_CMD
, 1);
1091 LLC_START_P_TIMER(linkp
);
1092 if (LLC_TIMERXPIRED(linkp
, ACK
) != LLC_TIMER_RUNNING
)
1093 LLC_START_ACK_TIMER(linkp
);
1096 llc_send(linkp
, LLCFT_INFO
, LLC_CMD
, 0);
1097 if (LLC_TIMERXPIRED(linkp
, ACK
) != LLC_TIMER_RUNNING
)
1098 LLC_START_ACK_TIMER(linkp
);
1102 case LLC_LOCAL_BUSY_CLEARED
: {
1103 register int p
= LLC_GETFLAG(linkp
, P
);
1104 register int df
= LLC_GETFLAG(linkp
, DATA
);
1109 /* multiple possibilities */
1110 llc_send(linkp
, LLCFT_REJ
, LLC_CMD
, 1);
1111 LLC_START_REJ_TIMER(linkp
);
1112 LLC_START_P_TIMER(linkp
);
1113 LLC_NEWSTATE(linkp
, REJECT
);
1116 llc_send(linkp
, LLCFT_REJ
, LLC_CMD
, 0);
1117 LLC_START_REJ_TIMER(linkp
);
1118 LLC_NEWSTATE(linkp
, REJECT
);
1124 /* multiple possibilities */
1125 llc_send(linkp
, LLCFT_RR
, LLC_CMD
, 1);
1126 LLC_START_P_TIMER(linkp
);
1127 LLC_NEWSTATE(linkp
, NORMAL
);
1130 llc_send(linkp
, LLCFT_RR
, LLC_CMD
, 0);
1131 LLC_NEWSTATE(linkp
, NORMAL
);
1137 /* multiple possibilities */
1138 llc_send(linkp
, LLCFT_RR
, LLC_CMD
, 1);
1139 LLC_START_P_TIMER(linkp
);
1140 LLC_NEWSTATE(linkp
, REJECT
);
1143 llc_send(linkp
, LLCFT_RR
, LLC_CMD
, 0);
1144 LLC_NEWSTATE(linkp
, REJECT
);
1151 case LLC_INVALID_NS
+ LLC_CMD
:
1152 case LLC_INVALID_NS
+ LLC_RSP
: {
1153 register int p
= LLC_GETFLAG(linkp
, P
);
1154 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1156 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1157 llc_send(linkp
, LLCFT_RNR
, LLC_RSP
, 1);
1158 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1159 if (LLC_GETFLAG(linkp
, DATA
) == 0)
1160 LLC_SETFLAG(linkp
, DATA
, 1);
1162 } else if ((cmdrsp
== LLC_CMD
&& pollfinal
== 0 && p
== 0) ||
1163 (cmdrsp
== LLC_RSP
&& pollfinal
== p
)) {
1164 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 0);
1165 LLC_UPDATE_P_FLAG(linkp
, cmdrsp
, pollfinal
);
1166 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1167 if (LLC_GETFLAG(linkp
, DATA
) == 0)
1168 LLC_SETFLAG(linkp
, DATA
, 1);
1169 if (cmdrsp
== LLC_RSP
&& pollfinal
== 1) {
1170 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1172 } else if (pollfinal
== 0 && p
== 1) {
1173 llc_send(linkp
, LLCFT_RNR
, LLC_RSP
, 1);
1174 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1175 if (LLC_GETFLAG(linkp
, DATA
) == 0)
1176 LLC_SETFLAG(linkp
, DATA
, 1);
1181 case LLCFT_INFO
+ LLC_CMD
:
1182 case LLCFT_INFO
+ LLC_RSP
: {
1183 register int p
= LLC_GETFLAG(linkp
, P
);
1184 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1186 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1187 LLC_INC(linkp
->llcl_vr
);
1188 llc_send(linkp
, LLCFT_RNR
, LLC_RSP
, 1);
1189 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1190 if (LLC_GETFLAG(linkp
, DATA
) == 2)
1191 LLC_STOP_REJ_TIMER(linkp
);
1192 LLC_SETFLAG(linkp
, DATA
, 0);
1193 action
= LLC_DATA_INDICATION
;
1194 } else if ((cmdrsp
== LLC_CMD
&& pollfinal
== 0 && p
== 0) ||
1195 (cmdrsp
== LLC_RSP
&& pollfinal
== p
)) {
1196 LLC_INC(linkp
->llcl_vr
);
1197 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 1);
1198 LLC_START_P_TIMER(linkp
);
1199 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1200 if (LLC_GETFLAG(linkp
, DATA
) == 2)
1201 LLC_STOP_REJ_TIMER(linkp
);
1202 if (cmdrsp
== LLC_RSP
&& pollfinal
== 1)
1203 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1204 action
= LLC_DATA_INDICATION
;
1205 } else if (pollfinal
== 0 && p
== 1) {
1206 LLC_INC(linkp
->llcl_vr
);
1207 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 0);
1208 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1209 if (LLC_GETFLAG(linkp
, DATA
) == 2)
1210 LLC_STOP_REJ_TIMER(linkp
);
1211 LLC_SETFLAG(linkp
, DATA
, 0);
1212 action
= LLC_DATA_INDICATION
;
1216 case LLCFT_RR
+ LLC_CMD
:
1217 case LLCFT_RR
+ LLC_RSP
:
1218 case LLCFT_RNR
+ LLC_CMD
:
1219 case LLCFT_RNR
+ LLC_RSP
: {
1220 register int p
= LLC_GETFLAG(linkp
, P
);
1221 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1223 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1224 llc_send(linkp
, LLCFT_RNR
, LLC_RSP
, 1);
1225 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1226 if (frame_kind
== LLCFT_RR
) {
1227 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1229 LLC_SET_REMOTE_BUSY(linkp
, action
);
1231 } else if (pollfinal
= 0 ||
1232 (cmdrsp
== LLC_RSP
&& pollfinal
== 1)) {
1233 LLC_UPDATE_P_FLAG(linkp
, cmdrsp
, pollfinal
);
1234 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1235 if (frame_kind
== LLCFT_RR
) {
1236 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1238 LLC_SET_REMOTE_BUSY(linkp
, action
);
1243 case LLCFT_REJ
+ LLC_CMD
:
1244 case LLCFT_REJ
+ LLC_RSP
: {
1245 register int p
= LLC_GETFLAG(linkp
, P
);
1246 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1248 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1249 linkp
->llcl_vs
= nr
;
1250 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1251 llc_send(linkp
, LLCFT_RNR
, LLC_RSP
, 1);
1252 llc_resend(linkp
, LLC_CMD
, 0);
1253 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1254 } else if ((cmdrsp
== LLC_CMD
&& pollfinal
== 0 && p
== 0) ||
1255 (cmdrsp
== LLC_RSP
&& pollfinal
== p
)) {
1256 linkp
->llcl_vs
= nr
;
1257 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1258 LLC_UPDATE_P_FLAG(linkp
, cmdrsp
, pollfinal
);
1259 llc_resend(linkp
, LLC_CMD
, 0);
1260 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1261 } else if (pollfinal
== 0 && p
== 1) {
1262 linkp
->llcl_vs
= nr
;
1263 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1264 llc_resend(linkp
, LLC_CMD
, 0);
1265 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1269 case NL_INITIATE_PF_CYCLE
:
1270 if (LLC_GETFLAG(linkp
, P
) == 0) {
1271 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 1);
1272 LLC_START_P_TIMER(linkp
);
1276 case LLC_P_TIMER_EXPIRED
:
1277 /* multiple possibilities */
1278 if (linkp
->llcl_retry
< llc_n2
) {
1279 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 1);
1280 LLC_START_P_TIMER(linkp
);
1281 linkp
->llcl_retry
++;
1282 LLC_NEWSTATE(linkp
, AWAIT_BUSY
);
1286 case LLC_ACK_TIMER_EXPIRED
:
1287 case LLC_BUSY_TIMER_EXPIRED
:
1288 if (LLC_GETFLAG(linkp
, P
) == 0 && linkp
->llcl_retry
< llc_n2
) {
1289 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 1);
1290 LLC_START_P_TIMER(linkp
);
1291 linkp
->llcl_retry
++;
1292 LLC_NEWSTATE(linkp
, AWAIT_BUSY
);
1296 case LLC_REJ_TIMER_EXPIRED
:
1297 if (linkp
->llcl_retry
< llc_n2
)
1298 if (LLC_GETFLAG(linkp
, P
) == 0) {
1299 /* multiple possibilities */
1300 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 1);
1301 LLC_START_P_TIMER(linkp
);
1302 linkp
->llcl_retry
++;
1303 LLC_SETFLAG(linkp
, DATA
, 1);
1304 LLC_NEWSTATE(linkp
, AWAIT_BUSY
);
1307 LLC_SETFLAG(linkp
, DATA
, 1);
1308 LLC_NEWSTATE(linkp
, BUSY
);
1314 if (action
== LLC_PASSITON
)
1315 action
= llc_state_NBRAcore(linkp
, frame
, frame_kind
,
1322 * REJECT --- A data link connection exists between the local LLC service
1323 * access point and the remote LLC service access point. The local
1324 * connection component has requested that the remote connection
1325 * component resend a specific I PDU that the local connection
1326 * componnent has detected as being out of sequence. Both I PDUs and
1327 * supervisory PDUs may be sent and received.
1330 llc_state_REJECT(struct llc_linkcb
*linkp
, struct llc
*frame
, int frame_kind
,
1331 int cmdrsp
, int pollfinal
)
1333 int action
= LLC_PASSITON
;
1335 switch(frame_kind
+ cmdrsp
) {
1336 case NL_DATA_REQUEST
:
1337 if (LLC_GETFLAG(linkp
, P
) == 0) {
1338 llc_send(linkp
, LLCFT_INFO
, LLC_CMD
, 1);
1339 LLC_START_P_TIMER(linkp
);
1340 if (LLC_TIMERXPIRED(linkp
, ACK
) != LLC_TIMER_RUNNING
)
1341 LLC_START_ACK_TIMER(linkp
);
1342 LLC_NEWSTATE(linkp
, REJECT
);
1345 llc_send(linkp
, LLCFT_INFO
, LLC_CMD
, 0);
1346 if (LLC_TIMERXPIRED(linkp
, ACK
) != LLC_TIMER_RUNNING
)
1347 LLC_START_ACK_TIMER(linkp
);
1348 LLC_NEWSTATE(linkp
, REJECT
);
1352 case NL_LOCAL_BUSY_DETECTED
:
1353 if (LLC_GETFLAG(linkp
, P
) == 0) {
1354 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 1);
1355 LLC_START_P_TIMER(linkp
);
1356 LLC_SETFLAG(linkp
, DATA
, 2);
1357 LLC_NEWSTATE(linkp
, BUSY
);
1360 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 0);
1361 LLC_SETFLAG(linkp
, DATA
, 2);
1362 LLC_NEWSTATE(linkp
, BUSY
);
1366 case LLC_INVALID_NS
+ LLC_CMD
:
1367 case LLC_INVALID_NS
+ LLC_RSP
: {
1368 register int p
= LLC_GETFLAG(linkp
, P
);
1369 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1371 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1372 llc_send(linkp
, LLCFT_RR
, LLC_RSP
, 1);
1373 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1375 } else if (pollfinal
== 0 ||
1376 (cmdrsp
== LLC_RSP
&& pollfinal
== 1 && p
== 1)) {
1377 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1378 LLC_UPDATE_P_FLAG(linkp
, cmdrsp
, pollfinal
);
1379 if (cmdrsp
== LLC_RSP
&& pollfinal
== 1) {
1380 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1385 case LLCFT_INFO
+ LLC_CMD
:
1386 case LLCFT_INFO
+ LLC_RSP
: {
1387 register int p
= LLC_GETFLAG(linkp
, P
);
1388 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1390 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1391 LLC_INC(linkp
->llcl_vr
);
1392 LLC_SENDACKNOWLEDGE(linkp
, LLC_RSP
, 1);
1393 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1394 LLC_STOP_REJ_TIMER(linkp
);
1395 LLC_NEWSTATE(linkp
, NORMAL
);
1396 action
= LLC_DATA_INDICATION
;
1397 } else if ((cmdrsp
= LLC_RSP
&& pollfinal
== p
) ||
1398 (cmdrsp
== LLC_CMD
&& pollfinal
== 0 && p
== 0)) {
1399 LLC_INC(linkp
->llcl_vr
);
1400 LLC_SENDACKNOWLEDGE(linkp
, LLC_CMD
, 1);
1401 LLC_START_P_TIMER(linkp
);
1402 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1403 if (cmdrsp
== LLC_RSP
&& pollfinal
== 1)
1404 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1405 LLC_STOP_REJ_TIMER(linkp
);
1406 LLC_NEWSTATE(linkp
, NORMAL
);
1407 action
= LLC_DATA_INDICATION
;
1408 } else if (pollfinal
== 0 && p
== 1) {
1409 LLC_INC(linkp
->llcl_vr
);
1410 LLC_SENDACKNOWLEDGE(linkp
, LLC_CMD
, 0);
1411 LLC_STOP_REJ_TIMER(linkp
);
1412 LLC_NEWSTATE(linkp
, NORMAL
);
1413 action
= LLC_DATA_INDICATION
;
1417 case LLCFT_RR
+ LLC_CMD
:
1418 case LLCFT_RR
+ LLC_RSP
: {
1419 register int p
= LLC_GETFLAG(linkp
, P
);
1420 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1422 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1423 LLC_SENDACKNOWLEDGE(linkp
, LLC_RSP
, 1);
1424 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1425 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1426 } else if (pollfinal
== 0 ||
1427 (cmdrsp
== LLC_RSP
&& pollfinal
== 1 && p
== 1)) {
1428 LLC_UPDATE_P_FLAG(linkp
, cmdrsp
, pollfinal
);
1429 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1430 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1434 case LLCFT_RNR
+ LLC_CMD
:
1435 case LLCFT_RNR
+ LLC_RSP
: {
1436 register int p
= LLC_GETFLAG(linkp
, P
);
1437 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1439 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1440 llc_send(linkp
, LLCFT_RR
, LLC_RSP
, 1);
1441 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1442 LLC_SET_REMOTE_BUSY(linkp
, action
);
1443 } else if (pollfinal
== 0 ||
1444 (cmdrsp
== LLC_RSP
&& pollfinal
== 1 && p
== 1)) {
1445 LLC_UPDATE_P_FLAG(linkp
, cmdrsp
, pollfinal
);
1446 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1451 case LLCFT_REJ
+ LLC_CMD
:
1452 case LLCFT_REJ
+ LLC_RSP
: {
1453 register int p
= LLC_GETFLAG(linkp
, P
);
1454 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1456 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1457 linkp
->llcl_vs
= nr
;
1458 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1459 llc_resend(linkp
, LLC_RSP
, 1);
1460 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1461 } else if ((cmdrsp
== LLC_CMD
&& pollfinal
== 0 && p
== 0) ||
1462 (cmdrsp
== LLC_RSP
&& pollfinal
== p
)) {
1463 linkp
->llcl_vs
= nr
;
1464 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1465 LLC_UPDATE_P_FLAG(linkp
, cmdrsp
, pollfinal
);
1466 llc_resend(linkp
, LLC_CMD
, 0);
1467 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1468 } else if (pollfinal
== 0 && p
== 1) {
1469 linkp
->llcl_vs
= nr
;
1470 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1471 llc_resend(linkp
, LLC_CMD
, 0);
1472 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1476 case NL_INITIATE_PF_CYCLE
:
1477 if (LLC_GETFLAG(linkp
, P
) == 0) {
1478 llc_send(linkp
, LLCFT_RR
, LLC_CMD
, 1);
1479 LLC_START_P_TIMER(linkp
);
1483 case LLC_REJ_TIMER_EXPIRED
:
1484 if (LLC_GETFLAG(linkp
, P
) == 0 && linkp
->llcl_retry
< llc_n2
) {
1485 llc_send(linkp
, LLCFT_REJ
, LLC_CMD
, 1);
1486 LLC_START_P_TIMER(linkp
);
1487 LLC_START_REJ_TIMER(linkp
);
1488 linkp
->llcl_retry
++;
1491 case LLC_P_TIMER_EXPIRED
:
1492 if (linkp
->llcl_retry
< llc_n2
) {
1493 llc_send(linkp
, LLCFT_RR
, LLC_CMD
, 1);
1494 LLC_START_P_TIMER(linkp
);
1495 LLC_START_REJ_TIMER(linkp
);
1496 linkp
->llcl_retry
++;
1497 LLC_NEWSTATE(linkp
, AWAIT_REJECT
);
1501 case LLC_ACK_TIMER_EXPIRED
:
1502 case LLC_BUSY_TIMER_EXPIRED
:
1503 if (LLC_GETFLAG(linkp
, P
) == 0 && linkp
->llcl_retry
< llc_n2
) {
1504 llc_send(linkp
, LLCFT_RR
, LLC_CMD
, 1);
1505 LLC_START_P_TIMER(linkp
);
1506 LLC_START_REJ_TIMER(linkp
);
1507 linkp
->llcl_retry
++;
1509 * I cannot locate the description of RESET_V(S)
1510 * in ISO 8802-2, table 7-1, state REJECT, last event,
1511 * and assume they meant to set V(S) to 0 ...
1513 linkp
->llcl_vs
= 0; /* XXX */
1514 LLC_NEWSTATE(linkp
, AWAIT_REJECT
);
1520 if (action
== LLC_PASSITON
)
1521 action
= llc_state_NBRAcore(linkp
, frame
, frame_kind
,
1528 * AWAIT --- A data link connection exists between the local LLC service access
1529 * point and the remote LLC service access point. The local LLC is
1530 * performing a timer recovery operation and has sent a command PDU
1531 * with the P bit set to ``1'', and is awaiting an acknowledgement
1532 * from the remote LLC. I PDUs may be received but not sent.
1533 * Supervisory PDUs may be both sent and received.
1536 llc_state_AWAIT(struct llc_linkcb
*linkp
, struct llc
*frame
, int frame_kind
,
1537 int cmdrsp
, int pollfinal
)
1539 int action
= LLC_PASSITON
;
1541 switch(frame_kind
+ cmdrsp
) {
1542 case LLC_LOCAL_BUSY_DETECTED
:
1543 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 0);
1544 LLC_SETFLAG(linkp
, DATA
, 0);
1545 LLC_NEWSTATE(linkp
, AWAIT_BUSY
);
1548 case LLC_INVALID_NS
+ LLC_CMD
:
1549 case LLC_INVALID_NS
+ LLC_RSP
: {
1550 register int p
= LLC_GETFLAG(linkp
, P
);
1551 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1553 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1554 llc_send(linkp
, LLCFT_REJ
, LLC_RSP
, 1);
1555 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1556 LLC_START_REJ_TIMER(linkp
);
1557 LLC_NEWSTATE(linkp
, AWAIT_REJECT
);
1559 } else if (cmdrsp
== LLC_RSP
&& pollfinal
== 1) {
1560 llc_send(linkp
, LLCFT_REJ
, LLC_CMD
, 0);
1561 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1562 linkp
->llcl_vs
= nr
;
1563 LLC_STOP_P_TIMER(linkp
);
1564 llc_resend(linkp
, LLC_CMD
, 0);
1565 LLC_START_REJ_TIMER(linkp
);
1566 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1567 LLC_NEWSTATE(linkp
, REJECT
);
1568 } else if (pollfinal
== 0) {
1569 llc_send(linkp
, LLCFT_REJ
, LLC_CMD
, 0);
1570 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1571 LLC_START_REJ_TIMER(linkp
);
1572 LLC_NEWSTATE(linkp
, AWAIT_REJECT
);
1577 case LLCFT_INFO
+ LLC_RSP
:
1578 case LLCFT_INFO
+ LLC_CMD
: {
1579 register int p
= LLC_GETFLAG(linkp
, P
);
1580 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1582 LLC_INC(linkp
->llcl_vr
);
1583 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1584 llc_send(linkp
, LLCFT_RR
, LLC_RSP
, 1);
1585 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1586 action
= LLC_DATA_INDICATION
;
1587 } else if (cmdrsp
== LLC_RSP
&& pollfinal
== 1) {
1588 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1589 linkp
->llcl_vs
= nr
;
1590 llc_resend(linkp
, LLC_CMD
, 1);
1591 LLC_START_P_TIMER(linkp
);
1592 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1593 LLC_NEWSTATE(linkp
, NORMAL
);
1594 action
= LLC_DATA_INDICATION
;
1595 } else if (pollfinal
== 0) {
1596 llc_send(linkp
, LLCFT_RR
, LLC_CMD
, 0);
1597 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1598 action
= LLC_DATA_INDICATION
;
1602 case LLCFT_RR
+ LLC_CMD
:
1603 case LLCFT_RR
+ LLC_RSP
:
1604 case LLCFT_REJ
+ LLC_CMD
:
1605 case LLCFT_REJ
+ LLC_RSP
: {
1606 register int p
= LLC_GETFLAG(linkp
, P
);
1607 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1609 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1610 llc_send(linkp
, LLCFT_RR
, LLC_RSP
, 1);
1611 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1612 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1613 } else if (cmdrsp
== LLC_RSP
&& pollfinal
== 1) {
1614 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1615 linkp
->llcl_vs
= nr
;
1616 LLC_STOP_P_TIMER(linkp
);
1617 llc_resend(linkp
, LLC_CMD
, 0);
1618 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1619 LLC_NEWSTATE(linkp
, NORMAL
);
1620 } else if (pollfinal
== 0) {
1621 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1622 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1626 case LLCFT_RNR
+ LLC_CMD
:
1627 case LLCFT_RNR
+ LLC_RSP
: {
1628 register int p
= LLC_GETFLAG(linkp
, P
);
1629 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1631 if (pollfinal
== 1 && cmdrsp
== LLC_CMD
) {
1632 llc_send(linkp
, LLCFT_RR
, LLC_RSP
, 1);
1633 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1634 LLC_SET_REMOTE_BUSY(linkp
, action
);
1635 } else if (pollfinal
== 1 && cmdrsp
== LLC_RSP
) {
1636 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1637 linkp
->llcl_vs
= nr
;
1638 LLC_STOP_P_TIMER(linkp
);
1639 LLC_SET_REMOTE_BUSY(linkp
, action
);
1640 LLC_NEWSTATE(linkp
, NORMAL
);
1641 } else if (pollfinal
== 0) {
1642 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1643 LLC_SET_REMOTE_BUSY(linkp
, action
);
1647 case LLC_P_TIMER_EXPIRED
:
1648 if (linkp
->llcl_retry
< llc_n2
) {
1649 llc_send(linkp
, LLCFT_RR
, LLC_CMD
, 1);
1650 LLC_START_P_TIMER(linkp
);
1651 linkp
->llcl_retry
++;
1656 if (action
== LLC_PASSITON
)
1657 action
= llc_state_NBRAcore(linkp
, frame
, frame_kind
,
1664 * AWAIT_BUSY --- A data link connection exists between the local LLC service
1665 * access point and the remote LLC service access point. The
1666 * local LLC is performing a timer recovery operation and has
1667 * sent a command PDU with the P bit set to ``1'', and is
1668 * awaiting an acknowledgement from the remote LLC. I PDUs may
1669 * not be sent. Local conditions make it likely that the
1670 * information feld of receoved I PDUs will be ignored.
1671 * Supervisory PDUs may be both sent and received.
1674 llc_state_AWAIT_BUSY(struct llc_linkcb
*linkp
, struct llc
*frame
, int frame_kind
,
1675 int cmdrsp
, int pollfinal
)
1677 int action
= LLC_PASSITON
;
1679 switch(frame_kind
+ cmdrsp
) {
1680 case LLC_LOCAL_BUSY_CLEARED
:
1681 switch (LLC_GETFLAG(linkp
, DATA
)) {
1683 llc_send(linkp
, LLCFT_REJ
, LLC_CMD
, 0);
1684 LLC_START_REJ_TIMER(linkp
);
1685 LLC_NEWSTATE(linkp
, AWAIT_REJECT
);
1689 llc_send(linkp
, LLCFT_RR
, LLC_CMD
, 0);
1690 LLC_NEWSTATE(linkp
, AWAIT
);
1694 llc_send(linkp
, LLCFT_RR
, LLC_CMD
, 0);
1695 LLC_NEWSTATE(linkp
, AWAIT_REJECT
);
1700 case LLC_INVALID_NS
+ LLC_CMD
:
1701 case LLC_INVALID_NS
+ LLC_RSP
: {
1702 register int p
= LLC_GETFLAG(linkp
, P
);
1703 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1705 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1706 llc_send(linkp
, LLCFT_RNR
, LLC_RSP
, 1);
1707 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1708 LLC_SETFLAG(linkp
, DATA
, 1);
1710 } else if (cmdrsp
== LLC_RSP
&& pollfinal
== 1) {
1712 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 0);
1713 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1714 linkp
->llcl_vs
= nr
;
1715 LLC_STOP_P_TIMER(linkp
);
1716 LLC_SETFLAG(linkp
, DATA
, 1);
1717 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1718 llc_resend(linkp
, LLC_CMD
, 0);
1719 LLC_NEWSTATE(linkp
, BUSY
);
1720 } else if (pollfinal
== 0) {
1722 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 0);
1723 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1724 LLC_SETFLAG(linkp
, DATA
, 1);
1728 case LLCFT_INFO
+ LLC_CMD
:
1729 case LLCFT_INFO
+ LLC_RSP
: {
1730 register int p
= LLC_GETFLAG(linkp
, P
);
1731 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1733 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1734 llc_send(linkp
, LLCFT_RNR
, LLC_RSP
, 1);
1735 LLC_INC(linkp
->llcl_vr
);
1736 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1737 LLC_SETFLAG(linkp
, DATA
, 0);
1738 action
= LLC_DATA_INDICATION
;
1739 } else if (cmdrsp
== LLC_RSP
&& pollfinal
== 1) {
1740 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 1);
1741 LLC_INC(linkp
->llcl_vr
);
1742 LLC_START_P_TIMER(linkp
);
1743 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1744 linkp
->llcl_vs
= nr
;
1745 LLC_SETFLAG(linkp
, DATA
, 0);
1746 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1747 llc_resend(linkp
, LLC_CMD
, 0);
1748 LLC_NEWSTATE(linkp
, BUSY
);
1749 action
= LLC_DATA_INDICATION
;
1750 } else if (pollfinal
== 0) {
1751 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 0);
1752 LLC_INC(linkp
->llcl_vr
);
1753 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1754 LLC_SETFLAG(linkp
, DATA
, 0);
1755 action
= LLC_DATA_INDICATION
;
1759 case LLCFT_RR
+ LLC_CMD
:
1760 case LLCFT_REJ
+ LLC_CMD
:
1761 case LLCFT_RR
+ LLC_RSP
:
1762 case LLCFT_REJ
+ LLC_RSP
: {
1763 register int p
= LLC_GETFLAG(linkp
, P
);
1764 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1766 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1767 llc_send(linkp
, LLCFT_RNR
, LLC_RSP
, 1);
1768 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1769 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1770 } else if (cmdrsp
== LLC_RSP
&& pollfinal
== 1) {
1771 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1772 linkp
->llcl_vs
= nr
;
1773 LLC_STOP_P_TIMER(linkp
);
1774 llc_resend(linkp
, LLC_CMD
, 0);
1775 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1776 LLC_NEWSTATE(linkp
, BUSY
);
1777 } else if (pollfinal
== 0) {
1778 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1779 linkp
->llcl_vs
= nr
;
1780 LLC_STOP_P_TIMER(linkp
);
1781 llc_resend(linkp
, LLC_CMD
, 0);
1782 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1786 case LLCFT_RNR
+ LLC_CMD
:
1787 case LLCFT_RNR
+ LLC_RSP
: {
1788 register int p
= LLC_GETFLAG(linkp
, P
);
1789 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1791 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1792 llc_send(linkp
, LLCFT_RNR
, LLC_RSP
, 1);
1793 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1794 LLC_SET_REMOTE_BUSY(linkp
, action
);
1795 } else if (cmdrsp
== LLC_RSP
&& pollfinal
== 1) {
1796 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1797 linkp
->llcl_vs
= nr
;
1798 LLC_STOP_P_TIMER(linkp
);
1799 LLC_SET_REMOTE_BUSY(linkp
, action
);
1800 LLC_NEWSTATE(linkp
, BUSY
);
1801 } else if (pollfinal
== 0) {
1802 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1803 LLC_SET_REMOTE_BUSY(linkp
, action
);
1807 case LLC_P_TIMER_EXPIRED
:
1808 if (linkp
->llcl_retry
< llc_n2
) {
1809 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 1);
1810 LLC_START_P_TIMER(linkp
);
1811 linkp
->llcl_retry
++;
1816 if (action
== LLC_PASSITON
)
1817 action
= llc_state_NBRAcore(linkp
, frame
, frame_kind
,
1824 * AWAIT_REJECT --- A data link connection exists between the local LLC service
1825 * access point and the remote LLC service access point. The
1826 * local connection component has requested that the remote
1827 * connection component re-transmit a specific I PDU that the
1828 * local connection component has detected as being out of
1829 * sequence. Before the local LLC entered this state it was
1830 * performing a timer recovery operation and had sent a
1831 * command PDU with the P bit set to ``1'', and is still
1832 * awaiting an acknowledgment from the remote LLC. I PDUs may
1833 * be received but not transmitted. Supervisory PDUs may be
1834 * both transmitted and received.
1837 llc_state_AWAIT_REJECT(struct llc_linkcb
*linkp
, struct llc
*frame
, int frame_kind
,
1838 int cmdrsp
, int pollfinal
)
1840 int action
= LLC_PASSITON
;
1842 switch(frame_kind
+ cmdrsp
) {
1843 case LLC_LOCAL_BUSY_DETECTED
:
1844 llc_send(linkp
, LLCFT_RNR
, LLC_CMD
, 0);
1845 LLC_SETFLAG(linkp
, DATA
, 2);
1846 LLC_NEWSTATE(linkp
, AWAIT_BUSY
);
1849 case LLC_INVALID_NS
+ LLC_CMD
:
1850 case LLC_INVALID_NS
+ LLC_RSP
: {
1851 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1853 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1854 llc_send(linkp
, LLCFT_RR
, LLC_RSP
, 1);
1855 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1857 } else if (cmdrsp
== LLC_RSP
&& pollfinal
== 1) {
1858 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1859 linkp
->llcl_vs
= nr
;
1860 llc_resend(linkp
, LLC_CMD
, 1);
1861 LLC_START_P_TIMER(linkp
);
1862 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1863 LLC_NEWSTATE(linkp
, REJECT
);
1864 } else if (pollfinal
== 0) {
1865 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1870 case LLCFT_INFO
+ LLC_CMD
:
1871 case LLCFT_INFO
+ LLC_RSP
: {
1872 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1874 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1875 LLC_INC(linkp
->llcl_vr
);
1876 llc_send(linkp
, LLCFT_RR
, LLC_RSP
, 1);
1877 LLC_STOP_REJ_TIMER(linkp
);
1878 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1879 LLC_NEWSTATE(linkp
, AWAIT
);
1880 action
= LLC_DATA_INDICATION
;
1881 } else if (cmdrsp
== LLC_RSP
&& pollfinal
== 1) {
1882 LLC_INC(linkp
->llcl_vr
);
1883 LLC_STOP_P_TIMER(linkp
);
1884 LLC_STOP_REJ_TIMER(linkp
);
1885 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1886 linkp
->llcl_vs
= nr
;
1887 llc_resend(linkp
, LLC_CMD
, 0);
1888 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1889 LLC_NEWSTATE(linkp
, NORMAL
);
1890 action
= LLC_DATA_INDICATION
;
1891 } else if (pollfinal
== 0) {
1892 LLC_INC(linkp
->llcl_vr
);
1893 llc_send(linkp
, LLCFT_RR
, LLC_CMD
, 0);
1894 LLC_STOP_REJ_TIMER(linkp
);
1895 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1896 LLC_NEWSTATE(linkp
, AWAIT
);
1897 action
= LLC_DATA_INDICATION
;
1901 case LLCFT_RR
+ LLC_CMD
:
1902 case LLCFT_REJ
+ LLC_CMD
:
1903 case LLCFT_RR
+ LLC_RSP
:
1904 case LLCFT_REJ
+ LLC_RSP
: {
1905 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1907 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1908 llc_send(linkp
, LLCFT_RR
, LLC_RSP
, 1);
1909 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1910 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1911 } else if (cmdrsp
== LLC_RSP
&& pollfinal
== 1) {
1912 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1913 linkp
->llcl_vs
= nr
;
1914 llc_resend(linkp
, LLC_CMD
, 1);
1915 LLC_START_P_TIMER(linkp
);
1916 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1917 LLC_NEWSTATE(linkp
, REJECT
);
1918 } else if (pollfinal
== 0) {
1919 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1920 LLC_CLEAR_REMOTE_BUSY(linkp
, action
);
1924 case LLCFT_RNR
+ LLC_CMD
:
1925 case LLCFT_RNR
+ LLC_RSP
: {
1926 register int nr
= LLCGBITS(frame
->llc_control_ext
, s_nr
);
1928 if (cmdrsp
== LLC_CMD
&& pollfinal
== 1) {
1929 llc_send(linkp
, LLCFT_RR
, LLC_RSP
, 1);
1930 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1931 LLC_SET_REMOTE_BUSY(linkp
, action
);
1932 } else if (cmdrsp
== LLC_RSP
&& pollfinal
== 1) {
1933 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1934 linkp
->llcl_vs
= nr
;
1935 LLC_STOP_P_TIMER(linkp
);
1936 LLC_SET_REMOTE_BUSY(linkp
, action
);
1937 LLC_NEWSTATE(linkp
, REJECT
);
1938 } else if (pollfinal
== 0) {
1939 LLC_UPDATE_NR_RECEIVED(linkp
, nr
);
1940 LLC_SET_REMOTE_BUSY(linkp
, action
);
1944 case LLC_P_TIMER_EXPIRED
:
1945 if (linkp
->llcl_retry
< llc_n2
) {
1946 llc_send(linkp
, LLCFT_REJ
, LLC_CMD
, 1);
1947 LLC_START_P_TIMER(linkp
);
1948 linkp
->llcl_retry
++;
1953 if (action
== LLC_PASSITON
)
1954 action
= llc_state_NBRAcore(linkp
, frame
, frame_kind
,
1962 * llc_statehandler() --- Wrapper for llc_state_*() functions.
1963 * Deals with action codes and checks for
1968 llc_statehandler(struct llc_linkcb
*linkp
, struct llc
*frame
, int frame_kind
,
1969 int cmdrsp
, int pollfinal
)
1971 register int action
= 0;
1974 * To check for ``zombie'' links each time llc_statehandler() gets called
1975 * the AGE timer of linkp is reset. If it expires llc_timer() will
1976 * take care of the link --- i.e. kill it 8=)
1978 LLC_STARTTIMER(linkp
, AGE
);
1981 * Now call the current statehandler function.
1983 action
= (*linkp
->llcl_statehandler
)(linkp
, frame
, frame_kind
,
1985 once_more_and_again
:
1987 case LLC_CONNECT_INDICATION
: {
1990 LLC_TRACE(linkp
, LLCTR_INTERESTING
, "CONNECT INDICATION");
1991 linkp
->llcl_nlnext
=
1992 (*linkp
->llcl_sapinfo
->si_ctlinput
)
1993 (PRC_CONNECT_INDICATION
,
1994 (struct sockaddr
*) &linkp
->llcl_addr
, (caddr_t
) linkp
);
1995 if (linkp
->llcl_nlnext
== 0)
1996 naction
= NL_DISCONNECT_REQUEST
;
1997 else naction
= NL_CONNECT_RESPONSE
;
1998 action
= (*linkp
->llcl_statehandler
)(linkp
, frame
, naction
, 0, 0);
1999 goto once_more_and_again
;
2001 case LLC_CONNECT_CONFIRM
:
2002 /* llc_resend(linkp, LLC_CMD, 0); */
2005 case LLC_DISCONNECT_INDICATION
:
2006 LLC_TRACE(linkp
, LLCTR_INTERESTING
, "DISCONNECT INDICATION");
2007 (*linkp
->llcl_sapinfo
->si_ctlinput
)
2008 (PRC_DISCONNECT_INDICATION
,
2009 (struct sockaddr
*) &linkp
->llcl_addr
, linkp
->llcl_nlnext
);
2011 /* internally visible only */
2012 case LLC_RESET_CONFIRM
:
2013 case LLC_RESET_INDICATION_LOCAL
:
2015 * not much we can do here, the state machine either makes it or
2019 case LLC_RESET_INDICATION_REMOTE
:
2020 LLC_TRACE(linkp
, LLCTR_SHOULDKNOW
, "RESET INDICATION (REMOTE)");
2021 action
= (*linkp
->llcl_statehandler
)(linkp
, frame
,
2022 NL_RESET_RESPONSE
, 0, 0);
2023 goto once_more_and_again
;
2025 LLC_TRACE(linkp
, LLCTR_URGENT
, "FRMR SENT");
2027 case LLC_FRMR_RECEIVED
:
2028 LLC_TRACE(linkp
, LLCTR_URGEN
, "FRMR RECEIVED");
2029 action
= (*linkp
->llcl_statehandler
)(linkp
, frame
,
2030 NL_RESET_REQUEST
, 0, 0);
2032 goto once_more_and_again
;
2033 case LLC_REMOTE_BUSY
:
2034 LLC_TRACE(linkp
, LLCTR_SHOULDKNOW
, "REMOTE BUSY");
2036 case LLC_REMOTE_NOT_BUSY
:
2037 LLC_TRACE(linkp
, LLCTR_SHOULDKNOW
, "REMOTE BUSY CLEARED");
2039 * try to get queued frames out
2046 * Only LLC_DATA_INDICATION is for the time being
2047 * passed up to the network layer entity.
2048 * The remaining action codes are for the time
2049 * being visible internally only.
2050 * However, this can/may be changed if necessary.
2058 * Core LLC2 routines
2062 * The INIT call. This routine is called once after the system is booted.
2067 llcintrq
.ifq_maxlen
= IFQ_MAXLEN
;
2072 * In case of a link reset we need to shuffle the frames queued inside the
2077 llc_resetwindow(struct llc_linkcb
*linkp
)
2079 register struct mbuf
*mptr
= (struct mbuf
*) 0;
2080 register struct mbuf
*anchor
= (struct mbuf
*)0;
2083 /* Pick up all queued frames and collect them in a linked mbuf list */
2084 if (linkp
->llcl_slotsfree
!= linkp
->llcl_window
) {
2085 i
= llc_seq2slot(linkp
, linkp
->llcl_nr_received
);
2086 anchor
= mptr
= linkp
->llcl_output_buffers
[i
];
2087 for (; i
!= linkp
->llcl_freeslot
;
2088 i
= llc_seq2slot(linkp
, i
+1)) {
2089 if (linkp
->llcl_output_buffers
[i
]) {
2090 mptr
->m_nextpkt
= linkp
->llcl_output_buffers
[i
];
2091 mptr
= mptr
->m_nextpkt
;
2092 } else panic("LLC2 window broken");
2097 mptr
->m_nextpkt
= (struct mbuf
*) 0;
2099 /* Now --- plug 'em in again */
2100 if (anchor
!= (struct mbuf
*)0) {
2101 for (i
= 0, mptr
= anchor
; mptr
!= (struct mbuf
*) 0; i
++) {
2102 linkp
->llcl_output_buffers
[i
] = mptr
;
2103 mptr
= mptr
->m_nextpkt
;
2104 linkp
->llcl_output_buffers
[i
]->m_nextpkt
= (struct mbuf
*)0;
2106 linkp
->llcl_freeslot
= i
;
2107 } else linkp
->llcl_freeslot
= 0;
2109 /* We're resetting the link, the next frame to be acknowledged is 0 */
2110 linkp
->llcl_nr_received
= 0;
2112 /* set distance between LLC2 sequence number and the top of window to 0 */
2113 linkp
->llcl_projvs
= linkp
->llcl_freeslot
;
2119 * llc_newlink() --- We allocate enough memory to contain a link control block
2120 * and initialize it properly. We don't intiate the actual
2121 * setup of the LLC2 link here.
2124 llc_newlink(struct sockaddr_dl
*dst
, struct ifnet
*ifp
, struct rtentry
*nlrt
,
2125 caddr_t nlnext
, struct rtentry
*llrt
)
2127 struct llc_linkcb
*nlinkp
;
2128 u_char sap
= LLSAPADDR(dst
);
2132 /* allocate memory for link control block */
2133 MALLOC(nlinkp
, struct llc_linkcb
*, sizeof(struct llc_linkcb
),
2137 bzero((caddr_t
)nlinkp
, sizeof(struct llc_linkcb
));
2139 /* copy link address */
2140 sdl_copy(dst
, &nlinkp
->llcl_addr
);
2142 /* hold on to the network layer route entry */
2143 nlinkp
->llcl_nlrt
= nlrt
;
2145 /* likewise the network layer control block */
2146 nlinkp
->llcl_nlnext
= nlnext
;
2148 /* jot down the link layer route entry */
2149 nlinkp
->llcl_llrt
= llrt
;
2152 nlinkp
->llcl_writeqh
= nlinkp
->llcl_writeqt
= NULL
;
2154 /* setup initial state handler function */
2155 nlinkp
->llcl_statehandler
= llc_state_ADM
;
2157 /* hold on to interface pointer */
2158 nlinkp
->llcl_if
= ifp
;
2160 /* get service access point information */
2161 nlinkp
->llcl_sapinfo
= llc_getsapinfo(sap
, ifp
);
2163 /* get window size from SAP info block */
2164 if ((llcwindow
= nlinkp
->llcl_sapinfo
->si_window
) == 0)
2165 llcwindow
= LLC_MAX_WINDOW
;
2167 /* allocate memory for window buffer */
2168 MALLOC(nlinkp
->llcl_output_buffers
, struct mbuf
**,
2169 llcwindow
*sizeof(struct mbuf
*), M_PCB
, M_NOWAIT
);
2170 if (nlinkp
->llcl_output_buffers
== 0) {
2171 FREE(nlinkp
, M_PCB
);
2174 bzero((caddr_t
)nlinkp
->llcl_output_buffers
,
2175 llcwindow
*sizeof(struct mbuf
*));
2177 /* set window size & slotsfree */
2178 nlinkp
->llcl_slotsfree
= nlinkp
->llcl_window
= llcwindow
;
2180 /* enter into linked listed of link control blocks */
2181 insque(nlinkp
, &llccb_q
);
2187 * llc_dellink() --- farewell to link control block
2189 llc_dellink(struct llc_linkcb
*linkp
)
2191 register struct mbuf
*m
;
2192 register struct mbuf
*n
;
2193 register struct npaidbentry
*sapinfo
= linkp
->llcl_sapinfo
;
2196 /* notify upper layer of imminent death */
2197 if (linkp
->llcl_nlnext
&& sapinfo
->si_ctlinput
)
2198 (*sapinfo
->si_ctlinput
)
2199 (PRC_DISCONNECT_INDICATION
,
2200 (struct sockaddr
*)&linkp
->llcl_addr
, linkp
->llcl_nlnext
);
2203 if (linkp
->llcl_llrt
)
2204 ((struct npaidbentry
*)(linkp
->llcl_llrt
->rt_llinfo
))->np_link
2205 = (struct llc_linkcb
*) 0;
2207 /* leave link control block queue */
2210 /* drop queued packets */
2211 for (m
= linkp
->llcl_writeqh
; m
;) {
2217 /* drop packets in the window */
2218 for(i
= 0; i
< linkp
->llcl_window
; i
++)
2219 if (linkp
->llcl_output_buffers
[i
])
2220 m_freem(linkp
->llcl_output_buffers
[i
]);
2222 /* return the window space */
2223 FREE((caddr_t
)linkp
->llcl_output_buffers
, M_PCB
);
2225 /* return the control block space --- now it's gone ... */
2226 FREE((caddr_t
)linkp
, M_PCB
);
2229 llc_decode(struct llc
* frame
, struct llc_linkcb
* linkp
)
2231 register int ft
= LLC_BAD_PDU
;
2233 if ((frame
->llc_control
& 01) == 0) {
2235 /* S or U frame ? */
2236 } else switch (frame
->llc_control
) {
2240 case LLC_UI_P
: ft
= LLC_UI
; break;
2242 case LLC_DM_P
: ft
=LLCFT_DM
; break;
2244 case LLC_DISC_P
: ft
= LLCFT_DISC
; break;
2246 case LLC_UA_P
: ft
= LLCFT_UA
; break;
2248 case LLC_SABME_P
: ft
= LLCFT_SABME
; break;
2250 case LLC_FRMR_P
: ft
= LLCFT_FRMR
; break;
2252 case LLC_XID_P
: ft
= LLCFT_XID
; break;
2254 case LLC_TEST_P
: ft
= LLCFT_TEST
; break;
2257 case LLC_RR
: ft
= LLCFT_RR
; break;
2258 case LLC_RNR
: ft
= LLCFT_RNR
; break;
2259 case LLC_REJ
: ft
= LLCFT_REJ
; break;
2265 if (LLCGBITS(frame
->llc_control
, i_ns
) != linkp
->llcl_vr
) {
2266 ft
= LLC_INVALID_NS
;
2269 /* fall thru --- yeeeeeee */
2274 if (LLC_NR_VALID(linkp
, LLCGBITS(frame
->llc_control_ext
,
2276 ft
= LLC_INVALID_NR
;
2285 * llc_anytimersup() --- Checks if at least one timer is still up and running.
2288 llc_anytimersup(struct llc_linkcb
* linkp
)
2292 FOR_ALL_LLC_TIMERS(i
)
2293 if (linkp
->llcl_timers
[i
] > 0)
2295 if (i
== LLC_AGE_SHIFT
)
2301 * llc_link_dump() - dump link info
2304 #define SAL(s) ((struct sockaddr_dl *)&(s)->llcl_addr)
2305 #define CHECK(l, s) if (LLC_STATEEQ(l, s)) return #s
2307 char *timer_names
[] = {"ACK", "P", "BUSY", "REJ", "AGE"};
2310 llc_getstatename(struct llc_linkcb
*linkp
)
2314 CHECK(linkp
, RESET_WAIT
);
2315 CHECK(linkp
, RESET_CHECK
);
2316 CHECK(linkp
, SETUP
);
2317 CHECK(linkp
, RESET
);
2318 CHECK(linkp
, D_CONN
);
2319 CHECK(linkp
, ERROR
);
2320 CHECK(linkp
, NORMAL
);
2322 CHECK(linkp
, REJECT
);
2323 CHECK(linkp
, AWAIT
);
2324 CHECK(linkp
, AWAIT_BUSY
);
2325 CHECK(linkp
, AWAIT_REJECT
);
2327 return "UNKNOWN - eh?";
2331 llc_link_dump(struct llc_linkcb
* linkp
, const char *message
)
2334 register char *state
;
2336 /* print interface */
2337 printf("if %s%d\n", linkp
->llcl_if
->if_name
, linkp
->llcl_if
->if_unit
);
2340 printf(">> %s <<\n", message
);
2342 /* print MAC and LSAP */
2343 printf("llc addr ");
2344 for (i
= 0; i
< (SAL(linkp
)->sdl_alen
)-2; i
++)
2345 printf("%x:", (char)*(LLADDR(SAL(linkp
))+i
) & 0xff);
2346 printf("%x,", (char)*(LLADDR(SAL(linkp
))+i
) & 0xff);
2347 printf("%x\n", (char)*(LLADDR(SAL(linkp
))+i
+1) & 0xff);
2349 /* print state we're in and timers */
2350 printf("state %s, ", llc_getstatename(linkp
));
2351 for (i
= LLC_ACK_SHIFT
; i
< LLC_AGE_SHIFT
; i
++)
2352 printf("%s-%c %d/", timer_names
[i
],
2353 (linkp
->llcl_timerflags
& (1<<i
) ? 'R' : 'S'),
2354 linkp
->llcl_timers
[i
]);
2355 printf("%s-%c %d\n", timer_names
[i
], (linkp
->llcl_timerflags
& (1<<i
) ?
2356 'R' : 'S'), linkp
->llcl_timers
[i
]);
2358 /* print flag values */
2359 printf("flags P %d/F %d/S %d/DATA %d/REMOTE_BUSY %d\n",
2360 LLC_GETFLAG(linkp
, P
), LLC_GETFLAG(linkp
, S
),
2361 LLC_GETFLAG(linkp
, DATA
), LLC_GETFLAG(linkp
, REMOTE_BUSY
));
2363 /* print send and receive state variables, ack, and window */
2364 printf("V(R) %d/V(S) %d/N(R) received %d/window %d/freeslot %d\n",
2365 linkp
->llcl_vs
, linkp
->llcl_vr
, linkp
->llcl_nr_received
,
2366 linkp
->llcl_window
, linkp
->llcl_freeslot
);
2368 /* further expansions can follow here */
2373 llc_trace(struct llc_linkcb
*linkp
, int level
, const char *message
)
2375 if (linkp
->llcl_sapinfo
->si_trace
&& level
> llc_tracelevel
)
2376 llc_link_dump(linkp
, message
);