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