xref: /csrg-svn/sys/netccitt/pk_subr.c (revision 49018)
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*49018Ssklower  *	@(#)pk_subr.c	7.12 (Berkeley) 05/03/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;
50*49018Ssklower 	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);
5642277Ssklower 		if (so) {
5742277Ssklower 			error = soreserve (so, pk_sendspace, pk_recvspace);
5842277Ssklower 			lcp -> lcd_so = so;
5942277Ssklower 			if (so -> so_options & SO_ACCEPTCONN)
6042277Ssklower 				lcp -> lcd_state = LISTEN;
6142277Ssklower 			else
6242277Ssklower 				lcp -> lcd_state = READY;
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 	}
70*49018Ssklower 	lcp -> lcd_send = pk_output;
7142277Ssklower 	return (lcp);
7241593Ssklower }
7341593Ssklower 
7441593Ssklower /*
7541593Ssklower  *  Disconnect X.25 protocol from socket.
7641593Ssklower  */
7741593Ssklower 
7841593Ssklower pk_disconnect (lcp)
7941593Ssklower register struct pklcd *lcp;
8041593Ssklower {
8141593Ssklower 	register struct socket *so = lcp -> lcd_so;
8241593Ssklower 	register struct pklcd *l, *p;
8341593Ssklower 
8441593Ssklower 	switch (lcp -> lcd_state) {
8541593Ssklower 	case LISTEN:
8641593Ssklower 		for (p = 0, l = pk_listenhead; l && l != lcp; p = l, l = l -> lcd_listen);
8741593Ssklower 		if (p == 0) {
8841593Ssklower 			if (l != 0)
8941593Ssklower 				pk_listenhead = l -> lcd_listen;
9041593Ssklower 		}
9141593Ssklower 		else
9241593Ssklower 		if (l != 0)
9341593Ssklower 			p -> lcd_listen = l -> lcd_listen;
9441593Ssklower 		pk_close (lcp);
9541593Ssklower 		break;
9641593Ssklower 
9741593Ssklower 	case READY:
9841593Ssklower 		pk_acct (lcp);
9941593Ssklower 		pk_close (lcp);
10041593Ssklower 		break;
10141593Ssklower 
10241593Ssklower 	case SENT_CLEAR:
10341593Ssklower 	case RECEIVED_CLEAR:
10441593Ssklower 		break;
10541593Ssklower 
10641593Ssklower 	default:
10741593Ssklower 		pk_acct (lcp);
10842140Ssklower 		if (so) {
10942140Ssklower 			soisdisconnecting (so);
11042140Ssklower 			sbflush (&so -> so_rcv);
11142140Ssklower 		}
11245895Ssklower 		pk_clear (lcp, 241, 0); /* Normal Disconnect */
11341593Ssklower 
11441593Ssklower 	}
11541593Ssklower }
11641593Ssklower 
11741593Ssklower /*
11841593Ssklower  *  Close an X.25 Logical Channel. Discard all space held by the
11941593Ssklower  *  connection and internal descriptors. Wake up any sleepers.
12041593Ssklower  */
12141593Ssklower 
12241593Ssklower pk_close (lcp)
12341593Ssklower struct pklcd *lcp;
12441593Ssklower {
12541593Ssklower 	register struct socket *so = lcp -> lcd_so;
12641593Ssklower 
12741593Ssklower 	pk_freelcd (lcp);
12841593Ssklower 
12941593Ssklower 	if (so == NULL)
13041593Ssklower 		return;
13141593Ssklower 
13241593Ssklower 	so -> so_pcb = 0;
13341593Ssklower 	soisdisconnected (so);
13445895Ssklower 	/* sofree (so);	/* gak!!! you can't do that here */
13541593Ssklower }
13641593Ssklower 
13741593Ssklower /*
13841593Ssklower  *  Create a template to be used to send X.25 packets on a logical
13941593Ssklower  *  channel. It allocates an mbuf and fills in a skeletal packet
14041593Ssklower  *  depending on its type. This packet is passed to pk_output where
14141593Ssklower  *  the remainer of the packet is filled in.
14241593Ssklower */
14341593Ssklower 
14445895Ssklower struct mbuf *
14541593Ssklower pk_template (lcn, type)
14641593Ssklower int lcn, type;
14741593Ssklower {
14841593Ssklower 	register struct mbuf *m;
14941593Ssklower 	register struct x25_packet *xp;
15041593Ssklower 
15145297Ssklower 	MGETHDR (m, M_DONTWAIT, MT_HEADER);
15241593Ssklower 	if (m == 0)
15341593Ssklower 		panic ("pk_template");
15441593Ssklower 	m -> m_act = 0;
15541593Ssklower 
15641593Ssklower 	/*
15741593Ssklower 	 * Efficiency hack: leave a four byte gap at the beginning
15841593Ssklower 	 * of the packet level header with the hope that this will
15941593Ssklower 	 * be enough room for the link level to insert its header.
16041593Ssklower 	 */
16145297Ssklower 	m -> m_data += max_linkhdr;
16241593Ssklower 	m -> m_len = PKHEADERLN;
16341593Ssklower 
16441593Ssklower 	xp = mtod (m, struct x25_packet *);
16541593Ssklower 	*(long *)xp = 0;		/* ugly, but fast */
16641593Ssklower /*	xp -> q_bit = 0;*/
16741593Ssklower 	xp -> fmt_identifier = 1;
16841593Ssklower /*	xp -> lc_group_number = 0;*/
16941593Ssklower 
17045574Ssklower 	SET_LCN(xp, lcn);
17141593Ssklower 	xp -> packet_type = type;
17241593Ssklower 
17345895Ssklower 	return (m);
17441593Ssklower }
17541593Ssklower 
17641593Ssklower /*
17741593Ssklower  *  This routine restarts all the virtual circuits. Actually,
17841593Ssklower  *  the virtual circuits are not "restarted" as such. Instead,
17941593Ssklower  *  any active switched circuit is simply returned to READY
18041593Ssklower  *  state.
18141593Ssklower  */
18241593Ssklower 
18341593Ssklower pk_restart (pkp, restart_cause)
18441593Ssklower register struct pkcb *pkp;
18541593Ssklower int restart_cause;
18641593Ssklower {
18745895Ssklower 	register struct mbuf *m;
18841593Ssklower 	register struct pklcd *lcp;
18941593Ssklower 	register int i;
19041593Ssklower 
19141593Ssklower 	/* Restart all logical channels. */
19245297Ssklower 	if (pkp -> pk_chan == 0)
19342140Ssklower 		return;
19445297Ssklower 	for (i = 1; i <= pkp -> pk_maxlcn; ++i)
19545297Ssklower 		if ((lcp = pkp -> pk_chan[i]) != NULL) {
19645895Ssklower 			if (lcp -> lcd_so) {
19745297Ssklower 				lcp -> lcd_so -> so_error = ENETRESET;
19845895Ssklower 				pk_close (lcp);
19945895Ssklower 			} else {
20045895Ssklower 				pk_flush (lcp);
20145895Ssklower 				lcp -> lcd_state = READY;
20245895Ssklower 				if (lcp -> lcd_upper)
20347271Ssklower 					lcp -> lcd_upper (lcp, 0);
20445895Ssklower 			}
20541593Ssklower 		}
20641593Ssklower 
20741593Ssklower 	if (restart_cause < 0)
20841593Ssklower 		return;
20941593Ssklower 
21045297Ssklower 	pkp -> pk_state = DTE_SENT_RESTART;
21145297Ssklower 	lcp = pkp -> pk_chan[0];
21245895Ssklower 	m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESTART);
21345895Ssklower 	m -> m_len += 2;
21447271Ssklower 	mtod (m, struct x25_packet *) -> packet_data = 0;	/* DTE only */
21547271Ssklower 	mtod (m, octet *)[4]  = restart_cause;
21641593Ssklower 	pk_output (lcp);
21741593Ssklower }
21841593Ssklower 
21941593Ssklower 
22041593Ssklower /*
22141593Ssklower  *  This procedure frees up the Logical Channel Descripter.
22241593Ssklower  */
22341593Ssklower 
22441593Ssklower pk_freelcd (lcp)
22541593Ssklower register struct pklcd *lcp;
22641593Ssklower {
22741593Ssklower 	if (lcp == NULL)
22841593Ssklower 		return;
22941593Ssklower 
23041593Ssklower 	if (lcp -> lcd_lcn > 0)
23141593Ssklower 		lcp -> lcd_pkp -> pk_chan[lcp -> lcd_lcn] = NULL;
23241593Ssklower 
23347271Ssklower 	pk_flush (lcp);
23447271Ssklower 	remque (&lcp -> lcd_q);
23547271Ssklower 	free ((caddr_t)lcp, M_PCB);
23641593Ssklower }
23741593Ssklower 
23841593Ssklower 
23941593Ssklower /*
24041593Ssklower  *  Bind a address and protocol value to a socket.  The important
24141593Ssklower  *  part is the protocol value - the first four characters of the
24241593Ssklower  *  Call User Data field.
24341593Ssklower  */
24441593Ssklower 
24541593Ssklower pk_bind (lcp, nam)
24641593Ssklower struct pklcd *lcp;
24741593Ssklower struct mbuf *nam;
24841593Ssklower {
24941593Ssklower 	register struct pkcb *pkp;
25041593Ssklower 	register struct pklcd *pp;
25142277Ssklower 	register struct sockaddr_x25 *sa;
25241593Ssklower 
25341593Ssklower 	if (nam == NULL)
25441593Ssklower 		return (EADDRNOTAVAIL);
25541593Ssklower 	if (lcp -> lcd_ceaddr)				/* XXX */
25641593Ssklower 		return (EADDRINUSE);
25745895Ssklower 	if (pk_checksockaddr (nam))
25841593Ssklower 		return (EINVAL);
25941593Ssklower 	sa = mtod (nam, struct sockaddr_x25 *);
26041593Ssklower 
26141593Ssklower 	/*
26241593Ssklower 	 * If the user wishes to accept calls only from a particular
26341593Ssklower 	 * net (net != 0), make sure the net is known
26441593Ssklower 	 */
26541593Ssklower 
26641593Ssklower 	if (sa -> x25_net)
26741593Ssklower 		for (pkp = pkcbhead; ; pkp = pkp -> pk_next) {
26841593Ssklower 			if (pkp == 0)
26941593Ssklower 				return (ENETUNREACH);
27045165Ssklower 			if (pkp -> pk_xcp -> xc_addr.x25_net == sa -> x25_net)
27141593Ssklower 				break;
27241593Ssklower 		}
27341593Ssklower 
27445895Ssklower 	/*
27545895Ssklower 	 * For ISO's sake permit default listeners, but only one such . . .
27645895Ssklower 	 */
27745895Ssklower 	for (pp = pk_listenhead; pp; pp = pp -> lcd_listen) {
27845895Ssklower 		register struct sockaddr_x25 *sa2 = pp -> lcd_ceaddr;
27945895Ssklower 		if ((sa2 -> x25_udlen == sa -> x25_udlen) &&
28045895Ssklower 		    (sa2 -> x25_udlen == 0 ||
28145895Ssklower 		     (bcmp (sa2 -> x25_udata, sa -> x25_udata,
28245895Ssklower 			    min (sa2 -> x25_udlen, sa -> x25_udlen)) == 0)))
28345895Ssklower 				return (EADDRINUSE);
28445895Ssklower 	}
28542277Ssklower 	lcp -> lcd_laddr = *sa;
28642277Ssklower 	lcp -> lcd_ceaddr = &lcp -> lcd_laddr;
28741593Ssklower 	return (0);
28841593Ssklower }
28941593Ssklower 
29041593Ssklower /*
29145895Ssklower  * Include a bound control block in the list of listeners.
29245895Ssklower  */
29345895Ssklower pk_listen (lcp)
29445895Ssklower register struct pklcd *lcp;
29545895Ssklower {
29645895Ssklower 	register struct pklcd **pp;
29745895Ssklower 
29845895Ssklower 	if (lcp -> lcd_ceaddr == 0)
29945895Ssklower 		return (EDESTADDRREQ);
30045895Ssklower 
30145895Ssklower 	lcp -> lcd_state = LISTEN;
30245895Ssklower 	/*
30345895Ssklower 	 * Add default listener at end, any others at start.
30445895Ssklower 	 */
30545895Ssklower 	if (lcp -> lcd_ceaddr -> x25_udlen == 0) {
30645895Ssklower 		for (pp = &pk_listenhead; *pp; )
30745895Ssklower 			pp = &((*pp) -> lcd_listen);
30845895Ssklower 		*pp = lcp;
30945895Ssklower 	} else {
31045895Ssklower 		lcp -> lcd_listen = pk_listenhead;
31145895Ssklower 		pk_listenhead = lcp;
31245895Ssklower 	}
31345895Ssklower 	return (0);
31445895Ssklower }
31545895Ssklower /*
31645895Ssklower  * Include a listening control block for the benefit of other protocols.
31745895Ssklower  */
31845895Ssklower pk_protolisten (spi, spilen, callee)
31947271Ssklower int (*callee) ();
32045895Ssklower {
32145895Ssklower 	register struct pklcd *lcp = pk_attach ((struct socket *)0);
32245895Ssklower 	register struct mbuf *nam;
32345895Ssklower 	register struct sockaddr_x25 *sa;
32445895Ssklower 	int error = ENOBUFS;
32545895Ssklower 
32645895Ssklower 	if (lcp) {
32747271Ssklower 		if (nam = m_getclr (MT_SONAME, M_DONTWAIT)) {
32847271Ssklower 			sa = mtod (nam, struct sockaddr_x25 *);
32945895Ssklower 			sa -> x25_family = AF_CCITT;
33045895Ssklower 			sa -> x25_len = nam -> m_len = sizeof (*sa);
33145895Ssklower 			sa -> x25_udlen = spilen;
33245895Ssklower 			sa -> x25_udata[0] = spi;
33345895Ssklower 			lcp -> lcd_upper = callee;
33445895Ssklower 			lcp -> lcd_flags = X25_MBS_HOLD;
33545895Ssklower 			error = pk_bind (lcp, nam) || pk_listen (lcp);
33645895Ssklower 			(void) m_free (nam);
33745895Ssklower 		}
33845895Ssklower 		if (error)
33947271Ssklower 			pk_freelcd (lcp);
34045895Ssklower 	}
34145895Ssklower 	return error; /* Hopefully Zero !*/
34245895Ssklower }
34345895Ssklower 
34445895Ssklower /*
34541593Ssklower  * Associate a logical channel descriptor with a network.
34641593Ssklower  * Fill in the default network specific parameters and then
34741593Ssklower  * set any parameters explicitly specified by the user or
34841593Ssklower  * by the remote DTE.
34941593Ssklower  */
35041593Ssklower 
35141593Ssklower pk_assoc (pkp, lcp, sa)
35241593Ssklower register struct pkcb *pkp;
35341593Ssklower register struct pklcd *lcp;
35441593Ssklower register struct sockaddr_x25 *sa;
35541593Ssklower {
35641593Ssklower 
35741593Ssklower 	lcp -> lcd_pkp = pkp;
35841593Ssklower 	lcp -> lcd_packetsize = pkp -> pk_xcp -> xc_psize;
35941593Ssklower 	lcp -> lcd_windowsize = pkp -> pk_xcp -> xc_pwsize;
36041593Ssklower 	lcp -> lcd_rsn = MODULUS - 1;
36141593Ssklower 	pkp -> pk_chan[lcp -> lcd_lcn] = lcp;
36241593Ssklower 
36341593Ssklower 	if (sa -> x25_opts.op_psize)
36441593Ssklower 		lcp -> lcd_packetsize = sa -> x25_opts.op_psize;
36541593Ssklower 	else
36641593Ssklower 		sa -> x25_opts.op_psize = lcp -> lcd_packetsize;
36741593Ssklower 	if (sa -> x25_opts.op_wsize)
36841593Ssklower 		lcp -> lcd_windowsize = sa -> x25_opts.op_wsize;
36941593Ssklower 	else
37041593Ssklower 		sa -> x25_opts.op_wsize = lcp -> lcd_windowsize;
37145165Ssklower 	sa -> x25_net = pkp -> pk_xcp -> xc_addr.x25_net;
37241593Ssklower 	lcp -> lcd_flags = sa -> x25_opts.op_flags;
37341593Ssklower 	lcp -> lcd_stime = time.tv_sec;
37441593Ssklower }
37541593Ssklower 
37645895Ssklower pk_connect (lcp, sa)
37741593Ssklower register struct pklcd *lcp;
37842277Ssklower register struct sockaddr_x25 *sa;
37941593Ssklower {
38041593Ssklower 	register struct pkcb *pkp;
38141593Ssklower 
38241593Ssklower 	if (sa -> x25_addr[0] == '\0')
38341593Ssklower 		return (EDESTADDRREQ);
38445297Ssklower 	if (lcp -> lcd_pkp == 0)
38545297Ssklower 	    for (pkp = pkcbhead; ; pkp = pkp -> pk_next) {
38641593Ssklower 		if (pkp == 0)
38741593Ssklower 			return (ENETUNREACH);
38841593Ssklower 		/*
38941593Ssklower 		 * use first net configured (last in list
39041593Ssklower 		 * headed by pkcbhead) if net is zero
39141593Ssklower 		 */
39241593Ssklower 		if (sa -> x25_net == 0 && pkp -> pk_next == 0)
39341593Ssklower 			break;
39445165Ssklower 		if (sa -> x25_net == pkp -> pk_xcp -> xc_addr.x25_net)
39541593Ssklower 			break;
39641593Ssklower 	}
39741593Ssklower 
39841593Ssklower 	if (pkp -> pk_state != DTE_READY)
39941593Ssklower 		return (ENETDOWN);
40041593Ssklower 	if ((lcp -> lcd_lcn = pk_getlcn (pkp)) == 0)
40141593Ssklower 		return (EMFILE);
40242277Ssklower 	lcp -> lcd_faddr = *sa;
40345297Ssklower 	lcp -> lcd_ceaddr = & lcp -> lcd_faddr;
40441593Ssklower 	pk_assoc (pkp, lcp, lcp -> lcd_ceaddr);
40545165Ssklower 	if (lcp -> lcd_so)
40642140Ssklower 		soisconnecting (lcp -> lcd_so);
40741593Ssklower 	lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL);
40842277Ssklower 	pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp);
40947271Ssklower 	return (*pkp -> pk_start) (lcp);
41041593Ssklower }
41141593Ssklower 
41241593Ssklower /*
41341593Ssklower  *  Build the rest of the CALL REQUEST packet. Fill in calling
41441593Ssklower  *  address, facilities fields and the user data field.
41541593Ssklower  */
41641593Ssklower 
41742277Ssklower pk_callrequest (lcp, sa, xcp)
41841593Ssklower struct pklcd *lcp;
41942277Ssklower register struct sockaddr_x25 *sa;
42041593Ssklower register struct x25config *xcp;
42141593Ssklower {
42241593Ssklower 	register struct x25_calladdr *a;
42345895Ssklower 	register struct mbuf *m = lcp -> lcd_template;
42447271Ssklower 	register struct x25_packet *xp = mtod (m, struct x25_packet *);
42541593Ssklower 	unsigned posn = 0;
42641593Ssklower 	octet *cp;
42741593Ssklower 
42845574Ssklower 	if (lcp -> lcd_flags & X25_DBIT)
42945895Ssklower 		xp -> d_bit = 1;
43045895Ssklower 	a = (struct x25_calladdr *) &xp -> packet_data;
43145165Ssklower 	a -> calling_addrlen = strlen (xcp -> xc_addr.x25_addr);
43241593Ssklower 	a -> called_addrlen = strlen (sa -> x25_addr);
43341593Ssklower 	cp = (octet *) a -> address_field;
43441593Ssklower 	to_bcd (&cp, (int)a -> called_addrlen, sa -> x25_addr, &posn);
43545165Ssklower 	to_bcd (&cp, (int)a -> calling_addrlen, xcp -> xc_addr.x25_addr, &posn);
43641593Ssklower 	if (posn & 0x01)
43741593Ssklower 		*cp++ &= 0xf0;
43845895Ssklower 	m -> m_len += cp - (octet *) a;
43941593Ssklower 
44045895Ssklower 	if (lcp -> lcd_facilities) {
44147271Ssklower 		m -> m_pkthdr.len +=
44247271Ssklower 			(m -> m_next = lcp -> lcd_facilities) -> m_len;
44345895Ssklower 		lcp -> lcd_facilities = 0;
44445895Ssklower 	} else
44545895Ssklower 		build_facilities (m, sa, (int)xcp -> xc_type);
44641593Ssklower 
44747271Ssklower 	m_copyback (m, m -> m_pkthdr.len, sa -> x25_udlen, sa -> x25_udata);
44841593Ssklower #ifdef ANDREW
44941593Ssklower 	printf ("call: ");
45045297Ssklower 	for (cp = mtod (m, octet *), posn = 0; posn < m -> m_len; ++posn)
45141593Ssklower 		printf ("%x ", *cp++);
45241593Ssklower 	printf ("\n");
45341593Ssklower #endif
45441593Ssklower }
45541593Ssklower 
45647271Ssklower static
45745895Ssklower build_facilities (m, sa, type)
45845895Ssklower register struct mbuf *m;
45941593Ssklower struct sockaddr_x25 *sa;
46041593Ssklower {
46145895Ssklower 	register octet *cp;
46241593Ssklower 	register octet *fcp;
46341593Ssklower 	register int revcharge;
46441593Ssklower 
46547271Ssklower 	cp = mtod (m, octet *) + m -> m_len;
46645895Ssklower 	fcp = cp + 1;
46741593Ssklower 	revcharge = sa -> x25_opts.op_flags & X25_REVERSE_CHARGE ? 1 : 0;
46841593Ssklower 	/*
46941593Ssklower 	 * This is specific to Datapac X.25(1976) DTEs.  International
47041593Ssklower 	 * calls must have the "hi priority" bit on.
47141593Ssklower 	 */
47241593Ssklower 	if (type == X25_1976 && sa -> x25_opts.op_psize == X25_PS128)
47341593Ssklower 		revcharge |= 02;
47441593Ssklower 	if (revcharge) {
47541593Ssklower 		*fcp++ = FACILITIES_REVERSE_CHARGE;
47641593Ssklower 		*fcp++ = revcharge;
47741593Ssklower 	}
47841593Ssklower 	switch (type) {
47941593Ssklower 	case X25_1980:
48041593Ssklower 	case X25_1984:
48141593Ssklower 		*fcp++ = FACILITIES_PACKETSIZE;
48241593Ssklower 		*fcp++ = sa -> x25_opts.op_psize;
48341593Ssklower 		*fcp++ = sa -> x25_opts.op_psize;
48441593Ssklower 
48541593Ssklower 		*fcp++ = FACILITIES_WINDOWSIZE;
48641593Ssklower 		*fcp++ = sa -> x25_opts.op_wsize;
48741593Ssklower 		*fcp++ = sa -> x25_opts.op_wsize;
48841593Ssklower 	}
48945895Ssklower 	*cp = fcp - cp - 1;
49045895Ssklower 	m -> m_pkthdr.len = (m -> m_len += *cp + 1);
49141593Ssklower }
49241593Ssklower 
49341593Ssklower to_bcd (a, len, x, posn)
49441593Ssklower register octet **a;
49541593Ssklower register char *x;
49641593Ssklower register int len;
49741593Ssklower register unsigned *posn;
49841593Ssklower {
49941593Ssklower 	while (--len >= 0)
50041593Ssklower 		if ((*posn)++ & 0x01)
50141593Ssklower 			*(*a)++ |= *x++ & 0x0F;
50241593Ssklower 		else
50341593Ssklower 			**a = *x++ << 4;
50441593Ssklower }
50541593Ssklower 
50641593Ssklower /*
50741593Ssklower  *  This routine gets the  first available logical channel number.  The
50841593Ssklower  *  search is from the highest number to lowest number (DTE).
50941593Ssklower  */
51041593Ssklower 
51141593Ssklower pk_getlcn (pkp)
51241593Ssklower register struct pkcb *pkp;
51341593Ssklower {
51441593Ssklower 	register int i;
51541593Ssklower 
51645297Ssklower 	if (pkp -> pk_chan == 0)
51742140Ssklower 		return (0);
51841593Ssklower 	for (i = pkp -> pk_maxlcn; i > 0; --i)
51941593Ssklower 		if (pkp -> pk_chan[i] == NULL)
52041593Ssklower 			break;
52141593Ssklower 	return (i);
52241593Ssklower 
52341593Ssklower }
52441593Ssklower 
52541593Ssklower /*
52641593Ssklower  *  This procedure sends a CLEAR request packet. The lc state is
52741593Ssklower  *  set to "SENT_CLEAR".
52841593Ssklower  */
52941593Ssklower 
53045895Ssklower pk_clear (lcp, diagnostic, abortive)
53145895Ssklower register struct pklcd *lcp;
53241593Ssklower {
53345895Ssklower 	register struct mbuf *m = pk_template (lcp -> lcd_lcn, X25_CLEAR);
53441593Ssklower 
53545895Ssklower 	m -> m_len += 2;
53647271Ssklower 	mtod (m, struct x25_packet *) -> packet_data = 0;
53747271Ssklower 	mtod (m, octet *)[4] = diagnostic;
53845895Ssklower 	if (lcp -> lcd_facilities) {
53945895Ssklower 		m -> m_next = lcp -> lcd_facilities;
54045895Ssklower 		m -> m_pkthdr.len += m -> m_next -> m_len;
54145895Ssklower 		lcp -> lcd_facilities = 0;
54245895Ssklower 	}
54345895Ssklower 	if (abortive)
54445895Ssklower 		lcp -> lcd_template = m;
54545895Ssklower 	else {
54645895Ssklower 		struct socket *so = lcp -> lcd_so;
54745895Ssklower 		struct sockbuf *sb = so ? & so -> so_snd : & lcp -> lcd_sb;
54847271Ssklower 		sbappendrecord (sb, m);
54945895Ssklower 	}
55041593Ssklower 	pk_output (lcp);
55141593Ssklower 
55241593Ssklower }
55341593Ssklower 
55447271Ssklower /*
55547271Ssklower  * This procedure generates RNR's or RR's to inhibit or enable
55647271Ssklower  * inward data flow, if the current state changes (blocked ==> open or
55747271Ssklower  * vice versa), or if forced to generate one.  One forces RNR's to ack data.
55847271Ssklower  */
55947271Ssklower pk_flowcontrol (lcp, inhibit, forced)
56047271Ssklower register struct pklcd *lcp;
56147271Ssklower {
56247271Ssklower 	inhibit = (inhibit != 0);
56347271Ssklower 	if (lcp == 0 || lcp -> lcd_state != DATA_TRANSFER ||
56447271Ssklower 	    (forced == 0 && lcp -> lcd_rxrnr_condition == inhibit))
56547271Ssklower 		return;
56647271Ssklower 	lcp -> lcd_rxrnr_condition = inhibit;
56747271Ssklower 	lcp -> lcd_template = pk_template (lcp -> lcd_lcn, inhibit ? RNR : RR);
56847271Ssklower 	pk_output (lcp);
56947271Ssklower }
57047271Ssklower 
57141593Ssklower /*
57247271Ssklower  *  This procedure sends a RESET request packet. It re-intializes
57341593Ssklower  *  virtual circuit.
57441593Ssklower  */
57541593Ssklower 
57641593Ssklower static
57745895Ssklower pk_reset (lcp, diagnostic)
57841593Ssklower register struct pklcd *lcp;
57941593Ssklower {
58045895Ssklower 	register struct mbuf *m;
58145895Ssklower 	register struct socket *so = lcp -> lcd_so;
58241593Ssklower 
58341593Ssklower 	if (lcp -> lcd_state != DATA_TRANSFER)
58441593Ssklower 		return;
58541593Ssklower 
58645895Ssklower 	if (so)
58745895Ssklower 		so -> so_error = ECONNRESET;
58841593Ssklower 	lcp -> lcd_reset_condition = TRUE;
58941593Ssklower 
59041593Ssklower 	/* Reset all the control variables for the channel. */
59145895Ssklower 	pk_flush (lcp);
59241593Ssklower 	lcp -> lcd_window_condition = lcp -> lcd_rnr_condition =
59341593Ssklower 		lcp -> lcd_intrconf_pending = FALSE;
59441593Ssklower 	lcp -> lcd_rsn = MODULUS - 1;
59541593Ssklower 	lcp -> lcd_ssn = 0;
59641593Ssklower 	lcp -> lcd_output_window = lcp -> lcd_input_window =
59741593Ssklower 		lcp -> lcd_last_transmitted_pr = 0;
59845895Ssklower 	m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET);
59945895Ssklower 	m -> m_len += 2;
60047271Ssklower 	mtod (m, struct x25_packet *) -> packet_data = 0;
60147271Ssklower 	mtod (m, octet *)[4] = diagnostic;
60245895Ssklower 	pk_output (lcp);
60345895Ssklower 
60445895Ssklower }
60545895Ssklower 
60645895Ssklower /*
60745895Ssklower  * This procedure frees all data queued for output or delivery on a
60845895Ssklower  *  virtual circuit.
60945895Ssklower  */
61045895Ssklower 
61145895Ssklower pk_flush (lcp)
61245895Ssklower register struct pklcd *lcp;
61345895Ssklower {
61445895Ssklower 	register struct socket *so;
61545895Ssklower 
61645895Ssklower 	if (lcp -> lcd_template)
61745895Ssklower 		m_freem (lcp -> lcd_template);
61845895Ssklower 
61945895Ssklower 	if (lcp -> lcd_cps) {
62047271Ssklower 		m_freem (lcp -> lcd_cps);
62145895Ssklower 		lcp -> lcd_cps = 0;
62245895Ssklower 	}
62347271Ssklower 	if (lcp -> lcd_facilities) {
62447271Ssklower 		m_freem (lcp -> lcd_facilities);
62547271Ssklower 		lcp -> lcd_facilities = 0;
62647271Ssklower 	}
62747271Ssklower 	if (so = lcp -> lcd_so) {
62842140Ssklower 		sbflush (&so -> so_rcv);
62942140Ssklower 		sbflush (&so -> so_snd);
63045895Ssklower 	} else
63145895Ssklower 		sbflush (&lcp -> lcd_sb);
63241593Ssklower }
63341593Ssklower 
63441593Ssklower /*
63541593Ssklower  *  This procedure handles all local protocol procedure errors.
63641593Ssklower  */
63741593Ssklower 
63845895Ssklower pk_procerror (error, lcp, errstr, diagnostic)
63941593Ssklower register struct pklcd *lcp;
64041593Ssklower char *errstr;
64141593Ssklower {
64241593Ssklower 
64341593Ssklower 	pk_message (lcp -> lcd_lcn, lcp -> lcd_pkp -> pk_xcp, errstr);
64441593Ssklower 
64541593Ssklower 	switch (error) {
64641593Ssklower 	case CLEAR:
64745297Ssklower 		if (lcp -> lcd_so) {
64845297Ssklower 			lcp -> lcd_so -> so_error = ECONNABORTED;
64945297Ssklower 			soisdisconnecting (lcp -> lcd_so);
65041593Ssklower 		}
65145895Ssklower 		pk_clear (lcp, diagnostic, 1);
65241593Ssklower 		break;
65341593Ssklower 
65441593Ssklower 	case RESET:
65545895Ssklower 		pk_reset (lcp, diagnostic);
65641593Ssklower 	}
65741593Ssklower }
65841593Ssklower 
65941593Ssklower /*
66041593Ssklower  *  This procedure is called during the DATA TRANSFER state to check
66141593Ssklower  *  and  process  the P(R) values  received  in the DATA,  RR OR RNR
66241593Ssklower  *  packets.
66341593Ssklower  */
66441593Ssklower 
66541593Ssklower pk_ack (lcp, pr)
66641593Ssklower struct pklcd *lcp;
66741593Ssklower unsigned pr;
66841593Ssklower {
66941593Ssklower 	register struct socket *so = lcp -> lcd_so;
67041593Ssklower 
67141593Ssklower 	if (lcp -> lcd_output_window == pr)
67241593Ssklower 		return (PACKET_OK);
67341593Ssklower 	if (lcp -> lcd_output_window < lcp -> lcd_ssn) {
67441593Ssklower 		if (pr < lcp -> lcd_output_window || pr > lcp -> lcd_ssn) {
67545895Ssklower 			pk_procerror (RESET, lcp,
67645895Ssklower 				"p(r) flow control error", 2);
67741593Ssklower 			return (ERROR_PACKET);
67841593Ssklower 		}
67941593Ssklower 	}
68041593Ssklower 	else {
68141593Ssklower 		if (pr < lcp -> lcd_output_window && pr > lcp -> lcd_ssn) {
68245895Ssklower 			pk_procerror (RESET, lcp,
68347271Ssklower 				"p(r) flow control error #2", 2);
68441593Ssklower 			return (ERROR_PACKET);
68541593Ssklower 		}
68641593Ssklower 	}
68741593Ssklower 
68841593Ssklower 	lcp -> lcd_output_window = pr;		/* Rotate window. */
68941593Ssklower 	if (lcp -> lcd_window_condition == TRUE)
69041593Ssklower 		lcp -> lcd_window_condition = FALSE;
69141593Ssklower 
69242140Ssklower 	if (so && ((so -> so_snd.sb_flags & SB_WAIT) || so -> so_snd.sb_sel))
69341593Ssklower 		sowwakeup (so);
69443361Ssklower 	if (lcp -> lcd_upper)
69547271Ssklower 		(*lcp -> lcd_upper) (lcp, 0);
69641593Ssklower 
69741593Ssklower 	return (PACKET_OK);
69841593Ssklower }
69941593Ssklower 
70041593Ssklower /*
70141593Ssklower  *  This procedure decodes the X.25 level 3 packet returning a
70241593Ssklower  *  code to be used in switchs or arrays.
70341593Ssklower  */
70441593Ssklower 
70541593Ssklower pk_decode (xp)
70641593Ssklower register struct x25_packet *xp;
70741593Ssklower {
70841593Ssklower 	register int type;
70941593Ssklower 
71041593Ssklower 	if (xp -> fmt_identifier != 1)
71141593Ssklower 		return (INVALID_PACKET);
71245895Ssklower #ifdef ancient_history
71341593Ssklower 	/*
71441593Ssklower 	 *  Make sure that the logical channel group number is 0.
71541593Ssklower 	 *  This restriction may be removed at some later date.
71641593Ssklower 	 */
71741593Ssklower 	if (xp -> lc_group_number != 0)
71841593Ssklower 		return (INVALID_PACKET);
71945895Ssklower #endif
72041593Ssklower 	/*
72141593Ssklower 	 *  Test for data packet first.
72241593Ssklower 	 */
72341593Ssklower 	if (!(xp -> packet_type & DATA_PACKET_DESIGNATOR))
72441593Ssklower 		return (DATA);
72541593Ssklower 
72641593Ssklower 	/*
72741593Ssklower 	 *  Test if flow control packet (RR or RNR).
72841593Ssklower 	 */
72941593Ssklower 	if (!(xp -> packet_type & RR_OR_RNR_PACKET_DESIGNATOR))
73047271Ssklower 		switch (xp -> packet_type & 0x1f) {
73147271Ssklower 		case X25_RR:
73241593Ssklower 			return (RR);
73347271Ssklower 		case X25_RNR:
73441593Ssklower 			return (RNR);
73547271Ssklower 		case X25_REJECT:
73647271Ssklower 			return (REJECT);
73747271Ssklower 		}
73841593Ssklower 
73941593Ssklower 	/*
74041593Ssklower 	 *  Determine the rest of the packet types.
74141593Ssklower 	 */
74241593Ssklower 	switch (xp -> packet_type) {
74341593Ssklower 	case X25_CALL:
74441593Ssklower 		type = CALL;
74541593Ssklower 		break;
74641593Ssklower 
74741593Ssklower 	case X25_CALL_ACCEPTED:
74841593Ssklower 		type = CALL_ACCEPTED;
74941593Ssklower 		break;
75041593Ssklower 
75141593Ssklower 	case X25_CLEAR:
75241593Ssklower 		type = CLEAR;
75341593Ssklower 		break;
75441593Ssklower 
75541593Ssklower 	case X25_CLEAR_CONFIRM:
75641593Ssklower 		type = CLEAR_CONF;
75741593Ssklower 		break;
75841593Ssklower 
75941593Ssklower 	case X25_INTERRUPT:
76041593Ssklower 		type = INTERRUPT;
76141593Ssklower 		break;
76241593Ssklower 
76341593Ssklower 	case X25_INTERRUPT_CONFIRM:
76441593Ssklower 		type = INTERRUPT_CONF;
76541593Ssklower 		break;
76641593Ssklower 
76741593Ssklower 	case X25_RESET:
76841593Ssklower 		type = RESET;
76941593Ssklower 		break;
77041593Ssklower 
77141593Ssklower 	case X25_RESET_CONFIRM:
77241593Ssklower 		type = RESET_CONF;
77341593Ssklower 		break;
77441593Ssklower 
77541593Ssklower 	case X25_RESTART:
77641593Ssklower 		type = RESTART;
77741593Ssklower 		break;
77841593Ssklower 
77941593Ssklower 	case X25_RESTART_CONFIRM:
78041593Ssklower 		type = RESTART_CONF;
78141593Ssklower 		break;
78241593Ssklower 
78347271Ssklower 	case X25_DIAGNOSTIC:
78448873Ssklower 		type = DIAG_TYPE;
78547271Ssklower 		break;
78647271Ssklower 
78741593Ssklower 	default:
78841593Ssklower 		type = INVALID_PACKET;
78941593Ssklower 	}
79041593Ssklower 	return (type);
79141593Ssklower }
79241593Ssklower 
79341593Ssklower /*
79441593Ssklower  *  A restart packet has been received. Print out the reason
79541593Ssklower  *  for the restart.
79641593Ssklower  */
79741593Ssklower 
79841593Ssklower pk_restartcause (pkp, xp)
79941593Ssklower struct pkcb *pkp;
80041593Ssklower register struct x25_packet *xp;
80141593Ssklower {
80241593Ssklower 	register struct x25config *xcp = pkp -> pk_xcp;
80345574Ssklower 	register int lcn = LCN(xp);
80441593Ssklower 
80541593Ssklower 	switch (xp -> packet_data) {
80641593Ssklower 	case X25_RESTART_LOCAL_PROCEDURE_ERROR:
80741593Ssklower 		pk_message (lcn, xcp, "restart: local procedure error");
80841593Ssklower 		break;
80941593Ssklower 
81041593Ssklower 	case X25_RESTART_NETWORK_CONGESTION:
81141593Ssklower 		pk_message (lcn, xcp, "restart: network congestion");
81241593Ssklower 		break;
81341593Ssklower 
81441593Ssklower 	case X25_RESTART_NETWORK_OPERATIONAL:
81541593Ssklower 		pk_message (lcn, xcp, "restart: network operational");
81641593Ssklower 		break;
81741593Ssklower 
81841593Ssklower 	default:
81941593Ssklower 		pk_message (lcn, xcp, "restart: unknown cause");
82041593Ssklower 	}
82141593Ssklower }
82241593Ssklower 
82341593Ssklower #define MAXRESETCAUSE	7
82441593Ssklower 
82541593Ssklower int     Reset_cause[] = {
82641593Ssklower 	EXRESET, EXROUT, 0, EXRRPE, 0, EXRLPE, 0, EXRNCG
82741593Ssklower };
82841593Ssklower 
82941593Ssklower /*
83041593Ssklower  *  A reset packet has arrived. Return the cause to the user.
83141593Ssklower  */
83241593Ssklower 
83341593Ssklower pk_resetcause (pkp, xp)
83441593Ssklower struct pkcb *pkp;
83541593Ssklower register struct x25_packet *xp;
83641593Ssklower {
83745297Ssklower 	register struct pklcd *lcp =
83845574Ssklower 				pkp -> pk_chan[LCN(xp)];
83941593Ssklower 	register int code = xp -> packet_data;
84041593Ssklower 
84141593Ssklower 	if (code > MAXRESETCAUSE)
84241593Ssklower 		code = 7;	/* EXRNCG */
84341593Ssklower 
84447271Ssklower 	pk_message(LCN(xp), lcp -> lcd_pkp, "reset code 0x%x, diagnostic 0x%x",
84547271Ssklower 			xp -> packet_data, 4[(u_char *)xp]);
84647271Ssklower 
84745297Ssklower 	lcp -> lcd_so -> so_error = Reset_cause[code];
84841593Ssklower }
84941593Ssklower 
85041593Ssklower #define MAXCLEARCAUSE	25
85141593Ssklower 
85241593Ssklower int     Clear_cause[] = {
85341593Ssklower 	EXCLEAR, EXCBUSY, 0, EXCINV, 0, EXCNCG, 0,
85441593Ssklower 	0, 0, EXCOUT, 0, EXCAB, 0, EXCNOB, 0, 0, 0, EXCRPE,
85541593Ssklower 	0, EXCLPE, 0, 0, 0, 0, 0, EXCRRC
85641593Ssklower };
85741593Ssklower 
85841593Ssklower /*
85941593Ssklower  *  A clear packet has arrived. Return the cause to the user.
86041593Ssklower  */
86141593Ssklower 
86241593Ssklower pk_clearcause (pkp, xp)
86341593Ssklower struct pkcb *pkp;
86441593Ssklower register struct x25_packet *xp;
86541593Ssklower {
86645297Ssklower 	register struct pklcd *lcp =
86745574Ssklower 		pkp -> pk_chan[LCN(xp)];
86841593Ssklower 	register int code = xp -> packet_data;
86941593Ssklower 
87041593Ssklower 	if (code > MAXCLEARCAUSE)
87141593Ssklower 		code = 5;	/* EXRNCG */
87245297Ssklower 	lcp -> lcd_so -> so_error = Clear_cause[code];
87341593Ssklower }
87441593Ssklower 
87541593Ssklower char *
87641593Ssklower format_ntn (xcp)
87741593Ssklower register struct x25config *xcp;
87841593Ssklower {
87941593Ssklower 
88045165Ssklower 	return (xcp -> xc_addr.x25_addr);
88141593Ssklower }
88241593Ssklower 
88341593Ssklower /* VARARGS1 */
88441593Ssklower pk_message (lcn, xcp, fmt, a1, a2, a3, a4, a5, a6)
88541593Ssklower struct x25config *xcp;
88641593Ssklower char *fmt;
88741593Ssklower {
88841593Ssklower 
88941593Ssklower 	if (lcn)
89041593Ssklower 		if (pkcbhead -> pk_next)
89141593Ssklower 			printf ("X.25(%s): lcn %d: ", format_ntn (xcp), lcn);
89241593Ssklower 		else
89341593Ssklower 			printf ("X.25: lcn %d: ", lcn);
89441593Ssklower 	else
89541593Ssklower 		if (pkcbhead -> pk_next)
89641593Ssklower 			printf ("X.25(%s): ", format_ntn (xcp));
89741593Ssklower 		else
89841593Ssklower 			printf ("X.25: ");
89941593Ssklower 
90041593Ssklower 	printf (fmt, a1, a2, a3, a4, a5, a6);
90141593Ssklower 	printf ("\n");
90241593Ssklower }
90345297Ssklower 
90447271Ssklower pk_ifattach (ia, lloutput, llnext)
90545297Ssklower register struct x25_ifaddr *ia;
90647271Ssklower int (*lloutput) ();
90745297Ssklower caddr_t llnext;
90845297Ssklower {
90945297Ssklower 	/* this is here because you can't include both pk_var and hd_var */
91045297Ssklower 	/* this will probably be replace by a streams gluing mechanism */
91145297Ssklower 	ia -> ia_pkcb.pk_lloutput = lloutput;
91245297Ssklower 	ia -> ia_pkcb.pk_llnext = llnext;
91345297Ssklower }
91445297Ssklower 
91547271Ssklower pk_fragment (lcp, m0, qbit, mbit, wait)
91645297Ssklower struct mbuf *m0;
91745297Ssklower register struct pklcd *lcp;
91845297Ssklower {
91945297Ssklower 	register struct mbuf *m = m0;
92045297Ssklower 	register struct x25_packet *xp;
92145297Ssklower 	register struct sockbuf *sb;
92247271Ssklower 	struct mbuf *head = 0, *next, **mp = &head, *m_split ();
92345297Ssklower 	int totlen, psize = 1 << (lcp -> lcd_packetsize);
92445297Ssklower 
92545297Ssklower 	if (m == 0)
92645297Ssklower 		return;
92745895Ssklower 	if (m -> m_flags & M_PKTHDR == 0)
92847271Ssklower 		panic ("pk_fragment");
92945297Ssklower 	totlen = m -> m_pkthdr.len;
93045574Ssklower 	m -> m_act = 0;
93145297Ssklower 	sb = lcp -> lcd_so ? &lcp -> lcd_so -> so_snd : & lcp -> lcd_sb;
93245297Ssklower 	do {
93345297Ssklower 		if (totlen > psize) {
93447271Ssklower 			if ((next = m_split (m, psize, wait)) == 0)
93545297Ssklower 				goto abort;
93645297Ssklower 			totlen -= psize;
93745574Ssklower 		} else
93845574Ssklower 			next = 0;
93945297Ssklower 		M_PREPEND(m, PKHEADERLN, wait);
94045297Ssklower 		if (m == 0)
94145297Ssklower 			goto abort;
94245574Ssklower 		*mp = m;
94345574Ssklower 		mp = & m -> m_act;
94445574Ssklower 		*mp = 0;
94547271Ssklower 		xp = mtod (m, struct x25_packet *);
94645297Ssklower 		0[(char *)xp] = 0;
94745297Ssklower 		if (qbit)
94845574Ssklower 			xp -> q_bit = 1;
94945574Ssklower 		if (lcp -> lcd_flags & X25_DBIT)
95045574Ssklower 			xp -> d_bit = 1;
95145297Ssklower 		xp -> fmt_identifier = 1;
95245297Ssklower 		xp -> packet_type = X25_DATA;
95345574Ssklower 		SET_LCN(xp, lcp -> lcd_lcn);
95445574Ssklower 		if (next || (mbit && (totlen == psize ||
95545574Ssklower 				      (lcp -> lcd_flags & X25_DBIT))))
95645297Ssklower 			MBIT(xp) = 1;
95745297Ssklower 	} while (m = next);
95845574Ssklower 	for (m = head; m; m = next) {
95945297Ssklower 		next = m -> m_act;
96045297Ssklower 		m -> m_act = 0;
96147271Ssklower 		sbappendrecord (sb, m);
96245297Ssklower 	}
96345297Ssklower 	return 0;
96445297Ssklower abort:
96545574Ssklower 	if (wait)
96647271Ssklower 		panic ("pk_fragment null mbuf after wait");
96745574Ssklower 	if (next)
96847271Ssklower 		m_freem (next);
96945574Ssklower 	for (m = head; m; m = next) {
97045297Ssklower 		next = m -> m_act;
97147271Ssklower 		m_freem (m);
97245297Ssklower 	}
97345297Ssklower 	return ENOBUFS;
97445297Ssklower }
97545574Ssklower 
97645574Ssklower struct mbuf *
97747271Ssklower m_split (m0, len0, wait)
97845574Ssklower register struct mbuf *m0;
97945574Ssklower int len0;
98045574Ssklower {
98145574Ssklower 	register struct mbuf *m, *n;
98245574Ssklower 	unsigned len = len0;
98345574Ssklower 
98445574Ssklower 	for (m = m0; m && len > m -> m_len; m = m -> m_next)
98545574Ssklower 		len -= m -> m_len;
98645574Ssklower 	if (m == 0)
98745574Ssklower 		return (0);
98845574Ssklower 	if (m0 -> m_flags & M_PKTHDR) {
98945574Ssklower 		MGETHDR(n, wait, m0 -> m_type);
99045574Ssklower 		if (n == 0)
99145574Ssklower 			return (0);
99245574Ssklower 		n -> m_pkthdr.rcvif = m0 -> m_pkthdr.rcvif;
99345574Ssklower 		n -> m_pkthdr.len = m0 -> m_pkthdr.len - len0;
99445574Ssklower 		m0 -> m_pkthdr.len = len0;
99545574Ssklower 		if (m -> m_flags & M_EXT)
99645574Ssklower 			goto extpacket;
99745574Ssklower 		if (len > MHLEN) {
99845574Ssklower 			/* m can't be the lead packet */
99945574Ssklower 			MH_ALIGN(n, 0);
100047271Ssklower 			n -> m_next = m_split (m, len, wait);
100145574Ssklower 			if (n -> m_next == 0) {
100247271Ssklower 				(void) m_free (n);
100345574Ssklower 				return (0);
100445574Ssklower 			} else
100545574Ssklower 				return (n);
100645574Ssklower 		} else
100745574Ssklower 			MH_ALIGN(n, len);
100845574Ssklower 	} else if (len == m -> m_len) {
100945574Ssklower 		n = m -> m_next;
101045574Ssklower 		m -> m_next = 0;
101145574Ssklower 		return (n);
101245574Ssklower 	}
101345574Ssklower extpacket:
101445574Ssklower 	len = m -> m_len - len;		/* remainder to be copied */
101545574Ssklower 	m -> m_len -= len;		/* now equals original len */
101645895Ssklower 	if (m -> m_flags & M_EXT) {
101745574Ssklower 		n -> m_flags |= M_EXT;
101845574Ssklower 		n -> m_ext = m -> m_ext;
101947271Ssklower 		mclrefcnt[mtocl (m -> m_ext.ext_buf)]++;
102045574Ssklower 		n -> m_data = m -> m_data + m -> m_len;
102145574Ssklower 	} else {
102245574Ssklower 		MGET(n, wait, m -> m_type);
102345574Ssklower 		if (n == 0) {
102445574Ssklower 			m -> m_len += len;
102545574Ssklower 			return (0);
102645574Ssklower 		}
102745574Ssklower 		M_ALIGN(n, len);
102847271Ssklower 		bcopy (mtod (m, caddr_t), mtod (n, caddr_t), len);
102945574Ssklower 	}
103045574Ssklower 	n -> m_len = len;
103145574Ssklower 	n -> m_next = m -> m_next;
103245574Ssklower 	m -> m_next = 0;
103345574Ssklower 	return (n);
103445574Ssklower }
1035