ipx_usrreq.c revision 139823
1139823Simp/*-
2139623Srwatson * Copyright (c) 2004-2005 Robert N. M. Watson
311819Sjulian * Copyright (c) 1995, Mike Mitchell
411819Sjulian * Copyright (c) 1984, 1985, 1986, 1987, 1993
511819Sjulian *	The Regents of the University of California.  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.
1511819Sjulian * 3. All advertising materials mentioning features or use of this software
1611819Sjulian *    must display the following acknowledgement:
1711819Sjulian *	This product includes software developed by the University of
1811819Sjulian *	California, Berkeley and its contributors.
1911819Sjulian * 4. Neither the name of the University nor the names of its contributors
2011819Sjulian *    may be used to endorse or promote products derived from this software
2111819Sjulian *    without specific prior written permission.
2211819Sjulian *
2311819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2411819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2511819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2611819Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2711819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2811819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2911819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3011819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3111819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3211819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3311819Sjulian * SUCH DAMAGE.
3411819Sjulian *
3512057Sjulian *	@(#)ipx_usrreq.c
3611819Sjulian */
3711819Sjulian
38116189Sobrien#include <sys/cdefs.h>
39116189Sobrien__FBSDID("$FreeBSD: head/sys/netipx/ipx_usrreq.c 139823 2005-01-07 01:45:51Z imp $");
40116189Sobrien
4131742Seivind#include "opt_ipx.h"
4231742Seivind
4311819Sjulian#include <sys/param.h>
4419947Sjhay#include <sys/kernel.h>
4595759Stanimura#include <sys/lock.h>
4611819Sjulian#include <sys/mbuf.h>
4711819Sjulian#include <sys/protosw.h>
4895759Stanimura#include <sys/signalvar.h>
4911819Sjulian#include <sys/socket.h>
5011819Sjulian#include <sys/socketvar.h>
5195759Stanimura#include <sys/sx.h>
5219947Sjhay#include <sys/sysctl.h>
5395759Stanimura#include <sys/systm.h>
5411819Sjulian
5511819Sjulian#include <net/if.h>
5611819Sjulian#include <net/route.h>
5711819Sjulian
5811947Sjulian#include <netinet/in.h>
5911947Sjulian
6011819Sjulian#include <netipx/ipx.h>
6195759Stanimura#include <netipx/ipx_if.h>
6295759Stanimura#include <netipx/ipx_ip.h>
6311819Sjulian#include <netipx/ipx_pcb.h>
6411819Sjulian#include <netipx/ipx_var.h>
6511819Sjulian
6611819Sjulian/*
6711819Sjulian * IPX protocol implementation.
6811819Sjulian */
6911819Sjulian
7033181Seivindstatic int ipxsendspace = IPXSNDQ;
7119947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW,
7219947Sjhay            &ipxsendspace, 0, "");
7333181Seivindstatic int ipxrecvspace = IPXRCVQ;
7419947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
7519947Sjhay            &ipxrecvspace, 0, "");
7619947Sjhay
7724659Sjhaystatic	int ipx_usr_abort(struct socket *so);
7883366Sjulianstatic	int ipx_attach(struct socket *so, int proto, struct thread *td);
7983366Sjulianstatic	int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
8028270Swollmanstatic	int ipx_connect(struct socket *so, struct sockaddr *nam,
8183366Sjulian			struct thread *td);
8224659Sjhaystatic	int ipx_detach(struct socket *so);
8324659Sjhaystatic	int ipx_disconnect(struct socket *so);
8424659Sjhaystatic	int ipx_send(struct socket *so, int flags, struct mbuf *m,
85139584Srwatson		     struct sockaddr *addr, struct mbuf *control,
8683366Sjulian		     struct thread *td);
8724659Sjhaystatic	int ipx_shutdown(struct socket *so);
8883366Sjulianstatic	int ripx_attach(struct socket *so, int proto, struct thread *td);
8925652Sjhaystatic	int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0);
9024659Sjhay
9125652Sjhaystruct	pr_usrreqs ipx_usrreqs = {
92137386Sphk	.pru_abort =		ipx_usr_abort,
93137386Sphk	.pru_attach =		ipx_attach,
94137386Sphk	.pru_bind =		ipx_bind,
95137386Sphk	.pru_connect =		ipx_connect,
96137386Sphk	.pru_control =		ipx_control,
97137386Sphk	.pru_detach =		ipx_detach,
98137386Sphk	.pru_disconnect =	ipx_disconnect,
99137386Sphk	.pru_peeraddr =		ipx_peeraddr,
100137386Sphk	.pru_send =		ipx_send,
101137386Sphk	.pru_shutdown =		ipx_shutdown,
102137386Sphk	.pru_sockaddr =		ipx_sockaddr,
10324659Sjhay};
10424659Sjhay
10525652Sjhaystruct	pr_usrreqs ripx_usrreqs = {
106137386Sphk	.pru_abort =		ipx_usr_abort,
107137386Sphk	.pru_attach =		ripx_attach,
108137386Sphk	.pru_bind =		ipx_bind,
109137386Sphk	.pru_connect =		ipx_connect,
110137386Sphk	.pru_control =		ipx_control,
111137386Sphk	.pru_detach =		ipx_detach,
112137386Sphk	.pru_disconnect =	ipx_disconnect,
113137386Sphk	.pru_peeraddr =		ipx_peeraddr,
114137386Sphk	.pru_send =		ipx_send,
115137386Sphk	.pru_shutdown =		ipx_shutdown,
116137386Sphk	.pru_sockaddr =		ipx_sockaddr,
11724659Sjhay};
11824659Sjhay
11911819Sjulian/*
12011819Sjulian *  This may also be called for raw listeners.
12111819Sjulian */
12211819Sjulianvoid
12311819Sjulianipx_input(m, ipxp)
12411819Sjulian	struct mbuf *m;
12511819Sjulian	register struct ipxpcb *ipxp;
12611819Sjulian{
12711819Sjulian	register struct ipx *ipx = mtod(m, struct ipx *);
12811819Sjulian	struct ifnet *ifp = m->m_pkthdr.rcvif;
12915245Sjhay	struct sockaddr_ipx ipx_ipx;
13011819Sjulian
131139623Srwatson	KASSERT(ipxp != NULL, ("ipx_input: NULL ipxpcb"));
13211819Sjulian	/*
13311819Sjulian	 * Construct sockaddr format source address.
13411819Sjulian	 * Stuff source address and datagram in user buffer.
13511819Sjulian	 */
13615245Sjhay	ipx_ipx.sipx_len = sizeof(ipx_ipx);
13715245Sjhay	ipx_ipx.sipx_family = AF_IPX;
13811819Sjulian	ipx_ipx.sipx_addr = ipx->ipx_sna;
13915245Sjhay	ipx_ipx.sipx_zero[0] = '\0';
14015245Sjhay	ipx_ipx.sipx_zero[1] = '\0';
14125652Sjhay	if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) {
14211819Sjulian		register struct ifaddr *ifa;
14311819Sjulian
144139584Srwatson		for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL;
14571999Sphk		     ifa = TAILQ_NEXT(ifa, ifa_link)) {
14611819Sjulian			if (ifa->ifa_addr->sa_family == AF_IPX) {
14711819Sjulian				ipx_ipx.sipx_addr.x_net =
14811819Sjulian					IA_SIPX(ifa)->sipx_addr.x_net;
14911819Sjulian				break;
15011819Sjulian			}
15111819Sjulian		}
15211819Sjulian	}
15311819Sjulian	ipxp->ipxp_rpt = ipx->ipx_pt;
154139588Srwatson	if ((ipxp->ipxp_flags & IPXP_RAWIN) == 0) {
15525652Sjhay		m->m_len -= sizeof(struct ipx);
15625652Sjhay		m->m_pkthdr.len -= sizeof(struct ipx);
15725652Sjhay		m->m_data += sizeof(struct ipx);
15811819Sjulian	}
159139588Srwatson	if (sbappendaddr(&ipxp->ipxp_socket->so_rcv,
160139588Srwatson	    (struct sockaddr *)&ipx_ipx, m, NULL) == 0)
161139588Srwatson		m_freem(m);
162139588Srwatson	else
163139588Srwatson		sorwakeup(ipxp->ipxp_socket);
16411819Sjulian}
16511819Sjulian
16611819Sjulian/*
16711819Sjulian * Drop connection, reporting
16811819Sjulian * the specified error.
16911819Sjulian */
17011819Sjulianvoid
17111819Sjulianipx_drop(ipxp, errno)
17211819Sjulian	register struct ipxpcb *ipxp;
17311819Sjulian	int errno;
17411819Sjulian{
17511819Sjulian	struct socket *so = ipxp->ipxp_socket;
17611819Sjulian
17711819Sjulian	/*
17825652Sjhay	 * someday, in the IPX world
17911819Sjulian	 * we will generate error protocol packets
18011819Sjulian	 * announcing that the socket has gone away.
18125652Sjhay	 *
18225652Sjhay	 * XXX Probably never. IPX does not have error packets.
18311819Sjulian	 */
18411819Sjulian	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
18511819Sjulian		tp->t_state = TCPS_CLOSED;
18625652Sjhay		tcp_output(tp);
18711819Sjulian	}*/
18811819Sjulian	so->so_error = errno;
18911819Sjulian	ipx_pcbdisconnect(ipxp);
19011819Sjulian	soisdisconnected(so);
19111819Sjulian}
19211819Sjulian
19325652Sjhaystatic int
19411819Sjulianipx_output(ipxp, m0)
19511819Sjulian	struct ipxpcb *ipxp;
19611819Sjulian	struct mbuf *m0;
19711819Sjulian{
19811819Sjulian	register struct ipx *ipx;
19911819Sjulian	register struct socket *so;
20011819Sjulian	register int len = 0;
20111819Sjulian	register struct route *ro;
20254799Sgreen	struct mbuf *m;
20311819Sjulian	struct mbuf *mprev = NULL;
20411819Sjulian
20511819Sjulian	/*
20611819Sjulian	 * Calculate data length.
20711819Sjulian	 */
20825652Sjhay	for (m = m0; m != NULL; m = m->m_next) {
20911819Sjulian		mprev = m;
21011819Sjulian		len += m->m_len;
21111819Sjulian	}
21211819Sjulian	/*
21311819Sjulian	 * Make sure packet is actually of even length.
21411819Sjulian	 */
215139584Srwatson
21611819Sjulian	if (len & 1) {
21711819Sjulian		m = mprev;
21811819Sjulian		if ((m->m_flags & M_EXT) == 0 &&
21911819Sjulian			(m->m_len + m->m_data < &m->m_dat[MLEN])) {
22050519Sjhay			mtod(m, char*)[m->m_len++] = 0;
22111819Sjulian		} else {
222111119Simp			struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
22311819Sjulian
22425652Sjhay			if (m1 == NULL) {
22511819Sjulian				m_freem(m0);
22611819Sjulian				return (ENOBUFS);
22711819Sjulian			}
22811819Sjulian			m1->m_len = 1;
22911819Sjulian			* mtod(m1, char *) = 0;
23011819Sjulian			m->m_next = m1;
23111819Sjulian		}
23211819Sjulian		m0->m_pkthdr.len++;
23311819Sjulian	}
23411819Sjulian
23511819Sjulian	/*
23611819Sjulian	 * Fill in mbuf with extended IPX header
23711819Sjulian	 * and addresses and length put into network format.
23811819Sjulian	 */
23911819Sjulian	m = m0;
24011819Sjulian	if (ipxp->ipxp_flags & IPXP_RAWOUT) {
24111819Sjulian		ipx = mtod(m, struct ipx *);
24211819Sjulian	} else {
243111119Simp		M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT);
24425652Sjhay		if (m == NULL)
24511819Sjulian			return (ENOBUFS);
24611819Sjulian		ipx = mtod(m, struct ipx *);
24711819Sjulian		ipx->ipx_tc = 0;
24811819Sjulian		ipx->ipx_pt = ipxp->ipxp_dpt;
24911819Sjulian		ipx->ipx_sna = ipxp->ipxp_laddr;
25011819Sjulian		ipx->ipx_dna = ipxp->ipxp_faddr;
25125652Sjhay		len += sizeof(struct ipx);
25211819Sjulian	}
25311819Sjulian
25411819Sjulian	ipx->ipx_len = htons((u_short)len);
25511819Sjulian
25650519Sjhay	if (ipxp->ipxp_flags & IPXP_CHECKSUM) {
25711819Sjulian		ipx->ipx_sum = ipx_cksum(m, len);
25811819Sjulian	} else
25911819Sjulian		ipx->ipx_sum = 0xffff;
26011819Sjulian
26111819Sjulian	/*
26211819Sjulian	 * Output datagram.
26311819Sjulian	 */
26411819Sjulian	so = ipxp->ipxp_socket;
26597658Stanimura	if (so->so_options & SO_DONTROUTE)
26625652Sjhay		return (ipx_outputfl(m, (struct route *)NULL,
26797658Stanimura		    (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
26811819Sjulian	/*
26911819Sjulian	 * Use cached route for previous datagram if
27011819Sjulian	 * possible.  If the previous net was the same
27111819Sjulian	 * and the interface was a broadcast medium, or
27211819Sjulian	 * if the previous destination was identical,
27311819Sjulian	 * then we are ok.
27411819Sjulian	 *
27511819Sjulian	 * NB: We don't handle broadcasts because that
27611819Sjulian	 *     would require 3 subroutine calls.
27711819Sjulian	 */
27811819Sjulian	ro = &ipxp->ipxp_route;
27911819Sjulian#ifdef ancient_history
28011819Sjulian	/*
28111819Sjulian	 * I think that this will all be handled in ipx_pcbconnect!
28211819Sjulian	 */
28325652Sjhay	if (ro->ro_rt != NULL) {
28411819Sjulian		if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
28511819Sjulian			/*
28611819Sjulian			 * This assumes we have no GH type routes
28711819Sjulian			 */
28811819Sjulian			if (ro->ro_rt->rt_flags & RTF_HOST) {
28911819Sjulian				if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
29011819Sjulian					goto re_route;
29111819Sjulian
29211819Sjulian			}
29311819Sjulian			if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
29411819Sjulian				register struct ipx_addr *dst =
29511819Sjulian						&satoipx_addr(ro->ro_dst);
29611819Sjulian				dst->x_host = ipx->ipx_dna.x_host;
29711819Sjulian			}
298139584Srwatson			/*
29911819Sjulian			 * Otherwise, we go through the same gateway
30011819Sjulian			 * and dst is already set up.
30111819Sjulian			 */
30211819Sjulian		} else {
30311819Sjulian		re_route:
30411819Sjulian			RTFREE(ro->ro_rt);
30525652Sjhay			ro->ro_rt = NULL;
30611819Sjulian		}
30711819Sjulian	}
30811819Sjulian	ipxp->ipxp_lastdst = ipx->ipx_dna;
30911819Sjulian#endif /* ancient_history */
31097658Stanimura	return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
31111819Sjulian}
31219947Sjhay
31311819Sjulianint
31438482Swollmanipx_ctloutput(so, sopt)
31511819Sjulian	struct socket *so;
31638482Swollman	struct sockopt *sopt;
31711819Sjulian{
31811819Sjulian	struct ipxpcb *ipxp = sotoipxpcb(so);
31938482Swollman	int mask, error, optval;
32038482Swollman	short soptval;
32138482Swollman	struct ipx ioptval;
32211819Sjulian
32338482Swollman	error = 0;
32411819Sjulian	if (ipxp == NULL)
32511819Sjulian		return (EINVAL);
32611819Sjulian
32738482Swollman	switch (sopt->sopt_dir) {
32838482Swollman	case SOPT_GET:
32938482Swollman		switch (sopt->sopt_name) {
33011819Sjulian		case SO_ALL_PACKETS:
33111819Sjulian			mask = IPXP_ALL_PACKETS;
33211819Sjulian			goto get_flags;
33311819Sjulian
33411819Sjulian		case SO_HEADERS_ON_INPUT:
33511819Sjulian			mask = IPXP_RAWIN;
33611819Sjulian			goto get_flags;
33750519Sjhay
33850519Sjhay		case SO_IPX_CHECKSUM:
33950519Sjhay			mask = IPXP_CHECKSUM;
34050519Sjhay			goto get_flags;
341139584Srwatson
34211819Sjulian		case SO_HEADERS_ON_OUTPUT:
34311819Sjulian			mask = IPXP_RAWOUT;
34411819Sjulian		get_flags:
34538482Swollman			soptval = ipxp->ipxp_flags & mask;
34638482Swollman			error = sooptcopyout(sopt, &soptval, sizeof soptval);
34711819Sjulian			break;
34811819Sjulian
34911819Sjulian		case SO_DEFAULT_HEADERS:
35038482Swollman			ioptval.ipx_len = 0;
35138482Swollman			ioptval.ipx_sum = 0;
35238482Swollman			ioptval.ipx_tc = 0;
35338482Swollman			ioptval.ipx_pt = ipxp->ipxp_dpt;
35438482Swollman			ioptval.ipx_dna = ipxp->ipxp_faddr;
35538482Swollman			ioptval.ipx_sna = ipxp->ipxp_laddr;
35638482Swollman			error = sooptcopyout(sopt, &soptval, sizeof soptval);
35711819Sjulian			break;
35811819Sjulian
35911819Sjulian		case SO_SEQNO:
360139584Srwatson			error = sooptcopyout(sopt, &ipx_pexseq,
36138482Swollman					     sizeof ipx_pexseq);
36238482Swollman			ipx_pexseq++;
36311819Sjulian			break;
36411819Sjulian
36511819Sjulian		default:
36611819Sjulian			error = EINVAL;
36711819Sjulian		}
36811819Sjulian		break;
36911819Sjulian
37038482Swollman	case SOPT_SET:
37138482Swollman		switch (sopt->sopt_name) {
37211819Sjulian		case SO_ALL_PACKETS:
37311819Sjulian			mask = IPXP_ALL_PACKETS;
37411819Sjulian			goto set_head;
37511819Sjulian
37611819Sjulian		case SO_HEADERS_ON_INPUT:
37711819Sjulian			mask = IPXP_RAWIN;
37811819Sjulian			goto set_head;
37911819Sjulian
38050519Sjhay		case SO_IPX_CHECKSUM:
38150519Sjhay			mask = IPXP_CHECKSUM;
38250519Sjhay
38311819Sjulian		case SO_HEADERS_ON_OUTPUT:
38411819Sjulian			mask = IPXP_RAWOUT;
38511819Sjulian		set_head:
38638482Swollman			error = sooptcopyin(sopt, &optval, sizeof optval,
38738482Swollman					    sizeof optval);
38838482Swollman			if (error)
38938482Swollman				break;
39038482Swollman			if (optval)
39138482Swollman				ipxp->ipxp_flags |= mask;
39238482Swollman			else
39338482Swollman				ipxp->ipxp_flags &= ~mask;
39411819Sjulian			break;
39511819Sjulian
39611819Sjulian		case SO_DEFAULT_HEADERS:
39738482Swollman			error = sooptcopyin(sopt, &ioptval, sizeof ioptval,
39838482Swollman					    sizeof ioptval);
39938482Swollman			if (error)
40038482Swollman				break;
40138482Swollman			ipxp->ipxp_dpt = ioptval.ipx_pt;
40211819Sjulian			break;
40311819Sjulian#ifdef IPXIP
40411819Sjulian		case SO_IPXIP_ROUTE:
40538482Swollman			error = ipxip_route(so, sopt);
40611819Sjulian			break;
40711819Sjulian#endif /* IPXIP */
40811819Sjulian		default:
40911819Sjulian			error = EINVAL;
41011819Sjulian		}
41111819Sjulian		break;
41211819Sjulian	}
41311819Sjulian	return (error);
41411819Sjulian}
41511819Sjulian
41624659Sjhaystatic int
41724659Sjhayipx_usr_abort(so)
41811819Sjulian	struct socket *so;
41911819Sjulian{
42024659Sjhay	int s;
42111819Sjulian	struct ipxpcb *ipxp = sotoipxpcb(so);
42211819Sjulian
42324659Sjhay	s = splnet();
42424659Sjhay	ipx_pcbdetach(ipxp);
42524659Sjhay	splx(s);
426130387Srwatson	soisdisconnected(so);
427136682Srwatson	ACCEPT_LOCK();
428130387Srwatson	SOCK_LOCK(so);
42986487Sdillon	sotryfree(so);
43024659Sjhay	return (0);
43124659Sjhay}
43211819Sjulian
43324659Sjhaystatic int
43483366Sjulianipx_attach(so, proto, td)
43524659Sjhay	struct socket *so;
43624659Sjhay	int proto;
43783366Sjulian	struct thread *td;
43824659Sjhay{
43924659Sjhay	int error;
44024659Sjhay	int s;
44124659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
44224659Sjhay
44324659Sjhay	if (ipxp != NULL)
44424659Sjhay		return (EINVAL);
44524659Sjhay	s = splnet();
446139444Srwatson	error = ipx_pcballoc(so, &ipxpcb_list, td);
44724659Sjhay	splx(s);
44824659Sjhay	if (error == 0)
44919947Sjhay		error = soreserve(so, ipxsendspace, ipxrecvspace);
45024659Sjhay	return (error);
45124659Sjhay}
45211819Sjulian
45324659Sjhaystatic int
45483366Sjulianipx_bind(so, nam, td)
45524659Sjhay	struct socket *so;
45628270Swollman	struct sockaddr *nam;
45783366Sjulian	struct thread *td;
45824659Sjhay{
45924659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
46011819Sjulian
46183366Sjulian	return (ipx_pcbbind(ipxp, nam, td));
46224659Sjhay}
46311819Sjulian
46424659Sjhaystatic int
46583366Sjulianipx_connect(so, nam, td)
46624659Sjhay	struct socket *so;
46728270Swollman	struct sockaddr *nam;
46883366Sjulian	struct thread *td;
46924659Sjhay{
47024659Sjhay	int error;
47124659Sjhay	int s;
47224659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
47311819Sjulian
47424659Sjhay	if (!ipx_nullhost(ipxp->ipxp_faddr))
47524659Sjhay		return (EISCONN);
47624659Sjhay	s = splnet();
47783366Sjulian	error = ipx_pcbconnect(ipxp, nam, td);
47824659Sjhay	splx(s);
47997658Stanimura	if (error == 0)
48024659Sjhay		soisconnected(so);
48124659Sjhay	return (error);
48224659Sjhay}
48311819Sjulian
48424659Sjhaystatic int
48524659Sjhayipx_detach(so)
48624659Sjhay	struct socket *so;
48724659Sjhay{
48824659Sjhay	int s;
48924659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
49011819Sjulian
49124659Sjhay	if (ipxp == NULL)
49224659Sjhay		return (ENOTCONN);
49324659Sjhay	s = splnet();
49424659Sjhay	ipx_pcbdetach(ipxp);
49524659Sjhay	splx(s);
49624659Sjhay	return (0);
49724659Sjhay}
49811819Sjulian
49924659Sjhaystatic int
50024659Sjhayipx_disconnect(so)
50124659Sjhay	struct socket *so;
50224659Sjhay{
50324659Sjhay	int s;
50424659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
50511819Sjulian
50624659Sjhay	if (ipx_nullhost(ipxp->ipxp_faddr))
50724659Sjhay		return (ENOTCONN);
50824659Sjhay	s = splnet();
50924659Sjhay	ipx_pcbdisconnect(ipxp);
51024659Sjhay	splx(s);
51124659Sjhay	soisdisconnected(so);
51224659Sjhay	return (0);
51324659Sjhay}
51411819Sjulian
51524659Sjhayint
51624659Sjhayipx_peeraddr(so, nam)
51724659Sjhay	struct socket *so;
51828270Swollman	struct sockaddr **nam;
51924659Sjhay{
52024659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
52111819Sjulian
522139587Srwatson	ipx_setpeeraddr(ipxp, nam);
52324659Sjhay	return (0);
52424659Sjhay}
52524659Sjhay
52624659Sjhaystatic int
52783366Sjulianipx_send(so, flags, m, nam, control, td)
52824659Sjhay	struct socket *so;
52924659Sjhay	int flags;
53024659Sjhay	struct mbuf *m;
53128270Swollman	struct sockaddr *nam;
53224659Sjhay	struct mbuf *control;
53383366Sjulian	struct thread *td;
53424659Sjhay{
53524659Sjhay	int error;
53624659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
53724659Sjhay	struct ipx_addr laddr;
53824659Sjhay	int s = 0;
53924659Sjhay
54025652Sjhay	if (nam != NULL) {
54124659Sjhay		laddr = ipxp->ipxp_laddr;
54224659Sjhay		if (!ipx_nullhost(ipxp->ipxp_faddr)) {
54324659Sjhay			error = EISCONN;
54424659Sjhay			goto send_release;
54511819Sjulian		}
54624659Sjhay		/*
54724659Sjhay		 * Must block input while temporarily connected.
54824659Sjhay		 */
54924659Sjhay		s = splnet();
55083366Sjulian		error = ipx_pcbconnect(ipxp, nam, td);
55124659Sjhay		if (error) {
55211819Sjulian			splx(s);
55324659Sjhay			goto send_release;
55411819Sjulian		}
55524659Sjhay	} else {
55624659Sjhay		if (ipx_nullhost(ipxp->ipxp_faddr)) {
55724659Sjhay			error = ENOTCONN;
55824659Sjhay			goto send_release;
55924659Sjhay		}
56011819Sjulian	}
56124659Sjhay	error = ipx_output(ipxp, m);
56224659Sjhay	m = NULL;
56325652Sjhay	if (nam != NULL) {
56424659Sjhay		ipx_pcbdisconnect(ipxp);
56524659Sjhay		splx(s);
56643712Sjhay		ipxp->ipxp_laddr = laddr;
56724659Sjhay	}
56811819Sjulian
56924659Sjhaysend_release:
57011819Sjulian	if (m != NULL)
57111819Sjulian		m_freem(m);
57211819Sjulian	return (error);
57311819Sjulian}
57419947Sjhay
57524659Sjhaystatic int
57624659Sjhayipx_shutdown(so)
57724659Sjhay	struct socket *so;
57824659Sjhay{
57924659Sjhay	socantsendmore(so);
58024659Sjhay	return (0);
58124659Sjhay}
58224659Sjhay
58311819Sjulianint
58424659Sjhayipx_sockaddr(so, nam)
58511819Sjulian	struct socket *so;
58628270Swollman	struct sockaddr **nam;
58711819Sjulian{
58811819Sjulian	struct ipxpcb *ipxp = sotoipxpcb(so);
58911819Sjulian
590139587Srwatson	ipx_setsockaddr(ipxp, nam);
59124659Sjhay	return (0);
59224659Sjhay}
59311819Sjulian
59424659Sjhaystatic int
59583366Sjulianripx_attach(so, proto, td)
59624659Sjhay	struct socket *so;
59724659Sjhay	int proto;
59883366Sjulian	struct thread *td;
59924659Sjhay{
60024659Sjhay	int error = 0;
60124659Sjhay	int s;
60224659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
60311819Sjulian
60493593Sjhb	if (td != NULL && (error = suser(td)) != 0)
60525345Sjhay		return (error);
60624659Sjhay	s = splnet();
607139444Srwatson	error = ipx_pcballoc(so, &ipxrawpcb_list, td);
60824659Sjhay	splx(s);
60924659Sjhay	if (error)
61024659Sjhay		return (error);
61124659Sjhay	error = soreserve(so, ipxsendspace, ipxrecvspace);
61224659Sjhay	if (error)
61324659Sjhay		return (error);
61424659Sjhay	ipxp = sotoipxpcb(so);
61524659Sjhay	ipxp->ipxp_faddr.x_host = ipx_broadhost;
61624659Sjhay	ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
61711819Sjulian	return (error);
61811819Sjulian}
619