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