xref: /csrg-svn/sys/netccitt/pk_subr.c (revision 49018)
1 /*
2  * Copyright (c) University of British Columbia, 1984
3  * Copyright (c) 1990 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * the Laboratory for Computation Vision and the Computer Science Department
8  * of the University of British Columbia.
9  *
10  * %sccs.include.redist.c%
11  *
12  *	@(#)pk_subr.c	7.12 (Berkeley) 05/03/91
13  */
14 
15 #include "param.h"
16 #include "systm.h"
17 #include "mbuf.h"
18 #include "socket.h"
19 #include "protosw.h"
20 #include "socketvar.h"
21 #include "errno.h"
22 #include "time.h"
23 #include "kernel.h"
24 
25 #include "../net/if.h"
26 
27 #include "x25.h"
28 #include "pk.h"
29 #include "pk_var.h"
30 #include "x25err.h"
31 
32 int     pk_sendspace = 1024 * 2 + 8;
33 int     pk_recvspace = 1024 * 2 + 8;
34 
35 struct pklcd_q pklcd_q = {&pklcd_q, &pklcd_q};
36 
37 /*
38  *  Attach X.25 protocol to socket, allocate logical channel descripter
39  *  and buffer space, and enter LISTEN state if we are to accept
40  *  IN-COMMING CALL packets.
41  *
42  */
43 
44 struct pklcd *
45 pk_attach (so)
46 struct socket *so;
47 {
48 	register struct pklcd *lcp;
49 	register int error = ENOBUFS;
50 	int pk_output();
51 
52 	MALLOC(lcp, struct pklcd *, sizeof (*lcp), M_PCB, M_NOWAIT);
53 	if (lcp) {
54 		bzero ((caddr_t)lcp, sizeof (*lcp));
55 		insque (&lcp -> lcd_q, &pklcd_q);
56 		if (so) {
57 			error = soreserve (so, pk_sendspace, pk_recvspace);
58 			lcp -> lcd_so = so;
59 			if (so -> so_options & SO_ACCEPTCONN)
60 				lcp -> lcd_state = LISTEN;
61 			else
62 				lcp -> lcd_state = READY;
63 		} else
64 			sbreserve (&lcp -> lcd_sb, pk_sendspace);
65 	}
66 	if (so) {
67 		so -> so_pcb = (caddr_t) lcp;
68 		so -> so_error = error;
69 	}
70 	lcp -> lcd_send = pk_output;
71 	return (lcp);
72 }
73 
74 /*
75  *  Disconnect X.25 protocol from socket.
76  */
77 
78 pk_disconnect (lcp)
79 register struct pklcd *lcp;
80 {
81 	register struct socket *so = lcp -> lcd_so;
82 	register struct pklcd *l, *p;
83 
84 	switch (lcp -> lcd_state) {
85 	case LISTEN:
86 		for (p = 0, l = pk_listenhead; l && l != lcp; p = l, l = l -> lcd_listen);
87 		if (p == 0) {
88 			if (l != 0)
89 				pk_listenhead = l -> lcd_listen;
90 		}
91 		else
92 		if (l != 0)
93 			p -> lcd_listen = l -> lcd_listen;
94 		pk_close (lcp);
95 		break;
96 
97 	case READY:
98 		pk_acct (lcp);
99 		pk_close (lcp);
100 		break;
101 
102 	case SENT_CLEAR:
103 	case RECEIVED_CLEAR:
104 		break;
105 
106 	default:
107 		pk_acct (lcp);
108 		if (so) {
109 			soisdisconnecting (so);
110 			sbflush (&so -> so_rcv);
111 		}
112 		pk_clear (lcp, 241, 0); /* Normal Disconnect */
113 
114 	}
115 }
116 
117 /*
118  *  Close an X.25 Logical Channel. Discard all space held by the
119  *  connection and internal descriptors. Wake up any sleepers.
120  */
121 
122 pk_close (lcp)
123 struct pklcd *lcp;
124 {
125 	register struct socket *so = lcp -> lcd_so;
126 
127 	pk_freelcd (lcp);
128 
129 	if (so == NULL)
130 		return;
131 
132 	so -> so_pcb = 0;
133 	soisdisconnected (so);
134 	/* sofree (so);	/* gak!!! you can't do that here */
135 }
136 
137 /*
138  *  Create a template to be used to send X.25 packets on a logical
139  *  channel. It allocates an mbuf and fills in a skeletal packet
140  *  depending on its type. This packet is passed to pk_output where
141  *  the remainer of the packet is filled in.
142 */
143 
144 struct mbuf *
145 pk_template (lcn, type)
146 int lcn, type;
147 {
148 	register struct mbuf *m;
149 	register struct x25_packet *xp;
150 
151 	MGETHDR (m, M_DONTWAIT, MT_HEADER);
152 	if (m == 0)
153 		panic ("pk_template");
154 	m -> m_act = 0;
155 
156 	/*
157 	 * Efficiency hack: leave a four byte gap at the beginning
158 	 * of the packet level header with the hope that this will
159 	 * be enough room for the link level to insert its header.
160 	 */
161 	m -> m_data += max_linkhdr;
162 	m -> m_len = PKHEADERLN;
163 
164 	xp = mtod (m, struct x25_packet *);
165 	*(long *)xp = 0;		/* ugly, but fast */
166 /*	xp -> q_bit = 0;*/
167 	xp -> fmt_identifier = 1;
168 /*	xp -> lc_group_number = 0;*/
169 
170 	SET_LCN(xp, lcn);
171 	xp -> packet_type = type;
172 
173 	return (m);
174 }
175 
176 /*
177  *  This routine restarts all the virtual circuits. Actually,
178  *  the virtual circuits are not "restarted" as such. Instead,
179  *  any active switched circuit is simply returned to READY
180  *  state.
181  */
182 
183 pk_restart (pkp, restart_cause)
184 register struct pkcb *pkp;
185 int restart_cause;
186 {
187 	register struct mbuf *m;
188 	register struct pklcd *lcp;
189 	register int i;
190 
191 	/* Restart all logical channels. */
192 	if (pkp -> pk_chan == 0)
193 		return;
194 	for (i = 1; i <= pkp -> pk_maxlcn; ++i)
195 		if ((lcp = pkp -> pk_chan[i]) != NULL) {
196 			if (lcp -> lcd_so) {
197 				lcp -> lcd_so -> so_error = ENETRESET;
198 				pk_close (lcp);
199 			} else {
200 				pk_flush (lcp);
201 				lcp -> lcd_state = READY;
202 				if (lcp -> lcd_upper)
203 					lcp -> lcd_upper (lcp, 0);
204 			}
205 		}
206 
207 	if (restart_cause < 0)
208 		return;
209 
210 	pkp -> pk_state = DTE_SENT_RESTART;
211 	lcp = pkp -> pk_chan[0];
212 	m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESTART);
213 	m -> m_len += 2;
214 	mtod (m, struct x25_packet *) -> packet_data = 0;	/* DTE only */
215 	mtod (m, octet *)[4]  = restart_cause;
216 	pk_output (lcp);
217 }
218 
219 
220 /*
221  *  This procedure frees up the Logical Channel Descripter.
222  */
223 
224 pk_freelcd (lcp)
225 register struct pklcd *lcp;
226 {
227 	if (lcp == NULL)
228 		return;
229 
230 	if (lcp -> lcd_lcn > 0)
231 		lcp -> lcd_pkp -> pk_chan[lcp -> lcd_lcn] = NULL;
232 
233 	pk_flush (lcp);
234 	remque (&lcp -> lcd_q);
235 	free ((caddr_t)lcp, M_PCB);
236 }
237 
238 
239 /*
240  *  Bind a address and protocol value to a socket.  The important
241  *  part is the protocol value - the first four characters of the
242  *  Call User Data field.
243  */
244 
245 pk_bind (lcp, nam)
246 struct pklcd *lcp;
247 struct mbuf *nam;
248 {
249 	register struct pkcb *pkp;
250 	register struct pklcd *pp;
251 	register struct sockaddr_x25 *sa;
252 
253 	if (nam == NULL)
254 		return (EADDRNOTAVAIL);
255 	if (lcp -> lcd_ceaddr)				/* XXX */
256 		return (EADDRINUSE);
257 	if (pk_checksockaddr (nam))
258 		return (EINVAL);
259 	sa = mtod (nam, struct sockaddr_x25 *);
260 
261 	/*
262 	 * If the user wishes to accept calls only from a particular
263 	 * net (net != 0), make sure the net is known
264 	 */
265 
266 	if (sa -> x25_net)
267 		for (pkp = pkcbhead; ; pkp = pkp -> pk_next) {
268 			if (pkp == 0)
269 				return (ENETUNREACH);
270 			if (pkp -> pk_xcp -> xc_addr.x25_net == sa -> x25_net)
271 				break;
272 		}
273 
274 	/*
275 	 * For ISO's sake permit default listeners, but only one such . . .
276 	 */
277 	for (pp = pk_listenhead; pp; pp = pp -> lcd_listen) {
278 		register struct sockaddr_x25 *sa2 = pp -> lcd_ceaddr;
279 		if ((sa2 -> x25_udlen == sa -> x25_udlen) &&
280 		    (sa2 -> x25_udlen == 0 ||
281 		     (bcmp (sa2 -> x25_udata, sa -> x25_udata,
282 			    min (sa2 -> x25_udlen, sa -> x25_udlen)) == 0)))
283 				return (EADDRINUSE);
284 	}
285 	lcp -> lcd_laddr = *sa;
286 	lcp -> lcd_ceaddr = &lcp -> lcd_laddr;
287 	return (0);
288 }
289 
290 /*
291  * Include a bound control block in the list of listeners.
292  */
293 pk_listen (lcp)
294 register struct pklcd *lcp;
295 {
296 	register struct pklcd **pp;
297 
298 	if (lcp -> lcd_ceaddr == 0)
299 		return (EDESTADDRREQ);
300 
301 	lcp -> lcd_state = LISTEN;
302 	/*
303 	 * Add default listener at end, any others at start.
304 	 */
305 	if (lcp -> lcd_ceaddr -> x25_udlen == 0) {
306 		for (pp = &pk_listenhead; *pp; )
307 			pp = &((*pp) -> lcd_listen);
308 		*pp = lcp;
309 	} else {
310 		lcp -> lcd_listen = pk_listenhead;
311 		pk_listenhead = lcp;
312 	}
313 	return (0);
314 }
315 /*
316  * Include a listening control block for the benefit of other protocols.
317  */
318 pk_protolisten (spi, spilen, callee)
319 int (*callee) ();
320 {
321 	register struct pklcd *lcp = pk_attach ((struct socket *)0);
322 	register struct mbuf *nam;
323 	register struct sockaddr_x25 *sa;
324 	int error = ENOBUFS;
325 
326 	if (lcp) {
327 		if (nam = m_getclr (MT_SONAME, M_DONTWAIT)) {
328 			sa = mtod (nam, struct sockaddr_x25 *);
329 			sa -> x25_family = AF_CCITT;
330 			sa -> x25_len = nam -> m_len = sizeof (*sa);
331 			sa -> x25_udlen = spilen;
332 			sa -> x25_udata[0] = spi;
333 			lcp -> lcd_upper = callee;
334 			lcp -> lcd_flags = X25_MBS_HOLD;
335 			error = pk_bind (lcp, nam) || pk_listen (lcp);
336 			(void) m_free (nam);
337 		}
338 		if (error)
339 			pk_freelcd (lcp);
340 	}
341 	return error; /* Hopefully Zero !*/
342 }
343 
344 /*
345  * Associate a logical channel descriptor with a network.
346  * Fill in the default network specific parameters and then
347  * set any parameters explicitly specified by the user or
348  * by the remote DTE.
349  */
350 
351 pk_assoc (pkp, lcp, sa)
352 register struct pkcb *pkp;
353 register struct pklcd *lcp;
354 register struct sockaddr_x25 *sa;
355 {
356 
357 	lcp -> lcd_pkp = pkp;
358 	lcp -> lcd_packetsize = pkp -> pk_xcp -> xc_psize;
359 	lcp -> lcd_windowsize = pkp -> pk_xcp -> xc_pwsize;
360 	lcp -> lcd_rsn = MODULUS - 1;
361 	pkp -> pk_chan[lcp -> lcd_lcn] = lcp;
362 
363 	if (sa -> x25_opts.op_psize)
364 		lcp -> lcd_packetsize = sa -> x25_opts.op_psize;
365 	else
366 		sa -> x25_opts.op_psize = lcp -> lcd_packetsize;
367 	if (sa -> x25_opts.op_wsize)
368 		lcp -> lcd_windowsize = sa -> x25_opts.op_wsize;
369 	else
370 		sa -> x25_opts.op_wsize = lcp -> lcd_windowsize;
371 	sa -> x25_net = pkp -> pk_xcp -> xc_addr.x25_net;
372 	lcp -> lcd_flags = sa -> x25_opts.op_flags;
373 	lcp -> lcd_stime = time.tv_sec;
374 }
375 
376 pk_connect (lcp, sa)
377 register struct pklcd *lcp;
378 register struct sockaddr_x25 *sa;
379 {
380 	register struct pkcb *pkp;
381 
382 	if (sa -> x25_addr[0] == '\0')
383 		return (EDESTADDRREQ);
384 	if (lcp -> lcd_pkp == 0)
385 	    for (pkp = pkcbhead; ; pkp = pkp -> pk_next) {
386 		if (pkp == 0)
387 			return (ENETUNREACH);
388 		/*
389 		 * use first net configured (last in list
390 		 * headed by pkcbhead) if net is zero
391 		 */
392 		if (sa -> x25_net == 0 && pkp -> pk_next == 0)
393 			break;
394 		if (sa -> x25_net == pkp -> pk_xcp -> xc_addr.x25_net)
395 			break;
396 	}
397 
398 	if (pkp -> pk_state != DTE_READY)
399 		return (ENETDOWN);
400 	if ((lcp -> lcd_lcn = pk_getlcn (pkp)) == 0)
401 		return (EMFILE);
402 	lcp -> lcd_faddr = *sa;
403 	lcp -> lcd_ceaddr = & lcp -> lcd_faddr;
404 	pk_assoc (pkp, lcp, lcp -> lcd_ceaddr);
405 	if (lcp -> lcd_so)
406 		soisconnecting (lcp -> lcd_so);
407 	lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL);
408 	pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp);
409 	return (*pkp -> pk_start) (lcp);
410 }
411 
412 /*
413  *  Build the rest of the CALL REQUEST packet. Fill in calling
414  *  address, facilities fields and the user data field.
415  */
416 
417 pk_callrequest (lcp, sa, xcp)
418 struct pklcd *lcp;
419 register struct sockaddr_x25 *sa;
420 register struct x25config *xcp;
421 {
422 	register struct x25_calladdr *a;
423 	register struct mbuf *m = lcp -> lcd_template;
424 	register struct x25_packet *xp = mtod (m, struct x25_packet *);
425 	unsigned posn = 0;
426 	octet *cp;
427 
428 	if (lcp -> lcd_flags & X25_DBIT)
429 		xp -> d_bit = 1;
430 	a = (struct x25_calladdr *) &xp -> packet_data;
431 	a -> calling_addrlen = strlen (xcp -> xc_addr.x25_addr);
432 	a -> called_addrlen = strlen (sa -> x25_addr);
433 	cp = (octet *) a -> address_field;
434 	to_bcd (&cp, (int)a -> called_addrlen, sa -> x25_addr, &posn);
435 	to_bcd (&cp, (int)a -> calling_addrlen, xcp -> xc_addr.x25_addr, &posn);
436 	if (posn & 0x01)
437 		*cp++ &= 0xf0;
438 	m -> m_len += cp - (octet *) a;
439 
440 	if (lcp -> lcd_facilities) {
441 		m -> m_pkthdr.len +=
442 			(m -> m_next = lcp -> lcd_facilities) -> m_len;
443 		lcp -> lcd_facilities = 0;
444 	} else
445 		build_facilities (m, sa, (int)xcp -> xc_type);
446 
447 	m_copyback (m, m -> m_pkthdr.len, sa -> x25_udlen, sa -> x25_udata);
448 #ifdef ANDREW
449 	printf ("call: ");
450 	for (cp = mtod (m, octet *), posn = 0; posn < m -> m_len; ++posn)
451 		printf ("%x ", *cp++);
452 	printf ("\n");
453 #endif
454 }
455 
456 static
457 build_facilities (m, sa, type)
458 register struct mbuf *m;
459 struct sockaddr_x25 *sa;
460 {
461 	register octet *cp;
462 	register octet *fcp;
463 	register int revcharge;
464 
465 	cp = mtod (m, octet *) + m -> m_len;
466 	fcp = cp + 1;
467 	revcharge = sa -> x25_opts.op_flags & X25_REVERSE_CHARGE ? 1 : 0;
468 	/*
469 	 * This is specific to Datapac X.25(1976) DTEs.  International
470 	 * calls must have the "hi priority" bit on.
471 	 */
472 	if (type == X25_1976 && sa -> x25_opts.op_psize == X25_PS128)
473 		revcharge |= 02;
474 	if (revcharge) {
475 		*fcp++ = FACILITIES_REVERSE_CHARGE;
476 		*fcp++ = revcharge;
477 	}
478 	switch (type) {
479 	case X25_1980:
480 	case X25_1984:
481 		*fcp++ = FACILITIES_PACKETSIZE;
482 		*fcp++ = sa -> x25_opts.op_psize;
483 		*fcp++ = sa -> x25_opts.op_psize;
484 
485 		*fcp++ = FACILITIES_WINDOWSIZE;
486 		*fcp++ = sa -> x25_opts.op_wsize;
487 		*fcp++ = sa -> x25_opts.op_wsize;
488 	}
489 	*cp = fcp - cp - 1;
490 	m -> m_pkthdr.len = (m -> m_len += *cp + 1);
491 }
492 
493 to_bcd (a, len, x, posn)
494 register octet **a;
495 register char *x;
496 register int len;
497 register unsigned *posn;
498 {
499 	while (--len >= 0)
500 		if ((*posn)++ & 0x01)
501 			*(*a)++ |= *x++ & 0x0F;
502 		else
503 			**a = *x++ << 4;
504 }
505 
506 /*
507  *  This routine gets the  first available logical channel number.  The
508  *  search is from the highest number to lowest number (DTE).
509  */
510 
511 pk_getlcn (pkp)
512 register struct pkcb *pkp;
513 {
514 	register int i;
515 
516 	if (pkp -> pk_chan == 0)
517 		return (0);
518 	for (i = pkp -> pk_maxlcn; i > 0; --i)
519 		if (pkp -> pk_chan[i] == NULL)
520 			break;
521 	return (i);
522 
523 }
524 
525 /*
526  *  This procedure sends a CLEAR request packet. The lc state is
527  *  set to "SENT_CLEAR".
528  */
529 
530 pk_clear (lcp, diagnostic, abortive)
531 register struct pklcd *lcp;
532 {
533 	register struct mbuf *m = pk_template (lcp -> lcd_lcn, X25_CLEAR);
534 
535 	m -> m_len += 2;
536 	mtod (m, struct x25_packet *) -> packet_data = 0;
537 	mtod (m, octet *)[4] = diagnostic;
538 	if (lcp -> lcd_facilities) {
539 		m -> m_next = lcp -> lcd_facilities;
540 		m -> m_pkthdr.len += m -> m_next -> m_len;
541 		lcp -> lcd_facilities = 0;
542 	}
543 	if (abortive)
544 		lcp -> lcd_template = m;
545 	else {
546 		struct socket *so = lcp -> lcd_so;
547 		struct sockbuf *sb = so ? & so -> so_snd : & lcp -> lcd_sb;
548 		sbappendrecord (sb, m);
549 	}
550 	pk_output (lcp);
551 
552 }
553 
554 /*
555  * This procedure generates RNR's or RR's to inhibit or enable
556  * inward data flow, if the current state changes (blocked ==> open or
557  * vice versa), or if forced to generate one.  One forces RNR's to ack data.
558  */
559 pk_flowcontrol (lcp, inhibit, forced)
560 register struct pklcd *lcp;
561 {
562 	inhibit = (inhibit != 0);
563 	if (lcp == 0 || lcp -> lcd_state != DATA_TRANSFER ||
564 	    (forced == 0 && lcp -> lcd_rxrnr_condition == inhibit))
565 		return;
566 	lcp -> lcd_rxrnr_condition = inhibit;
567 	lcp -> lcd_template = pk_template (lcp -> lcd_lcn, inhibit ? RNR : RR);
568 	pk_output (lcp);
569 }
570 
571 /*
572  *  This procedure sends a RESET request packet. It re-intializes
573  *  virtual circuit.
574  */
575 
576 static
577 pk_reset (lcp, diagnostic)
578 register struct pklcd *lcp;
579 {
580 	register struct mbuf *m;
581 	register struct socket *so = lcp -> lcd_so;
582 
583 	if (lcp -> lcd_state != DATA_TRANSFER)
584 		return;
585 
586 	if (so)
587 		so -> so_error = ECONNRESET;
588 	lcp -> lcd_reset_condition = TRUE;
589 
590 	/* Reset all the control variables for the channel. */
591 	pk_flush (lcp);
592 	lcp -> lcd_window_condition = lcp -> lcd_rnr_condition =
593 		lcp -> lcd_intrconf_pending = FALSE;
594 	lcp -> lcd_rsn = MODULUS - 1;
595 	lcp -> lcd_ssn = 0;
596 	lcp -> lcd_output_window = lcp -> lcd_input_window =
597 		lcp -> lcd_last_transmitted_pr = 0;
598 	m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET);
599 	m -> m_len += 2;
600 	mtod (m, struct x25_packet *) -> packet_data = 0;
601 	mtod (m, octet *)[4] = diagnostic;
602 	pk_output (lcp);
603 
604 }
605 
606 /*
607  * This procedure frees all data queued for output or delivery on a
608  *  virtual circuit.
609  */
610 
611 pk_flush (lcp)
612 register struct pklcd *lcp;
613 {
614 	register struct socket *so;
615 
616 	if (lcp -> lcd_template)
617 		m_freem (lcp -> lcd_template);
618 
619 	if (lcp -> lcd_cps) {
620 		m_freem (lcp -> lcd_cps);
621 		lcp -> lcd_cps = 0;
622 	}
623 	if (lcp -> lcd_facilities) {
624 		m_freem (lcp -> lcd_facilities);
625 		lcp -> lcd_facilities = 0;
626 	}
627 	if (so = lcp -> lcd_so) {
628 		sbflush (&so -> so_rcv);
629 		sbflush (&so -> so_snd);
630 	} else
631 		sbflush (&lcp -> lcd_sb);
632 }
633 
634 /*
635  *  This procedure handles all local protocol procedure errors.
636  */
637 
638 pk_procerror (error, lcp, errstr, diagnostic)
639 register struct pklcd *lcp;
640 char *errstr;
641 {
642 
643 	pk_message (lcp -> lcd_lcn, lcp -> lcd_pkp -> pk_xcp, errstr);
644 
645 	switch (error) {
646 	case CLEAR:
647 		if (lcp -> lcd_so) {
648 			lcp -> lcd_so -> so_error = ECONNABORTED;
649 			soisdisconnecting (lcp -> lcd_so);
650 		}
651 		pk_clear (lcp, diagnostic, 1);
652 		break;
653 
654 	case RESET:
655 		pk_reset (lcp, diagnostic);
656 	}
657 }
658 
659 /*
660  *  This procedure is called during the DATA TRANSFER state to check
661  *  and  process  the P(R) values  received  in the DATA,  RR OR RNR
662  *  packets.
663  */
664 
665 pk_ack (lcp, pr)
666 struct pklcd *lcp;
667 unsigned pr;
668 {
669 	register struct socket *so = lcp -> lcd_so;
670 
671 	if (lcp -> lcd_output_window == pr)
672 		return (PACKET_OK);
673 	if (lcp -> lcd_output_window < lcp -> lcd_ssn) {
674 		if (pr < lcp -> lcd_output_window || pr > lcp -> lcd_ssn) {
675 			pk_procerror (RESET, lcp,
676 				"p(r) flow control error", 2);
677 			return (ERROR_PACKET);
678 		}
679 	}
680 	else {
681 		if (pr < lcp -> lcd_output_window && pr > lcp -> lcd_ssn) {
682 			pk_procerror (RESET, lcp,
683 				"p(r) flow control error #2", 2);
684 			return (ERROR_PACKET);
685 		}
686 	}
687 
688 	lcp -> lcd_output_window = pr;		/* Rotate window. */
689 	if (lcp -> lcd_window_condition == TRUE)
690 		lcp -> lcd_window_condition = FALSE;
691 
692 	if (so && ((so -> so_snd.sb_flags & SB_WAIT) || so -> so_snd.sb_sel))
693 		sowwakeup (so);
694 	if (lcp -> lcd_upper)
695 		(*lcp -> lcd_upper) (lcp, 0);
696 
697 	return (PACKET_OK);
698 }
699 
700 /*
701  *  This procedure decodes the X.25 level 3 packet returning a
702  *  code to be used in switchs or arrays.
703  */
704 
705 pk_decode (xp)
706 register struct x25_packet *xp;
707 {
708 	register int type;
709 
710 	if (xp -> fmt_identifier != 1)
711 		return (INVALID_PACKET);
712 #ifdef ancient_history
713 	/*
714 	 *  Make sure that the logical channel group number is 0.
715 	 *  This restriction may be removed at some later date.
716 	 */
717 	if (xp -> lc_group_number != 0)
718 		return (INVALID_PACKET);
719 #endif
720 	/*
721 	 *  Test for data packet first.
722 	 */
723 	if (!(xp -> packet_type & DATA_PACKET_DESIGNATOR))
724 		return (DATA);
725 
726 	/*
727 	 *  Test if flow control packet (RR or RNR).
728 	 */
729 	if (!(xp -> packet_type & RR_OR_RNR_PACKET_DESIGNATOR))
730 		switch (xp -> packet_type & 0x1f) {
731 		case X25_RR:
732 			return (RR);
733 		case X25_RNR:
734 			return (RNR);
735 		case X25_REJECT:
736 			return (REJECT);
737 		}
738 
739 	/*
740 	 *  Determine the rest of the packet types.
741 	 */
742 	switch (xp -> packet_type) {
743 	case X25_CALL:
744 		type = CALL;
745 		break;
746 
747 	case X25_CALL_ACCEPTED:
748 		type = CALL_ACCEPTED;
749 		break;
750 
751 	case X25_CLEAR:
752 		type = CLEAR;
753 		break;
754 
755 	case X25_CLEAR_CONFIRM:
756 		type = CLEAR_CONF;
757 		break;
758 
759 	case X25_INTERRUPT:
760 		type = INTERRUPT;
761 		break;
762 
763 	case X25_INTERRUPT_CONFIRM:
764 		type = INTERRUPT_CONF;
765 		break;
766 
767 	case X25_RESET:
768 		type = RESET;
769 		break;
770 
771 	case X25_RESET_CONFIRM:
772 		type = RESET_CONF;
773 		break;
774 
775 	case X25_RESTART:
776 		type = RESTART;
777 		break;
778 
779 	case X25_RESTART_CONFIRM:
780 		type = RESTART_CONF;
781 		break;
782 
783 	case X25_DIAGNOSTIC:
784 		type = DIAG_TYPE;
785 		break;
786 
787 	default:
788 		type = INVALID_PACKET;
789 	}
790 	return (type);
791 }
792 
793 /*
794  *  A restart packet has been received. Print out the reason
795  *  for the restart.
796  */
797 
798 pk_restartcause (pkp, xp)
799 struct pkcb *pkp;
800 register struct x25_packet *xp;
801 {
802 	register struct x25config *xcp = pkp -> pk_xcp;
803 	register int lcn = LCN(xp);
804 
805 	switch (xp -> packet_data) {
806 	case X25_RESTART_LOCAL_PROCEDURE_ERROR:
807 		pk_message (lcn, xcp, "restart: local procedure error");
808 		break;
809 
810 	case X25_RESTART_NETWORK_CONGESTION:
811 		pk_message (lcn, xcp, "restart: network congestion");
812 		break;
813 
814 	case X25_RESTART_NETWORK_OPERATIONAL:
815 		pk_message (lcn, xcp, "restart: network operational");
816 		break;
817 
818 	default:
819 		pk_message (lcn, xcp, "restart: unknown cause");
820 	}
821 }
822 
823 #define MAXRESETCAUSE	7
824 
825 int     Reset_cause[] = {
826 	EXRESET, EXROUT, 0, EXRRPE, 0, EXRLPE, 0, EXRNCG
827 };
828 
829 /*
830  *  A reset packet has arrived. Return the cause to the user.
831  */
832 
833 pk_resetcause (pkp, xp)
834 struct pkcb *pkp;
835 register struct x25_packet *xp;
836 {
837 	register struct pklcd *lcp =
838 				pkp -> pk_chan[LCN(xp)];
839 	register int code = xp -> packet_data;
840 
841 	if (code > MAXRESETCAUSE)
842 		code = 7;	/* EXRNCG */
843 
844 	pk_message(LCN(xp), lcp -> lcd_pkp, "reset code 0x%x, diagnostic 0x%x",
845 			xp -> packet_data, 4[(u_char *)xp]);
846 
847 	lcp -> lcd_so -> so_error = Reset_cause[code];
848 }
849 
850 #define MAXCLEARCAUSE	25
851 
852 int     Clear_cause[] = {
853 	EXCLEAR, EXCBUSY, 0, EXCINV, 0, EXCNCG, 0,
854 	0, 0, EXCOUT, 0, EXCAB, 0, EXCNOB, 0, 0, 0, EXCRPE,
855 	0, EXCLPE, 0, 0, 0, 0, 0, EXCRRC
856 };
857 
858 /*
859  *  A clear packet has arrived. Return the cause to the user.
860  */
861 
862 pk_clearcause (pkp, xp)
863 struct pkcb *pkp;
864 register struct x25_packet *xp;
865 {
866 	register struct pklcd *lcp =
867 		pkp -> pk_chan[LCN(xp)];
868 	register int code = xp -> packet_data;
869 
870 	if (code > MAXCLEARCAUSE)
871 		code = 5;	/* EXRNCG */
872 	lcp -> lcd_so -> so_error = Clear_cause[code];
873 }
874 
875 char *
876 format_ntn (xcp)
877 register struct x25config *xcp;
878 {
879 
880 	return (xcp -> xc_addr.x25_addr);
881 }
882 
883 /* VARARGS1 */
884 pk_message (lcn, xcp, fmt, a1, a2, a3, a4, a5, a6)
885 struct x25config *xcp;
886 char *fmt;
887 {
888 
889 	if (lcn)
890 		if (pkcbhead -> pk_next)
891 			printf ("X.25(%s): lcn %d: ", format_ntn (xcp), lcn);
892 		else
893 			printf ("X.25: lcn %d: ", lcn);
894 	else
895 		if (pkcbhead -> pk_next)
896 			printf ("X.25(%s): ", format_ntn (xcp));
897 		else
898 			printf ("X.25: ");
899 
900 	printf (fmt, a1, a2, a3, a4, a5, a6);
901 	printf ("\n");
902 }
903 
904 pk_ifattach (ia, lloutput, llnext)
905 register struct x25_ifaddr *ia;
906 int (*lloutput) ();
907 caddr_t llnext;
908 {
909 	/* this is here because you can't include both pk_var and hd_var */
910 	/* this will probably be replace by a streams gluing mechanism */
911 	ia -> ia_pkcb.pk_lloutput = lloutput;
912 	ia -> ia_pkcb.pk_llnext = llnext;
913 }
914 
915 pk_fragment (lcp, m0, qbit, mbit, wait)
916 struct mbuf *m0;
917 register struct pklcd *lcp;
918 {
919 	register struct mbuf *m = m0;
920 	register struct x25_packet *xp;
921 	register struct sockbuf *sb;
922 	struct mbuf *head = 0, *next, **mp = &head, *m_split ();
923 	int totlen, psize = 1 << (lcp -> lcd_packetsize);
924 
925 	if (m == 0)
926 		return;
927 	if (m -> m_flags & M_PKTHDR == 0)
928 		panic ("pk_fragment");
929 	totlen = m -> m_pkthdr.len;
930 	m -> m_act = 0;
931 	sb = lcp -> lcd_so ? &lcp -> lcd_so -> so_snd : & lcp -> lcd_sb;
932 	do {
933 		if (totlen > psize) {
934 			if ((next = m_split (m, psize, wait)) == 0)
935 				goto abort;
936 			totlen -= psize;
937 		} else
938 			next = 0;
939 		M_PREPEND(m, PKHEADERLN, wait);
940 		if (m == 0)
941 			goto abort;
942 		*mp = m;
943 		mp = & m -> m_act;
944 		*mp = 0;
945 		xp = mtod (m, struct x25_packet *);
946 		0[(char *)xp] = 0;
947 		if (qbit)
948 			xp -> q_bit = 1;
949 		if (lcp -> lcd_flags & X25_DBIT)
950 			xp -> d_bit = 1;
951 		xp -> fmt_identifier = 1;
952 		xp -> packet_type = X25_DATA;
953 		SET_LCN(xp, lcp -> lcd_lcn);
954 		if (next || (mbit && (totlen == psize ||
955 				      (lcp -> lcd_flags & X25_DBIT))))
956 			MBIT(xp) = 1;
957 	} while (m = next);
958 	for (m = head; m; m = next) {
959 		next = m -> m_act;
960 		m -> m_act = 0;
961 		sbappendrecord (sb, m);
962 	}
963 	return 0;
964 abort:
965 	if (wait)
966 		panic ("pk_fragment null mbuf after wait");
967 	if (next)
968 		m_freem (next);
969 	for (m = head; m; m = next) {
970 		next = m -> m_act;
971 		m_freem (m);
972 	}
973 	return ENOBUFS;
974 }
975 
976 struct mbuf *
977 m_split (m0, len0, wait)
978 register struct mbuf *m0;
979 int len0;
980 {
981 	register struct mbuf *m, *n;
982 	unsigned len = len0;
983 
984 	for (m = m0; m && len > m -> m_len; m = m -> m_next)
985 		len -= m -> m_len;
986 	if (m == 0)
987 		return (0);
988 	if (m0 -> m_flags & M_PKTHDR) {
989 		MGETHDR(n, wait, m0 -> m_type);
990 		if (n == 0)
991 			return (0);
992 		n -> m_pkthdr.rcvif = m0 -> m_pkthdr.rcvif;
993 		n -> m_pkthdr.len = m0 -> m_pkthdr.len - len0;
994 		m0 -> m_pkthdr.len = len0;
995 		if (m -> m_flags & M_EXT)
996 			goto extpacket;
997 		if (len > MHLEN) {
998 			/* m can't be the lead packet */
999 			MH_ALIGN(n, 0);
1000 			n -> m_next = m_split (m, len, wait);
1001 			if (n -> m_next == 0) {
1002 				(void) m_free (n);
1003 				return (0);
1004 			} else
1005 				return (n);
1006 		} else
1007 			MH_ALIGN(n, len);
1008 	} else if (len == m -> m_len) {
1009 		n = m -> m_next;
1010 		m -> m_next = 0;
1011 		return (n);
1012 	}
1013 extpacket:
1014 	len = m -> m_len - len;		/* remainder to be copied */
1015 	m -> m_len -= len;		/* now equals original len */
1016 	if (m -> m_flags & M_EXT) {
1017 		n -> m_flags |= M_EXT;
1018 		n -> m_ext = m -> m_ext;
1019 		mclrefcnt[mtocl (m -> m_ext.ext_buf)]++;
1020 		n -> m_data = m -> m_data + m -> m_len;
1021 	} else {
1022 		MGET(n, wait, m -> m_type);
1023 		if (n == 0) {
1024 			m -> m_len += len;
1025 			return (0);
1026 		}
1027 		M_ALIGN(n, len);
1028 		bcopy (mtod (m, caddr_t), mtod (n, caddr_t), len);
1029 	}
1030 	n -> m_len = len;
1031 	n -> m_next = m -> m_next;
1032 	m -> m_next = 0;
1033 	return (n);
1034 }
1035