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