ipx_usrreq.c revision 185928
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: head/sys/netipx/ipx_usrreq.c 185928 2008-12-11 10:29:35Z rwatson $");
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
9311819Sjulian/*
9411819Sjulian * IPX protocol implementation.
9511819Sjulian */
9611819Sjulian
9733181Seivindstatic int ipxsendspace = IPXSNDQ;
9819947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW,
99180816Strhodes            &ipxsendspace, 0, "Send buffer space");
10033181Seivindstatic int ipxrecvspace = IPXRCVQ;
10119947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
102180816Strhodes            &ipxrecvspace, 0, "Receive buffer space");
10319947Sjhay
104157366Srwatsonstatic	void ipx_usr_abort(struct socket *so);
10583366Sjulianstatic	int ipx_attach(struct socket *so, int proto, struct thread *td);
10683366Sjulianstatic	int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
10728270Swollmanstatic	int ipx_connect(struct socket *so, struct sockaddr *nam,
10883366Sjulian			struct thread *td);
109157370Srwatsonstatic	void ipx_detach(struct socket *so);
11024659Sjhaystatic	int ipx_disconnect(struct socket *so);
11124659Sjhaystatic	int ipx_send(struct socket *so, int flags, struct mbuf *m,
112139584Srwatson		     struct sockaddr *addr, struct mbuf *control,
11383366Sjulian		     struct thread *td);
11424659Sjhaystatic	int ipx_shutdown(struct socket *so);
11583366Sjulianstatic	int ripx_attach(struct socket *so, int proto, struct thread *td);
11625652Sjhaystatic	int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0);
117160549Srwatsonstatic	void ipx_usr_close(struct socket *so);
11824659Sjhay
11925652Sjhaystruct	pr_usrreqs ipx_usrreqs = {
120137386Sphk	.pru_abort =		ipx_usr_abort,
121137386Sphk	.pru_attach =		ipx_attach,
122137386Sphk	.pru_bind =		ipx_bind,
123137386Sphk	.pru_connect =		ipx_connect,
124137386Sphk	.pru_control =		ipx_control,
125137386Sphk	.pru_detach =		ipx_detach,
126137386Sphk	.pru_disconnect =	ipx_disconnect,
127137386Sphk	.pru_peeraddr =		ipx_peeraddr,
128137386Sphk	.pru_send =		ipx_send,
129137386Sphk	.pru_shutdown =		ipx_shutdown,
130137386Sphk	.pru_sockaddr =		ipx_sockaddr,
131160549Srwatson	.pru_close =		ipx_usr_close,
13224659Sjhay};
13324659Sjhay
13425652Sjhaystruct	pr_usrreqs ripx_usrreqs = {
135137386Sphk	.pru_abort =		ipx_usr_abort,
136137386Sphk	.pru_attach =		ripx_attach,
137137386Sphk	.pru_bind =		ipx_bind,
138137386Sphk	.pru_connect =		ipx_connect,
139137386Sphk	.pru_control =		ipx_control,
140137386Sphk	.pru_detach =		ipx_detach,
141137386Sphk	.pru_disconnect =	ipx_disconnect,
142137386Sphk	.pru_peeraddr =		ipx_peeraddr,
143137386Sphk	.pru_send =		ipx_send,
144137386Sphk	.pru_shutdown =		ipx_shutdown,
145137386Sphk	.pru_sockaddr =		ipx_sockaddr,
146160549Srwatson	.pru_close =		ipx_usr_close,
14724659Sjhay};
14824659Sjhay
14911819Sjulian/*
15011819Sjulian *  This may also be called for raw listeners.
15111819Sjulian */
15211819Sjulianvoid
153169463Srwatsonipx_input(struct mbuf *m, struct ipxpcb *ipxp)
15411819Sjulian{
155169463Srwatson	struct ipx *ipx = mtod(m, struct ipx *);
15611819Sjulian	struct ifnet *ifp = m->m_pkthdr.rcvif;
15715245Sjhay	struct sockaddr_ipx ipx_ipx;
15811819Sjulian
159139623Srwatson	KASSERT(ipxp != NULL, ("ipx_input: NULL ipxpcb"));
160139929Srwatson	IPX_LOCK_ASSERT(ipxp);
16111819Sjulian	/*
16211819Sjulian	 * Construct sockaddr format source address.
16311819Sjulian	 * Stuff source address and datagram in user buffer.
16411819Sjulian	 */
16515245Sjhay	ipx_ipx.sipx_len = sizeof(ipx_ipx);
16615245Sjhay	ipx_ipx.sipx_family = AF_IPX;
16711819Sjulian	ipx_ipx.sipx_addr = ipx->ipx_sna;
16815245Sjhay	ipx_ipx.sipx_zero[0] = '\0';
16915245Sjhay	ipx_ipx.sipx_zero[1] = '\0';
17025652Sjhay	if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) {
171169463Srwatson		struct ifaddr *ifa;
17211819Sjulian
173139584Srwatson		for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL;
17471999Sphk		     ifa = TAILQ_NEXT(ifa, ifa_link)) {
17511819Sjulian			if (ifa->ifa_addr->sa_family == AF_IPX) {
17611819Sjulian				ipx_ipx.sipx_addr.x_net =
17711819Sjulian					IA_SIPX(ifa)->sipx_addr.x_net;
17811819Sjulian				break;
17911819Sjulian			}
18011819Sjulian		}
18111819Sjulian	}
18211819Sjulian	ipxp->ipxp_rpt = ipx->ipx_pt;
183139588Srwatson	if ((ipxp->ipxp_flags & IPXP_RAWIN) == 0) {
18425652Sjhay		m->m_len -= sizeof(struct ipx);
18525652Sjhay		m->m_pkthdr.len -= sizeof(struct ipx);
18625652Sjhay		m->m_data += sizeof(struct ipx);
18711819Sjulian	}
188139588Srwatson	if (sbappendaddr(&ipxp->ipxp_socket->so_rcv,
189139588Srwatson	    (struct sockaddr *)&ipx_ipx, m, NULL) == 0)
190139588Srwatson		m_freem(m);
191139588Srwatson	else
192139588Srwatson		sorwakeup(ipxp->ipxp_socket);
19311819Sjulian}
19411819Sjulian
19511819Sjulian/*
19611819Sjulian * Drop connection, reporting
19711819Sjulian * the specified error.
19811819Sjulian */
19911819Sjulianvoid
200169463Srwatsonipx_drop(struct ipxpcb *ipxp, int errno)
20111819Sjulian{
20211819Sjulian	struct socket *so = ipxp->ipxp_socket;
20311819Sjulian
204139929Srwatson	IPX_LIST_LOCK_ASSERT();
205139929Srwatson	IPX_LOCK_ASSERT(ipxp);
206139929Srwatson
20711819Sjulian	/*
20825652Sjhay	 * someday, in the IPX world
20911819Sjulian	 * we will generate error protocol packets
21011819Sjulian	 * announcing that the socket has gone away.
21125652Sjhay	 *
21225652Sjhay	 * XXX Probably never. IPX does not have error packets.
21311819Sjulian	 */
21411819Sjulian	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
21511819Sjulian		tp->t_state = TCPS_CLOSED;
21625652Sjhay		tcp_output(tp);
21711819Sjulian	}*/
21811819Sjulian	so->so_error = errno;
21911819Sjulian	ipx_pcbdisconnect(ipxp);
22011819Sjulian	soisdisconnected(so);
22111819Sjulian}
22211819Sjulian
22325652Sjhaystatic int
224169463Srwatsonipx_output(struct ipxpcb *ipxp, struct mbuf *m0)
22511819Sjulian{
226169463Srwatson	struct ipx *ipx;
227169463Srwatson	struct socket *so;
228169463Srwatson	int len = 0;
229169463Srwatson	struct route *ro;
23054799Sgreen	struct mbuf *m;
23111819Sjulian	struct mbuf *mprev = NULL;
23211819Sjulian
233139929Srwatson	IPX_LOCK_ASSERT(ipxp);
234139929Srwatson
23511819Sjulian	/*
23611819Sjulian	 * Calculate data length.
23711819Sjulian	 */
23825652Sjhay	for (m = m0; m != NULL; m = m->m_next) {
23911819Sjulian		mprev = m;
24011819Sjulian		len += m->m_len;
24111819Sjulian	}
24211819Sjulian	/*
24311819Sjulian	 * Make sure packet is actually of even length.
24411819Sjulian	 */
245139584Srwatson
24611819Sjulian	if (len & 1) {
24711819Sjulian		m = mprev;
24811819Sjulian		if ((m->m_flags & M_EXT) == 0 &&
24911819Sjulian			(m->m_len + m->m_data < &m->m_dat[MLEN])) {
25050519Sjhay			mtod(m, char*)[m->m_len++] = 0;
25111819Sjulian		} else {
252111119Simp			struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
25311819Sjulian
25425652Sjhay			if (m1 == NULL) {
25511819Sjulian				m_freem(m0);
25611819Sjulian				return (ENOBUFS);
25711819Sjulian			}
25811819Sjulian			m1->m_len = 1;
25911819Sjulian			* mtod(m1, char *) = 0;
26011819Sjulian			m->m_next = m1;
26111819Sjulian		}
26211819Sjulian		m0->m_pkthdr.len++;
26311819Sjulian	}
26411819Sjulian
26511819Sjulian	/*
26611819Sjulian	 * Fill in mbuf with extended IPX header
26711819Sjulian	 * and addresses and length put into network format.
26811819Sjulian	 */
26911819Sjulian	m = m0;
27011819Sjulian	if (ipxp->ipxp_flags & IPXP_RAWOUT) {
27111819Sjulian		ipx = mtod(m, struct ipx *);
27211819Sjulian	} else {
273111119Simp		M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT);
27425652Sjhay		if (m == NULL)
27511819Sjulian			return (ENOBUFS);
27611819Sjulian		ipx = mtod(m, struct ipx *);
27711819Sjulian		ipx->ipx_tc = 0;
27811819Sjulian		ipx->ipx_pt = ipxp->ipxp_dpt;
27911819Sjulian		ipx->ipx_sna = ipxp->ipxp_laddr;
28011819Sjulian		ipx->ipx_dna = ipxp->ipxp_faddr;
28125652Sjhay		len += sizeof(struct ipx);
28211819Sjulian	}
28311819Sjulian
28411819Sjulian	ipx->ipx_len = htons((u_short)len);
28511819Sjulian
28650519Sjhay	if (ipxp->ipxp_flags & IPXP_CHECKSUM) {
28711819Sjulian		ipx->ipx_sum = ipx_cksum(m, len);
28811819Sjulian	} else
28911819Sjulian		ipx->ipx_sum = 0xffff;
29011819Sjulian
29111819Sjulian	/*
29211819Sjulian	 * Output datagram.
29311819Sjulian	 */
29411819Sjulian	so = ipxp->ipxp_socket;
29597658Stanimura	if (so->so_options & SO_DONTROUTE)
29625652Sjhay		return (ipx_outputfl(m, (struct route *)NULL,
29797658Stanimura		    (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
29811819Sjulian	/*
29911819Sjulian	 * Use cached route for previous datagram if
30011819Sjulian	 * possible.  If the previous net was the same
30111819Sjulian	 * and the interface was a broadcast medium, or
30211819Sjulian	 * if the previous destination was identical,
30311819Sjulian	 * then we are ok.
30411819Sjulian	 *
30511819Sjulian	 * NB: We don't handle broadcasts because that
30611819Sjulian	 *     would require 3 subroutine calls.
30711819Sjulian	 */
30811819Sjulian	ro = &ipxp->ipxp_route;
30911819Sjulian#ifdef ancient_history
31011819Sjulian	/*
31111819Sjulian	 * I think that this will all be handled in ipx_pcbconnect!
31211819Sjulian	 */
31325652Sjhay	if (ro->ro_rt != NULL) {
31411819Sjulian		if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
31511819Sjulian			/*
31611819Sjulian			 * This assumes we have no GH type routes
31711819Sjulian			 */
31811819Sjulian			if (ro->ro_rt->rt_flags & RTF_HOST) {
31911819Sjulian				if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
32011819Sjulian					goto re_route;
32111819Sjulian
32211819Sjulian			}
32311819Sjulian			if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
324169463Srwatson				struct ipx_addr *dst =
32511819Sjulian						&satoipx_addr(ro->ro_dst);
32611819Sjulian				dst->x_host = ipx->ipx_dna.x_host;
32711819Sjulian			}
328139584Srwatson			/*
32911819Sjulian			 * Otherwise, we go through the same gateway
33011819Sjulian			 * and dst is already set up.
33111819Sjulian			 */
33211819Sjulian		} else {
33311819Sjulian		re_route:
33411819Sjulian			RTFREE(ro->ro_rt);
33525652Sjhay			ro->ro_rt = NULL;
33611819Sjulian		}
33711819Sjulian	}
33811819Sjulian	ipxp->ipxp_lastdst = ipx->ipx_dna;
33911819Sjulian#endif /* ancient_history */
34097658Stanimura	return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
34111819Sjulian}
34219947Sjhay
34311819Sjulianint
344169463Srwatsonipx_ctloutput(struct socket *so, struct sockopt *sopt)
34511819Sjulian{
34611819Sjulian	struct ipxpcb *ipxp = sotoipxpcb(so);
34738482Swollman	int mask, error, optval;
34838482Swollman	short soptval;
34938482Swollman	struct ipx ioptval;
350139930Srwatson	long seq;
35111819Sjulian
352157128Srwatson	KASSERT(ipxp != NULL, ("ipx_ctloutput: ipxp == NULL"));
35338482Swollman	error = 0;
35411819Sjulian
35538482Swollman	switch (sopt->sopt_dir) {
35638482Swollman	case SOPT_GET:
35738482Swollman		switch (sopt->sopt_name) {
35811819Sjulian		case SO_ALL_PACKETS:
35911819Sjulian			mask = IPXP_ALL_PACKETS;
36011819Sjulian			goto get_flags;
36111819Sjulian
36211819Sjulian		case SO_HEADERS_ON_INPUT:
36311819Sjulian			mask = IPXP_RAWIN;
36411819Sjulian			goto get_flags;
36550519Sjhay
36650519Sjhay		case SO_IPX_CHECKSUM:
36750519Sjhay			mask = IPXP_CHECKSUM;
36850519Sjhay			goto get_flags;
369139584Srwatson
37011819Sjulian		case SO_HEADERS_ON_OUTPUT:
37111819Sjulian			mask = IPXP_RAWOUT;
37211819Sjulian		get_flags:
373139930Srwatson			/* Unlocked read. */
37438482Swollman			soptval = ipxp->ipxp_flags & mask;
37538482Swollman			error = sooptcopyout(sopt, &soptval, sizeof soptval);
37611819Sjulian			break;
37711819Sjulian
37811819Sjulian		case SO_DEFAULT_HEADERS:
37938482Swollman			ioptval.ipx_len = 0;
38038482Swollman			ioptval.ipx_sum = 0;
38138482Swollman			ioptval.ipx_tc = 0;
382139930Srwatson			IPX_LOCK(ipxp);
38338482Swollman			ioptval.ipx_pt = ipxp->ipxp_dpt;
38438482Swollman			ioptval.ipx_dna = ipxp->ipxp_faddr;
38538482Swollman			ioptval.ipx_sna = ipxp->ipxp_laddr;
386139930Srwatson			IPX_UNLOCK(ipxp);
38738482Swollman			error = sooptcopyout(sopt, &soptval, sizeof soptval);
38811819Sjulian			break;
38911819Sjulian
39011819Sjulian		case SO_SEQNO:
391139930Srwatson			IPX_LIST_LOCK();
392139930Srwatson			seq = ipx_pexseq;
39338482Swollman			ipx_pexseq++;
394139930Srwatson			IPX_LIST_UNLOCK();
395139930Srwatson			error = sooptcopyout(sopt, &seq, sizeof seq);
39611819Sjulian			break;
39711819Sjulian
39811819Sjulian		default:
39911819Sjulian			error = EINVAL;
40011819Sjulian		}
40111819Sjulian		break;
40211819Sjulian
40338482Swollman	case SOPT_SET:
40438482Swollman		switch (sopt->sopt_name) {
40511819Sjulian		case SO_ALL_PACKETS:
40611819Sjulian			mask = IPXP_ALL_PACKETS;
40711819Sjulian			goto set_head;
40811819Sjulian
40911819Sjulian		case SO_HEADERS_ON_INPUT:
41011819Sjulian			mask = IPXP_RAWIN;
41111819Sjulian			goto set_head;
41211819Sjulian
41350519Sjhay		case SO_IPX_CHECKSUM:
41450519Sjhay			mask = IPXP_CHECKSUM;
415185928Srwatson			goto set_head;
41650519Sjhay
41711819Sjulian		case SO_HEADERS_ON_OUTPUT:
41811819Sjulian			mask = IPXP_RAWOUT;
41911819Sjulian		set_head:
42038482Swollman			error = sooptcopyin(sopt, &optval, sizeof optval,
42138482Swollman					    sizeof optval);
42238482Swollman			if (error)
42338482Swollman				break;
424139930Srwatson			IPX_LOCK(ipxp);
42538482Swollman			if (optval)
42638482Swollman				ipxp->ipxp_flags |= mask;
42738482Swollman			else
42838482Swollman				ipxp->ipxp_flags &= ~mask;
429139930Srwatson			IPX_UNLOCK(ipxp);
43011819Sjulian			break;
43111819Sjulian
43211819Sjulian		case SO_DEFAULT_HEADERS:
43338482Swollman			error = sooptcopyin(sopt, &ioptval, sizeof ioptval,
43438482Swollman					    sizeof ioptval);
43538482Swollman			if (error)
43638482Swollman				break;
437139930Srwatson			/* Unlocked write. */
43838482Swollman			ipxp->ipxp_dpt = ioptval.ipx_pt;
43911819Sjulian			break;
44011819Sjulian		default:
44111819Sjulian			error = EINVAL;
44211819Sjulian		}
44311819Sjulian		break;
44411819Sjulian	}
44511819Sjulian	return (error);
44611819Sjulian}
44711819Sjulian
448157366Srwatsonstatic void
449169463Srwatsonipx_usr_abort(struct socket *so)
45011819Sjulian{
45111819Sjulian
452160549Srwatson	/* XXXRW: Possibly ipx_disconnect() here? */
453130387Srwatson	soisdisconnected(so);
45424659Sjhay}
45511819Sjulian
45624659Sjhaystatic int
457169463Srwatsonipx_attach(struct socket *so, int proto, struct thread *td)
45824659Sjhay{
459157672Scognet#ifdef INVARIANTS
460139929Srwatson	struct ipxpcb *ipxp = sotoipxpcb(so);
461157672Scognet#endif
46224659Sjhay	int error;
46324659Sjhay
464157128Srwatson	KASSERT(ipxp == NULL, ("ipx_attach: ipxp != NULL"));
465157128Srwatson	error = soreserve(so, ipxsendspace, ipxrecvspace);
466157128Srwatson	if (error != 0)
467157128Srwatson		return (error);
468139929Srwatson	IPX_LIST_LOCK();
469139444Srwatson	error = ipx_pcballoc(so, &ipxpcb_list, td);
470139929Srwatson	IPX_LIST_UNLOCK();
47124659Sjhay	return (error);
47224659Sjhay}
47311819Sjulian
47424659Sjhaystatic int
475169463Srwatsonipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
47624659Sjhay{
47724659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
478139929Srwatson	int error;
47911819Sjulian
480157128Srwatson	KASSERT(ipxp != NULL, ("ipx_bind: ipxp == NULL"));
481139929Srwatson	IPX_LIST_LOCK();
482139929Srwatson	IPX_LOCK(ipxp);
483139929Srwatson	error = ipx_pcbbind(ipxp, nam, td);
484139929Srwatson	IPX_UNLOCK(ipxp);
485139929Srwatson	IPX_LIST_UNLOCK();
486139929Srwatson	return (error);
48724659Sjhay}
48811819Sjulian
489160549Srwatsonstatic void
490169463Srwatsonipx_usr_close(struct socket *so)
491160549Srwatson{
492160549Srwatson
493160549Srwatson	/* XXXRW: Possibly ipx_disconnect() here? */
494160549Srwatson	soisdisconnected(so);
495160549Srwatson}
496160549Srwatson
49724659Sjhaystatic int
498169463Srwatsonipx_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
49924659Sjhay{
500139929Srwatson	struct ipxpcb *ipxp = sotoipxpcb(so);
50124659Sjhay	int error;
50211819Sjulian
503157128Srwatson	KASSERT(ipxp != NULL, ("ipx_connect: ipxp == NULL"));
504139929Srwatson	IPX_LIST_LOCK();
505139929Srwatson	IPX_LOCK(ipxp);
506139929Srwatson	if (!ipx_nullhost(ipxp->ipxp_faddr)) {
507139929Srwatson		error = EISCONN;
508139929Srwatson		goto out;
509139929Srwatson	}
51083366Sjulian	error = ipx_pcbconnect(ipxp, nam, td);
51197658Stanimura	if (error == 0)
51224659Sjhay		soisconnected(so);
513139929Srwatsonout:
514139929Srwatson	IPX_UNLOCK(ipxp);
515139929Srwatson	IPX_LIST_UNLOCK();
51624659Sjhay	return (error);
51724659Sjhay}
51811819Sjulian
519157370Srwatsonstatic void
520169463Srwatsonipx_detach(struct socket *so)
52124659Sjhay{
52224659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
52311819Sjulian
524160549Srwatson	/* XXXRW: Should assert detached. */
525157128Srwatson	KASSERT(ipxp != NULL, ("ipx_detach: ipxp == NULL"));
526139929Srwatson	IPX_LIST_LOCK();
527139929Srwatson	IPX_LOCK(ipxp);
52824659Sjhay	ipx_pcbdetach(ipxp);
529157128Srwatson	ipx_pcbfree(ipxp);
530139929Srwatson	IPX_LIST_UNLOCK();
53124659Sjhay}
53211819Sjulian
53324659Sjhaystatic int
534169463Srwatsonipx_disconnect(struct socket *so)
53524659Sjhay{
53624659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
537139929Srwatson	int error;
53811819Sjulian
539157128Srwatson	KASSERT(ipxp != NULL, ("ipx_disconnect: ipxp == NULL"));
540139929Srwatson	IPX_LIST_LOCK();
541139929Srwatson	IPX_LOCK(ipxp);
542139929Srwatson	error = 0;
543139929Srwatson	if (ipx_nullhost(ipxp->ipxp_faddr)) {
544139929Srwatson		error = ENOTCONN;
545139929Srwatson		goto out;
546139929Srwatson	}
54724659Sjhay	ipx_pcbdisconnect(ipxp);
54824659Sjhay	soisdisconnected(so);
549139929Srwatsonout:
550139929Srwatson	IPX_UNLOCK(ipxp);
551139929Srwatson	IPX_LIST_UNLOCK();
55224659Sjhay	return (0);
55324659Sjhay}
55411819Sjulian
55524659Sjhayint
556169463Srwatsonipx_peeraddr(struct socket *so, struct sockaddr **nam)
55724659Sjhay{
55824659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
55911819Sjulian
560157128Srwatson	KASSERT(ipxp != NULL, ("ipx_peeraddr: ipxp == NULL"));
561169462Srwatson	ipx_getpeeraddr(ipxp, nam);
56224659Sjhay	return (0);
56324659Sjhay}
56424659Sjhay
56524659Sjhaystatic int
566169463Srwatsonipx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
567169463Srwatson    struct mbuf *control, struct thread *td)
56824659Sjhay{
56924659Sjhay	int error;
57024659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
57124659Sjhay	struct ipx_addr laddr;
57224659Sjhay
573157128Srwatson	KASSERT(ipxp != NULL, ("ipxp_send: ipxp == NULL"));
574139929Srwatson	/*
575139929Srwatson	 * Attempt to only acquire the necessary locks: if the socket is
576139929Srwatson	 * already connected, we don't need to hold the IPX list lock to be
577139929Srwatson	 * used by ipx_pcbconnect() and ipx_pcbdisconnect(), just the IPX
578139929Srwatson	 * pcb lock.
579139929Srwatson	 */
58025652Sjhay	if (nam != NULL) {
581139929Srwatson		IPX_LIST_LOCK();
582139929Srwatson		IPX_LOCK(ipxp);
58324659Sjhay		laddr = ipxp->ipxp_laddr;
58424659Sjhay		if (!ipx_nullhost(ipxp->ipxp_faddr)) {
585139929Srwatson			IPX_UNLOCK(ipxp);
586139929Srwatson			IPX_LIST_UNLOCK();
58724659Sjhay			error = EISCONN;
58824659Sjhay			goto send_release;
58911819Sjulian		}
59024659Sjhay		/*
59124659Sjhay		 * Must block input while temporarily connected.
59224659Sjhay		 */
59383366Sjulian		error = ipx_pcbconnect(ipxp, nam, td);
59424659Sjhay		if (error) {
595139929Srwatson			IPX_UNLOCK(ipxp);
596139929Srwatson			IPX_LIST_UNLOCK();
59724659Sjhay			goto send_release;
59811819Sjulian		}
59924659Sjhay	} else {
600139929Srwatson		IPX_LOCK(ipxp);
60124659Sjhay		if (ipx_nullhost(ipxp->ipxp_faddr)) {
602139929Srwatson			IPX_UNLOCK(ipxp);
60324659Sjhay			error = ENOTCONN;
60424659Sjhay			goto send_release;
60524659Sjhay		}
60611819Sjulian	}
60724659Sjhay	error = ipx_output(ipxp, m);
60824659Sjhay	m = NULL;
60925652Sjhay	if (nam != NULL) {
61024659Sjhay		ipx_pcbdisconnect(ipxp);
61143712Sjhay		ipxp->ipxp_laddr = laddr;
612139929Srwatson		IPX_UNLOCK(ipxp);
613139929Srwatson		IPX_LIST_UNLOCK();
614139929Srwatson	} else
615139929Srwatson		IPX_UNLOCK(ipxp);
61611819Sjulian
61724659Sjhaysend_release:
61811819Sjulian	if (m != NULL)
61911819Sjulian		m_freem(m);
62011819Sjulian	return (error);
62111819Sjulian}
62219947Sjhay
62324659Sjhaystatic int
62424659Sjhayipx_shutdown(so)
62524659Sjhay	struct socket *so;
62624659Sjhay{
627157128Srwatson
628157128Srwatson	KASSERT(so->so_pcb != NULL, ("ipx_shutdown: so_pcb == NULL"));
62924659Sjhay	socantsendmore(so);
63024659Sjhay	return (0);
63124659Sjhay}
63224659Sjhay
63311819Sjulianint
634169463Srwatsonipx_sockaddr(struct socket *so, struct sockaddr **nam)
63511819Sjulian{
63611819Sjulian	struct ipxpcb *ipxp = sotoipxpcb(so);
63711819Sjulian
638157128Srwatson	KASSERT(ipxp != NULL, ("ipx_sockaddr: ipxp == NULL"));
639169462Srwatson	ipx_getsockaddr(ipxp, nam);
64024659Sjhay	return (0);
64124659Sjhay}
64211819Sjulian
64324659Sjhaystatic int
644169463Srwatsonripx_attach(struct socket *so, int proto, struct thread *td)
64524659Sjhay{
64624659Sjhay	int error = 0;
64724659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
64811819Sjulian
649157128Srwatson	KASSERT(ipxp == NULL, ("ripx_attach: ipxp != NULL"));
650164033Srwatson
651164033Srwatson	if (td != NULL) {
652164033Srwatson		error = priv_check(td, PRIV_NETIPX_RAW);
653164033Srwatson		if (error)
654164033Srwatson			return (error);
655164033Srwatson	}
656164033Srwatson
657139929Srwatson	/*
658139929Srwatson	 * We hold the IPX list lock for the duration as address parameters
659139929Srwatson	 * of the IPX pcb are changed.  Since no one else holds a reference
660139929Srwatson	 * to the ipxpcb yet, we don't need the ipxpcb lock here.
661139929Srwatson	 */
662139929Srwatson	IPX_LIST_LOCK();
663139444Srwatson	error = ipx_pcballoc(so, &ipxrawpcb_list, td);
66424659Sjhay	if (error)
665139929Srwatson		goto out;
666139929Srwatson	ipxp = sotoipxpcb(so);
66724659Sjhay	error = soreserve(so, ipxsendspace, ipxrecvspace);
66824659Sjhay	if (error)
669139929Srwatson		goto out;
67024659Sjhay	ipxp->ipxp_faddr.x_host = ipx_broadhost;
67124659Sjhay	ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
672139929Srwatsonout:
673139929Srwatson	IPX_LIST_UNLOCK();
67411819Sjulian	return (error);
67511819Sjulian}
676