]> git.saurik.com Git - apple/xnu.git/blob - bsd/netccitt/llc_subr.c
c8c56d1cf15c2c2653582c0452398a300cdb5fe7
[apple/xnu.git] / bsd / netccitt / llc_subr.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
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.
27 *
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.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
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.
47 *
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
58 * SUCH DAMAGE.
59 *
60 * @(#)llc_subr.c 8.1 (Berkeley) 6/10/93
61 */
62
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/mbuf.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>
71 #include <sys/time.h>
72 #include <sys/kernel.h>
73 #include <sys/malloc.h>
74
75 #include <net/if.h>
76 #include <net/if_dl.h>
77 #include <net/if_llc.h>
78 #include <net/route.h>
79
80 #include <netccitt/dll.h>
81 #include <netccitt/llc_var.h>
82
83 /*
84 * Frame names for diagnostic messages
85 */
86 char *frame_names[] = { "INFO", "RR", "RNR", "REJ", "DM", "SABME", "DISC",
87 "UA", "FRMR", "UI", "XID", "TEST", "ILLEGAL", "TIMER", "N2xT1"};
88
89
90 /*
91 * Trace level
92 */
93 int llc_tracelevel = LLCTR_URGENT;
94
95 /*
96 * Values for accessing various bitfields
97 */
98 struct bitslice llc_bitslice[] = {
99 /* mask, shift value */
100 { 0x1, 0x0 },
101 { 0xfe, 0x1 },
102 { 0x3, 0x0 },
103 { 0xc, 0x2 },
104 { 0x10, 0x4 },
105 { 0xe0, 0x5 },
106 { 0x1f, 0x0 }
107 };
108
109 /*
110 * We keep the link control blocks on a doubly linked list -
111 * primarily for checking in llc_time()
112 */
113
114 struct llccb_q llccb_q = { &llccb_q, &llccb_q };
115
116 /*
117 * Flag for signalling wether route tree for AF_LINK has been
118 * initialized yet.
119 */
120
121 int af_link_rts_init_done = 0;
122
123
124 /*
125 * Functions dealing with struct sockaddr_dl */
126
127 /* Compare sdl_a w/ sdl_b */
128
129 sdl_cmp(struct sockaddr_dl *sdl_a, struct sockaddr_dl *sdl_b)
130 {
131 if (LLADDRLEN(sdl_a) != LLADDRLEN(sdl_b))
132 return(1);
133 return(bcmp((caddr_t) sdl_a->sdl_data, (caddr_t) sdl_b->sdl_data,
134 LLADDRLEN(sdl_a)));
135 }
136
137 /* Copy sdl_f to sdl_t */
138
139 sdl_copy(struct sockaddr_dl *sdl_f, struct sockaddr_dl *sdl_t)
140 {
141 bcopy((caddr_t) sdl_f, (caddr_t) sdl_t, sdl_f->sdl_len);
142 }
143
144 /* Swap sdl_a w/ sdl_b */
145
146 sdl_swapaddr(struct sockaddr_dl *sdl_a, struct sockaddr_dl *sdl_b)
147 {
148 struct sockaddr_dl sdl_tmp;
149
150 sdl_copy(sdl_a, &sdl_tmp);
151 sdl_copy(sdl_b, sdl_a);
152 sdl_copy(&sdl_tmp, sdl_b);
153 }
154
155 /* Fetch the sdl of the associated if */
156
157 struct sockaddr_dl *
158 sdl_getaddrif(struct ifnet *ifp)
159 {
160 register struct ifaddr *ifa;
161
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));
165
166 return((struct sockaddr_dl *)0);
167 }
168
169 /* Check addr of interface with the one given */
170
171 sdl_checkaddrif(struct ifnet *ifp, struct sockaddr_dl *sdl_c)
172 {
173 register struct ifaddr *ifa;
174
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))
178 return(1);
179
180 return(0);
181 }
182
183 /* Build an sdl from MAC addr, DLSAP addr, and interface */
184
185 sdl_setaddrif(struct ifnet *ifp, u_char *mac_addr, u_char dlsap_addr,
186 u_char mac_len, struct sockaddr_dl *sdl_to)
187 {
188 register struct sockaddr_dl *sdl_tmp;
189
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;
195 return(1);
196 } else return(0);
197 }
198
199 /* Fill out the sdl header aggregate */
200
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)
203 {
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) )
208 return(0);
209 else return(1);
210 }
211
212 static struct sockaddr_dl sap_saddr;
213 static struct sockaddr_dl sap_sgate = {
214 sizeof(struct sockaddr_dl), /* _len */
215 AF_LINK /* _af */
216 };
217
218 /*
219 * Set sapinfo for SAP address, llcconfig, af, and interface
220 */
221 struct npaidbentry *
222 llc_setsapinfo(struct ifnet *ifp, u_char af, u_char sap, struct dllconfig *llconf)
223 {
224 struct protosw *pp;
225 struct sockaddr_dl *ifdl_addr;
226 struct rtentry *sirt = (struct rtentry *)0;
227 struct npaidbentry *sapinfo;
228 u_char saploc;
229 int size = sizeof(struct npaidbentry);
230
231 USES_AF_LINK_RTS;
232
233 /*
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.
237 */
238 pp = pffindtype (af, SOCK_STREAM);
239 if (pp == 0 || pp->pr_input == 0 || pp->pr_ctlinput == 0) {
240 printf("network level protosw error");
241 return 0;
242 }
243
244 /*
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.
248 */
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++;
255
256 /* now enter it */
257 rtrequest(RTM_ADD, (struct sockaddr *)&sap_saddr,
258 (struct sockaddr *)&sap_sgate, 0, 0, &sirt);
259 if (sirt == 0)
260 return 0;
261
262 /* Plug in config information in rt->rt_llinfo */
263
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;
267 if (sapinfo) {
268 bzero ((caddr_t)sapinfo, size);
269 /*
270 * For the time being we support LLC CLASS II here
271 * only
272 */
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)
277 llc_tracelevel--;
278 else llc_tracelevel++;
279 sapinfo->si_input = pp->pr_input;
280 sapinfo->si_ctlinput = (caddr_t (*)())pp->pr_ctlinput;
281
282 return (sapinfo);
283 }
284
285 return 0;
286 }
287
288 /*
289 * Get sapinfo for SAP address and interface
290 */
291 struct npaidbentry *
292 llc_getsapinfo(u_char sap, struct ifnet *ifp)
293 {
294 struct sockaddr_dl *ifdl_addr;
295 struct sockaddr_dl si_addr;
296 struct rtentry *sirt;
297 u_char saploc;
298
299 USES_AF_LINK_RTS;
300
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;
305 si_addr.sdl_alen++;
306
307 if ((sirt = rtalloc1((struct sockaddr *)&si_addr, 0)))
308 sirt->rt_refcnt--;
309 else return(0);
310
311 return((struct npaidbentry *)sirt->rt_llinfo);
312 }
313
314 /*
315 * llc_seq2slot() --- We only allocate enough memory to hold the window. This
316 * introduces the necessity to keep track of two ``pointers''
317 *
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
323 *
324 * A new frame is inserted at llcl_output_buffers[llcl_freeslot], after
325 * which both llcl_freeslot and llcl_projvs are incremented.
326 *
327 * The slot sl(sn) for any given sequence number sn is given by
328 *
329 * sl(sn) = (llcl_freeslot + llcl_window - 1 - (llcl_projvs +
330 * LLC_MAX_SEQUENCE- sn) % LLC_MAX_SEQUENCE) %
331 * llcl_window
332 *
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).
337 */
338
339 short
340 llc_seq2slot(struct llc_linkcb *linkp, short seqn)
341 {
342 register sn = 0;
343
344 sn = (linkp->llcl_freeslot + linkp->llcl_window -
345 (linkp->llcl_projvs + LLC_MAX_SEQUENCE - seqn) %
346 LLC_MAX_SEQUENCE) % linkp->llcl_window;
347
348 return sn;
349 }
350
351 /*
352 * LLC2 link state handler
353 *
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].
361 *
362 * [Preceeding each state handler function is the description as taken from
363 * ISO 8802-2, section 7.9.2.1]
364 */
365
366 /*
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''.
373 */
374 int
375 llc_state_ADM(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
376 int cmdrsp, int pollfinal)
377 {
378 int action = 0;
379
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);
387 break;
388 case LLCFT_SABME + LLC_CMD:
389 /*
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 ...
394 */
395 LLC_SETFLAG(linkp, F, pollfinal);
396 LLC_NEWSTATE(linkp, CONN);
397 action = LLC_CONNECT_INDICATION;
398 break;
399 case LLCFT_DISC + LLC_CMD:
400 llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal);
401 break;
402 default:
403 if (cmdrsp == LLC_CMD && pollfinal == 1)
404 llc_send(linkp, LLCFT_DM, LLC_RSP, 1);
405 /* remain in ADM state */
406 }
407
408 return action;
409 }
410
411 /*
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.
415 */
416 int
417 llc_state_CONN(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
418 int cmdrsp, int pollfinal)
419 {
420 int action = 0;
421
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);
429 break;
430 case NL_DISCONNECT_REQUEST:
431 llc_send(linkp, LLCFT_DM, LLC_RSP, LLC_GETFLAG(linkp, F));
432 LLC_NEWSTATE(linkp, ADM);
433 break;
434 case LLCFT_SABME + LLC_CMD:
435 LLC_SETFLAG(linkp, F, pollfinal);
436 break;
437 case LLCFT_DM + LLC_RSP:
438 LLC_NEWSTATE(linkp, ADM);
439 action = LLC_DISCONNECT_INDICATION;
440 break;
441 /* all other frames effect nothing here */
442 }
443
444 return action;
445 }
446
447 /*
448 * RESET_WAIT --- The local connection component is waiting for the local user
449 * to indicate a RESET_REQUEST or a DISCONNECT_REQUEST.
450 */
451 int
452 llc_state_RESET_WAIT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
453 int cmdrsp, int pollfinal)
454 {
455 int action = 0;
456
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);
465 } else {
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;
473 }
474 break;
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);
482 } else {
483 llc_send(linkp, LLCFT_DM, LLC_RSP,
484 LLC_GETFLAG(linkp, F));
485 LLC_NEWSTATE(linkp, ADM);
486 }
487 break;
488 case LLCFT_DM + LLC_RSP:
489 LLC_NEWSTATE(linkp, ADM);
490 action = LLC_DISCONNECT_INDICATION;
491 break;
492 case LLCFT_SABME + LLC_CMD:
493 LLC_SETFLAG(linkp, S, 1);
494 LLC_SETFLAG(linkp, F, pollfinal);
495 break;
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;
500 break;
501 }
502
503 return action;
504 }
505
506 /*
507 * RESET_CHECK --- The local connection component is waiting for the local user
508 * to accept or refuse a remote reset request.
509 */
510 int
511 llc_state_RESET_CHECK(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
512 int cmdrsp, int pollfinal)
513 {
514 int action = 0;
515
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);
523 break;
524 case NL_DISCONNECT_REQUEST:
525 llc_send(linkp, LLCFT_DM, LLC_RSP, LLC_GETFLAG(linkp, F));
526 LLC_NEWSTATE(linkp, ADM);
527 break;
528 case LLCFT_DM + LLC_RSP:
529 action = LLC_DISCONNECT_INDICATION;
530 break;
531 case LLCFT_SABME + LLC_CMD:
532 LLC_SETFLAG(linkp, F, pollfinal);
533 break;
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;
538 break;
539 }
540
541 return action;
542 }
543
544 /*
545 * SETUP --- The connection component has transmitted an SABME command PDU to a
546 * remote LLC DSAP and is waiting for a reply.
547 */
548 int
549 llc_state_SETUP(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
550 int cmdrsp, int pollfinal)
551 {
552 int action = 0;
553
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);
559 break;
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;
568 }
569 break;
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);
580 linkp->llcl_retry++;
581 } else {
582 LLC_NEWSTATE(linkp, ADM);
583 action = LLC_DISCONNECT_INDICATION;
584 }
585 break;
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;
591 break;
592 case LLCFT_DM + LLC_RSP:
593 LLC_STOP_ACK_TIMER(linkp);
594 LLC_NEWSTATE(linkp, ADM);
595 action = LLC_DISCONNECT_INDICATION;
596 break;
597 }
598
599 return action;
600 }
601
602 /*
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.
607 */
608 int
609 llc_state_RESET(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
610 int cmdrsp, int pollfinal)
611 {
612 int action = 0;
613
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);
619 break;
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;
628 }
629 break;
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);
640 linkp->llcl_retry++;
641 } else {
642 LLC_NEWSTATE(linkp, ADM);
643 action = LLC_DISCONNECT_INDICATION;
644 }
645 break;
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;
651 break;
652 case LLCFT_DM + LLC_RSP:
653 LLC_STOP_ACK_TIMER(linkp);
654 LLC_NEWSTATE(linkp, ADM);
655 action = LLC_DISCONNECT_INDICATION;
656 break;
657 }
658
659 return action;
660 }
661
662 /*
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
665 * for a reply.
666 */
667 int
668 llc_state_D_CONN(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
669 int cmdrsp, int pollfinal)
670 {
671 int action = 0;
672
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);
678 break;
679 case LLCFT_UA + LLC_RSP:
680 if (LLC_GETFLAG(linkp, P) == pollfinal) {
681 LLC_STOP_ACK_TIMER(linkp);
682 LLC_NEWSTATE(linkp, ADM);
683 }
684 break;
685 case LLCFT_DISC + LLC_CMD:
686 llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal);
687 break;
688 case LLCFT_DM + LLC_RSP:
689 LLC_STOP_ACK_TIMER(linkp);
690 LLC_NEWSTATE(linkp, ADM);
691 break;
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);
697 linkp->llcl_retry++;
698 } else LLC_NEWSTATE(linkp, ADM);
699 break;
700 }
701
702 return action;
703 }
704
705 /*
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.
709 */
710 int
711 llc_state_ERROR(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
712 int cmdrsp, int pollfinal)
713 {
714 int action = 0;
715
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;
721 break;
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;
727 break;
728 case LLCFT_DM + LLC_RSP:
729 LLC_STOP_ACK_TIMER(linkp);
730 LLC_NEWSTATE(linkp, ADM);
731 action = LLC_DISCONNECT_INDICATION;
732 break;
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;
738 break;
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);
743 linkp->llcl_retry++;
744 } else {
745 LLC_SETFLAG(linkp, S, 0);
746 LLC_NEWSTATE(linkp, RESET_WAIT);
747 action = LLC_RESET_INDICATION_LOCAL;
748 }
749 break;
750 default:
751 if (cmdrsp == LLC_CMD){
752 llc_send(linkp, LLCFT_FRMR, LLC_RSP, pollfinal);
753 LLC_START_ACK_TIMER(linkp);
754 }
755 break;
756
757 }
758
759 return action;
760 }
761
762 /*
763 * NORMAL, BUSY, REJECT, AWAIT, AWAIT_BUSY, and AWAIT_REJECT all share
764 * a common core state handler.
765 */
766 int
767 llc_state_NBRAcore(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
768 int cmdrsp, int pollfinal)
769 {
770 int action = 0;
771
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);
780 break;
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);
789 break;
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;
795 break;
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;
801 break;
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;
807 break;
808 case LLCFT_DM + LLC_RSP:
809 LLC_STOP_ALL_TIMERS(linkp);
810 LLC_NEWSTATE(linkp, ADM);
811 action = LLC_DISCONNECT_INDICATION;
812 break;
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;
824 break;
825 case LLC_INVALID_NR + LLC_RSP:
826 case LLC_INVALID_NS + LLC_RSP:
827 case LLCFT_UA + LLC_RSP:
828 case LLC_BAD_PDU: {
829 char frmrcause = 0;
830
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;
835 }
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;
843 break;
844 }
845 default:
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;
854 }
855 break;
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;
865 }
866 break;
867 }
868
869 return action;
870 }
871
872 /*
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.
876 */
877 int
878 llc_state_NORMAL(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
879 int cmdrsp, int pollfinal)
880 {
881 int action = LLC_PASSITON;
882
883 switch(frame_kind + cmdrsp) {
884 case NL_DATA_REQUEST:
885 if (LLC_GETFLAG(linkp, REMOTE_BUSY) == 0) {
886 #ifdef not_now
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);
893 } else {
894 #endif
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);
899 #ifdef not_now
900 }
901 #endif
902 action = 0;
903 }
904 break;
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);
913 action = 0;
914 } else {
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);
919 action = 0;
920 }
921 break;
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);
926
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);
932 action = 0;
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);
938 action = 0;
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);
947 } else action = 0;
948 LLC_NEWSTATE(linkp, REJECT);
949 }
950 break;
951 }
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);
956
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;
976 }
977 break;
978 }
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);
983
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);
993 }
994 break;
995 }
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);
1000
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);
1010 }
1011 break;
1012 }
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);
1017
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);
1035 }
1036 break;
1037 }
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);
1042 action = 0;
1043 }
1044 break;
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);
1051 action = 0;
1052 }
1053 break;
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);
1062 action = 0;
1063 }
1064 break;
1065 }
1066 if (action == LLC_PASSITON)
1067 action = llc_state_NBRAcore(linkp, frame, frame_kind,
1068 cmdrsp, pollfinal);
1069
1070 return action;
1071 }
1072
1073 /*
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
1078 * and received.
1079 */
1080 int
1081 llc_state_BUSY(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
1082 int cmdrsp, int pollfinal)
1083 {
1084 int action = LLC_PASSITON;
1085
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);
1094 action = 0;
1095 } else {
1096 llc_send(linkp, LLCFT_INFO, LLC_CMD, 0);
1097 if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING)
1098 LLC_START_ACK_TIMER(linkp);
1099 action = 0;
1100 }
1101 break;
1102 case LLC_LOCAL_BUSY_CLEARED: {
1103 register int p = LLC_GETFLAG(linkp, P);
1104 register int df = LLC_GETFLAG(linkp, DATA);
1105
1106 switch (df) {
1107 case 1:
1108 if (p == 0) {
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);
1114 action = 0;
1115 } else {
1116 llc_send(linkp, LLCFT_REJ, LLC_CMD, 0);
1117 LLC_START_REJ_TIMER(linkp);
1118 LLC_NEWSTATE(linkp, REJECT);
1119 action = 0;
1120 }
1121 break;
1122 case 0:
1123 if (p == 0) {
1124 /* multiple possibilities */
1125 llc_send(linkp, LLCFT_RR, LLC_CMD, 1);
1126 LLC_START_P_TIMER(linkp);
1127 LLC_NEWSTATE(linkp, NORMAL);
1128 action = 0;
1129 } else {
1130 llc_send(linkp, LLCFT_RR, LLC_CMD, 0);
1131 LLC_NEWSTATE(linkp, NORMAL);
1132 action = 0;
1133 }
1134 break;
1135 case 2:
1136 if (p == 0) {
1137 /* multiple possibilities */
1138 llc_send(linkp, LLCFT_RR, LLC_CMD, 1);
1139 LLC_START_P_TIMER(linkp);
1140 LLC_NEWSTATE(linkp, REJECT);
1141 action = 0;
1142 } else {
1143 llc_send(linkp, LLCFT_RR, LLC_CMD, 0);
1144 LLC_NEWSTATE(linkp, REJECT);
1145 action =0;
1146 }
1147 break;
1148 }
1149 break;
1150 }
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);
1155
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);
1161 action = 0;
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);
1171 } else action = 0;
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);
1177 action = 0;
1178 }
1179 break;
1180 }
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);
1185
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;
1213 }
1214 break;
1215 }
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);
1222
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);
1228 } else {
1229 LLC_SET_REMOTE_BUSY(linkp, action);
1230 }
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);
1237 } else {
1238 LLC_SET_REMOTE_BUSY(linkp, action);
1239 }
1240 }
1241 break;
1242 }
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);
1247
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);
1266 }
1267 break;
1268 }
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);
1273 action = 0;
1274 }
1275 break;
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);
1283 action = 0;
1284 }
1285 break;
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);
1293 action = 0;
1294 }
1295 break;
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);
1305 action = 0;
1306 } else{
1307 LLC_SETFLAG(linkp, DATA, 1);
1308 LLC_NEWSTATE(linkp, BUSY);
1309 action = 0;
1310 }
1311
1312 break;
1313 }
1314 if (action == LLC_PASSITON)
1315 action = llc_state_NBRAcore(linkp, frame, frame_kind,
1316 cmdrsp, pollfinal);
1317
1318 return action;
1319 }
1320
1321 /*
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.
1328 */
1329 int
1330 llc_state_REJECT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
1331 int cmdrsp, int pollfinal)
1332 {
1333 int action = LLC_PASSITON;
1334
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);
1343 action = 0;
1344 } else {
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);
1349 action = 0;
1350 }
1351 break;
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);
1358 action = 0;
1359 } else {
1360 llc_send(linkp, LLCFT_RNR, LLC_CMD, 0);
1361 LLC_SETFLAG(linkp, DATA, 2);
1362 LLC_NEWSTATE(linkp, BUSY);
1363 action = 0;
1364 }
1365 break;
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);
1370
1371 if (cmdrsp == LLC_CMD && pollfinal == 1) {
1372 llc_send(linkp, LLCFT_RR, LLC_RSP, 1);
1373 LLC_UPDATE_NR_RECEIVED(linkp, nr);
1374 action = 0;
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);
1381 } else action = 0;
1382 }
1383 break;
1384 }
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);
1389
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;
1414 }
1415 break;
1416 }
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);
1421
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);
1431 }
1432 break;
1433 }
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);
1438
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);
1447 action = 0;
1448 }
1449 break;
1450 }
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);
1455
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);
1473 }
1474 break;
1475 }
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);
1480 action = 0;
1481 }
1482 break;
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++;
1489 action = 0;
1490 }
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);
1498 action = 0;
1499 }
1500 break;
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++;
1508 /*
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 ...
1512 */
1513 linkp->llcl_vs = 0; /* XXX */
1514 LLC_NEWSTATE(linkp, AWAIT_REJECT);
1515 action = 0;
1516 }
1517
1518 break;
1519 }
1520 if (action == LLC_PASSITON)
1521 action = llc_state_NBRAcore(linkp, frame, frame_kind,
1522 cmdrsp, pollfinal);
1523
1524 return action;
1525 }
1526
1527 /*
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.
1534 */
1535 int
1536 llc_state_AWAIT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
1537 int cmdrsp, int pollfinal)
1538 {
1539 int action = LLC_PASSITON;
1540
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);
1546 action = 0;
1547 break;
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);
1552
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);
1558 action = 0;
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);
1573 action = 0;
1574 }
1575 break;
1576 }
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);
1581
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;
1599 }
1600 break;
1601 }
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);
1608
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);
1623 }
1624 break;
1625 }
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);
1630
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);
1644 }
1645 break;
1646 }
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++;
1652 action = 0;
1653 }
1654 break;
1655 }
1656 if (action == LLC_PASSITON)
1657 action = llc_state_NBRAcore(linkp, frame, frame_kind,
1658 cmdrsp, pollfinal);
1659
1660 return action;
1661 }
1662
1663 /*
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.
1672 */
1673 int
1674 llc_state_AWAIT_BUSY(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
1675 int cmdrsp, int pollfinal)
1676 {
1677 int action = LLC_PASSITON;
1678
1679 switch(frame_kind + cmdrsp) {
1680 case LLC_LOCAL_BUSY_CLEARED:
1681 switch (LLC_GETFLAG(linkp, DATA)) {
1682 case 1:
1683 llc_send(linkp, LLCFT_REJ, LLC_CMD, 0);
1684 LLC_START_REJ_TIMER(linkp);
1685 LLC_NEWSTATE(linkp, AWAIT_REJECT);
1686 action = 0;
1687 break;
1688 case 0:
1689 llc_send(linkp, LLCFT_RR, LLC_CMD, 0);
1690 LLC_NEWSTATE(linkp, AWAIT);
1691 action = 0;
1692 break;
1693 case 2:
1694 llc_send(linkp, LLCFT_RR, LLC_CMD, 0);
1695 LLC_NEWSTATE(linkp, AWAIT_REJECT);
1696 action = 0;
1697 break;
1698 }
1699 break;
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);
1704
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);
1709 action = 0;
1710 } else if (cmdrsp == LLC_RSP && pollfinal == 1) {
1711 /* optionally */
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) {
1721 /* optionally */
1722 llc_send(linkp, LLCFT_RNR, LLC_CMD, 0);
1723 LLC_UPDATE_NR_RECEIVED(linkp, nr);
1724 LLC_SETFLAG(linkp, DATA, 1);
1725 action = 0;
1726 }
1727 }
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);
1732
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;
1756 }
1757 break;
1758 }
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);
1765
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);
1783 }
1784 break;
1785 }
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);
1790
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);
1804 }
1805 break;
1806 }
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++;
1812 action = 0;
1813 }
1814 break;
1815 }
1816 if (action == LLC_PASSITON)
1817 action = llc_state_NBRAcore(linkp, frame, frame_kind,
1818 cmdrsp, pollfinal);
1819
1820 return action;
1821 }
1822
1823 /*
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.
1835 */
1836 int
1837 llc_state_AWAIT_REJECT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
1838 int cmdrsp, int pollfinal)
1839 {
1840 int action = LLC_PASSITON;
1841
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);
1847 action = 0;
1848 break;
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);
1852
1853 if (cmdrsp == LLC_CMD && pollfinal == 1) {
1854 llc_send(linkp, LLCFT_RR, LLC_RSP, 1);
1855 LLC_UPDATE_NR_RECEIVED(linkp, nr);
1856 action = 0;
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);
1866 action = 0;
1867 }
1868 break;
1869 }
1870 case LLCFT_INFO + LLC_CMD:
1871 case LLCFT_INFO + LLC_RSP: {
1872 register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
1873
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;
1898 }
1899 break;
1900 }
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);
1906
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);
1921 }
1922 break;
1923 }
1924 case LLCFT_RNR + LLC_CMD:
1925 case LLCFT_RNR + LLC_RSP: {
1926 register int nr = LLCGBITS(frame->llc_control_ext, s_nr);
1927
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);
1941 }
1942 break;
1943 }
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++;
1949 action = 0;
1950 }
1951 break;
1952 }
1953 if (action == LLC_PASSITON)
1954 action = llc_state_NBRAcore(linkp, frame, frame_kind,
1955 cmdrsp, pollfinal);
1956
1957 return action;
1958 }
1959
1960
1961 /*
1962 * llc_statehandler() --- Wrapper for llc_state_*() functions.
1963 * Deals with action codes and checks for
1964 * ``stuck'' links.
1965 */
1966
1967 int
1968 llc_statehandler(struct llc_linkcb *linkp, struct llc *frame, int frame_kind,
1969 int cmdrsp, int pollfinal)
1970 {
1971 register int action = 0;
1972
1973 /*
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=)
1977 */
1978 LLC_STARTTIMER(linkp, AGE);
1979
1980 /*
1981 * Now call the current statehandler function.
1982 */
1983 action = (*linkp->llcl_statehandler)(linkp, frame, frame_kind,
1984 cmdrsp, pollfinal);
1985 once_more_and_again:
1986 switch (action) {
1987 case LLC_CONNECT_INDICATION: {
1988 int naction;
1989
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;
2000 }
2001 case LLC_CONNECT_CONFIRM:
2002 /* llc_resend(linkp, LLC_CMD, 0); */
2003 llc_start(linkp);
2004 break;
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);
2010 break;
2011 /* internally visible only */
2012 case LLC_RESET_CONFIRM:
2013 case LLC_RESET_INDICATION_LOCAL:
2014 /*
2015 * not much we can do here, the state machine either makes it or
2016 * brakes it ...
2017 */
2018 break;
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;
2024 case LLC_FRMR_SENT:
2025 LLC_TRACE(linkp, LLCTR_URGENT, "FRMR SENT");
2026 break;
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);
2031
2032 goto once_more_and_again;
2033 case LLC_REMOTE_BUSY:
2034 LLC_TRACE(linkp, LLCTR_SHOULDKNOW, "REMOTE BUSY");
2035 break;
2036 case LLC_REMOTE_NOT_BUSY:
2037 LLC_TRACE(linkp, LLCTR_SHOULDKNOW, "REMOTE BUSY CLEARED");
2038 /*
2039 * try to get queued frames out
2040 */
2041 llc_start(linkp);
2042 break;
2043 }
2044
2045 /*
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.
2051 */
2052
2053 return action;
2054 }
2055
2056
2057 /*
2058 * Core LLC2 routines
2059 */
2060
2061 /*
2062 * The INIT call. This routine is called once after the system is booted.
2063 */
2064
2065 llc_init()
2066 {
2067 llcintrq.ifq_maxlen = IFQ_MAXLEN;
2068 }
2069
2070
2071 /*
2072 * In case of a link reset we need to shuffle the frames queued inside the
2073 * LLC2 window.
2074 */
2075
2076 void
2077 llc_resetwindow(struct llc_linkcb *linkp)
2078 {
2079 register struct mbuf *mptr = (struct mbuf *) 0;
2080 register struct mbuf *anchor = (struct mbuf *)0;
2081 register short i;
2082
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");
2093 }
2094 }
2095 /* clean closure */
2096 if (mptr)
2097 mptr->m_nextpkt = (struct mbuf *) 0;
2098
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;
2105 }
2106 linkp->llcl_freeslot = i;
2107 } else linkp->llcl_freeslot = 0;
2108
2109 /* We're resetting the link, the next frame to be acknowledged is 0 */
2110 linkp->llcl_nr_received = 0;
2111
2112 /* set distance between LLC2 sequence number and the top of window to 0 */
2113 linkp->llcl_projvs = linkp->llcl_freeslot;
2114
2115 return;
2116 }
2117
2118 /*
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.
2122 */
2123 struct llc_linkcb *
2124 llc_newlink(struct sockaddr_dl *dst, struct ifnet *ifp, struct rtentry *nlrt,
2125 caddr_t nlnext, struct rtentry *llrt)
2126 {
2127 struct llc_linkcb *nlinkp;
2128 u_char sap = LLSAPADDR(dst);
2129 short llcwindow;
2130
2131
2132 /* allocate memory for link control block */
2133 MALLOC(nlinkp, struct llc_linkcb *, sizeof(struct llc_linkcb),
2134 M_PCB, M_NOWAIT);
2135 if (nlinkp == 0)
2136 return (NULL);
2137 bzero((caddr_t)nlinkp, sizeof(struct llc_linkcb));
2138
2139 /* copy link address */
2140 sdl_copy(dst, &nlinkp->llcl_addr);
2141
2142 /* hold on to the network layer route entry */
2143 nlinkp->llcl_nlrt = nlrt;
2144
2145 /* likewise the network layer control block */
2146 nlinkp->llcl_nlnext = nlnext;
2147
2148 /* jot down the link layer route entry */
2149 nlinkp->llcl_llrt = llrt;
2150
2151 /* reset writeq */
2152 nlinkp->llcl_writeqh = nlinkp->llcl_writeqt = NULL;
2153
2154 /* setup initial state handler function */
2155 nlinkp->llcl_statehandler = llc_state_ADM;
2156
2157 /* hold on to interface pointer */
2158 nlinkp->llcl_if = ifp;
2159
2160 /* get service access point information */
2161 nlinkp->llcl_sapinfo = llc_getsapinfo(sap, ifp);
2162
2163 /* get window size from SAP info block */
2164 if ((llcwindow = nlinkp->llcl_sapinfo->si_window) == 0)
2165 llcwindow = LLC_MAX_WINDOW;
2166
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);
2172 return(NULL);
2173 }
2174 bzero((caddr_t)nlinkp->llcl_output_buffers,
2175 llcwindow*sizeof(struct mbuf *));
2176
2177 /* set window size & slotsfree */
2178 nlinkp->llcl_slotsfree = nlinkp->llcl_window = llcwindow;
2179
2180 /* enter into linked listed of link control blocks */
2181 insque(nlinkp, &llccb_q);
2182
2183 return(nlinkp);
2184 }
2185
2186 /*
2187 * llc_dellink() --- farewell to link control block
2188 */
2189 llc_dellink(struct llc_linkcb *linkp)
2190 {
2191 register struct mbuf *m;
2192 register struct mbuf *n;
2193 register struct npaidbentry *sapinfo = linkp->llcl_sapinfo;
2194 register i;
2195
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);
2201
2202 /* pull the plug */
2203 if (linkp->llcl_llrt)
2204 ((struct npaidbentry *)(linkp->llcl_llrt->rt_llinfo))->np_link
2205 = (struct llc_linkcb *) 0;
2206
2207 /* leave link control block queue */
2208 remque(linkp);
2209
2210 /* drop queued packets */
2211 for (m = linkp->llcl_writeqh; m;) {
2212 n = m->m_act;
2213 m_freem(m);
2214 m = n;
2215 }
2216
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]);
2221
2222 /* return the window space */
2223 FREE((caddr_t)linkp->llcl_output_buffers, M_PCB);
2224
2225 /* return the control block space --- now it's gone ... */
2226 FREE((caddr_t)linkp, M_PCB);
2227 }
2228
2229 llc_decode(struct llc* frame, struct llc_linkcb * linkp)
2230 {
2231 register int ft = LLC_BAD_PDU;
2232
2233 if ((frame->llc_control & 01) == 0) {
2234 ft = LLCFT_INFO;
2235 /* S or U frame ? */
2236 } else switch (frame->llc_control) {
2237
2238 /* U frames */
2239 case LLC_UI:
2240 case LLC_UI_P: ft = LLC_UI; break;
2241 case LLC_DM:
2242 case LLC_DM_P: ft =LLCFT_DM; break;
2243 case LLC_DISC:
2244 case LLC_DISC_P: ft = LLCFT_DISC; break;
2245 case LLC_UA:
2246 case LLC_UA_P: ft = LLCFT_UA; break;
2247 case LLC_SABME:
2248 case LLC_SABME_P: ft = LLCFT_SABME; break;
2249 case LLC_FRMR:
2250 case LLC_FRMR_P: ft = LLCFT_FRMR; break;
2251 case LLC_XID:
2252 case LLC_XID_P: ft = LLCFT_XID; break;
2253 case LLC_TEST:
2254 case LLC_TEST_P: ft = LLCFT_TEST; break;
2255
2256 /* S frames */
2257 case LLC_RR: ft = LLCFT_RR; break;
2258 case LLC_RNR: ft = LLCFT_RNR; break;
2259 case LLC_REJ: ft = LLCFT_REJ; break;
2260 } /* switch */
2261
2262 if (linkp) {
2263 switch (ft) {
2264 case LLCFT_INFO:
2265 if (LLCGBITS(frame->llc_control, i_ns) != linkp->llcl_vr) {
2266 ft = LLC_INVALID_NS;
2267 break;
2268 }
2269 /* fall thru --- yeeeeeee */
2270 case LLCFT_RR:
2271 case LLCFT_RNR:
2272 case LLCFT_REJ:
2273 /* splash! */
2274 if (LLC_NR_VALID(linkp, LLCGBITS(frame->llc_control_ext,
2275 s_nr)) == 0)
2276 ft = LLC_INVALID_NR;
2277 break;
2278 }
2279 }
2280
2281 return ft;
2282 }
2283
2284 /*
2285 * llc_anytimersup() --- Checks if at least one timer is still up and running.
2286 */
2287 int
2288 llc_anytimersup(struct llc_linkcb * linkp)
2289 {
2290 register int i;
2291
2292 FOR_ALL_LLC_TIMERS(i)
2293 if (linkp->llcl_timers[i] > 0)
2294 break;
2295 if (i == LLC_AGE_SHIFT)
2296 return 0;
2297 else return 1;
2298 }
2299
2300 /*
2301 * llc_link_dump() - dump link info
2302 */
2303
2304 #define SAL(s) ((struct sockaddr_dl *)&(s)->llcl_addr)
2305 #define CHECK(l, s) if (LLC_STATEEQ(l, s)) return #s
2306
2307 char *timer_names[] = {"ACK", "P", "BUSY", "REJ", "AGE"};
2308
2309 char *
2310 llc_getstatename(struct llc_linkcb *linkp)
2311 {
2312 CHECK(linkp, ADM);
2313 CHECK(linkp, CONN);
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);
2321 CHECK(linkp, BUSY);
2322 CHECK(linkp, REJECT);
2323 CHECK(linkp, AWAIT);
2324 CHECK(linkp, AWAIT_BUSY);
2325 CHECK(linkp, AWAIT_REJECT);
2326
2327 return "UNKNOWN - eh?";
2328 }
2329
2330 void
2331 llc_link_dump(struct llc_linkcb* linkp, const char *message)
2332 {
2333 register int i;
2334 register char *state;
2335
2336 /* print interface */
2337 printf("if %s%d\n", linkp->llcl_if->if_name, linkp->llcl_if->if_unit);
2338
2339 /* print message */
2340 printf(">> %s <<\n", message);
2341
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);
2348
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]);
2357
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));
2362
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);
2367
2368 /* further expansions can follow here */
2369
2370 }
2371
2372 void
2373 llc_trace(struct llc_linkcb *linkp, int level, const char *message)
2374 {
2375 if (linkp->llcl_sapinfo->si_trace && level > llc_tracelevel)
2376 llc_link_dump(linkp, message);
2377
2378 return;
2379 }