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