1139823Simp/*-
2157128Srwatson * Copyright (c) 1984, 1985, 1986, 1987, 1993
3157128Srwatson *	The Regents of the University of California.
4157128Srwatson * Copyright (c) 2004-2006 Robert N. M. Watson
5157128Srwatson * All rights reserved.
611819Sjulian *
711819Sjulian * Redistribution and use in source and binary forms, with or without
811819Sjulian * modification, are permitted provided that the following conditions
911819Sjulian * are met:
1011819Sjulian * 1. Redistributions of source code must retain the above copyright
1111819Sjulian *    notice, this list of conditions and the following disclaimer.
1211819Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1311819Sjulian *    notice, this list of conditions and the following disclaimer in the
1411819Sjulian *    documentation and/or other materials provided with the distribution.
15165899Srwatson * 4. Neither the name of the University nor the names of its contributors
16165899Srwatson *    may be used to endorse or promote products derived from this software
17165899Srwatson *    without specific prior written permission.
18165899Srwatson *
19165899Srwatson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20165899Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21165899Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22165899Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23165899Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24165899Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25165899Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26165899Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27165899Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28165899Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29165899Srwatson * SUCH DAMAGE.
30165899Srwatson *
31165899Srwatson * Copyright (c) 1995, Mike Mitchell
32165899Srwatson * All rights reserved.
33165899Srwatson *
34165899Srwatson * Redistribution and use in source and binary forms, with or without
35165899Srwatson * modification, are permitted provided that the following conditions
36165899Srwatson * are met:
37165899Srwatson * 1. Redistributions of source code must retain the above copyright
38165899Srwatson *    notice, this list of conditions and the following disclaimer.
39165899Srwatson * 2. Redistributions in binary form must reproduce the above copyright
40165899Srwatson *    notice, this list of conditions and the following disclaimer in the
41165899Srwatson *    documentation and/or other materials provided with the distribution.
4211819Sjulian * 3. All advertising materials mentioning features or use of this software
4311819Sjulian *    must display the following acknowledgement:
4411819Sjulian *	This product includes software developed by the University of
4511819Sjulian *	California, Berkeley and its contributors.
4611819Sjulian * 4. Neither the name of the University nor the names of its contributors
4711819Sjulian *    may be used to endorse or promote products derived from this software
4811819Sjulian *    without specific prior written permission.
4911819Sjulian *
5011819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5111819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5211819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5311819Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5411819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5511819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5611819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5711819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5811819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5911819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6011819Sjulian * SUCH DAMAGE.
6111819Sjulian *
6212057Sjulian *	@(#)ipx_usrreq.c
6311819Sjulian */
6411819Sjulian
65116189Sobrien#include <sys/cdefs.h>
66116189Sobrien__FBSDID("$FreeBSD$");
67116189Sobrien
6831742Seivind#include "opt_ipx.h"
6931742Seivind
7011819Sjulian#include <sys/param.h>
7119947Sjhay#include <sys/kernel.h>
7295759Stanimura#include <sys/lock.h>
7311819Sjulian#include <sys/mbuf.h>
74164033Srwatson#include <sys/priv.h>
7511819Sjulian#include <sys/protosw.h>
7695759Stanimura#include <sys/signalvar.h>
7711819Sjulian#include <sys/socket.h>
7811819Sjulian#include <sys/socketvar.h>
7995759Stanimura#include <sys/sx.h>
8019947Sjhay#include <sys/sysctl.h>
8195759Stanimura#include <sys/systm.h>
8211819Sjulian
8311819Sjulian#include <net/if.h>
8411819Sjulian#include <net/route.h>
8511819Sjulian
8611947Sjulian#include <netinet/in.h>
8711947Sjulian
8811819Sjulian#include <netipx/ipx.h>
8995759Stanimura#include <netipx/ipx_if.h>
9011819Sjulian#include <netipx/ipx_pcb.h>
9111819Sjulian#include <netipx/ipx_var.h>
9211819Sjulian
93194544Srwatson#include <security/mac/mac_framework.h>
94194544Srwatson
9511819Sjulian/*
9611819Sjulian * IPX protocol implementation.
9711819Sjulian */
9811819Sjulian
9933181Seivindstatic int ipxsendspace = IPXSNDQ;
10019947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW,
101180816Strhodes            &ipxsendspace, 0, "Send buffer space");
10233181Seivindstatic int ipxrecvspace = IPXRCVQ;
10319947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
104180816Strhodes            &ipxrecvspace, 0, "Receive buffer space");
10519947Sjhay
106157366Srwatsonstatic	void ipx_usr_abort(struct socket *so);
10783366Sjulianstatic	int ipx_attach(struct socket *so, int proto, struct thread *td);
10883366Sjulianstatic	int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
10928270Swollmanstatic	int ipx_connect(struct socket *so, struct sockaddr *nam,
11083366Sjulian			struct thread *td);
111157370Srwatsonstatic	void ipx_detach(struct socket *so);
11224659Sjhaystatic	int ipx_disconnect(struct socket *so);
11324659Sjhaystatic	int ipx_send(struct socket *so, int flags, struct mbuf *m,
114139584Srwatson		     struct sockaddr *addr, struct mbuf *control,
11583366Sjulian		     struct thread *td);
11624659Sjhaystatic	int ipx_shutdown(struct socket *so);
11783366Sjulianstatic	int ripx_attach(struct socket *so, int proto, struct thread *td);
11825652Sjhaystatic	int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0);
119160549Srwatsonstatic	void ipx_usr_close(struct socket *so);
12024659Sjhay
12125652Sjhaystruct	pr_usrreqs ipx_usrreqs = {
122137386Sphk	.pru_abort =		ipx_usr_abort,
123137386Sphk	.pru_attach =		ipx_attach,
124137386Sphk	.pru_bind =		ipx_bind,
125137386Sphk	.pru_connect =		ipx_connect,
126137386Sphk	.pru_control =		ipx_control,
127137386Sphk	.pru_detach =		ipx_detach,
128137386Sphk	.pru_disconnect =	ipx_disconnect,
129137386Sphk	.pru_peeraddr =		ipx_peeraddr,
130137386Sphk	.pru_send =		ipx_send,
131137386Sphk	.pru_shutdown =		ipx_shutdown,
132137386Sphk	.pru_sockaddr =		ipx_sockaddr,
133160549Srwatson	.pru_close =		ipx_usr_close,
13424659Sjhay};
13524659Sjhay
13625652Sjhaystruct	pr_usrreqs ripx_usrreqs = {
137137386Sphk	.pru_abort =		ipx_usr_abort,
138137386Sphk	.pru_attach =		ripx_attach,
139137386Sphk	.pru_bind =		ipx_bind,
140137386Sphk	.pru_connect =		ipx_connect,
141137386Sphk	.pru_control =		ipx_control,
142137386Sphk	.pru_detach =		ipx_detach,
143137386Sphk	.pru_disconnect =	ipx_disconnect,
144137386Sphk	.pru_peeraddr =		ipx_peeraddr,
145137386Sphk	.pru_send =		ipx_send,
146137386Sphk	.pru_shutdown =		ipx_shutdown,
147137386Sphk	.pru_sockaddr =		ipx_sockaddr,
148160549Srwatson	.pru_close =		ipx_usr_close,
14924659Sjhay};
15024659Sjhay
15111819Sjulian/*
15211819Sjulian *  This may also be called for raw listeners.
15311819Sjulian */
15411819Sjulianvoid
155169463Srwatsonipx_input(struct mbuf *m, struct ipxpcb *ipxp)
15611819Sjulian{
157169463Srwatson	struct ipx *ipx = mtod(m, struct ipx *);
15811819Sjulian	struct ifnet *ifp = m->m_pkthdr.rcvif;
15915245Sjhay	struct sockaddr_ipx ipx_ipx;
16011819Sjulian
161139623Srwatson	KASSERT(ipxp != NULL, ("ipx_input: NULL ipxpcb"));
162139929Srwatson	IPX_LOCK_ASSERT(ipxp);
16311819Sjulian	/*
16411819Sjulian	 * Construct sockaddr format source address.
16511819Sjulian	 * Stuff source address and datagram in user buffer.
16611819Sjulian	 */
16715245Sjhay	ipx_ipx.sipx_len = sizeof(ipx_ipx);
16815245Sjhay	ipx_ipx.sipx_family = AF_IPX;
16911819Sjulian	ipx_ipx.sipx_addr = ipx->ipx_sna;
17015245Sjhay	ipx_ipx.sipx_zero[0] = '\0';
17115245Sjhay	ipx_ipx.sipx_zero[1] = '\0';
17225652Sjhay	if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) {
173169463Srwatson		struct ifaddr *ifa;
17411819Sjulian
175139584Srwatson		for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL;
17671999Sphk		     ifa = TAILQ_NEXT(ifa, ifa_link)) {
17711819Sjulian			if (ifa->ifa_addr->sa_family == AF_IPX) {
17811819Sjulian				ipx_ipx.sipx_addr.x_net =
17911819Sjulian					IA_SIPX(ifa)->sipx_addr.x_net;
18011819Sjulian				break;
18111819Sjulian			}
18211819Sjulian		}
18311819Sjulian	}
18411819Sjulian	ipxp->ipxp_rpt = ipx->ipx_pt;
185139588Srwatson	if ((ipxp->ipxp_flags & IPXP_RAWIN) == 0) {
18625652Sjhay		m->m_len -= sizeof(struct ipx);
18725652Sjhay		m->m_pkthdr.len -= sizeof(struct ipx);
18825652Sjhay		m->m_data += sizeof(struct ipx);
18911819Sjulian	}
190194561Srwatson#ifdef MAC
191194561Srwatson	if (mac_socket_check_deliver(ipxp->ipxp_socket, m) != 0) {
192194561Srwatson		m_freem(m);
193194561Srwatson		return;
194194561Srwatson	}
195194561Srwatson#endif
196139588Srwatson	if (sbappendaddr(&ipxp->ipxp_socket->so_rcv,
197139588Srwatson	    (struct sockaddr *)&ipx_ipx, m, NULL) == 0)
198139588Srwatson		m_freem(m);
199139588Srwatson	else
200139588Srwatson		sorwakeup(ipxp->ipxp_socket);
20111819Sjulian}
20211819Sjulian
20311819Sjulian/*
20411819Sjulian * Drop connection, reporting
20511819Sjulian * the specified error.
20611819Sjulian */
20711819Sjulianvoid
208169463Srwatsonipx_drop(struct ipxpcb *ipxp, int errno)
20911819Sjulian{
21011819Sjulian	struct socket *so = ipxp->ipxp_socket;
21111819Sjulian
212139929Srwatson	IPX_LIST_LOCK_ASSERT();
213139929Srwatson	IPX_LOCK_ASSERT(ipxp);
214139929Srwatson
21511819Sjulian	/*
21625652Sjhay	 * someday, in the IPX world
21711819Sjulian	 * we will generate error protocol packets
21811819Sjulian	 * announcing that the socket has gone away.
21925652Sjhay	 *
22025652Sjhay	 * XXX Probably never. IPX does not have error packets.
22111819Sjulian	 */
22211819Sjulian	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
22311819Sjulian		tp->t_state = TCPS_CLOSED;
22425652Sjhay		tcp_output(tp);
22511819Sjulian	}*/
22611819Sjulian	so->so_error = errno;
22711819Sjulian	ipx_pcbdisconnect(ipxp);
22811819Sjulian	soisdisconnected(so);
22911819Sjulian}
23011819Sjulian
23125652Sjhaystatic int
232169463Srwatsonipx_output(struct ipxpcb *ipxp, struct mbuf *m0)
23311819Sjulian{
234169463Srwatson	struct ipx *ipx;
235169463Srwatson	struct socket *so;
236169463Srwatson	int len = 0;
237169463Srwatson	struct route *ro;
23854799Sgreen	struct mbuf *m;
23911819Sjulian	struct mbuf *mprev = NULL;
24011819Sjulian
241139929Srwatson	IPX_LOCK_ASSERT(ipxp);
242139929Srwatson
24311819Sjulian	/*
24411819Sjulian	 * Calculate data length.
24511819Sjulian	 */
24625652Sjhay	for (m = m0; m != NULL; m = m->m_next) {
24711819Sjulian		mprev = m;
24811819Sjulian		len += m->m_len;
24911819Sjulian	}
25011819Sjulian	/*
25111819Sjulian	 * Make sure packet is actually of even length.
25211819Sjulian	 */
253139584Srwatson
25411819Sjulian	if (len & 1) {
25511819Sjulian		m = mprev;
25611819Sjulian		if ((m->m_flags & M_EXT) == 0 &&
25711819Sjulian			(m->m_len + m->m_data < &m->m_dat[MLEN])) {
25850519Sjhay			mtod(m, char*)[m->m_len++] = 0;
25911819Sjulian		} else {
260243882Sglebius			struct mbuf *m1 = m_get(M_NOWAIT, MT_DATA);
26111819Sjulian
26225652Sjhay			if (m1 == NULL) {
26311819Sjulian				m_freem(m0);
26411819Sjulian				return (ENOBUFS);
26511819Sjulian			}
26611819Sjulian			m1->m_len = 1;
26711819Sjulian			* mtod(m1, char *) = 0;
26811819Sjulian			m->m_next = m1;
26911819Sjulian		}
27011819Sjulian		m0->m_pkthdr.len++;
27111819Sjulian	}
27211819Sjulian
27311819Sjulian	/*
27411819Sjulian	 * Fill in mbuf with extended IPX header
27511819Sjulian	 * and addresses and length put into network format.
27611819Sjulian	 */
27711819Sjulian	m = m0;
27811819Sjulian	if (ipxp->ipxp_flags & IPXP_RAWOUT) {
27911819Sjulian		ipx = mtod(m, struct ipx *);
28011819Sjulian	} else {
281243882Sglebius		M_PREPEND(m, sizeof(struct ipx), M_NOWAIT);
28225652Sjhay		if (m == NULL)
28311819Sjulian			return (ENOBUFS);
28411819Sjulian		ipx = mtod(m, struct ipx *);
28511819Sjulian		ipx->ipx_tc = 0;
28611819Sjulian		ipx->ipx_pt = ipxp->ipxp_dpt;
28711819Sjulian		ipx->ipx_sna = ipxp->ipxp_laddr;
28811819Sjulian		ipx->ipx_dna = ipxp->ipxp_faddr;
28925652Sjhay		len += sizeof(struct ipx);
29011819Sjulian	}
29111819Sjulian
29211819Sjulian	ipx->ipx_len = htons((u_short)len);
29311819Sjulian
29450519Sjhay	if (ipxp->ipxp_flags & IPXP_CHECKSUM) {
29511819Sjulian		ipx->ipx_sum = ipx_cksum(m, len);
29611819Sjulian	} else
29711819Sjulian		ipx->ipx_sum = 0xffff;
29811819Sjulian
29911819Sjulian	/*
30011819Sjulian	 * Output datagram.
30111819Sjulian	 */
30211819Sjulian	so = ipxp->ipxp_socket;
30397658Stanimura	if (so->so_options & SO_DONTROUTE)
30425652Sjhay		return (ipx_outputfl(m, (struct route *)NULL,
30597658Stanimura		    (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
30611819Sjulian	/*
30711819Sjulian	 * Use cached route for previous datagram if
30811819Sjulian	 * possible.  If the previous net was the same
30911819Sjulian	 * and the interface was a broadcast medium, or
31011819Sjulian	 * if the previous destination was identical,
31111819Sjulian	 * then we are ok.
31211819Sjulian	 *
31311819Sjulian	 * NB: We don't handle broadcasts because that
31411819Sjulian	 *     would require 3 subroutine calls.
31511819Sjulian	 */
31611819Sjulian	ro = &ipxp->ipxp_route;
31711819Sjulian#ifdef ancient_history
31811819Sjulian	/*
31911819Sjulian	 * I think that this will all be handled in ipx_pcbconnect!
32011819Sjulian	 */
32125652Sjhay	if (ro->ro_rt != NULL) {
32211819Sjulian		if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
32311819Sjulian			/*
32411819Sjulian			 * This assumes we have no GH type routes
32511819Sjulian			 */
32611819Sjulian			if (ro->ro_rt->rt_flags & RTF_HOST) {
32711819Sjulian				if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
32811819Sjulian					goto re_route;
32911819Sjulian
33011819Sjulian			}
33111819Sjulian			if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
332169463Srwatson				struct ipx_addr *dst =
33311819Sjulian						&satoipx_addr(ro->ro_dst);
33411819Sjulian				dst->x_host = ipx->ipx_dna.x_host;
33511819Sjulian			}
336139584Srwatson			/*
33711819Sjulian			 * Otherwise, we go through the same gateway
33811819Sjulian			 * and dst is already set up.
33911819Sjulian			 */
34011819Sjulian		} else {
34111819Sjulian		re_route:
34211819Sjulian			RTFREE(ro->ro_rt);
34325652Sjhay			ro->ro_rt = NULL;
34411819Sjulian		}
34511819Sjulian	}
34611819Sjulian	ipxp->ipxp_lastdst = ipx->ipx_dna;
34711819Sjulian#endif /* ancient_history */
34897658Stanimura	return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
34911819Sjulian}
35019947Sjhay
35111819Sjulianint
352169463Srwatsonipx_ctloutput(struct socket *so, struct sockopt *sopt)
35311819Sjulian{
35411819Sjulian	struct ipxpcb *ipxp = sotoipxpcb(so);
35538482Swollman	int mask, error, optval;
35638482Swollman	short soptval;
35738482Swollman	struct ipx ioptval;
358139930Srwatson	long seq;
35911819Sjulian
360157128Srwatson	KASSERT(ipxp != NULL, ("ipx_ctloutput: ipxp == NULL"));
36138482Swollman	error = 0;
36211819Sjulian
36338482Swollman	switch (sopt->sopt_dir) {
36438482Swollman	case SOPT_GET:
36538482Swollman		switch (sopt->sopt_name) {
36611819Sjulian		case SO_ALL_PACKETS:
36711819Sjulian			mask = IPXP_ALL_PACKETS;
36811819Sjulian			goto get_flags;
36911819Sjulian
37011819Sjulian		case SO_HEADERS_ON_INPUT:
37111819Sjulian			mask = IPXP_RAWIN;
37211819Sjulian			goto get_flags;
37350519Sjhay
37450519Sjhay		case SO_IPX_CHECKSUM:
37550519Sjhay			mask = IPXP_CHECKSUM;
37650519Sjhay			goto get_flags;
377139584Srwatson
37811819Sjulian		case SO_HEADERS_ON_OUTPUT:
37911819Sjulian			mask = IPXP_RAWOUT;
38011819Sjulian		get_flags:
381139930Srwatson			/* Unlocked read. */
38238482Swollman			soptval = ipxp->ipxp_flags & mask;
38338482Swollman			error = sooptcopyout(sopt, &soptval, sizeof soptval);
38411819Sjulian			break;
38511819Sjulian
38611819Sjulian		case SO_DEFAULT_HEADERS:
38738482Swollman			ioptval.ipx_len = 0;
38838482Swollman			ioptval.ipx_sum = 0;
38938482Swollman			ioptval.ipx_tc = 0;
390139930Srwatson			IPX_LOCK(ipxp);
39138482Swollman			ioptval.ipx_pt = ipxp->ipxp_dpt;
39238482Swollman			ioptval.ipx_dna = ipxp->ipxp_faddr;
39338482Swollman			ioptval.ipx_sna = ipxp->ipxp_laddr;
394139930Srwatson			IPX_UNLOCK(ipxp);
39538482Swollman			error = sooptcopyout(sopt, &soptval, sizeof soptval);
39611819Sjulian			break;
39711819Sjulian
39811819Sjulian		case SO_SEQNO:
399139930Srwatson			IPX_LIST_LOCK();
400139930Srwatson			seq = ipx_pexseq;
40138482Swollman			ipx_pexseq++;
402139930Srwatson			IPX_LIST_UNLOCK();
403139930Srwatson			error = sooptcopyout(sopt, &seq, sizeof seq);
40411819Sjulian			break;
40511819Sjulian
40611819Sjulian		default:
40711819Sjulian			error = EINVAL;
40811819Sjulian		}
40911819Sjulian		break;
41011819Sjulian
41138482Swollman	case SOPT_SET:
41238482Swollman		switch (sopt->sopt_name) {
41311819Sjulian		case SO_ALL_PACKETS:
41411819Sjulian			mask = IPXP_ALL_PACKETS;
41511819Sjulian			goto set_head;
41611819Sjulian
41711819Sjulian		case SO_HEADERS_ON_INPUT:
41811819Sjulian			mask = IPXP_RAWIN;
41911819Sjulian			goto set_head;
42011819Sjulian
42150519Sjhay		case SO_IPX_CHECKSUM:
42250519Sjhay			mask = IPXP_CHECKSUM;
423185928Srwatson			goto set_head;
42450519Sjhay
42511819Sjulian		case SO_HEADERS_ON_OUTPUT:
42611819Sjulian			mask = IPXP_RAWOUT;
42711819Sjulian		set_head:
42838482Swollman			error = sooptcopyin(sopt, &optval, sizeof optval,
42938482Swollman					    sizeof optval);
43038482Swollman			if (error)
43138482Swollman				break;
432139930Srwatson			IPX_LOCK(ipxp);
43338482Swollman			if (optval)
43438482Swollman				ipxp->ipxp_flags |= mask;
43538482Swollman			else
43638482Swollman				ipxp->ipxp_flags &= ~mask;
437139930Srwatson			IPX_UNLOCK(ipxp);
43811819Sjulian			break;
43911819Sjulian
44011819Sjulian		case SO_DEFAULT_HEADERS:
44138482Swollman			error = sooptcopyin(sopt, &ioptval, sizeof ioptval,
44238482Swollman					    sizeof ioptval);
44338482Swollman			if (error)
44438482Swollman				break;
445139930Srwatson			/* Unlocked write. */
44638482Swollman			ipxp->ipxp_dpt = ioptval.ipx_pt;
44711819Sjulian			break;
44811819Sjulian		default:
44911819Sjulian			error = EINVAL;
45011819Sjulian		}
45111819Sjulian		break;
45211819Sjulian	}
45311819Sjulian	return (error);
45411819Sjulian}
45511819Sjulian
456157366Srwatsonstatic void
457169463Srwatsonipx_usr_abort(struct socket *so)
45811819Sjulian{
45911819Sjulian
460160549Srwatson	/* XXXRW: Possibly ipx_disconnect() here? */
461130387Srwatson	soisdisconnected(so);
46224659Sjhay}
46311819Sjulian
46424659Sjhaystatic int
465169463Srwatsonipx_attach(struct socket *so, int proto, struct thread *td)
46624659Sjhay{
467157672Scognet#ifdef INVARIANTS
468139929Srwatson	struct ipxpcb *ipxp = sotoipxpcb(so);
469157672Scognet#endif
47024659Sjhay	int error;
47124659Sjhay
472157128Srwatson	KASSERT(ipxp == NULL, ("ipx_attach: ipxp != NULL"));
473157128Srwatson	error = soreserve(so, ipxsendspace, ipxrecvspace);
474157128Srwatson	if (error != 0)
475157128Srwatson		return (error);
476139929Srwatson	IPX_LIST_LOCK();
477139444Srwatson	error = ipx_pcballoc(so, &ipxpcb_list, td);
478139929Srwatson	IPX_LIST_UNLOCK();
47924659Sjhay	return (error);
48024659Sjhay}
48111819Sjulian
48224659Sjhaystatic int
483169463Srwatsonipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
48424659Sjhay{
48524659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
486139929Srwatson	int error;
48711819Sjulian
488157128Srwatson	KASSERT(ipxp != NULL, ("ipx_bind: ipxp == NULL"));
489139929Srwatson	IPX_LIST_LOCK();
490139929Srwatson	IPX_LOCK(ipxp);
491139929Srwatson	error = ipx_pcbbind(ipxp, nam, td);
492139929Srwatson	IPX_UNLOCK(ipxp);
493139929Srwatson	IPX_LIST_UNLOCK();
494139929Srwatson	return (error);
49524659Sjhay}
49611819Sjulian
497160549Srwatsonstatic void
498169463Srwatsonipx_usr_close(struct socket *so)
499160549Srwatson{
500160549Srwatson
501160549Srwatson	/* XXXRW: Possibly ipx_disconnect() here? */
502160549Srwatson	soisdisconnected(so);
503160549Srwatson}
504160549Srwatson
50524659Sjhaystatic int
506169463Srwatsonipx_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
50724659Sjhay{
508139929Srwatson	struct ipxpcb *ipxp = sotoipxpcb(so);
50924659Sjhay	int error;
51011819Sjulian
511157128Srwatson	KASSERT(ipxp != NULL, ("ipx_connect: ipxp == NULL"));
512139929Srwatson	IPX_LIST_LOCK();
513139929Srwatson	IPX_LOCK(ipxp);
514139929Srwatson	if (!ipx_nullhost(ipxp->ipxp_faddr)) {
515139929Srwatson		error = EISCONN;
516139929Srwatson		goto out;
517139929Srwatson	}
51883366Sjulian	error = ipx_pcbconnect(ipxp, nam, td);
51997658Stanimura	if (error == 0)
52024659Sjhay		soisconnected(so);
521139929Srwatsonout:
522139929Srwatson	IPX_UNLOCK(ipxp);
523139929Srwatson	IPX_LIST_UNLOCK();
52424659Sjhay	return (error);
52524659Sjhay}
52611819Sjulian
527157370Srwatsonstatic void
528169463Srwatsonipx_detach(struct socket *so)
52924659Sjhay{
53024659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
53111819Sjulian
532160549Srwatson	/* XXXRW: Should assert detached. */
533157128Srwatson	KASSERT(ipxp != NULL, ("ipx_detach: ipxp == NULL"));
534139929Srwatson	IPX_LIST_LOCK();
535139929Srwatson	IPX_LOCK(ipxp);
53624659Sjhay	ipx_pcbdetach(ipxp);
537157128Srwatson	ipx_pcbfree(ipxp);
538139929Srwatson	IPX_LIST_UNLOCK();
53924659Sjhay}
54011819Sjulian
54124659Sjhaystatic int
542169463Srwatsonipx_disconnect(struct socket *so)
54324659Sjhay{
54424659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
545139929Srwatson	int error;
54611819Sjulian
547157128Srwatson	KASSERT(ipxp != NULL, ("ipx_disconnect: ipxp == NULL"));
548139929Srwatson	IPX_LIST_LOCK();
549139929Srwatson	IPX_LOCK(ipxp);
550139929Srwatson	error = 0;
551139929Srwatson	if (ipx_nullhost(ipxp->ipxp_faddr)) {
552139929Srwatson		error = ENOTCONN;
553139929Srwatson		goto out;
554139929Srwatson	}
55524659Sjhay	ipx_pcbdisconnect(ipxp);
55624659Sjhay	soisdisconnected(so);
557139929Srwatsonout:
558139929Srwatson	IPX_UNLOCK(ipxp);
559139929Srwatson	IPX_LIST_UNLOCK();
56024659Sjhay	return (0);
56124659Sjhay}
56211819Sjulian
56324659Sjhayint
564169463Srwatsonipx_peeraddr(struct socket *so, struct sockaddr **nam)
56524659Sjhay{
56624659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
56711819Sjulian
568157128Srwatson	KASSERT(ipxp != NULL, ("ipx_peeraddr: ipxp == NULL"));
569169462Srwatson	ipx_getpeeraddr(ipxp, nam);
57024659Sjhay	return (0);
57124659Sjhay}
57224659Sjhay
57324659Sjhaystatic int
574169463Srwatsonipx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
575169463Srwatson    struct mbuf *control, struct thread *td)
57624659Sjhay{
57724659Sjhay	int error;
57824659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
57924659Sjhay	struct ipx_addr laddr;
58024659Sjhay
581157128Srwatson	KASSERT(ipxp != NULL, ("ipxp_send: ipxp == NULL"));
582139929Srwatson	/*
583139929Srwatson	 * Attempt to only acquire the necessary locks: if the socket is
584139929Srwatson	 * already connected, we don't need to hold the IPX list lock to be
585139929Srwatson	 * used by ipx_pcbconnect() and ipx_pcbdisconnect(), just the IPX
586139929Srwatson	 * pcb lock.
587139929Srwatson	 */
588194544Srwatson#ifdef MAC
589194544Srwatson	mac_socket_create_mbuf(so, m);
590194544Srwatson#endif
59125652Sjhay	if (nam != NULL) {
592139929Srwatson		IPX_LIST_LOCK();
593139929Srwatson		IPX_LOCK(ipxp);
59424659Sjhay		laddr = ipxp->ipxp_laddr;
59524659Sjhay		if (!ipx_nullhost(ipxp->ipxp_faddr)) {
596139929Srwatson			IPX_UNLOCK(ipxp);
597139929Srwatson			IPX_LIST_UNLOCK();
59824659Sjhay			error = EISCONN;
59924659Sjhay			goto send_release;
60011819Sjulian		}
60124659Sjhay		/*
60224659Sjhay		 * Must block input while temporarily connected.
60324659Sjhay		 */
60483366Sjulian		error = ipx_pcbconnect(ipxp, nam, td);
60524659Sjhay		if (error) {
606139929Srwatson			IPX_UNLOCK(ipxp);
607139929Srwatson			IPX_LIST_UNLOCK();
60824659Sjhay			goto send_release;
60911819Sjulian		}
61024659Sjhay	} else {
611139929Srwatson		IPX_LOCK(ipxp);
61224659Sjhay		if (ipx_nullhost(ipxp->ipxp_faddr)) {
613139929Srwatson			IPX_UNLOCK(ipxp);
61424659Sjhay			error = ENOTCONN;
61524659Sjhay			goto send_release;
61624659Sjhay		}
61711819Sjulian	}
61824659Sjhay	error = ipx_output(ipxp, m);
61924659Sjhay	m = NULL;
62025652Sjhay	if (nam != NULL) {
62124659Sjhay		ipx_pcbdisconnect(ipxp);
62243712Sjhay		ipxp->ipxp_laddr = laddr;
623139929Srwatson		IPX_UNLOCK(ipxp);
624139929Srwatson		IPX_LIST_UNLOCK();
625139929Srwatson	} else
626139929Srwatson		IPX_UNLOCK(ipxp);
62711819Sjulian
62824659Sjhaysend_release:
62911819Sjulian	if (m != NULL)
63011819Sjulian		m_freem(m);
63111819Sjulian	return (error);
63211819Sjulian}
63319947Sjhay
63424659Sjhaystatic int
63524659Sjhayipx_shutdown(so)
63624659Sjhay	struct socket *so;
63724659Sjhay{
638157128Srwatson
639157128Srwatson	KASSERT(so->so_pcb != NULL, ("ipx_shutdown: so_pcb == NULL"));
64024659Sjhay	socantsendmore(so);
64124659Sjhay	return (0);
64224659Sjhay}
64324659Sjhay
64411819Sjulianint
645169463Srwatsonipx_sockaddr(struct socket *so, struct sockaddr **nam)
64611819Sjulian{
64711819Sjulian	struct ipxpcb *ipxp = sotoipxpcb(so);
64811819Sjulian
649157128Srwatson	KASSERT(ipxp != NULL, ("ipx_sockaddr: ipxp == NULL"));
650169462Srwatson	ipx_getsockaddr(ipxp, nam);
65124659Sjhay	return (0);
65224659Sjhay}
65311819Sjulian
65424659Sjhaystatic int
655169463Srwatsonripx_attach(struct socket *so, int proto, struct thread *td)
65624659Sjhay{
65724659Sjhay	int error = 0;
65824659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
65911819Sjulian
660157128Srwatson	KASSERT(ipxp == NULL, ("ripx_attach: ipxp != NULL"));
661164033Srwatson
662164033Srwatson	if (td != NULL) {
663164033Srwatson		error = priv_check(td, PRIV_NETIPX_RAW);
664164033Srwatson		if (error)
665164033Srwatson			return (error);
666164033Srwatson	}
667164033Srwatson
668139929Srwatson	/*
669139929Srwatson	 * We hold the IPX list lock for the duration as address parameters
670139929Srwatson	 * of the IPX pcb are changed.  Since no one else holds a reference
671139929Srwatson	 * to the ipxpcb yet, we don't need the ipxpcb lock here.
672139929Srwatson	 */
673139929Srwatson	IPX_LIST_LOCK();
674139444Srwatson	error = ipx_pcballoc(so, &ipxrawpcb_list, td);
67524659Sjhay	if (error)
676139929Srwatson		goto out;
677139929Srwatson	ipxp = sotoipxpcb(so);
67824659Sjhay	error = soreserve(so, ipxsendspace, ipxrecvspace);
67924659Sjhay	if (error)
680139929Srwatson		goto out;
68124659Sjhay	ipxp->ipxp_faddr.x_host = ipx_broadhost;
68224659Sjhay	ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
683139929Srwatsonout:
684139929Srwatson	IPX_LIST_UNLOCK();
68511819Sjulian	return (error);
68611819Sjulian}
687