xref: /csrg-svn/sys/netccitt/pk_usrreq.c (revision 45165)
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*45165Ssklower  *	@(#)pk_usrreq.c	7.7 (Berkeley) 08/30/90
1341709Ssklower  */
1441595Ssklower 
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"
2241595Ssklower #include "ioctl.h"
2341595Ssklower #include "user.h"
2441595Ssklower #include "stat.h"
2541595Ssklower 
2642140Ssklower #include "../net/if.h"
2741595Ssklower 
2842140Ssklower #include "x25.h"
2942140Ssklower #include "pk.h"
3042140Ssklower #include "pk_var.h"
3142140Ssklower 
3241595Ssklower struct	x25_packet *pk_template ();
3341595Ssklower 
3441595Ssklower /*
3541595Ssklower  *
3641595Ssklower  *  X.25 Packet level protocol interface to socket abstraction.
3741595Ssklower  *
3841595Ssklower  *  Process an X.25 user request on a logical channel.  If this is a send
3941595Ssklower  *  request then m is the mbuf chain of the send data. If this is a timer
4041595Ssklower  *  expiration (called from the software clock routine) them timertype is
4141595Ssklower  *  the particular timer.
4241595Ssklower  *
4341595Ssklower  */
4441595Ssklower 
4541936Ssklower pk_usrreq (so, req, m, nam, control)
4641595Ssklower struct socket *so;
4741595Ssklower int req;
4841595Ssklower register struct mbuf *m, *nam;
4941936Ssklower struct mbuf *control;
5041595Ssklower {
5141595Ssklower 	register struct pklcd *lcp = (struct pklcd *) so -> so_pcb;
5241595Ssklower 	register struct x25_packet *xp;
5341936Ssklower 	register int error = 0;
5441595Ssklower 
5541936Ssklower 	if (req == PRU_CONTROL)
5641936Ssklower 		return (pk_control(so, (int)m, (caddr_t)nam,
5741936Ssklower 			(struct ifnet *)control));
5841936Ssklower 	if (control && control->m_len) {
5941936Ssklower 		error = EINVAL;
6041936Ssklower 		goto release;
6141595Ssklower 	}
6241936Ssklower 	if (lcp == NULL && req != PRU_ATTACH) {
6341936Ssklower 		error = EINVAL;
6441936Ssklower 		goto release;
6541595Ssklower 	}
6641595Ssklower 
6741595Ssklower /*
6841595Ssklower 	pk_trace (pkcbhead, TR_USER, (struct pklcd *)0,
6941595Ssklower 		req, (struct x25_packet *)0);
7041595Ssklower */
7141595Ssklower 
7241595Ssklower 	switch (req) {
7341595Ssklower 	/*
7441595Ssklower 	 *  X.25 attaches to socket via PRU_ATTACH and allocates a logical
7541595Ssklower 	 *  channel descriptor.  If the socket is to  receive connections,
7641595Ssklower 	 *  then the LISTEN state is entered.
7741595Ssklower 	 */
7841595Ssklower 	case PRU_ATTACH:
7941595Ssklower 		if (lcp) {
8041595Ssklower 			error = EISCONN;
8141595Ssklower 			/* Socket already connected. */
8241595Ssklower 			break;
8341595Ssklower 		}
84*45165Ssklower 		lcp = pk_attach (so);
85*45165Ssklower 		if (lcp == 0)
86*45165Ssklower 			error = ENOBUFS;
8741595Ssklower 		break;
8841595Ssklower 
8941595Ssklower 	/*
9041595Ssklower 	 *  Detach a logical channel from the socket. If the state of the
9141595Ssklower 	 *  channel is embryonic, simply discard it. Otherwise we have to
9241595Ssklower 	 *  initiate a PRU_DISCONNECT which will finish later.
9341595Ssklower 	 */
9441595Ssklower 	case PRU_DETACH:
9541595Ssklower 		pk_disconnect (lcp);
9641595Ssklower 		break;
9741595Ssklower 
9841595Ssklower 	/*
9941595Ssklower 	 *  Give the socket an address.
10041595Ssklower 	 */
10141595Ssklower 	case PRU_BIND:
10241595Ssklower 		if (nam -> m_len == sizeof (struct x25_sockaddr))
10341595Ssklower 			old_to_new (nam);
10441595Ssklower 		error = pk_bind (lcp, nam);
10541595Ssklower 		break;
10641595Ssklower 
10741595Ssklower 	/*
10841595Ssklower 	 *  Prepare to accept connections.
10941595Ssklower 	 */
11041595Ssklower 	case PRU_LISTEN:
11141595Ssklower 		if (lcp -> lcd_ceaddr == 0) {
11241595Ssklower 			error = EDESTADDRREQ;
11341595Ssklower 			break;
11441595Ssklower 		}
11541595Ssklower 		lcp -> lcd_state = LISTEN;
11641595Ssklower 		lcp -> lcd_listen = pk_listenhead;
11741595Ssklower 		pk_listenhead = lcp;
11841595Ssklower 		break;
11941595Ssklower 
12041595Ssklower 	/*
12141595Ssklower 	 *  Initiate a CALL REQUEST to peer entity. Enter state SENT_CALL
12241595Ssklower 	 *  and mark the socket as connecting. Set timer waiting for
12341595Ssklower 	 *  CALL ACCEPT or CLEAR.
12441595Ssklower 	 */
12541595Ssklower 	case PRU_CONNECT:
12641595Ssklower 		if (nam -> m_len == sizeof (struct x25_sockaddr))
12741595Ssklower 			old_to_new (nam);
12842277Ssklower 		error = pk_connect (lcp, nam, (struct sockaddr_25 *)0);
12941595Ssklower 		break;
13041595Ssklower 
13141595Ssklower 	/*
13241595Ssklower 	 *  Initiate a disconnect to peer entity via a CLEAR REQUEST packet.
13341595Ssklower 	 *  The socket will be disconnected when we receive a confirmation
13441595Ssklower 	 *  or a clear collision.
13541595Ssklower 	 */
13641595Ssklower 	case PRU_DISCONNECT:
13741595Ssklower 		pk_disconnect (lcp);
13841595Ssklower 		break;
13941595Ssklower 
14041595Ssklower 	/*
14141595Ssklower 	 *  Accept an INCOMING CALL. Most of the work has already been done
14241595Ssklower 	 *  by pk_input. Just return the callers address to the user.
14341595Ssklower 	 */
14441595Ssklower 	case PRU_ACCEPT:
14541595Ssklower 		if (lcp -> lcd_craddr == NULL)
14641595Ssklower 			break;
14741595Ssklower 		bcopy ((caddr_t)lcp -> lcd_craddr, mtod (nam, caddr_t),
14841595Ssklower 			sizeof (struct sockaddr_x25));
14941595Ssklower 		nam -> m_len = sizeof (struct sockaddr_x25);
15041595Ssklower 		if (lcp -> lcd_flags & X25_OLDSOCKADDR)
15141595Ssklower 			new_to_old (nam);
15241595Ssklower 		break;
15341595Ssklower 
15441595Ssklower 	/*
15541595Ssklower 	 *  After a receive, we should send a RR.
15641595Ssklower 	 */
15741595Ssklower 	case PRU_RCVD:
15841595Ssklower 		lcp -> lcd_rxcnt++;
15941595Ssklower 		lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RR);
16041595Ssklower 		pk_output (lcp);
16141595Ssklower 		break;
16241595Ssklower 
16341595Ssklower 	/*
16441595Ssklower 	 *  Do send by placing data on the socket output queue.
16541595Ssklower 	 *  SHOULD WE USE m_cat HERE.
16641595Ssklower 	 */
16741595Ssklower 	case PRU_SEND:
16841595Ssklower 		error = pk_send (lcp, m);
16941595Ssklower 		break;
17041595Ssklower 
17141595Ssklower 	/*
17241595Ssklower 	 *  Abort a virtual circuit. For example all completed calls
17341595Ssklower 	 *  waiting acceptance.
17441595Ssklower 	 */
17541595Ssklower 	case PRU_ABORT:
17641595Ssklower 		pk_disconnect (lcp);
17741595Ssklower 		break;
17841595Ssklower 
17941595Ssklower 	/* Begin unimplemented hooks. */
18041595Ssklower 
18141595Ssklower 	case PRU_SHUTDOWN:
18241595Ssklower 		error = EOPNOTSUPP;
18341595Ssklower 		break;
18441595Ssklower 
18541595Ssklower 	case PRU_CONTROL:
18641595Ssklower 		error = EOPNOTSUPP;
18741595Ssklower 		break;
18841595Ssklower 
18941595Ssklower 	case PRU_SENSE:
19041595Ssklower #ifdef BSD4_3
19141595Ssklower 		((struct stat *)m) -> st_blksize = so -> so_snd.sb_hiwat;
19241595Ssklower #else
19341595Ssklower 		error = EOPNOTSUPP;
19441595Ssklower #endif
19541595Ssklower 		break;
19641595Ssklower 
19741595Ssklower 	/* End unimplemented hooks. */
19841595Ssklower 
19941595Ssklower 	case PRU_SOCKADDR:
20041595Ssklower 		if (lcp -> lcd_ceaddr == 0)
20141595Ssklower 			return (EADDRNOTAVAIL);
20241595Ssklower 		nam -> m_len = sizeof (struct sockaddr_x25);
20341595Ssklower 		bcopy ((caddr_t)lcp -> lcd_ceaddr, mtod (nam, caddr_t),
20441595Ssklower 			sizeof (struct sockaddr_x25));
20541595Ssklower 		if (lcp -> lcd_flags & X25_OLDSOCKADDR)
20641595Ssklower 			new_to_old (nam);
20741595Ssklower 		break;
20841595Ssklower 
20941595Ssklower 	case PRU_PEERADDR:
21041595Ssklower 		if (lcp -> lcd_state != DATA_TRANSFER)
21141595Ssklower 			return (ENOTCONN);
21241595Ssklower 		nam -> m_len = sizeof (struct sockaddr_x25);
21341595Ssklower 		bcopy (lcp -> lcd_craddr ? (caddr_t)lcp -> lcd_craddr :
21441595Ssklower 			(caddr_t)lcp -> lcd_ceaddr,
21541595Ssklower 			mtod (nam, caddr_t), sizeof (struct sockaddr_x25));
21641595Ssklower 		if (lcp -> lcd_flags & X25_OLDSOCKADDR)
21741595Ssklower 			new_to_old (nam);
21841595Ssklower 		break;
21941595Ssklower 
22041595Ssklower 	/*
22141595Ssklower 	 *  Receive INTERRUPT packet.
22241595Ssklower 	 */
22341595Ssklower 	case PRU_RCVOOB:
22441595Ssklower 		m -> m_len = 1;
22541595Ssklower 		*mtod (m, char *) = lcp -> lcd_intrdata;
22641595Ssklower 		break;
22741595Ssklower 
22841595Ssklower 	/*
22941595Ssklower 	 *  Send INTERRUPT packet.
23041595Ssklower 	 */
23141595Ssklower 	case PRU_SENDOOB:
23241595Ssklower 		m_freem (m);
23341595Ssklower 		if (lcp -> lcd_intrconf_pending) {
23441595Ssklower 			error = ETOOMANYREFS;
23541595Ssklower 			break;
23641595Ssklower 		}
23741595Ssklower 		lcp -> lcd_intrcnt++;
23841595Ssklower 		xp = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_INTERRUPT);
23941595Ssklower 		xp -> packet_data = 0;
24041595Ssklower 		(dtom (xp)) -> m_len++;
24141595Ssklower 		pk_output (lcp);
24241595Ssklower 		break;
24341595Ssklower 
24441595Ssklower 	default:
24541595Ssklower 		panic ("pk_usrreq");
24641595Ssklower 	}
24741936Ssklower release:
24841936Ssklower 	if (control != NULL)
24941936Ssklower 		m_freem(control);
25041936Ssklower 	if (m != NULL)
25141936Ssklower 		m_freem(m);
25241595Ssklower 	return (error);
25341595Ssklower }
25441595Ssklower 
25542277Ssklower /*
25642277Ssklower  * If you want to use UBC X.25 level 3 in conjunction with some
25742277Ssklower  * other X.25 level 2 driver, have the ifp->if_ioctl routine
25842277Ssklower  * assign pk_start to pkp -> pk_start when called with SIOCSIFCONF_X25.
25942277Ssklower  */
26042277Ssklower /* ARGSUSED */
26142277Ssklower pk_start (lcp)
26242277Ssklower register struct pklcd *lcp;
26342277Ssklower {
26442277Ssklower 	extern int pk_send();
26542277Ssklower 
266*45165Ssklower 	lcp -> lcd_send = pk_send;
26742277Ssklower 	return (pk_output(lcp));
26842277Ssklower }
26942277Ssklower 
27041595Ssklower /*ARGSUSED*/
27141595Ssklower pk_control (so, cmd, data, ifp)
27241595Ssklower struct socket *so;
27341595Ssklower int cmd;
27441595Ssklower caddr_t data;
27541595Ssklower register struct ifnet *ifp;
27641595Ssklower {
27742140Ssklower 	register struct ifreq_x25 *ifr = (struct ifreq_x25 *)data;
27841595Ssklower 	register struct ifaddr *ifa = 0;
27941936Ssklower 	register struct x25_ifaddr *ia = 0;
28042277Ssklower 	struct pklcd *dev_lcp = 0;
28141936Ssklower 	int error, s;
28241936Ssklower 	unsigned n;
28341595Ssklower 
28441595Ssklower 	/*
28541595Ssklower 	 * Find address for this interface, if it exists.
28641595Ssklower 	 */
28741595Ssklower 	if (ifp)
28841595Ssklower 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
28942140Ssklower 			if (ifa->ifa_addr->sa_family == AF_CCITT)
29041595Ssklower 				break;
29141595Ssklower 
29241936Ssklower 	ia = (struct x25_ifaddr *)ifa;
29341595Ssklower 	switch (cmd) {
29442140Ssklower 	case SIOCGIFCONF_X25:
29541595Ssklower 		if (ifa == 0)
29641595Ssklower 			return (EADDRNOTAVAIL);
297*45165Ssklower 		ifr->ifr_xc = ia->ia_xc;
29841595Ssklower 		return (0);
29941595Ssklower 
30042140Ssklower 	case SIOCSIFCONF_X25:
301*45165Ssklower 		if (error = suser(u.u_cred, &u.u_acflag))
302*45165Ssklower 			return (error);
30341595Ssklower 		if (ifp == 0)
30441595Ssklower 			panic("pk_control");
30541595Ssklower 		if (ifa == (struct ifaddr *)0) {
30641595Ssklower 			register struct mbuf *m;
30741595Ssklower 
30842277Ssklower 			MALLOC(ia, struct x25_ifaddr *, sizeof (*ia),
30942277Ssklower 				M_IFADDR, M_WAITOK);
31042277Ssklower 			if (ia == 0)
31141595Ssklower 				return (ENOBUFS);
31241595Ssklower 			if (ifa = ifp->if_addrlist) {
31341595Ssklower 				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
31441595Ssklower 					;
31541936Ssklower 				ifa->ifa_next = &ia->ia_ifa;
31641595Ssklower 			} else
31741936Ssklower 				ifp->if_addrlist = &ia->ia_ifa;
31841936Ssklower 			ifa = &ia->ia_ifa;
31942140Ssklower 			ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask;
320*45165Ssklower 			ifa->ifa_addr = (struct sockaddr *)&ia->ia_xc.xc_addr;
32142140Ssklower 			ia->ia_ifp = ifp;
32242140Ssklower 			ia->ia_pkcb.pk_ia = ia;
32342140Ssklower 			ia->ia_pkcb.pk_next = pkcbhead;
32442140Ssklower 			pkcbhead = &ia->ia_pkcb;
32541595Ssklower 		}
32642140Ssklower 		ia->ia_xcp = &(ifr->ifr_xc);
327*45165Ssklower 		if (ia->ia_chan && (ia->ia_maxlcn != ia->ia_xcp->xc_maxlcn)) {
328*45165Ssklower 			pk_restart(&ia->ia_pkcb, X25_RESTART_NETWORK_CONGESTION);
32942277Ssklower 			dev_lcp = ia->ia_chan[0];
33041936Ssklower 			free((caddr_t)ia->ia_chan, M_IFADDR);
33142277Ssklower 			ia->ia_chan = 0;
33241936Ssklower 		}
33342277Ssklower 		if (ia->ia_chan == 0) {
33442277Ssklower 			n = ia->ia_maxlcn * sizeof(struct pklcd *);
33542140Ssklower 			ia->ia_chan = (struct pklcd **) malloc(n, M_IFADDR);
33642277Ssklower 			if (ia->ia_chan) {
33742277Ssklower 				bzero((caddr_t)ia->ia_chan, n);
33842277Ssklower 				if (dev_lcp == 0)
33942277Ssklower 					dev_lcp = pk_attach((struct socket *)0);
340*45165Ssklower 				ia->ia_chan[0] = dev_lcp;
34142277Ssklower 			} else {
34242277Ssklower 				if (dev_lcp)
34342277Ssklower 					pk_close(dev_lcp);
34442277Ssklower 				ia->ia_xcp = &ia->ia_xc;
34542277Ssklower 				return (ENOBUFS);
34642277Ssklower 			}
34742140Ssklower 		}
34841595Ssklower 		/*
34941595Ssklower 		 * Give the interface a chance to initialize if this
35041595Ssklower 		 * is its first address, and to validate the address.
35141595Ssklower 		 */
35241936Ssklower 		s = splimp();
35341936Ssklower 		if (ifp->if_ioctl)
354*45165Ssklower 			error = (*ifp->if_ioctl)(ifp, SIOCSIFCONF_X25, ifa);
35541595Ssklower 		splx(s);
35641936Ssklower 		if (error == 0) {
35741936Ssklower 			ia->ia_xc = *ia->ia_xcp;
35841936Ssklower 		}
35941936Ssklower 		ia->ia_xcp = &ia->ia_xc;
36041936Ssklower 		return (error);
36141595Ssklower 
36241595Ssklower 	default:
36341595Ssklower 		if (ifp == 0 || ifp->if_ioctl == 0)
36441595Ssklower 			return (EOPNOTSUPP);
36541595Ssklower 		return ((*ifp->if_ioctl)(ifp, cmd, data));
36641595Ssklower 	}
36741595Ssklower }
36841595Ssklower 
369*45165Ssklower pk_ctloutput(cmd, so, level, optname, mp)
370*45165Ssklower struct socket *so;
371*45165Ssklower struct mbuf **mp;
372*45165Ssklower int cmd, level, optname;
373*45165Ssklower {
374*45165Ssklower 	register struct mbuf *m = *mp;
375*45165Ssklower 	int error;
376*45165Ssklower 
377*45165Ssklower 	if (cmd == PRCO_SETOPT) switch (optname) {
378*45165Ssklower 	case PK_ACCTFILE:
379*45165Ssklower 		if (m == 0)
380*45165Ssklower 			return (EINVAL);
381*45165Ssklower 		if (m->m_len)
382*45165Ssklower 			error = pk_accton(mtod(m, char *));
383*45165Ssklower 		else
384*45165Ssklower 			error = pk_accton((char *)0);
385*45165Ssklower 		(void) m_freem(m);
386*45165Ssklower 		*mp = 0;
387*45165Ssklower 		return (error);
388*45165Ssklower 	}
389*45165Ssklower 	if (*mp) {
390*45165Ssklower 		(void) m_freem(*mp);
391*45165Ssklower 		*mp = 0;
392*45165Ssklower 	}
393*45165Ssklower 	return (EOPNOTSUPP);
394*45165Ssklower 
395*45165Ssklower }
396*45165Ssklower 
39741595Ssklower /*
39841595Ssklower  * Do an in-place conversion of an "old style"
39941595Ssklower  * socket address to the new style
40041595Ssklower  */
40141595Ssklower 
40241595Ssklower static
40341595Ssklower old_to_new (m)
40441595Ssklower register struct mbuf *m;
40541595Ssklower {
40641595Ssklower 	register struct x25_sockaddr *oldp;
40741595Ssklower 	register struct sockaddr_x25 *newp;
40841595Ssklower 	register char *ocp, *ncp;
40941595Ssklower 	struct sockaddr_x25 new;
41041595Ssklower 
41141595Ssklower 	oldp = mtod (m, struct x25_sockaddr *);
41241595Ssklower 	newp = &new;
41341595Ssklower 	bzero ((caddr_t)newp, sizeof (*newp));
41441595Ssklower 
41541595Ssklower 	newp -> x25_family = AF_CCITT;
41641595Ssklower 	newp->x25_opts.op_flags = (oldp->xaddr_facilities & X25_REVERSE_CHARGE)
41741595Ssklower 		| X25_MQBIT | X25_OLDSOCKADDR;
41841595Ssklower 	if (oldp -> xaddr_facilities & XS_HIPRIO)	/* Datapac specific */
41941595Ssklower 		newp -> x25_opts.op_psize = X25_PS128;
42041595Ssklower 	bcopy ((caddr_t)oldp -> xaddr_addr, newp -> x25_addr,
42141595Ssklower 		(unsigned)min (oldp -> xaddr_len, sizeof (newp -> x25_addr) - 1));
42241595Ssklower 	bcopy ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4);
42341595Ssklower 	newp -> x25_udlen = 4;
42441595Ssklower 
42541595Ssklower 	ocp = (caddr_t)oldp -> xaddr_userdata;
42641595Ssklower 	ncp = newp -> x25_udata + 4;
42741595Ssklower 	while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) {
42841595Ssklower 		*ncp++ = *ocp++;
42941595Ssklower 		newp -> x25_udlen++;
43041595Ssklower 	}
43141595Ssklower 
43241595Ssklower 	bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp));
43341595Ssklower 	m->m_len = sizeof (*newp);
43441595Ssklower }
43541595Ssklower 
43641595Ssklower /*
43741595Ssklower  * Do an in-place conversion of a new style
43841595Ssklower  * socket address to the old style
43941595Ssklower  */
44041595Ssklower 
44141595Ssklower static
44241595Ssklower new_to_old (m)
44341595Ssklower register struct mbuf *m;
44441595Ssklower {
44541595Ssklower 	register struct x25_sockaddr *oldp;
44641595Ssklower 	register struct sockaddr_x25 *newp;
44741595Ssklower 	register char *ocp, *ncp;
44841595Ssklower 	struct x25_sockaddr old;
44941595Ssklower 
45041595Ssklower 	oldp = &old;
45141595Ssklower 	newp = mtod (m, struct sockaddr_x25 *);
45241595Ssklower 	bzero ((caddr_t)oldp, sizeof (*oldp));
45341595Ssklower 
45441595Ssklower 	oldp -> xaddr_facilities = newp -> x25_opts.op_flags & X25_REVERSE_CHARGE;
45541595Ssklower 	if (newp -> x25_opts.op_psize == X25_PS128)
45641595Ssklower 		oldp -> xaddr_facilities |= XS_HIPRIO;	/* Datapac specific */
45741595Ssklower 	ocp = (char *)oldp -> xaddr_addr;
45841595Ssklower 	ncp = newp -> x25_addr;
45941595Ssklower 	while (*ncp) {
46041595Ssklower 		*ocp++ = *ncp++;
46141595Ssklower 		oldp -> xaddr_len++;
46241595Ssklower 	}
46341595Ssklower 
46441595Ssklower 	bcopy (newp -> x25_udata, (caddr_t)oldp -> xaddr_proto, 4);
46541595Ssklower 	bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata,
46641595Ssklower 		(unsigned)(newp -> x25_udlen - 4));
46741595Ssklower 
46841595Ssklower 	bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp));
46941595Ssklower 	m -> m_len = sizeof (*oldp);
47041595Ssklower }
47141595Ssklower 
47241595Ssklower pk_send (lcp, m)
47341595Ssklower register struct pklcd *lcp;
47441595Ssklower register struct mbuf *m;
47541595Ssklower {
47641595Ssklower 	register struct x25_packet *xp;
47741595Ssklower 	register struct mbuf *m0;
47841595Ssklower 	register int len;
47941595Ssklower 
48041595Ssklower 	m0 = dtom ((xp = pk_template (lcp -> lcd_lcn, X25_DATA)));
48141595Ssklower 	m0 -> m_next = m;
48241595Ssklower 	/*
48341595Ssklower 	 * Application has elected (at call setup time) to prepend
48441595Ssklower 	 * a control byte to each packet written indicating m-bit
48541595Ssklower 	 * and q-bit status.  Examine and then discard this byte.
48641595Ssklower 	 */
48741595Ssklower 	if (lcp -> lcd_flags & X25_MQBIT) {
48841595Ssklower 		register octet *cp;
48941595Ssklower 
49041595Ssklower 		if (m -> m_len < 1) {
49141595Ssklower 			m_freem (m0);
49241595Ssklower 			return (EMSGSIZE);
49341595Ssklower 		}
49441595Ssklower 		cp = mtod (m, octet *);
49541595Ssklower 		if (*cp & 0x80)					/* XXX */
49641595Ssklower 			xp -> q_bit = 1;
49741595Ssklower 		xp -> packet_type |= (*cp & 0x40) >> 2;		/* XXX */
49841595Ssklower 		m -> m_len--;
49941936Ssklower 		m -> m_data++;
50041595Ssklower 	}
50141595Ssklower 	len = m -> m_len;
50241595Ssklower 	while (m -> m_next) {
50341595Ssklower 		m = m -> m_next;
50441595Ssklower 		len += m -> m_len;
50541595Ssklower 	}
50641595Ssklower 	if (len > (1 << lcp -> lcd_packetsize)) {
50741595Ssklower 		m_freem (m0);
50841595Ssklower 		return (EMSGSIZE);
50941595Ssklower 	}
51042277Ssklower 	if (lcp -> lcd_so)
51142277Ssklower 		sbappendrecord (&lcp -> lcd_so -> so_snd, m0);
51242277Ssklower 	else
51343362Ssklower 		sbappendrecord (&lcp -> lcd_sb, m0);
51441595Ssklower 	lcp -> lcd_template = 0;
51541595Ssklower 	lcp -> lcd_txcnt++;
51641595Ssklower 	pk_output (lcp);
51741595Ssklower 	return (0);
51841595Ssklower }
519