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