xref: /csrg-svn/sys/netns/idp_usrreq.c (revision 23977)
123202Smckusick /*
223202Smckusick  * Copyright (c) 1982 Regents of the University of California.
323202Smckusick  * All rights reserved.  The Berkeley software License Agreement
423202Smckusick  * specifies the terms and conditions for redistribution.
523202Smckusick  *
6*23977Ssklower  *      @(#)idp_usrreq.c	6.5 (Berkeley) 07/19/85
723202Smckusick  */
821479Ssklower 
921479Ssklower #include "param.h"
1021479Ssklower #include "dir.h"
1121479Ssklower #include "user.h"
1221479Ssklower #include "mbuf.h"
1321479Ssklower #include "protosw.h"
1421479Ssklower #include "socket.h"
1521479Ssklower #include "socketvar.h"
1621479Ssklower #include "errno.h"
1721479Ssklower #include "stat.h"
1821479Ssklower 
1921479Ssklower #include "../net/if.h"
2021479Ssklower #include "../net/route.h"
2121479Ssklower 
2221479Ssklower #include "ns.h"
2321479Ssklower #include "ns_pcb.h"
2421479Ssklower #include "idp.h"
2521479Ssklower #include "idp_var.h"
2621479Ssklower #include "ns_error.h"
2721479Ssklower 
2821479Ssklower /*
2921479Ssklower  * IDP protocol implementation.
3021479Ssklower  */
3121479Ssklower 
3221479Ssklower struct	sockaddr_ns idp_ns = { AF_NS };
3321479Ssklower 
34*23977Ssklower /*
35*23977Ssklower  *  This may also be called for raw listeners.
36*23977Ssklower  */
3721479Ssklower idp_input(m, nsp)
3821479Ssklower 	struct mbuf *m;
3921479Ssklower 	register struct nspcb *nsp;
4021479Ssklower {
4121479Ssklower 	register struct idp *idp = mtod(m, struct idp *);
4221479Ssklower 
43*23977Ssklower 	if (nsp==0) {
44*23977Ssklower 		nsp = ns_pcblookup(&idp->idp_sna,
45*23977Ssklower 					idp->idp_dna.x_port, NS_WILDCARD);
46*23977Ssklower 		if (nsp==0) {
47*23977Ssklower 			ns_error(m, NS_ERR_NOSOCK, 0);
48*23977Ssklower 			return;
49*23977Ssklower 		}
50*23977Ssklower 	}
51*23977Ssklower 
5221479Ssklower 	/*
5321479Ssklower 	 * Construct sockaddr format source address.
5421479Ssklower 	 * Stuff source address and datagram in user buffer.
5521479Ssklower 	 */
5621479Ssklower 	idp_ns.sns_addr = idp->idp_sna;
5721479Ssklower 	nsp->nsp_rpt = idp->idp_pt;
5821479Ssklower 	if ( ! (nsp->nsp_flags & NSP_RAWIN) ) {
5921479Ssklower 		m->m_len -= sizeof (struct idp);
6021479Ssklower 		m->m_off += sizeof (struct idp);
6121479Ssklower 	}
6221479Ssklower 	if (sbappendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns,
6321479Ssklower 	    m, (struct mbuf *)0) == 0)
6421479Ssklower 		goto bad;
6521479Ssklower 	sorwakeup(nsp->nsp_socket);
6621479Ssklower 	return;
6721479Ssklower bad:
6821479Ssklower 	m_freem(m);
6921479Ssklower }
7021479Ssklower 
7121479Ssklower idp_abort(nsp)
7221479Ssklower 	struct nspcb *nsp;
7321479Ssklower {
7421479Ssklower 	struct socket *so = nsp->nsp_socket;
7521479Ssklower 
7621479Ssklower 	ns_pcbdisconnect(nsp);
7721479Ssklower 	soisdisconnected(so);
7821479Ssklower }
79*23977Ssklower /*
80*23977Ssklower  * Drop connection, reporting
81*23977Ssklower  * the specified error.
82*23977Ssklower  */
83*23977Ssklower struct nspcb *
84*23977Ssklower idp_drop(nsp, errno)
85*23977Ssklower 	register struct nspcb *nsp;
86*23977Ssklower 	int errno;
87*23977Ssklower {
88*23977Ssklower 	struct socket *so = nsp->nsp_socket;
8921479Ssklower 
90*23977Ssklower 	/*
91*23977Ssklower 	 * someday, in the xerox world
92*23977Ssklower 	 * we will generate error protocol packets
93*23977Ssklower 	 * announcing that the socket has gone away.
94*23977Ssklower 	 */
95*23977Ssklower 	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
96*23977Ssklower 		tp->t_state = TCPS_CLOSED;
97*23977Ssklower 		(void) tcp_output(tp);
98*23977Ssklower 	}*/
99*23977Ssklower 	so->so_error = errno;
100*23977Ssklower 	ns_pcbdisconnect(nsp);
101*23977Ssklower 	soisdisconnected(so);
102*23977Ssklower }
103*23977Ssklower 
10421479Ssklower idp_output(nsp, m0)
10521479Ssklower 	struct nspcb *nsp;
10621479Ssklower 	struct mbuf *m0;
10721479Ssklower {
10821479Ssklower 	register struct mbuf *m;
10921479Ssklower 	register struct idp *idp;
11021479Ssklower 	register struct socket *so;
11121479Ssklower 	register int len = 0;
11221479Ssklower 	register struct route *ro;
11321479Ssklower 	struct mbuf *mprev;
11421479Ssklower 	extern int idpcksum;
11521479Ssklower 
11621479Ssklower 	/*
11721479Ssklower 	 * Calculate data length.
11821479Ssklower 	 */
11921479Ssklower 	for (m = m0; m; m = m->m_next) {
12021479Ssklower 		mprev = m;
12121479Ssklower 		len += m->m_len;
12221479Ssklower 	}
12321479Ssklower 	/*
12421479Ssklower 	 * Make sure packet is actually of even length.
12521479Ssklower 	 */
12621479Ssklower 
12721479Ssklower 	if (len & 1) {
12821479Ssklower 		m = mprev;
12921479Ssklower 		if (m->m_len + m->m_off < MMAXOFF) {
13021479Ssklower 			m->m_len++;
13121479Ssklower 		} else {
13221479Ssklower 			struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
13321479Ssklower 
13421699Ssklower 			if (m1 == 0) {
13521699Ssklower 				m_freem(m0);
13621699Ssklower 				return (ENOBUFS);
13721699Ssklower 			}
13821479Ssklower 			m1->m_len = 1;
13921479Ssklower 			m1->m_off = MMAXOFF - 1;
14021479Ssklower 			* mtod(m1, char *) = 0;
14121479Ssklower 			m->m_next = m1;
14221479Ssklower 		}
14321479Ssklower 	}
14421479Ssklower 
14521479Ssklower 	/*
14621479Ssklower 	 * Fill in mbuf with extended IDP header
14721479Ssklower 	 * and addresses and length put into network format.
14821479Ssklower 	 */
14921479Ssklower 	if (nsp->nsp_flags & NSP_RAWOUT) {
15021479Ssklower 		m = m0;
15121479Ssklower 		idp = mtod(m, struct idp *);
15221479Ssklower 	} else {
15321479Ssklower 		m = m_get(M_DONTWAIT, MT_HEADER);
15421479Ssklower 		if (m == 0) {
15521479Ssklower 			m_freem(m0);
15621479Ssklower 			return (ENOBUFS);
15721479Ssklower 		}
15821479Ssklower 		m->m_off = MMAXOFF - sizeof (struct idp);
15921479Ssklower 		m->m_len = sizeof (struct idp);
16021479Ssklower 		m->m_next = m0;
16121479Ssklower 		idp = mtod(m, struct idp *);
16221479Ssklower 		idp->idp_tc = 0;
16321479Ssklower 		idp->idp_pt = nsp->nsp_dpt;
16421479Ssklower 		idp->idp_sna = nsp->nsp_laddr;
16521479Ssklower 		idp->idp_dna = nsp->nsp_faddr;
16621479Ssklower 		len += sizeof (struct idp);
16721479Ssklower 	}
16821479Ssklower 
16921479Ssklower 	idp->idp_len = htons((u_short)len);
17021479Ssklower 
17121479Ssklower 	if (idpcksum) {
17221479Ssklower 		idp->idp_sum = 0;
17321479Ssklower 		len = ((len - 1) | 1) + 1;
17421479Ssklower 		idp->idp_sum = ns_cksum(m, len);
17521479Ssklower 	} else
17621479Ssklower 		idp->idp_sum = 0xffff;
17721479Ssklower 
17821479Ssklower 	/*
17921479Ssklower 	 * Output datagram.
18021479Ssklower 	 */
18121479Ssklower 	so = nsp->nsp_socket;
18221479Ssklower 	if (so->so_options & SO_DONTROUTE)
18321479Ssklower 		return (ns_output(m, (struct route *)0,
18421479Ssklower 		    (so->so_options & SO_BROADCAST) | NS_ROUTETOIF));
18521479Ssklower 	/*
18621479Ssklower 	 * Use cached route for previous datagram if
18721479Ssklower 	 * this is also to the same destination.
18821479Ssklower 	 *
18921479Ssklower 	 * NB: We don't handle broadcasts because that
19021479Ssklower 	 *     would require 3 subroutine calls.
19121479Ssklower 	 */
19221479Ssklower 	ro = &nsp->nsp_route;
19321479Ssklower 	if (ro->ro_rt &&
19421479Ssklower 		((*(long *)&nsp->nsp_lastnet)!=ns_netof(idp->idp_dna)) &&
19521479Ssklower 		!(ns_hosteq(satons_addr(ro->ro_dst), idp->idp_dna))) {
19621479Ssklower 		RTFREE(ro->ro_rt);
19721479Ssklower 		ro->ro_rt = (struct rtentry *)0;
19821479Ssklower 		nsp->nsp_lastnet = idp->idp_dna.x_net;
19921479Ssklower 	}
20021479Ssklower 	return (ns_output(m, ro, so->so_options & SO_BROADCAST));
20121479Ssklower }
20221479Ssklower /*ARGSUSED*/
20321479Ssklower idp_ctloutput(req, so, level, name, value)
20421479Ssklower 	int req, level;
20521479Ssklower 	struct socket *so;
20621479Ssklower 	int name;
20721479Ssklower 	struct mbuf **value;
20821479Ssklower {
20921479Ssklower 	register struct mbuf *m;
21021479Ssklower 	struct nspcb *nsp = sotonspcb(so);
21121479Ssklower 	int mask, error = 0;
212*23977Ssklower 	extern long ns_pexseq;
21321479Ssklower 
21423500Ssklower 	if (nsp == NULL)
21523500Ssklower 		return (EINVAL);
21621479Ssklower 
21721479Ssklower 	switch (req) {
21823500Ssklower 
21921479Ssklower 	case PRCO_GETOPT:
22023500Ssklower 		if (value==NULL)
22123500Ssklower 			return (EINVAL);
22221479Ssklower 		m = m_get(M_DONTWAIT, MT_DATA);
22323500Ssklower 		if (m==NULL)
22423500Ssklower 			return (ENOBUFS);
22521479Ssklower 		switch (name) {
22623500Ssklower 
22721479Ssklower 		case SO_HEADERS_ON_INPUT:
22821479Ssklower 			mask = NSP_RAWIN;
22921479Ssklower 			goto get_flags;
23023500Ssklower 
23121479Ssklower 		case SO_HEADERS_ON_OUTPUT:
23221479Ssklower 			mask = NSP_RAWOUT;
23321479Ssklower 		get_flags:
23421479Ssklower 			m->m_len = sizeof(short);
23521479Ssklower 			m->m_off = MMAXOFF - sizeof(short);
23621479Ssklower 			*mtod(m, short *) = nsp->nsp_flags & mask;
23721479Ssklower 			break;
23823500Ssklower 
23921479Ssklower 		case SO_DEFAULT_HEADERS:
24021479Ssklower 			m->m_len = sizeof(struct idp);
24121479Ssklower 			m->m_off = MMAXOFF - sizeof(struct idp);
24221479Ssklower 			{
24321479Ssklower 				register struct idp *idp = mtod(m, struct idp *);
24421479Ssklower 				idp->idp_len = 0;
24521479Ssklower 				idp->idp_sum = 0;
24621479Ssklower 				idp->idp_tc = 0;
24721479Ssklower 				idp->idp_pt = nsp->nsp_dpt;
24821479Ssklower 				idp->idp_dna = nsp->nsp_faddr;
24921479Ssklower 				idp->idp_sna = nsp->nsp_laddr;
25021479Ssklower 			}
251*23977Ssklower 			break;
252*23977Ssklower 
253*23977Ssklower 		case SO_SEQNO:
254*23977Ssklower 			m->m_len = sizeof(long);
255*23977Ssklower 			m->m_off = MMAXOFF - sizeof(long);
256*23977Ssklower 			*mtod(m, long *) = ns_pexseq++;
25721479Ssklower 		}
25821479Ssklower 		*value = m;
25921479Ssklower 		break;
26023500Ssklower 
26121479Ssklower 	case PRCO_SETOPT:
26221479Ssklower 		switch (name) {
26321479Ssklower 			int mask, *ok;
26421479Ssklower 
26521479Ssklower 		case SO_HEADERS_ON_INPUT:
26621479Ssklower 			mask = NSP_RAWIN;
26721479Ssklower 			goto set_head;
26823500Ssklower 
26921479Ssklower 		case SO_HEADERS_ON_OUTPUT:
27021479Ssklower 			mask = NSP_RAWOUT;
27121479Ssklower 		set_head:
27221479Ssklower 			if (value && *value) {
27321479Ssklower 				ok = mtod(*value, int *);
27421479Ssklower 				if (*ok)
27521479Ssklower 					nsp->nsp_flags |= mask;
27621479Ssklower 				else
27721479Ssklower 					nsp->nsp_flags &= ~mask;
27821479Ssklower 			} else error = EINVAL;
27921479Ssklower 			break;
28023500Ssklower 
28121479Ssklower 		case SO_DEFAULT_HEADERS:
28221479Ssklower 			{
28321479Ssklower 				register struct idp *idp
28421479Ssklower 				    = mtod(*value, struct idp *);
28521479Ssklower 				nsp->nsp_dpt = idp->idp_pt;
28621479Ssklower 			}
28721479Ssklower #ifdef NSIP
28821479Ssklower 			break;
28923500Ssklower 
29021479Ssklower 		case SO_NSIP_ROUTE:
29121479Ssklower 			error = nsip_route(*value);
29221479Ssklower #endif NSIP
29321479Ssklower 		}
29421479Ssklower 		if (value && *value)
29521479Ssklower 			m_freem(*value);
29621479Ssklower 		break;
29721479Ssklower 	}
29823500Ssklower 	return (error);
29921479Ssklower }
30021479Ssklower 
30121479Ssklower /*ARGSUSED*/
30221479Ssklower idp_usrreq(so, req, m, nam, rights)
30321479Ssklower 	struct socket *so;
30421479Ssklower 	int req;
30521479Ssklower 	struct mbuf *m, *nam, *rights;
30621479Ssklower {
30721479Ssklower 	struct nspcb *nsp = sotonspcb(so);
30821479Ssklower 	int error = 0;
30921479Ssklower 
31021479Ssklower 	if (req == PRU_CONTROL)
31121479Ssklower                 return (ns_control(so, (int)m, (caddr_t)nam,
31221479Ssklower 			(struct ifnet *)rights));
31321479Ssklower 	if (rights && rights->m_len) {
31421479Ssklower 		error = EINVAL;
31521479Ssklower 		goto release;
31621479Ssklower 	}
31721479Ssklower 	if (nsp == NULL && req != PRU_ATTACH) {
31821479Ssklower 		error = EINVAL;
31921479Ssklower 		goto release;
32021479Ssklower 	}
32121479Ssklower 	switch (req) {
32221479Ssklower 
32321479Ssklower 	case PRU_ATTACH:
32421479Ssklower 		if (nsp != NULL) {
32521479Ssklower 			error = EINVAL;
32621479Ssklower 			break;
32721479Ssklower 		}
32821479Ssklower 		error = ns_pcballoc(so, &nspcb);
32921479Ssklower 		if (error)
33021479Ssklower 			break;
33121479Ssklower 		error = soreserve(so, 2048, 2048);
33221479Ssklower 		if (error)
33321479Ssklower 			break;
33421479Ssklower 		break;
33521479Ssklower 
33621479Ssklower 	case PRU_DETACH:
33721479Ssklower 		if (nsp == NULL) {
33821479Ssklower 			error = ENOTCONN;
33921479Ssklower 			break;
34021479Ssklower 		}
34121479Ssklower 		ns_pcbdetach(nsp);
34221479Ssklower 		break;
34321479Ssklower 
34421479Ssklower 	case PRU_BIND:
34521479Ssklower 		error = ns_pcbbind(nsp, nam);
34621479Ssklower 		break;
34721479Ssklower 
34821479Ssklower 	case PRU_LISTEN:
34921479Ssklower 		error = EOPNOTSUPP;
35021479Ssklower 		break;
35121479Ssklower 
35221479Ssklower 	case PRU_CONNECT:
35321479Ssklower 		if (!ns_nullhost(nsp->nsp_faddr)) {
35421479Ssklower 			error = EISCONN;
35521479Ssklower 			break;
35621479Ssklower 		}
35721479Ssklower 		error = ns_pcbconnect(nsp, nam);
35821479Ssklower 		if (error == 0)
35921479Ssklower 			soisconnected(so);
36021479Ssklower 		break;
36121479Ssklower 
36221479Ssklower 	case PRU_CONNECT2:
36321479Ssklower 		error = EOPNOTSUPP;
36421479Ssklower 		break;
36521479Ssklower 
36621479Ssklower 	case PRU_ACCEPT:
36721479Ssklower 		error = EOPNOTSUPP;
36821479Ssklower 		break;
36921479Ssklower 
37021479Ssklower 	case PRU_DISCONNECT:
37121479Ssklower 		if (ns_nullhost(nsp->nsp_faddr)) {
37221479Ssklower 			error = ENOTCONN;
37321479Ssklower 			break;
37421479Ssklower 		}
37521479Ssklower 		ns_pcbdisconnect(nsp);
37621479Ssklower 		soisdisconnected(so);
37721479Ssklower 		break;
37821479Ssklower 
37921479Ssklower 	case PRU_SHUTDOWN:
38021479Ssklower 		socantsendmore(so);
38121479Ssklower 		break;
38221479Ssklower 
38321479Ssklower 	case PRU_SEND:
38421479Ssklower 	{
38521479Ssklower 		struct ns_addr laddr;
38621479Ssklower 		int s;
38721479Ssklower 
38821479Ssklower 		if (nam) {
38921479Ssklower 			laddr = nsp->nsp_laddr;
39021479Ssklower 			if (!ns_nullhost(nsp->nsp_faddr)) {
39121479Ssklower 				error = EISCONN;
39221479Ssklower 				break;
39321479Ssklower 			}
39421479Ssklower 			/*
39521479Ssklower 			 * Must block input while temporarily connected.
39621479Ssklower 			 */
39721479Ssklower 			s = splnet();
39821479Ssklower 			error = ns_pcbconnect(nsp, nam);
39921479Ssklower 			if (error) {
40021479Ssklower 				splx(s);
40121479Ssklower 				break;
40221479Ssklower 			}
40321479Ssklower 		} else {
40421479Ssklower 			if (ns_nullhost(nsp->nsp_faddr)) {
40521479Ssklower 				error = ENOTCONN;
40621479Ssklower 				break;
40721479Ssklower 			}
40821479Ssklower 		}
40921479Ssklower 		error = idp_output(nsp, m);
41021479Ssklower 		m = NULL;
41121479Ssklower 		if (nam) {
41221479Ssklower 			ns_pcbdisconnect(nsp);
41321479Ssklower 			splx(s);
41421479Ssklower 			nsp->nsp_laddr.x_host = laddr.x_host;
41521479Ssklower 			nsp->nsp_laddr.x_port = laddr.x_port;
41621479Ssklower 		}
41721479Ssklower 	}
41821479Ssklower 		break;
41921479Ssklower 
42021479Ssklower 	case PRU_ABORT:
42121479Ssklower 		ns_pcbdetach(nsp);
42221479Ssklower 		sofree(so);
42321479Ssklower 		soisdisconnected(so);
42421479Ssklower 		break;
42521479Ssklower 
42621479Ssklower 	case PRU_SOCKADDR:
42721479Ssklower 		ns_setsockaddr(nsp, nam);
42821479Ssklower 		break;
42921479Ssklower 
43021479Ssklower 	case PRU_PEERADDR:
43121479Ssklower 		ns_setpeeraddr(nsp, nam);
43221479Ssklower 		break;
43321479Ssklower 
43421479Ssklower 	case PRU_SENSE:
43521479Ssklower 		/*
43621479Ssklower 		 * stat: don't bother with a blocksize.
43721479Ssklower 		 */
43821479Ssklower 		return (0);
43921479Ssklower 
44021479Ssklower 	case PRU_SENDOOB:
44121479Ssklower 	case PRU_FASTTIMO:
44221479Ssklower 	case PRU_SLOWTIMO:
44321479Ssklower 	case PRU_PROTORCV:
44421479Ssklower 	case PRU_PROTOSEND:
44521479Ssklower 		error =  EOPNOTSUPP;
44621479Ssklower 		break;
44721479Ssklower 
44821479Ssklower 	case PRU_CONTROL:
44921479Ssklower 	case PRU_RCVD:
45021479Ssklower 	case PRU_RCVOOB:
45121479Ssklower 		return (EOPNOTSUPP);	/* do not free mbuf's */
45221479Ssklower 
45321479Ssklower 	default:
45421479Ssklower 		panic("idp_usrreq");
45521479Ssklower 	}
45621479Ssklower release:
45721479Ssklower 	if (m != NULL)
45821479Ssklower 		m_freem(m);
45921479Ssklower 	return (error);
46021479Ssklower }
46121479Ssklower /*ARGSUSED*/
46221479Ssklower idp_raw_usrreq(so, req, m, nam, rights)
46321479Ssklower 	struct socket *so;
46421479Ssklower 	int req;
46521479Ssklower 	struct mbuf *m, *nam, *rights;
46621479Ssklower {
46721479Ssklower 	int error = 0;
46821479Ssklower 	struct nspcb *nsp = sotonspcb(so);
46921479Ssklower 	extern struct nspcb nsrawpcb;
47021479Ssklower 
47121479Ssklower 	switch (req) {
47221479Ssklower 
47321479Ssklower 	case PRU_ATTACH:
47421479Ssklower 
47521699Ssklower 		if (!suser() || (nsp != NULL)) {
47621479Ssklower 			error = EINVAL;
47721479Ssklower 			break;
47821479Ssklower 		}
47921479Ssklower 		error = ns_pcballoc(so, &nsrawpcb);
48021479Ssklower 		if (error)
48121479Ssklower 			break;
48221479Ssklower 		error = soreserve(so, 2048, 2048);
48321479Ssklower 		if (error)
48421479Ssklower 			break;
48521479Ssklower 		nsp = sotonspcb(so);
48621479Ssklower 		nsp->nsp_faddr.x_host = ns_broadhost;
48721479Ssklower 		nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
48821479Ssklower 		break;
48921479Ssklower 	default:
49021479Ssklower 		error = idp_usrreq(so, req, m, nam, rights);
49121479Ssklower 	}
49223500Ssklower 	return (error);
49321479Ssklower }
49421479Ssklower 
495