xref: /csrg-svn/sys/netccitt/pk_subr.c (revision 49747)
141709Ssklower /*
241709Ssklower  * Copyright (c) University of British Columbia, 1984
341709Ssklower  * Copyright (c) 1990 The Regents of the University of California.
441709Ssklower  * All rights reserved.
541709Ssklower  *
641709Ssklower  * This code is derived from software contributed to Berkeley by
741709Ssklower  * the Laboratory for Computation Vision and the Computer Science Department
841709Ssklower  * of the University of British Columbia.
941709Ssklower  *
1041709Ssklower  * %sccs.include.redist.c%
1141709Ssklower  *
12*49747Ssklower  *	@(#)pk_subr.c	7.14 (Berkeley) 05/16/91
1341709Ssklower  */
1441593Ssklower 
1542140Ssklower #include "param.h"
1642140Ssklower #include "systm.h"
1742140Ssklower #include "mbuf.h"
1842140Ssklower #include "socket.h"
1942140Ssklower #include "protosw.h"
2042140Ssklower #include "socketvar.h"
2142140Ssklower #include "errno.h"
2242140Ssklower #include "time.h"
2342140Ssklower #include "kernel.h"
2441593Ssklower 
2542277Ssklower #include "../net/if.h"
2642277Ssklower 
2742140Ssklower #include "x25.h"
2842140Ssklower #include "pk.h"
2942140Ssklower #include "pk_var.h"
3042140Ssklower #include "x25err.h"
3141593Ssklower 
3241593Ssklower int     pk_sendspace = 1024 * 2 + 8;
3341593Ssklower int     pk_recvspace = 1024 * 2 + 8;
3441593Ssklower 
3547271Ssklower struct pklcd_q pklcd_q = {&pklcd_q, &pklcd_q};
3647271Ssklower 
3741593Ssklower /*
3841593Ssklower  *  Attach X.25 protocol to socket, allocate logical channel descripter
3941593Ssklower  *  and buffer space, and enter LISTEN state if we are to accept
4041593Ssklower  *  IN-COMMING CALL packets.
4141593Ssklower  *
4241593Ssklower  */
4341593Ssklower 
4442277Ssklower struct pklcd *
4541593Ssklower pk_attach (so)
4641593Ssklower struct socket *so;
4741593Ssklower {
4841593Ssklower 	register struct pklcd *lcp;
4942277Ssklower 	register int error = ENOBUFS;
5049018Ssklower 	int pk_output();
5141593Ssklower 
5247271Ssklower 	MALLOC(lcp, struct pklcd *, sizeof (*lcp), M_PCB, M_NOWAIT);
5342277Ssklower 	if (lcp) {
5447271Ssklower 		bzero ((caddr_t)lcp, sizeof (*lcp));
5547271Ssklower 		insque (&lcp -> lcd_q, &pklcd_q);
5649595Ssklower 		lcp -> lcd_state = READY;
5749595Ssklower 		lcp -> lcd_send = pk_output;
5842277Ssklower 		if (so) {
5942277Ssklower 			error = soreserve (so, pk_sendspace, pk_recvspace);
6042277Ssklower 			lcp -> lcd_so = so;
6142277Ssklower 			if (so -> so_options & SO_ACCEPTCONN)
6242277Ssklower 				lcp -> lcd_state = LISTEN;
6343361Ssklower 		} else
6445165Ssklower 			sbreserve (&lcp -> lcd_sb, pk_sendspace);
6542277Ssklower 	}
6642277Ssklower 	if (so) {
6742277Ssklower 		so -> so_pcb = (caddr_t) lcp;
6842277Ssklower 		so -> so_error = error;
6942277Ssklower 	}
7042277Ssklower 	return (lcp);
7141593Ssklower }
7241593Ssklower 
7341593Ssklower /*
7441593Ssklower  *  Disconnect X.25 protocol from socket.
7541593Ssklower  */
7641593Ssklower 
7741593Ssklower pk_disconnect (lcp)
7841593Ssklower register struct pklcd *lcp;
7941593Ssklower {
8041593Ssklower 	register struct socket *so = lcp -> lcd_so;
8141593Ssklower 	register struct pklcd *l, *p;
8241593Ssklower 
8341593Ssklower 	switch (lcp -> lcd_state) {
8441593Ssklower 	case LISTEN:
8541593Ssklower 		for (p = 0, l = pk_listenhead; l && l != lcp; p = l, l = l -> lcd_listen);
8641593Ssklower 		if (p == 0) {
8741593Ssklower 			if (l != 0)
8841593Ssklower 				pk_listenhead = l -> lcd_listen;
8941593Ssklower 		}
9041593Ssklower 		else
9141593Ssklower 		if (l != 0)
9241593Ssklower 			p -> lcd_listen = l -> lcd_listen;
9341593Ssklower 		pk_close (lcp);
9441593Ssklower 		break;
9541593Ssklower 
9641593Ssklower 	case READY:
9741593Ssklower 		pk_acct (lcp);
9841593Ssklower 		pk_close (lcp);
9941593Ssklower 		break;
10041593Ssklower 
10141593Ssklower 	case SENT_CLEAR:
10241593Ssklower 	case RECEIVED_CLEAR:
10341593Ssklower 		break;
10441593Ssklower 
10541593Ssklower 	default:
10641593Ssklower 		pk_acct (lcp);
10742140Ssklower 		if (so) {
10842140Ssklower 			soisdisconnecting (so);
10942140Ssklower 			sbflush (&so -> so_rcv);
11042140Ssklower 		}
11145895Ssklower 		pk_clear (lcp, 241, 0); /* Normal Disconnect */
11241593Ssklower 
11341593Ssklower 	}
11441593Ssklower }
11541593Ssklower 
11641593Ssklower /*
11741593Ssklower  *  Close an X.25 Logical Channel. Discard all space held by the
11841593Ssklower  *  connection and internal descriptors. Wake up any sleepers.
11941593Ssklower  */
12041593Ssklower 
12141593Ssklower pk_close (lcp)
12241593Ssklower struct pklcd *lcp;
12341593Ssklower {
12441593Ssklower 	register struct socket *so = lcp -> lcd_so;
12541593Ssklower 
12641593Ssklower 	pk_freelcd (lcp);
12741593Ssklower 
12841593Ssklower 	if (so == NULL)
12941593Ssklower 		return;
13041593Ssklower 
13141593Ssklower 	so -> so_pcb = 0;
13241593Ssklower 	soisdisconnected (so);
13345895Ssklower 	/* sofree (so);	/* gak!!! you can't do that here */
13441593Ssklower }
13541593Ssklower 
13641593Ssklower /*
13741593Ssklower  *  Create a template to be used to send X.25 packets on a logical
13841593Ssklower  *  channel. It allocates an mbuf and fills in a skeletal packet
13941593Ssklower  *  depending on its type. This packet is passed to pk_output where
14041593Ssklower  *  the remainer of the packet is filled in.
14141593Ssklower */
14241593Ssklower 
14345895Ssklower struct mbuf *
14441593Ssklower pk_template (lcn, type)
14541593Ssklower int lcn, type;
14641593Ssklower {
14741593Ssklower 	register struct mbuf *m;
14841593Ssklower 	register struct x25_packet *xp;
14941593Ssklower 
15045297Ssklower 	MGETHDR (m, M_DONTWAIT, MT_HEADER);
15141593Ssklower 	if (m == 0)
15241593Ssklower 		panic ("pk_template");
15341593Ssklower 	m -> m_act = 0;
15441593Ssklower 
15541593Ssklower 	/*
15641593Ssklower 	 * Efficiency hack: leave a four byte gap at the beginning
15741593Ssklower 	 * of the packet level header with the hope that this will
15841593Ssklower 	 * be enough room for the link level to insert its header.
15941593Ssklower 	 */
16045297Ssklower 	m -> m_data += max_linkhdr;
16149595Ssklower 	m -> m_pkthdr.len = m -> m_len = PKHEADERLN;
16241593Ssklower 
16341593Ssklower 	xp = mtod (m, struct x25_packet *);
16441593Ssklower 	*(long *)xp = 0;		/* ugly, but fast */
16541593Ssklower /*	xp -> q_bit = 0;*/
16641593Ssklower 	xp -> fmt_identifier = 1;
16741593Ssklower /*	xp -> lc_group_number = 0;*/
16841593Ssklower 
16945574Ssklower 	SET_LCN(xp, lcn);
17041593Ssklower 	xp -> packet_type = type;
17141593Ssklower 
17245895Ssklower 	return (m);
17341593Ssklower }
17441593Ssklower 
17541593Ssklower /*
17641593Ssklower  *  This routine restarts all the virtual circuits. Actually,
17741593Ssklower  *  the virtual circuits are not "restarted" as such. Instead,
17841593Ssklower  *  any active switched circuit is simply returned to READY
17941593Ssklower  *  state.
18041593Ssklower  */
18141593Ssklower 
18241593Ssklower pk_restart (pkp, restart_cause)
18341593Ssklower register struct pkcb *pkp;
18441593Ssklower int restart_cause;
18541593Ssklower {
18645895Ssklower 	register struct mbuf *m;
18741593Ssklower 	register struct pklcd *lcp;
18841593Ssklower 	register int i;
18941593Ssklower 
19041593Ssklower 	/* Restart all logical channels. */
19145297Ssklower 	if (pkp -> pk_chan == 0)
19242140Ssklower 		return;
19345297Ssklower 	for (i = 1; i <= pkp -> pk_maxlcn; ++i)
19445297Ssklower 		if ((lcp = pkp -> pk_chan[i]) != NULL) {
19545895Ssklower 			if (lcp -> lcd_so) {
19645297Ssklower 				lcp -> lcd_so -> so_error = ENETRESET;
19745895Ssklower 				pk_close (lcp);
19845895Ssklower 			} else {
19945895Ssklower 				pk_flush (lcp);
20045895Ssklower 				lcp -> lcd_state = READY;
20145895Ssklower 				if (lcp -> lcd_upper)
20247271Ssklower 					lcp -> lcd_upper (lcp, 0);
20345895Ssklower 			}
20441593Ssklower 		}
20541593Ssklower 
20641593Ssklower 	if (restart_cause < 0)
20741593Ssklower 		return;
20841593Ssklower 
20945297Ssklower 	pkp -> pk_state = DTE_SENT_RESTART;
21045297Ssklower 	lcp = pkp -> pk_chan[0];
21145895Ssklower 	m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESTART);
21249595Ssklower 	m -> m_pkthdr.len = m -> m_len += 2;
21347271Ssklower 	mtod (m, struct x25_packet *) -> packet_data = 0;	/* DTE only */
21447271Ssklower 	mtod (m, octet *)[4]  = restart_cause;
21541593Ssklower 	pk_output (lcp);
21641593Ssklower }
21741593Ssklower 
21841593Ssklower 
21941593Ssklower /*
22041593Ssklower  *  This procedure frees up the Logical Channel Descripter.
22141593Ssklower  */
22241593Ssklower 
22341593Ssklower pk_freelcd (lcp)
22441593Ssklower register struct pklcd *lcp;
22541593Ssklower {
22641593Ssklower 	if (lcp == NULL)
22741593Ssklower 		return;
22841593Ssklower 
22941593Ssklower 	if (lcp -> lcd_lcn > 0)
23041593Ssklower 		lcp -> lcd_pkp -> pk_chan[lcp -> lcd_lcn] = NULL;
23141593Ssklower 
23247271Ssklower 	pk_flush (lcp);
23347271Ssklower 	remque (&lcp -> lcd_q);
23447271Ssklower 	free ((caddr_t)lcp, M_PCB);
23541593Ssklower }
23641593Ssklower 
23741593Ssklower 
23841593Ssklower /*
23941593Ssklower  *  Bind a address and protocol value to a socket.  The important
24041593Ssklower  *  part is the protocol value - the first four characters of the
24141593Ssklower  *  Call User Data field.
24241593Ssklower  */
24341593Ssklower 
24441593Ssklower pk_bind (lcp, nam)
24541593Ssklower struct pklcd *lcp;
24641593Ssklower struct mbuf *nam;
24741593Ssklower {
24841593Ssklower 	register struct pkcb *pkp;
24941593Ssklower 	register struct pklcd *pp;
25042277Ssklower 	register struct sockaddr_x25 *sa;
25141593Ssklower 
25241593Ssklower 	if (nam == NULL)
25341593Ssklower 		return (EADDRNOTAVAIL);
25441593Ssklower 	if (lcp -> lcd_ceaddr)				/* XXX */
25541593Ssklower 		return (EADDRINUSE);
25645895Ssklower 	if (pk_checksockaddr (nam))
25741593Ssklower 		return (EINVAL);
25841593Ssklower 	sa = mtod (nam, struct sockaddr_x25 *);
25941593Ssklower 
26041593Ssklower 	/*
26141593Ssklower 	 * If the user wishes to accept calls only from a particular
26241593Ssklower 	 * net (net != 0), make sure the net is known
26341593Ssklower 	 */
26441593Ssklower 
26541593Ssklower 	if (sa -> x25_net)
26641593Ssklower 		for (pkp = pkcbhead; ; pkp = pkp -> pk_next) {
26741593Ssklower 			if (pkp == 0)
26841593Ssklower 				return (ENETUNREACH);
26945165Ssklower 			if (pkp -> pk_xcp -> xc_addr.x25_net == sa -> x25_net)
27041593Ssklower 				break;
27141593Ssklower 		}
27241593Ssklower 
27345895Ssklower 	/*
27445895Ssklower 	 * For ISO's sake permit default listeners, but only one such . . .
27545895Ssklower 	 */
27645895Ssklower 	for (pp = pk_listenhead; pp; pp = pp -> lcd_listen) {
27745895Ssklower 		register struct sockaddr_x25 *sa2 = pp -> lcd_ceaddr;
27845895Ssklower 		if ((sa2 -> x25_udlen == sa -> x25_udlen) &&
27945895Ssklower 		    (sa2 -> x25_udlen == 0 ||
28045895Ssklower 		     (bcmp (sa2 -> x25_udata, sa -> x25_udata,
28145895Ssklower 			    min (sa2 -> x25_udlen, sa -> x25_udlen)) == 0)))
28245895Ssklower 				return (EADDRINUSE);
28345895Ssklower 	}
28442277Ssklower 	lcp -> lcd_laddr = *sa;
28542277Ssklower 	lcp -> lcd_ceaddr = &lcp -> lcd_laddr;
28641593Ssklower 	return (0);
28741593Ssklower }
28841593Ssklower 
28941593Ssklower /*
29045895Ssklower  * Include a bound control block in the list of listeners.
29145895Ssklower  */
29245895Ssklower pk_listen (lcp)
29345895Ssklower register struct pklcd *lcp;
29445895Ssklower {
29545895Ssklower 	register struct pklcd **pp;
29645895Ssklower 
29745895Ssklower 	if (lcp -> lcd_ceaddr == 0)
29845895Ssklower 		return (EDESTADDRREQ);
29945895Ssklower 
30045895Ssklower 	lcp -> lcd_state = LISTEN;
30145895Ssklower 	/*
30245895Ssklower 	 * Add default listener at end, any others at start.
30345895Ssklower 	 */
30445895Ssklower 	if (lcp -> lcd_ceaddr -> x25_udlen == 0) {
30545895Ssklower 		for (pp = &pk_listenhead; *pp; )
30645895Ssklower 			pp = &((*pp) -> lcd_listen);
30745895Ssklower 		*pp = lcp;
30845895Ssklower 	} else {
30945895Ssklower 		lcp -> lcd_listen = pk_listenhead;
31045895Ssklower 		pk_listenhead = lcp;
31145895Ssklower 	}
31245895Ssklower 	return (0);
31345895Ssklower }
31445895Ssklower /*
31545895Ssklower  * Include a listening control block for the benefit of other protocols.
31645895Ssklower  */
31745895Ssklower pk_protolisten (spi, spilen, callee)
31847271Ssklower int (*callee) ();
31945895Ssklower {
32045895Ssklower 	register struct pklcd *lcp = pk_attach ((struct socket *)0);
32145895Ssklower 	register struct mbuf *nam;
32245895Ssklower 	register struct sockaddr_x25 *sa;
32345895Ssklower 	int error = ENOBUFS;
32445895Ssklower 
32545895Ssklower 	if (lcp) {
32647271Ssklower 		if (nam = m_getclr (MT_SONAME, M_DONTWAIT)) {
32747271Ssklower 			sa = mtod (nam, struct sockaddr_x25 *);
32845895Ssklower 			sa -> x25_family = AF_CCITT;
32945895Ssklower 			sa -> x25_len = nam -> m_len = sizeof (*sa);
33045895Ssklower 			sa -> x25_udlen = spilen;
33145895Ssklower 			sa -> x25_udata[0] = spi;
33245895Ssklower 			lcp -> lcd_upper = callee;
33345895Ssklower 			lcp -> lcd_flags = X25_MBS_HOLD;
33445895Ssklower 			error = pk_bind (lcp, nam) || pk_listen (lcp);
33545895Ssklower 			(void) m_free (nam);
33645895Ssklower 		}
33745895Ssklower 		if (error)
33847271Ssklower 			pk_freelcd (lcp);
33945895Ssklower 	}
34045895Ssklower 	return error; /* Hopefully Zero !*/
34145895Ssklower }
34245895Ssklower 
34345895Ssklower /*
34441593Ssklower  * Associate a logical channel descriptor with a network.
34541593Ssklower  * Fill in the default network specific parameters and then
34641593Ssklower  * set any parameters explicitly specified by the user or
34741593Ssklower  * by the remote DTE.
34841593Ssklower  */
34941593Ssklower 
35041593Ssklower pk_assoc (pkp, lcp, sa)
35141593Ssklower register struct pkcb *pkp;
35241593Ssklower register struct pklcd *lcp;
35341593Ssklower register struct sockaddr_x25 *sa;
35441593Ssklower {
35541593Ssklower 
35641593Ssklower 	lcp -> lcd_pkp = pkp;
35741593Ssklower 	lcp -> lcd_packetsize = pkp -> pk_xcp -> xc_psize;
35841593Ssklower 	lcp -> lcd_windowsize = pkp -> pk_xcp -> xc_pwsize;
35941593Ssklower 	lcp -> lcd_rsn = MODULUS - 1;
36041593Ssklower 	pkp -> pk_chan[lcp -> lcd_lcn] = lcp;
36141593Ssklower 
36241593Ssklower 	if (sa -> x25_opts.op_psize)
36341593Ssklower 		lcp -> lcd_packetsize = sa -> x25_opts.op_psize;
36441593Ssklower 	else
36541593Ssklower 		sa -> x25_opts.op_psize = lcp -> lcd_packetsize;
36641593Ssklower 	if (sa -> x25_opts.op_wsize)
36741593Ssklower 		lcp -> lcd_windowsize = sa -> x25_opts.op_wsize;
36841593Ssklower 	else
36941593Ssklower 		sa -> x25_opts.op_wsize = lcp -> lcd_windowsize;
37045165Ssklower 	sa -> x25_net = pkp -> pk_xcp -> xc_addr.x25_net;
37141593Ssklower 	lcp -> lcd_flags = sa -> x25_opts.op_flags;
37241593Ssklower 	lcp -> lcd_stime = time.tv_sec;
37341593Ssklower }
37441593Ssklower 
37545895Ssklower pk_connect (lcp, sa)
37641593Ssklower register struct pklcd *lcp;
37742277Ssklower register struct sockaddr_x25 *sa;
37841593Ssklower {
37941593Ssklower 	register struct pkcb *pkp;
38041593Ssklower 
38141593Ssklower 	if (sa -> x25_addr[0] == '\0')
38241593Ssklower 		return (EDESTADDRREQ);
38345297Ssklower 	if (lcp -> lcd_pkp == 0)
38445297Ssklower 	    for (pkp = pkcbhead; ; pkp = pkp -> pk_next) {
38541593Ssklower 		if (pkp == 0)
38641593Ssklower 			return (ENETUNREACH);
38741593Ssklower 		/*
38841593Ssklower 		 * use first net configured (last in list
38941593Ssklower 		 * headed by pkcbhead) if net is zero
39041593Ssklower 		 */
39141593Ssklower 		if (sa -> x25_net == 0 && pkp -> pk_next == 0)
39241593Ssklower 			break;
39345165Ssklower 		if (sa -> x25_net == pkp -> pk_xcp -> xc_addr.x25_net)
39441593Ssklower 			break;
39541593Ssklower 	}
39641593Ssklower 
39741593Ssklower 	if (pkp -> pk_state != DTE_READY)
39841593Ssklower 		return (ENETDOWN);
39941593Ssklower 	if ((lcp -> lcd_lcn = pk_getlcn (pkp)) == 0)
40041593Ssklower 		return (EMFILE);
40142277Ssklower 	lcp -> lcd_faddr = *sa;
40245297Ssklower 	lcp -> lcd_ceaddr = & lcp -> lcd_faddr;
40341593Ssklower 	pk_assoc (pkp, lcp, lcp -> lcd_ceaddr);
40445165Ssklower 	if (lcp -> lcd_so)
40542140Ssklower 		soisconnecting (lcp -> lcd_so);
40641593Ssklower 	lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL);
40742277Ssklower 	pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp);
40847271Ssklower 	return (*pkp -> pk_start) (lcp);
40941593Ssklower }
41041593Ssklower 
411*49747Ssklower struct bcdinfo {
412*49747Ssklower 	octet *cp;
413*49747Ssklower 	unsigned posn;
414*49747Ssklower };
41541593Ssklower /*
41641593Ssklower  *  Build the rest of the CALL REQUEST packet. Fill in calling
41741593Ssklower  *  address, facilities fields and the user data field.
41841593Ssklower  */
41941593Ssklower 
42042277Ssklower pk_callrequest (lcp, sa, xcp)
42141593Ssklower struct pklcd *lcp;
42242277Ssklower register struct sockaddr_x25 *sa;
42341593Ssklower register struct x25config *xcp;
42441593Ssklower {
42541593Ssklower 	register struct x25_calladdr *a;
42645895Ssklower 	register struct mbuf *m = lcp -> lcd_template;
42747271Ssklower 	register struct x25_packet *xp = mtod (m, struct x25_packet *);
428*49747Ssklower 	struct bcdinfo b;
42941593Ssklower 
43045574Ssklower 	if (lcp -> lcd_flags & X25_DBIT)
43145895Ssklower 		xp -> d_bit = 1;
43245895Ssklower 	a = (struct x25_calladdr *) &xp -> packet_data;
433*49747Ssklower 	b.cp = (octet *) a -> address_field;
434*49747Ssklower 	b.posn = 0;
435*49747Ssklower 	a -> called_addrlen = to_bcd (&b, sa, xcp);
436*49747Ssklower 	a -> calling_addrlen = to_bcd (&b, &xcp -> xc_addr, xcp);
437*49747Ssklower 	if (b.posn & 0x01)
438*49747Ssklower 		*b.cp++ &= 0xf0;
439*49747Ssklower 	m -> m_pkthdr.len = m -> m_len += b.cp - (octet *) a;
44041593Ssklower 
44145895Ssklower 	if (lcp -> lcd_facilities) {
44247271Ssklower 		m -> m_pkthdr.len +=
443*49747Ssklower 			(m -> m_next = lcp -> lcd_facilities) -> m_pkthdr.len;
44445895Ssklower 		lcp -> lcd_facilities = 0;
44545895Ssklower 	} else
446*49747Ssklower 		pk_build_facilities (m, sa, (int)xcp -> xc_type);
44741593Ssklower 
44847271Ssklower 	m_copyback (m, m -> m_pkthdr.len, sa -> x25_udlen, sa -> x25_udata);
44941593Ssklower }
45041593Ssklower 
451*49747Ssklower pk_build_facilities (m, sa, type)
45245895Ssklower register struct mbuf *m;
45341593Ssklower struct sockaddr_x25 *sa;
45441593Ssklower {
45545895Ssklower 	register octet *cp;
45641593Ssklower 	register octet *fcp;
45741593Ssklower 	register int revcharge;
45841593Ssklower 
45947271Ssklower 	cp = mtod (m, octet *) + m -> m_len;
46045895Ssklower 	fcp = cp + 1;
46141593Ssklower 	revcharge = sa -> x25_opts.op_flags & X25_REVERSE_CHARGE ? 1 : 0;
46241593Ssklower 	/*
46341593Ssklower 	 * This is specific to Datapac X.25(1976) DTEs.  International
46441593Ssklower 	 * calls must have the "hi priority" bit on.
46541593Ssklower 	 */
46641593Ssklower 	if (type == X25_1976 && sa -> x25_opts.op_psize == X25_PS128)
46741593Ssklower 		revcharge |= 02;
46841593Ssklower 	if (revcharge) {
46941593Ssklower 		*fcp++ = FACILITIES_REVERSE_CHARGE;
47041593Ssklower 		*fcp++ = revcharge;
47141593Ssklower 	}
47241593Ssklower 	switch (type) {
47341593Ssklower 	case X25_1980:
47441593Ssklower 	case X25_1984:
47541593Ssklower 		*fcp++ = FACILITIES_PACKETSIZE;
47641593Ssklower 		*fcp++ = sa -> x25_opts.op_psize;
47741593Ssklower 		*fcp++ = sa -> x25_opts.op_psize;
47841593Ssklower 
47941593Ssklower 		*fcp++ = FACILITIES_WINDOWSIZE;
48041593Ssklower 		*fcp++ = sa -> x25_opts.op_wsize;
48141593Ssklower 		*fcp++ = sa -> x25_opts.op_wsize;
48241593Ssklower 	}
48345895Ssklower 	*cp = fcp - cp - 1;
48445895Ssklower 	m -> m_pkthdr.len = (m -> m_len += *cp + 1);
48541593Ssklower }
48641593Ssklower 
487*49747Ssklower to_bcd (b, sa, xcp)
488*49747Ssklower register struct bcdinfo *b;
489*49747Ssklower struct sockaddr_x25 *sa;
490*49747Ssklower register struct x25config *xcp;
49141593Ssklower {
492*49747Ssklower 	register char *x = sa -> x25_addr;
493*49747Ssklower 	unsigned start = b -> posn;
494*49747Ssklower 	/*
495*49747Ssklower 	 * The nodnic and prepnd0 stuff looks tedious,
496*49747Ssklower 	 * but it does allow full X.121 addresses to be used,
497*49747Ssklower 	 * which is handy for routing info (& OSI type 37 addresses).
498*49747Ssklower 	 */
499*49747Ssklower 	if (xcp -> xc_addr.x25_net && (xcp -> xc_nodnic || xcp -> xc_prepnd0)) {
500*49747Ssklower 		char dnicname[sizeof(long) * NBBY/3 + 2];
501*49747Ssklower 		register char *p = dnicname;
502*49747Ssklower 
503*49747Ssklower 		sprintf (p, "%d", xcp -> xc_addr.x25_net & 0x7fff);
504*49747Ssklower 		for (; *p; p++) /* *p == 0 means dnic matched */
505*49747Ssklower 			if ((*p ^ *x++) & 0x0f)
506*49747Ssklower 				break;
507*49747Ssklower 		if (*p || xcp -> xc_nodnic == 0)
508*49747Ssklower 			x = sa -> x25_addr;
509*49747Ssklower 		if (*p && xcp -> xc_prepnd0) {
510*49747Ssklower 			if ((b -> posn)++ & 0x01)
511*49747Ssklower 				*(b -> cp)++;
512*49747Ssklower 			else
513*49747Ssklower 				*(b -> cp) = 0;
514*49747Ssklower 		}
515*49747Ssklower 	}
516*49747Ssklower 	while (*x)
517*49747Ssklower 		if ((b -> posn)++ & 0x01)
518*49747Ssklower 			*(b -> cp)++ |= *x++ & 0x0F;
51941593Ssklower 		else
520*49747Ssklower 			*(b -> cp) = *x++ << 4;
521*49747Ssklower 	return ((b -> posn) - start);
52241593Ssklower }
52341593Ssklower 
52441593Ssklower /*
52541593Ssklower  *  This routine gets the  first available logical channel number.  The
52641593Ssklower  *  search is from the highest number to lowest number (DTE).
52741593Ssklower  */
52841593Ssklower 
52941593Ssklower pk_getlcn (pkp)
53041593Ssklower register struct pkcb *pkp;
53141593Ssklower {
53241593Ssklower 	register int i;
53341593Ssklower 
53445297Ssklower 	if (pkp -> pk_chan == 0)
53542140Ssklower 		return (0);
53641593Ssklower 	for (i = pkp -> pk_maxlcn; i > 0; --i)
53741593Ssklower 		if (pkp -> pk_chan[i] == NULL)
53841593Ssklower 			break;
53941593Ssklower 	return (i);
54041593Ssklower 
54141593Ssklower }
54241593Ssklower 
54341593Ssklower /*
54441593Ssklower  *  This procedure sends a CLEAR request packet. The lc state is
54541593Ssklower  *  set to "SENT_CLEAR".
54641593Ssklower  */
54741593Ssklower 
54845895Ssklower pk_clear (lcp, diagnostic, abortive)
54945895Ssklower register struct pklcd *lcp;
55041593Ssklower {
55145895Ssklower 	register struct mbuf *m = pk_template (lcp -> lcd_lcn, X25_CLEAR);
55241593Ssklower 
55345895Ssklower 	m -> m_len += 2;
55447271Ssklower 	mtod (m, struct x25_packet *) -> packet_data = 0;
55547271Ssklower 	mtod (m, octet *)[4] = diagnostic;
55645895Ssklower 	if (lcp -> lcd_facilities) {
55745895Ssklower 		m -> m_next = lcp -> lcd_facilities;
55845895Ssklower 		m -> m_pkthdr.len += m -> m_next -> m_len;
55945895Ssklower 		lcp -> lcd_facilities = 0;
56045895Ssklower 	}
56145895Ssklower 	if (abortive)
56245895Ssklower 		lcp -> lcd_template = m;
56345895Ssklower 	else {
56445895Ssklower 		struct socket *so = lcp -> lcd_so;
56545895Ssklower 		struct sockbuf *sb = so ? & so -> so_snd : & lcp -> lcd_sb;
56647271Ssklower 		sbappendrecord (sb, m);
56745895Ssklower 	}
56841593Ssklower 	pk_output (lcp);
56941593Ssklower 
57041593Ssklower }
57141593Ssklower 
57247271Ssklower /*
57347271Ssklower  * This procedure generates RNR's or RR's to inhibit or enable
57447271Ssklower  * inward data flow, if the current state changes (blocked ==> open or
57547271Ssklower  * vice versa), or if forced to generate one.  One forces RNR's to ack data.
57647271Ssklower  */
57747271Ssklower pk_flowcontrol (lcp, inhibit, forced)
57847271Ssklower register struct pklcd *lcp;
57947271Ssklower {
58047271Ssklower 	inhibit = (inhibit != 0);
58147271Ssklower 	if (lcp == 0 || lcp -> lcd_state != DATA_TRANSFER ||
58247271Ssklower 	    (forced == 0 && lcp -> lcd_rxrnr_condition == inhibit))
58347271Ssklower 		return;
58447271Ssklower 	lcp -> lcd_rxrnr_condition = inhibit;
58547271Ssklower 	lcp -> lcd_template = pk_template (lcp -> lcd_lcn, inhibit ? RNR : RR);
58647271Ssklower 	pk_output (lcp);
58747271Ssklower }
58847271Ssklower 
58941593Ssklower /*
59047271Ssklower  *  This procedure sends a RESET request packet. It re-intializes
59141593Ssklower  *  virtual circuit.
59241593Ssklower  */
59341593Ssklower 
59441593Ssklower static
59545895Ssklower pk_reset (lcp, diagnostic)
59641593Ssklower register struct pklcd *lcp;
59741593Ssklower {
59845895Ssklower 	register struct mbuf *m;
59945895Ssklower 	register struct socket *so = lcp -> lcd_so;
60041593Ssklower 
60141593Ssklower 	if (lcp -> lcd_state != DATA_TRANSFER)
60241593Ssklower 		return;
60341593Ssklower 
60445895Ssklower 	if (so)
60545895Ssklower 		so -> so_error = ECONNRESET;
60641593Ssklower 	lcp -> lcd_reset_condition = TRUE;
60741593Ssklower 
60841593Ssklower 	/* Reset all the control variables for the channel. */
60945895Ssklower 	pk_flush (lcp);
61041593Ssklower 	lcp -> lcd_window_condition = lcp -> lcd_rnr_condition =
61141593Ssklower 		lcp -> lcd_intrconf_pending = FALSE;
61241593Ssklower 	lcp -> lcd_rsn = MODULUS - 1;
61341593Ssklower 	lcp -> lcd_ssn = 0;
61441593Ssklower 	lcp -> lcd_output_window = lcp -> lcd_input_window =
61541593Ssklower 		lcp -> lcd_last_transmitted_pr = 0;
61645895Ssklower 	m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET);
61749595Ssklower 	m -> m_pkthdr.len = m -> m_len += 2;
61847271Ssklower 	mtod (m, struct x25_packet *) -> packet_data = 0;
61947271Ssklower 	mtod (m, octet *)[4] = diagnostic;
62045895Ssklower 	pk_output (lcp);
62145895Ssklower 
62245895Ssklower }
62345895Ssklower 
62445895Ssklower /*
62545895Ssklower  * This procedure frees all data queued for output or delivery on a
62645895Ssklower  *  virtual circuit.
62745895Ssklower  */
62845895Ssklower 
62945895Ssklower pk_flush (lcp)
63045895Ssklower register struct pklcd *lcp;
63145895Ssklower {
63245895Ssklower 	register struct socket *so;
63345895Ssklower 
63445895Ssklower 	if (lcp -> lcd_template)
63545895Ssklower 		m_freem (lcp -> lcd_template);
63645895Ssklower 
63745895Ssklower 	if (lcp -> lcd_cps) {
63847271Ssklower 		m_freem (lcp -> lcd_cps);
63945895Ssklower 		lcp -> lcd_cps = 0;
64045895Ssklower 	}
64147271Ssklower 	if (lcp -> lcd_facilities) {
64247271Ssklower 		m_freem (lcp -> lcd_facilities);
64347271Ssklower 		lcp -> lcd_facilities = 0;
64447271Ssklower 	}
64547271Ssklower 	if (so = lcp -> lcd_so) {
64642140Ssklower 		sbflush (&so -> so_rcv);
64742140Ssklower 		sbflush (&so -> so_snd);
64845895Ssklower 	} else
64945895Ssklower 		sbflush (&lcp -> lcd_sb);
65041593Ssklower }
65141593Ssklower 
65241593Ssklower /*
65341593Ssklower  *  This procedure handles all local protocol procedure errors.
65441593Ssklower  */
65541593Ssklower 
65645895Ssklower pk_procerror (error, lcp, errstr, diagnostic)
65741593Ssklower register struct pklcd *lcp;
65841593Ssklower char *errstr;
65941593Ssklower {
66041593Ssklower 
66141593Ssklower 	pk_message (lcp -> lcd_lcn, lcp -> lcd_pkp -> pk_xcp, errstr);
66241593Ssklower 
66341593Ssklower 	switch (error) {
66441593Ssklower 	case CLEAR:
66545297Ssklower 		if (lcp -> lcd_so) {
66645297Ssklower 			lcp -> lcd_so -> so_error = ECONNABORTED;
66745297Ssklower 			soisdisconnecting (lcp -> lcd_so);
66841593Ssklower 		}
66945895Ssklower 		pk_clear (lcp, diagnostic, 1);
67041593Ssklower 		break;
67141593Ssklower 
67241593Ssklower 	case RESET:
67345895Ssklower 		pk_reset (lcp, diagnostic);
67441593Ssklower 	}
67541593Ssklower }
67641593Ssklower 
67741593Ssklower /*
67841593Ssklower  *  This procedure is called during the DATA TRANSFER state to check
67941593Ssklower  *  and  process  the P(R) values  received  in the DATA,  RR OR RNR
68041593Ssklower  *  packets.
68141593Ssklower  */
68241593Ssklower 
68341593Ssklower pk_ack (lcp, pr)
68441593Ssklower struct pklcd *lcp;
68541593Ssklower unsigned pr;
68641593Ssklower {
68741593Ssklower 	register struct socket *so = lcp -> lcd_so;
68841593Ssklower 
68941593Ssklower 	if (lcp -> lcd_output_window == pr)
69041593Ssklower 		return (PACKET_OK);
69141593Ssklower 	if (lcp -> lcd_output_window < lcp -> lcd_ssn) {
69241593Ssklower 		if (pr < lcp -> lcd_output_window || pr > lcp -> lcd_ssn) {
69345895Ssklower 			pk_procerror (RESET, lcp,
69445895Ssklower 				"p(r) flow control error", 2);
69541593Ssklower 			return (ERROR_PACKET);
69641593Ssklower 		}
69741593Ssklower 	}
69841593Ssklower 	else {
69941593Ssklower 		if (pr < lcp -> lcd_output_window && pr > lcp -> lcd_ssn) {
70045895Ssklower 			pk_procerror (RESET, lcp,
70147271Ssklower 				"p(r) flow control error #2", 2);
70241593Ssklower 			return (ERROR_PACKET);
70341593Ssklower 		}
70441593Ssklower 	}
70541593Ssklower 
70641593Ssklower 	lcp -> lcd_output_window = pr;		/* Rotate window. */
70741593Ssklower 	if (lcp -> lcd_window_condition == TRUE)
70841593Ssklower 		lcp -> lcd_window_condition = FALSE;
70941593Ssklower 
71042140Ssklower 	if (so && ((so -> so_snd.sb_flags & SB_WAIT) || so -> so_snd.sb_sel))
71141593Ssklower 		sowwakeup (so);
71241593Ssklower 
71341593Ssklower 	return (PACKET_OK);
71441593Ssklower }
71541593Ssklower 
71641593Ssklower /*
71741593Ssklower  *  This procedure decodes the X.25 level 3 packet returning a
71841593Ssklower  *  code to be used in switchs or arrays.
71941593Ssklower  */
72041593Ssklower 
72141593Ssklower pk_decode (xp)
72241593Ssklower register struct x25_packet *xp;
72341593Ssklower {
72441593Ssklower 	register int type;
72541593Ssklower 
72641593Ssklower 	if (xp -> fmt_identifier != 1)
72741593Ssklower 		return (INVALID_PACKET);
72845895Ssklower #ifdef ancient_history
72941593Ssklower 	/*
73041593Ssklower 	 *  Make sure that the logical channel group number is 0.
73141593Ssklower 	 *  This restriction may be removed at some later date.
73241593Ssklower 	 */
73341593Ssklower 	if (xp -> lc_group_number != 0)
73441593Ssklower 		return (INVALID_PACKET);
73545895Ssklower #endif
73641593Ssklower 	/*
73741593Ssklower 	 *  Test for data packet first.
73841593Ssklower 	 */
73941593Ssklower 	if (!(xp -> packet_type & DATA_PACKET_DESIGNATOR))
74041593Ssklower 		return (DATA);
74141593Ssklower 
74241593Ssklower 	/*
74341593Ssklower 	 *  Test if flow control packet (RR or RNR).
74441593Ssklower 	 */
74541593Ssklower 	if (!(xp -> packet_type & RR_OR_RNR_PACKET_DESIGNATOR))
74647271Ssklower 		switch (xp -> packet_type & 0x1f) {
74747271Ssklower 		case X25_RR:
74841593Ssklower 			return (RR);
74947271Ssklower 		case X25_RNR:
75041593Ssklower 			return (RNR);
75147271Ssklower 		case X25_REJECT:
75247271Ssklower 			return (REJECT);
75347271Ssklower 		}
75441593Ssklower 
75541593Ssklower 	/*
75641593Ssklower 	 *  Determine the rest of the packet types.
75741593Ssklower 	 */
75841593Ssklower 	switch (xp -> packet_type) {
75941593Ssklower 	case X25_CALL:
76041593Ssklower 		type = CALL;
76141593Ssklower 		break;
76241593Ssklower 
76341593Ssklower 	case X25_CALL_ACCEPTED:
76441593Ssklower 		type = CALL_ACCEPTED;
76541593Ssklower 		break;
76641593Ssklower 
76741593Ssklower 	case X25_CLEAR:
76841593Ssklower 		type = CLEAR;
76941593Ssklower 		break;
77041593Ssklower 
77141593Ssklower 	case X25_CLEAR_CONFIRM:
77241593Ssklower 		type = CLEAR_CONF;
77341593Ssklower 		break;
77441593Ssklower 
77541593Ssklower 	case X25_INTERRUPT:
77641593Ssklower 		type = INTERRUPT;
77741593Ssklower 		break;
77841593Ssklower 
77941593Ssklower 	case X25_INTERRUPT_CONFIRM:
78041593Ssklower 		type = INTERRUPT_CONF;
78141593Ssklower 		break;
78241593Ssklower 
78341593Ssklower 	case X25_RESET:
78441593Ssklower 		type = RESET;
78541593Ssklower 		break;
78641593Ssklower 
78741593Ssklower 	case X25_RESET_CONFIRM:
78841593Ssklower 		type = RESET_CONF;
78941593Ssklower 		break;
79041593Ssklower 
79141593Ssklower 	case X25_RESTART:
79241593Ssklower 		type = RESTART;
79341593Ssklower 		break;
79441593Ssklower 
79541593Ssklower 	case X25_RESTART_CONFIRM:
79641593Ssklower 		type = RESTART_CONF;
79741593Ssklower 		break;
79841593Ssklower 
79947271Ssklower 	case X25_DIAGNOSTIC:
80048873Ssklower 		type = DIAG_TYPE;
80147271Ssklower 		break;
80247271Ssklower 
80341593Ssklower 	default:
80441593Ssklower 		type = INVALID_PACKET;
80541593Ssklower 	}
80641593Ssklower 	return (type);
80741593Ssklower }
80841593Ssklower 
80941593Ssklower /*
81041593Ssklower  *  A restart packet has been received. Print out the reason
81141593Ssklower  *  for the restart.
81241593Ssklower  */
81341593Ssklower 
81441593Ssklower pk_restartcause (pkp, xp)
81541593Ssklower struct pkcb *pkp;
81641593Ssklower register struct x25_packet *xp;
81741593Ssklower {
81841593Ssklower 	register struct x25config *xcp = pkp -> pk_xcp;
81945574Ssklower 	register int lcn = LCN(xp);
82041593Ssklower 
82141593Ssklower 	switch (xp -> packet_data) {
82241593Ssklower 	case X25_RESTART_LOCAL_PROCEDURE_ERROR:
82341593Ssklower 		pk_message (lcn, xcp, "restart: local procedure error");
82441593Ssklower 		break;
82541593Ssklower 
82641593Ssklower 	case X25_RESTART_NETWORK_CONGESTION:
82741593Ssklower 		pk_message (lcn, xcp, "restart: network congestion");
82841593Ssklower 		break;
82941593Ssklower 
83041593Ssklower 	case X25_RESTART_NETWORK_OPERATIONAL:
83141593Ssklower 		pk_message (lcn, xcp, "restart: network operational");
83241593Ssklower 		break;
83341593Ssklower 
83441593Ssklower 	default:
83541593Ssklower 		pk_message (lcn, xcp, "restart: unknown cause");
83641593Ssklower 	}
83741593Ssklower }
83841593Ssklower 
83941593Ssklower #define MAXRESETCAUSE	7
84041593Ssklower 
84141593Ssklower int     Reset_cause[] = {
84241593Ssklower 	EXRESET, EXROUT, 0, EXRRPE, 0, EXRLPE, 0, EXRNCG
84341593Ssklower };
84441593Ssklower 
84541593Ssklower /*
84641593Ssklower  *  A reset packet has arrived. Return the cause to the user.
84741593Ssklower  */
84841593Ssklower 
84941593Ssklower pk_resetcause (pkp, xp)
85041593Ssklower struct pkcb *pkp;
85141593Ssklower register struct x25_packet *xp;
85241593Ssklower {
85345297Ssklower 	register struct pklcd *lcp =
85445574Ssklower 				pkp -> pk_chan[LCN(xp)];
85541593Ssklower 	register int code = xp -> packet_data;
85641593Ssklower 
85741593Ssklower 	if (code > MAXRESETCAUSE)
85841593Ssklower 		code = 7;	/* EXRNCG */
85941593Ssklower 
86047271Ssklower 	pk_message(LCN(xp), lcp -> lcd_pkp, "reset code 0x%x, diagnostic 0x%x",
86147271Ssklower 			xp -> packet_data, 4[(u_char *)xp]);
86247271Ssklower 
86345297Ssklower 	lcp -> lcd_so -> so_error = Reset_cause[code];
86441593Ssklower }
86541593Ssklower 
86641593Ssklower #define MAXCLEARCAUSE	25
86741593Ssklower 
86841593Ssklower int     Clear_cause[] = {
86941593Ssklower 	EXCLEAR, EXCBUSY, 0, EXCINV, 0, EXCNCG, 0,
87041593Ssklower 	0, 0, EXCOUT, 0, EXCAB, 0, EXCNOB, 0, 0, 0, EXCRPE,
87141593Ssklower 	0, EXCLPE, 0, 0, 0, 0, 0, EXCRRC
87241593Ssklower };
87341593Ssklower 
87441593Ssklower /*
87541593Ssklower  *  A clear packet has arrived. Return the cause to the user.
87641593Ssklower  */
87741593Ssklower 
87841593Ssklower pk_clearcause (pkp, xp)
87941593Ssklower struct pkcb *pkp;
88041593Ssklower register struct x25_packet *xp;
88141593Ssklower {
88245297Ssklower 	register struct pklcd *lcp =
88345574Ssklower 		pkp -> pk_chan[LCN(xp)];
88441593Ssklower 	register int code = xp -> packet_data;
88541593Ssklower 
88641593Ssklower 	if (code > MAXCLEARCAUSE)
88741593Ssklower 		code = 5;	/* EXRNCG */
88849595Ssklower 	if (lcp -> lcd_so)
88949595Ssklower 		lcp -> lcd_so -> so_error = Clear_cause[code];
89041593Ssklower }
89141593Ssklower 
89241593Ssklower char *
89341593Ssklower format_ntn (xcp)
89441593Ssklower register struct x25config *xcp;
89541593Ssklower {
89641593Ssklower 
89745165Ssklower 	return (xcp -> xc_addr.x25_addr);
89841593Ssklower }
89941593Ssklower 
90041593Ssklower /* VARARGS1 */
90141593Ssklower pk_message (lcn, xcp, fmt, a1, a2, a3, a4, a5, a6)
90241593Ssklower struct x25config *xcp;
90341593Ssklower char *fmt;
90441593Ssklower {
90541593Ssklower 
90641593Ssklower 	if (lcn)
90741593Ssklower 		if (pkcbhead -> pk_next)
90841593Ssklower 			printf ("X.25(%s): lcn %d: ", format_ntn (xcp), lcn);
90941593Ssklower 		else
91041593Ssklower 			printf ("X.25: lcn %d: ", lcn);
91141593Ssklower 	else
91241593Ssklower 		if (pkcbhead -> pk_next)
91341593Ssklower 			printf ("X.25(%s): ", format_ntn (xcp));
91441593Ssklower 		else
91541593Ssklower 			printf ("X.25: ");
91641593Ssklower 
91741593Ssklower 	printf (fmt, a1, a2, a3, a4, a5, a6);
91841593Ssklower 	printf ("\n");
91941593Ssklower }
92045297Ssklower 
92147271Ssklower pk_ifattach (ia, lloutput, llnext)
92245297Ssklower register struct x25_ifaddr *ia;
92347271Ssklower int (*lloutput) ();
92445297Ssklower caddr_t llnext;
92545297Ssklower {
92645297Ssklower 	/* this is here because you can't include both pk_var and hd_var */
92745297Ssklower 	/* this will probably be replace by a streams gluing mechanism */
92845297Ssklower 	ia -> ia_pkcb.pk_lloutput = lloutput;
92945297Ssklower 	ia -> ia_pkcb.pk_llnext = llnext;
93045297Ssklower }
93145297Ssklower 
93247271Ssklower pk_fragment (lcp, m0, qbit, mbit, wait)
93345297Ssklower struct mbuf *m0;
93445297Ssklower register struct pklcd *lcp;
93545297Ssklower {
93645297Ssklower 	register struct mbuf *m = m0;
93745297Ssklower 	register struct x25_packet *xp;
93845297Ssklower 	register struct sockbuf *sb;
93947271Ssklower 	struct mbuf *head = 0, *next, **mp = &head, *m_split ();
94045297Ssklower 	int totlen, psize = 1 << (lcp -> lcd_packetsize);
94145297Ssklower 
94245297Ssklower 	if (m == 0)
94349595Ssklower 		return 0;
94445895Ssklower 	if (m -> m_flags & M_PKTHDR == 0)
94547271Ssklower 		panic ("pk_fragment");
94645297Ssklower 	totlen = m -> m_pkthdr.len;
94745574Ssklower 	m -> m_act = 0;
94845297Ssklower 	sb = lcp -> lcd_so ? &lcp -> lcd_so -> so_snd : & lcp -> lcd_sb;
94945297Ssklower 	do {
95045297Ssklower 		if (totlen > psize) {
95147271Ssklower 			if ((next = m_split (m, psize, wait)) == 0)
95245297Ssklower 				goto abort;
95345297Ssklower 			totlen -= psize;
95445574Ssklower 		} else
95545574Ssklower 			next = 0;
95645297Ssklower 		M_PREPEND(m, PKHEADERLN, wait);
95745297Ssklower 		if (m == 0)
95845297Ssklower 			goto abort;
95945574Ssklower 		*mp = m;
96045574Ssklower 		mp = & m -> m_act;
96145574Ssklower 		*mp = 0;
96247271Ssklower 		xp = mtod (m, struct x25_packet *);
96345297Ssklower 		0[(char *)xp] = 0;
96445297Ssklower 		if (qbit)
96545574Ssklower 			xp -> q_bit = 1;
96645574Ssklower 		if (lcp -> lcd_flags & X25_DBIT)
96745574Ssklower 			xp -> d_bit = 1;
96845297Ssklower 		xp -> fmt_identifier = 1;
96945297Ssklower 		xp -> packet_type = X25_DATA;
97045574Ssklower 		SET_LCN(xp, lcp -> lcd_lcn);
97145574Ssklower 		if (next || (mbit && (totlen == psize ||
97245574Ssklower 				      (lcp -> lcd_flags & X25_DBIT))))
97345297Ssklower 			MBIT(xp) = 1;
97445297Ssklower 	} while (m = next);
97545574Ssklower 	for (m = head; m; m = next) {
97645297Ssklower 		next = m -> m_act;
97745297Ssklower 		m -> m_act = 0;
97847271Ssklower 		sbappendrecord (sb, m);
97945297Ssklower 	}
98045297Ssklower 	return 0;
98145297Ssklower abort:
98245574Ssklower 	if (wait)
98347271Ssklower 		panic ("pk_fragment null mbuf after wait");
98445574Ssklower 	if (next)
98547271Ssklower 		m_freem (next);
98645574Ssklower 	for (m = head; m; m = next) {
98745297Ssklower 		next = m -> m_act;
98847271Ssklower 		m_freem (m);
98945297Ssklower 	}
99045297Ssklower 	return ENOBUFS;
99145297Ssklower }
99245574Ssklower 
99345574Ssklower struct mbuf *
99447271Ssklower m_split (m0, len0, wait)
99545574Ssklower register struct mbuf *m0;
99645574Ssklower int len0;
99745574Ssklower {
99845574Ssklower 	register struct mbuf *m, *n;
99945574Ssklower 	unsigned len = len0;
100045574Ssklower 
100145574Ssklower 	for (m = m0; m && len > m -> m_len; m = m -> m_next)
100245574Ssklower 		len -= m -> m_len;
100345574Ssklower 	if (m == 0)
100445574Ssklower 		return (0);
100545574Ssklower 	if (m0 -> m_flags & M_PKTHDR) {
100645574Ssklower 		MGETHDR(n, wait, m0 -> m_type);
100745574Ssklower 		if (n == 0)
100845574Ssklower 			return (0);
100945574Ssklower 		n -> m_pkthdr.rcvif = m0 -> m_pkthdr.rcvif;
101045574Ssklower 		n -> m_pkthdr.len = m0 -> m_pkthdr.len - len0;
101145574Ssklower 		m0 -> m_pkthdr.len = len0;
101245574Ssklower 		if (m -> m_flags & M_EXT)
101345574Ssklower 			goto extpacket;
101445574Ssklower 		if (len > MHLEN) {
101545574Ssklower 			/* m can't be the lead packet */
101645574Ssklower 			MH_ALIGN(n, 0);
101747271Ssklower 			n -> m_next = m_split (m, len, wait);
101845574Ssklower 			if (n -> m_next == 0) {
101947271Ssklower 				(void) m_free (n);
102045574Ssklower 				return (0);
102145574Ssklower 			} else
102245574Ssklower 				return (n);
102345574Ssklower 		} else
102445574Ssklower 			MH_ALIGN(n, len);
102545574Ssklower 	} else if (len == m -> m_len) {
102645574Ssklower 		n = m -> m_next;
102745574Ssklower 		m -> m_next = 0;
102845574Ssklower 		return (n);
102945574Ssklower 	}
103045574Ssklower extpacket:
103145574Ssklower 	len = m -> m_len - len;		/* remainder to be copied */
103245574Ssklower 	m -> m_len -= len;		/* now equals original len */
103345895Ssklower 	if (m -> m_flags & M_EXT) {
103445574Ssklower 		n -> m_flags |= M_EXT;
103545574Ssklower 		n -> m_ext = m -> m_ext;
103647271Ssklower 		mclrefcnt[mtocl (m -> m_ext.ext_buf)]++;
103745574Ssklower 		n -> m_data = m -> m_data + m -> m_len;
103845574Ssklower 	} else {
103945574Ssklower 		MGET(n, wait, m -> m_type);
104045574Ssklower 		if (n == 0) {
104145574Ssklower 			m -> m_len += len;
104245574Ssklower 			return (0);
104345574Ssklower 		}
104445574Ssklower 		M_ALIGN(n, len);
104547271Ssklower 		bcopy (mtod (m, caddr_t), mtod (n, caddr_t), len);
104645574Ssklower 	}
104745574Ssklower 	n -> m_len = len;
104845574Ssklower 	n -> m_next = m -> m_next;
104945574Ssklower 	m -> m_next = 0;
105045574Ssklower 	return (n);
105145574Ssklower }
1052