xref: /csrg-svn/sys/netccitt/pk_usrreq.c (revision 41709)
1*41709Ssklower /*
2*41709Ssklower  * Copyright (c) University of British Columbia, 1984
3*41709Ssklower  * Copyright (c) 1990 The Regents of the University of California.
4*41709Ssklower  * All rights reserved.
5*41709Ssklower  *
6*41709Ssklower  * This code is derived from software contributed to Berkeley by
7*41709Ssklower  * the Laboratory for Computation Vision and the Computer Science Department
8*41709Ssklower  * of the University of British Columbia.
9*41709Ssklower  *
10*41709Ssklower  * %sccs.include.redist.c%
11*41709Ssklower  *
12*41709Ssklower  *	@(#)pk_usrreq.c	7.2 (Berkeley) 05/11/90
13*41709Ssklower  */
1441595Ssklower 
1541595Ssklower #include "../h/param.h"
1641595Ssklower #include "../h/systm.h"
1741595Ssklower #include "../h/mbuf.h"
1841595Ssklower #include "../h/socket.h"
1941595Ssklower #include "../h/protosw.h"
2041595Ssklower #include "../h/socketvar.h"
2141595Ssklower #include "../h/errno.h"
2241595Ssklower #ifdef BSD4_3
2341595Ssklower #include "../net/if.h"
2441595Ssklower #include "ioctl.h"
2541595Ssklower #include "dir.h"
2641595Ssklower #include "user.h"
2741595Ssklower #include "stat.h"
2841595Ssklower #endif
2941595Ssklower 
3041595Ssklower #include "../netccitt/x25.h"
3141595Ssklower #include "../netccitt/pk.h"
3241595Ssklower #include "../netccitt/pk_var.h"
3341595Ssklower 
3441595Ssklower struct	x25_packet *pk_template ();
3541595Ssklower 
3641595Ssklower /*
3741595Ssklower  *
3841595Ssklower  *  X.25 Packet level protocol interface to socket abstraction.
3941595Ssklower  *
4041595Ssklower  *  Process an X.25 user request on a logical channel.  If this is a send
4141595Ssklower  *  request then m is the mbuf chain of the send data. If this is a timer
4241595Ssklower  *  expiration (called from the software clock routine) them timertype is
4341595Ssklower  *  the particular timer.
4441595Ssklower  *
4541595Ssklower  */
4641595Ssklower 
4741595Ssklower pk_usrreq (so, req, m, nam, rights)
4841595Ssklower struct socket *so;
4941595Ssklower int req;
5041595Ssklower register struct mbuf *m, *nam;
5141595Ssklower struct mbuf *rights;
5241595Ssklower {
5341595Ssklower 	register struct pklcd *lcp = (struct pklcd *) so -> so_pcb;
5441595Ssklower 	register struct x25_packet *xp;
5541595Ssklower 	register int s = splnet (), error = 0;
5641595Ssklower 
5741595Ssklower #ifdef BSD4_3
5841595Ssklower 	if (req == PRU_CONTROL) {
5941595Ssklower 		error = pk_control(so, (int)m, (caddr_t)nam,
6041595Ssklower 			(struct ifnet *)rights);
6141595Ssklower 		splx (s);
6241595Ssklower 		return (error);
6341595Ssklower 	}
6441595Ssklower #endif
6541595Ssklower 	if (rights && rights -> m_len) {
6641595Ssklower 		splx (s);
6741595Ssklower 		return (EINVAL);
6841595Ssklower 	}
6941595Ssklower 
7041595Ssklower /*
7141595Ssklower 	pk_trace (pkcbhead, TR_USER, (struct pklcd *)0,
7241595Ssklower 		req, (struct x25_packet *)0);
7341595Ssklower */
7441595Ssklower 
7541595Ssklower 	if (lcp == NULL && req != PRU_ATTACH) {
7641595Ssklower 		splx (s);
7741595Ssklower 		return (EINVAL);
7841595Ssklower 	}
7941595Ssklower 
8041595Ssklower 	switch (req) {
8141595Ssklower 	/*
8241595Ssklower 	 *  X.25 attaches to socket via PRU_ATTACH and allocates a logical
8341595Ssklower 	 *  channel descriptor.  If the socket is to  receive connections,
8441595Ssklower 	 *  then the LISTEN state is entered.
8541595Ssklower 	 */
8641595Ssklower 	case PRU_ATTACH:
8741595Ssklower 		if (lcp) {
8841595Ssklower 			error = EISCONN;
8941595Ssklower 			/* Socket already connected. */
9041595Ssklower 			break;
9141595Ssklower 		}
9241595Ssklower 		error = pk_attach (so);
9341595Ssklower 		break;
9441595Ssklower 
9541595Ssklower 	/*
9641595Ssklower 	 *  Detach a logical channel from the socket. If the state of the
9741595Ssklower 	 *  channel is embryonic, simply discard it. Otherwise we have to
9841595Ssklower 	 *  initiate a PRU_DISCONNECT which will finish later.
9941595Ssklower 	 */
10041595Ssklower 	case PRU_DETACH:
10141595Ssklower 		pk_disconnect (lcp);
10241595Ssklower 		break;
10341595Ssklower 
10441595Ssklower 	/*
10541595Ssklower 	 *  Give the socket an address.
10641595Ssklower 	 */
10741595Ssklower 	case PRU_BIND:
10841595Ssklower 		if (nam -> m_len == sizeof (struct x25_sockaddr))
10941595Ssklower 			old_to_new (nam);
11041595Ssklower 		error = pk_bind (lcp, nam);
11141595Ssklower 		break;
11241595Ssklower 
11341595Ssklower 	/*
11441595Ssklower 	 *  Prepare to accept connections.
11541595Ssklower 	 */
11641595Ssklower 	case PRU_LISTEN:
11741595Ssklower 		if (lcp -> lcd_ceaddr == 0) {
11841595Ssklower 			error = EDESTADDRREQ;
11941595Ssklower 			break;
12041595Ssklower 		}
12141595Ssklower 		lcp -> lcd_state = LISTEN;
12241595Ssklower 		lcp -> lcd_listen = pk_listenhead;
12341595Ssklower 		pk_listenhead = lcp;
12441595Ssklower 		break;
12541595Ssklower 
12641595Ssklower 	/*
12741595Ssklower 	 *  Initiate a CALL REQUEST to peer entity. Enter state SENT_CALL
12841595Ssklower 	 *  and mark the socket as connecting. Set timer waiting for
12941595Ssklower 	 *  CALL ACCEPT or CLEAR.
13041595Ssklower 	 */
13141595Ssklower 	case PRU_CONNECT:
13241595Ssklower 		if (nam -> m_len == sizeof (struct x25_sockaddr))
13341595Ssklower 			old_to_new (nam);
13441595Ssklower 		error = pk_connect (lcp, nam);
13541595Ssklower 		break;
13641595Ssklower 
13741595Ssklower 	/*
13841595Ssklower 	 *  Initiate a disconnect to peer entity via a CLEAR REQUEST packet.
13941595Ssklower 	 *  The socket will be disconnected when we receive a confirmation
14041595Ssklower 	 *  or a clear collision.
14141595Ssklower 	 */
14241595Ssklower 	case PRU_DISCONNECT:
14341595Ssklower 		pk_disconnect (lcp);
14441595Ssklower 		break;
14541595Ssklower 
14641595Ssklower 	/*
14741595Ssklower 	 *  Accept an INCOMING CALL. Most of the work has already been done
14841595Ssklower 	 *  by pk_input. Just return the callers address to the user.
14941595Ssklower 	 */
15041595Ssklower 	case PRU_ACCEPT:
15141595Ssklower 		if (lcp -> lcd_craddr == NULL)
15241595Ssklower 			break;
15341595Ssklower 		bcopy ((caddr_t)lcp -> lcd_craddr, mtod (nam, caddr_t),
15441595Ssklower 			sizeof (struct sockaddr_x25));
15541595Ssklower 		nam -> m_len = sizeof (struct sockaddr_x25);
15641595Ssklower 		if (lcp -> lcd_flags & X25_OLDSOCKADDR)
15741595Ssklower 			new_to_old (nam);
15841595Ssklower 		break;
15941595Ssklower 
16041595Ssklower 	/*
16141595Ssklower 	 *  After a receive, we should send a RR.
16241595Ssklower 	 */
16341595Ssklower 	case PRU_RCVD:
16441595Ssklower 		lcp -> lcd_rxcnt++;
16541595Ssklower 		lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RR);
16641595Ssklower 		pk_output (lcp);
16741595Ssklower 		break;
16841595Ssklower 
16941595Ssklower 	/*
17041595Ssklower 	 *  Do send by placing data on the socket output queue.
17141595Ssklower 	 *  SHOULD WE USE m_cat HERE.
17241595Ssklower 	 */
17341595Ssklower 	case PRU_SEND:
17441595Ssklower 		error = pk_send (lcp, m);
17541595Ssklower 		break;
17641595Ssklower 
17741595Ssklower 	/*
17841595Ssklower 	 *  Abort a virtual circuit. For example all completed calls
17941595Ssklower 	 *  waiting acceptance.
18041595Ssklower 	 */
18141595Ssklower 	case PRU_ABORT:
18241595Ssklower 		pk_disconnect (lcp);
18341595Ssklower 		break;
18441595Ssklower 
18541595Ssklower 	/* Begin unimplemented hooks. */
18641595Ssklower 
18741595Ssklower 	case PRU_SHUTDOWN:
18841595Ssklower 		error = EOPNOTSUPP;
18941595Ssklower 		break;
19041595Ssklower 
19141595Ssklower 	case PRU_CONTROL:
19241595Ssklower 		error = EOPNOTSUPP;
19341595Ssklower 		break;
19441595Ssklower 
19541595Ssklower 	case PRU_SENSE:
19641595Ssklower #ifdef BSD4_3
19741595Ssklower 		((struct stat *)m) -> st_blksize = so -> so_snd.sb_hiwat;
19841595Ssklower #else
19941595Ssklower 		error = EOPNOTSUPP;
20041595Ssklower #endif
20141595Ssklower 		break;
20241595Ssklower 
20341595Ssklower 	/* End unimplemented hooks. */
20441595Ssklower 
20541595Ssklower 	case PRU_SOCKADDR:
20641595Ssklower 		if (lcp -> lcd_ceaddr == 0)
20741595Ssklower 			return (EADDRNOTAVAIL);
20841595Ssklower 		nam -> m_len = sizeof (struct sockaddr_x25);
20941595Ssklower 		bcopy ((caddr_t)lcp -> lcd_ceaddr, mtod (nam, caddr_t),
21041595Ssklower 			sizeof (struct sockaddr_x25));
21141595Ssklower 		if (lcp -> lcd_flags & X25_OLDSOCKADDR)
21241595Ssklower 			new_to_old (nam);
21341595Ssklower 		break;
21441595Ssklower 
21541595Ssklower 	case PRU_PEERADDR:
21641595Ssklower 		if (lcp -> lcd_state != DATA_TRANSFER)
21741595Ssklower 			return (ENOTCONN);
21841595Ssklower 		nam -> m_len = sizeof (struct sockaddr_x25);
21941595Ssklower 		bcopy (lcp -> lcd_craddr ? (caddr_t)lcp -> lcd_craddr :
22041595Ssklower 			(caddr_t)lcp -> lcd_ceaddr,
22141595Ssklower 			mtod (nam, caddr_t), sizeof (struct sockaddr_x25));
22241595Ssklower 		if (lcp -> lcd_flags & X25_OLDSOCKADDR)
22341595Ssklower 			new_to_old (nam);
22441595Ssklower 		break;
22541595Ssklower 
22641595Ssklower 	/*
22741595Ssklower 	 *  Receive INTERRUPT packet.
22841595Ssklower 	 */
22941595Ssklower 	case PRU_RCVOOB:
23041595Ssklower 		m -> m_len = 1;
23141595Ssklower 		*mtod (m, char *) = lcp -> lcd_intrdata;
23241595Ssklower 		break;
23341595Ssklower 
23441595Ssklower 	/*
23541595Ssklower 	 *  Send INTERRUPT packet.
23641595Ssklower 	 */
23741595Ssklower 	case PRU_SENDOOB:
23841595Ssklower 		m_freem (m);
23941595Ssklower 		if (lcp -> lcd_intrconf_pending) {
24041595Ssklower 			error = ETOOMANYREFS;
24141595Ssklower 			break;
24241595Ssklower 		}
24341595Ssklower 		lcp -> lcd_intrcnt++;
24441595Ssklower 		xp = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_INTERRUPT);
24541595Ssklower 		xp -> packet_data = 0;
24641595Ssklower 		(dtom (xp)) -> m_len++;
24741595Ssklower 		pk_output (lcp);
24841595Ssklower 		break;
24941595Ssklower 
25041595Ssklower 	default:
25141595Ssklower 		panic ("pk_usrreq");
25241595Ssklower 	}
25341595Ssklower 
25441595Ssklower 	splx (s);
25541595Ssklower 	return (error);
25641595Ssklower }
25741595Ssklower 
25841595Ssklower #ifdef BSD4_3
25941595Ssklower /*ARGSUSED*/
26041595Ssklower pk_control (so, cmd, data, ifp)
26141595Ssklower struct socket *so;
26241595Ssklower int cmd;
26341595Ssklower caddr_t data;
26441595Ssklower register struct ifnet *ifp;
26541595Ssklower {
26641595Ssklower 	register struct ifreq *ifr = (struct ifreq *)data;
26741595Ssklower 	register struct ifaddr *ifa = 0;
26841595Ssklower 	register int error, s;
26941595Ssklower 	struct sockaddr oldaddr;
27041595Ssklower 
27141595Ssklower 	/*
27241595Ssklower 	 * Find address for this interface, if it exists.
27341595Ssklower 	 */
27441595Ssklower 	if (ifp)
27541595Ssklower 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
27641595Ssklower 			if (ifa->ifa_addr.sa_family == AF_CCITT)
27741595Ssklower 				break;
27841595Ssklower 
27941595Ssklower 	switch (cmd) {
28041595Ssklower 	case SIOCGIFADDR:
28141595Ssklower 		if (ifa == 0)
28241595Ssklower 			return (EADDRNOTAVAIL);
28341595Ssklower 		ifr -> ifr_addr = ifa->ifa_addr;
28441595Ssklower 		return (0);
28541595Ssklower 
28641595Ssklower 	case SIOCSIFADDR:
28741595Ssklower 		if (!suser())
28841595Ssklower 			return (u.u_error);
28941595Ssklower 
29041595Ssklower 		if (ifp == 0)
29141595Ssklower 			panic("pk_control");
29241595Ssklower 		if (ifa == (struct ifaddr *)0) {
29341595Ssklower 			register struct ifaddr *ia;
29441595Ssklower 			register struct mbuf *m;
29541595Ssklower 
29641595Ssklower 			m = m_getclr(M_WAIT, MT_IFADDR);
29741595Ssklower 			if (m == (struct mbuf *)NULL)
29841595Ssklower 				return (ENOBUFS);
29941595Ssklower 			ia = mtod(m, struct ifaddr *);
30041595Ssklower 			if (ifa = ifp->if_addrlist) {
30141595Ssklower 				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
30241595Ssklower 					;
30341595Ssklower 				ifa->ifa_next = ia;
30441595Ssklower 			} else
30541595Ssklower 				ifp->if_addrlist = ia;
30641595Ssklower 			ifa = ia;
30741595Ssklower 			ifa->ifa_ifp = ifp;
30841595Ssklower 		}
30941595Ssklower 		oldaddr = ifa->ifa_addr;
31041595Ssklower 		s = splimp();
31141595Ssklower 		ifa->ifa_addr = ifr->ifr_addr;
31241595Ssklower 		/*
31341595Ssklower 		 * Give the interface a chance to initialize if this
31441595Ssklower 		 * is its first address, and to validate the address.
31541595Ssklower 		 */
31641595Ssklower 		if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ifa))) {
31741595Ssklower 			splx(s);
31841595Ssklower 			ifa->ifa_addr = oldaddr;
31941595Ssklower 			return (error);
32041595Ssklower 		}
32141595Ssklower 		splx(s);
32241595Ssklower #ifndef WATERLOO
32341595Ssklower 		(void) pk_accton ();
32441595Ssklower #endif
32541595Ssklower 		return (0);
32641595Ssklower 
32741595Ssklower 	default:
32841595Ssklower 		if (ifp == 0 || ifp->if_ioctl == 0)
32941595Ssklower 			return (EOPNOTSUPP);
33041595Ssklower 		return ((*ifp->if_ioctl)(ifp, cmd, data));
33141595Ssklower 	}
33241595Ssklower }
33341595Ssklower #endif
33441595Ssklower 
33541595Ssklower /*
33641595Ssklower  * Do an in-place conversion of an "old style"
33741595Ssklower  * socket address to the new style
33841595Ssklower  */
33941595Ssklower 
34041595Ssklower static
34141595Ssklower old_to_new (m)
34241595Ssklower register struct mbuf *m;
34341595Ssklower {
34441595Ssklower 	register struct x25_sockaddr *oldp;
34541595Ssklower 	register struct sockaddr_x25 *newp;
34641595Ssklower 	register char *ocp, *ncp;
34741595Ssklower 	struct sockaddr_x25 new;
34841595Ssklower 
34941595Ssklower 	oldp = mtod (m, struct x25_sockaddr *);
35041595Ssklower 	newp = &new;
35141595Ssklower 	bzero ((caddr_t)newp, sizeof (*newp));
35241595Ssklower 
35341595Ssklower 	newp -> x25_family = AF_CCITT;
35441595Ssklower 	newp->x25_opts.op_flags = (oldp->xaddr_facilities & X25_REVERSE_CHARGE)
35541595Ssklower 		| X25_MQBIT | X25_OLDSOCKADDR;
35641595Ssklower 	if (oldp -> xaddr_facilities & XS_HIPRIO)	/* Datapac specific */
35741595Ssklower 		newp -> x25_opts.op_psize = X25_PS128;
35841595Ssklower 	bcopy ((caddr_t)oldp -> xaddr_addr, newp -> x25_addr,
35941595Ssklower 		(unsigned)min (oldp -> xaddr_len, sizeof (newp -> x25_addr) - 1));
36041595Ssklower 	bcopy ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4);
36141595Ssklower 	newp -> x25_udlen = 4;
36241595Ssklower 
36341595Ssklower 	ocp = (caddr_t)oldp -> xaddr_userdata;
36441595Ssklower 	ncp = newp -> x25_udata + 4;
36541595Ssklower 	while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) {
36641595Ssklower 		*ncp++ = *ocp++;
36741595Ssklower 		newp -> x25_udlen++;
36841595Ssklower 	}
36941595Ssklower 
37041595Ssklower 	bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp));
37141595Ssklower 	m->m_len = sizeof (*newp);
37241595Ssklower }
37341595Ssklower 
37441595Ssklower /*
37541595Ssklower  * Do an in-place conversion of a new style
37641595Ssklower  * socket address to the old style
37741595Ssklower  */
37841595Ssklower 
37941595Ssklower static
38041595Ssklower new_to_old (m)
38141595Ssklower register struct mbuf *m;
38241595Ssklower {
38341595Ssklower 	register struct x25_sockaddr *oldp;
38441595Ssklower 	register struct sockaddr_x25 *newp;
38541595Ssklower 	register char *ocp, *ncp;
38641595Ssklower 	struct x25_sockaddr old;
38741595Ssklower 
38841595Ssklower 	oldp = &old;
38941595Ssklower 	newp = mtod (m, struct sockaddr_x25 *);
39041595Ssklower 	bzero ((caddr_t)oldp, sizeof (*oldp));
39141595Ssklower 
39241595Ssklower 	oldp -> xaddr_facilities = newp -> x25_opts.op_flags & X25_REVERSE_CHARGE;
39341595Ssklower 	if (newp -> x25_opts.op_psize == X25_PS128)
39441595Ssklower 		oldp -> xaddr_facilities |= XS_HIPRIO;	/* Datapac specific */
39541595Ssklower 	ocp = (char *)oldp -> xaddr_addr;
39641595Ssklower 	ncp = newp -> x25_addr;
39741595Ssklower 	while (*ncp) {
39841595Ssklower 		*ocp++ = *ncp++;
39941595Ssklower 		oldp -> xaddr_len++;
40041595Ssklower 	}
40141595Ssklower 
40241595Ssklower 	bcopy (newp -> x25_udata, (caddr_t)oldp -> xaddr_proto, 4);
40341595Ssklower 	bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata,
40441595Ssklower 		(unsigned)(newp -> x25_udlen - 4));
40541595Ssklower 
40641595Ssklower 	bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp));
40741595Ssklower 	m -> m_len = sizeof (*oldp);
40841595Ssklower }
40941595Ssklower 
41041595Ssklower pk_send (lcp, m)
41141595Ssklower register struct pklcd *lcp;
41241595Ssklower register struct mbuf *m;
41341595Ssklower {
41441595Ssklower 	register struct x25_packet *xp;
41541595Ssklower 	register struct mbuf *m0;
41641595Ssklower 	register int len;
41741595Ssklower 
41841595Ssklower 	m0 = dtom ((xp = pk_template (lcp -> lcd_lcn, X25_DATA)));
41941595Ssklower 	m0 -> m_next = m;
42041595Ssklower 	/*
42141595Ssklower 	 * Application has elected (at call setup time) to prepend
42241595Ssklower 	 * a control byte to each packet written indicating m-bit
42341595Ssklower 	 * and q-bit status.  Examine and then discard this byte.
42441595Ssklower 	 */
42541595Ssklower 	if (lcp -> lcd_flags & X25_MQBIT) {
42641595Ssklower 		register octet *cp;
42741595Ssklower 
42841595Ssklower 		if (m -> m_len < 1) {
42941595Ssklower 			m_freem (m0);
43041595Ssklower 			return (EMSGSIZE);
43141595Ssklower 		}
43241595Ssklower 		cp = mtod (m, octet *);
43341595Ssklower 		if (*cp & 0x80)					/* XXX */
43441595Ssklower 			xp -> q_bit = 1;
43541595Ssklower 		xp -> packet_type |= (*cp & 0x40) >> 2;		/* XXX */
43641595Ssklower 		m -> m_len--;
43741595Ssklower 		m -> m_off++;
43841595Ssklower 	}
43941595Ssklower 	len = m -> m_len;
44041595Ssklower 	while (m -> m_next) {
44141595Ssklower 		m = m -> m_next;
44241595Ssklower 		len += m -> m_len;
44341595Ssklower 	}
44441595Ssklower 	if (len > (1 << lcp -> lcd_packetsize)) {
44541595Ssklower 		m_freem (m0);
44641595Ssklower 		return (EMSGSIZE);
44741595Ssklower 	}
44841595Ssklower 
44941595Ssklower #ifdef BSD4_3
45041595Ssklower  	sbappendrecord (&lcp -> lcd_so -> so_snd, m0);
45141595Ssklower #else
45241595Ssklower 	m -> m_act = (struct mbuf *) 1;
45341595Ssklower 	sbappend (&lcp -> lcd_so -> so_snd, m0);
45441595Ssklower #endif
45541595Ssklower 	lcp -> lcd_template = 0;
45641595Ssklower 	lcp -> lcd_txcnt++;
45741595Ssklower 	pk_output (lcp);
45841595Ssklower 	return (0);
45941595Ssklower }
460