ipx_usrreq.c revision 130387
111819Sjulian/*
211819Sjulian * Copyright (c) 1995, Mike Mitchell
311819Sjulian * Copyright (c) 1984, 1985, 1986, 1987, 1993
411819Sjulian *	The Regents of the University of California.  All rights reserved.
511819Sjulian *
611819Sjulian * Redistribution and use in source and binary forms, with or without
711819Sjulian * modification, are permitted provided that the following conditions
811819Sjulian * are met:
911819Sjulian * 1. Redistributions of source code must retain the above copyright
1011819Sjulian *    notice, this list of conditions and the following disclaimer.
1111819Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1211819Sjulian *    notice, this list of conditions and the following disclaimer in the
1311819Sjulian *    documentation and/or other materials provided with the distribution.
1411819Sjulian * 3. All advertising materials mentioning features or use of this software
1511819Sjulian *    must display the following acknowledgement:
1611819Sjulian *	This product includes software developed by the University of
1711819Sjulian *	California, Berkeley and its contributors.
1811819Sjulian * 4. Neither the name of the University nor the names of its contributors
1911819Sjulian *    may be used to endorse or promote products derived from this software
2011819Sjulian *    without specific prior written permission.
2111819Sjulian *
2211819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2311819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2411819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2511819Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2611819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2711819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2811819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2911819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3011819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3111819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3211819Sjulian * SUCH DAMAGE.
3311819Sjulian *
3412057Sjulian *	@(#)ipx_usrreq.c
3511819Sjulian */
3611819Sjulian
37116189Sobrien#include <sys/cdefs.h>
38116189Sobrien__FBSDID("$FreeBSD: head/sys/netipx/ipx_usrreq.c 130387 2004-06-12 20:47:32Z rwatson $");
39116189Sobrien
4031742Seivind#include "opt_ipx.h"
4131742Seivind
4211819Sjulian#include <sys/param.h>
4319947Sjhay#include <sys/kernel.h>
4495759Stanimura#include <sys/lock.h>
4511819Sjulian#include <sys/mbuf.h>
4611819Sjulian#include <sys/protosw.h>
4795759Stanimura#include <sys/signalvar.h>
4811819Sjulian#include <sys/socket.h>
4911819Sjulian#include <sys/socketvar.h>
5095759Stanimura#include <sys/sx.h>
5119947Sjhay#include <sys/sysctl.h>
5295759Stanimura#include <sys/systm.h>
5311819Sjulian
5411819Sjulian#include <net/if.h>
5511819Sjulian#include <net/route.h>
5611819Sjulian
5711947Sjulian#include <netinet/in.h>
5811947Sjulian
5911819Sjulian#include <netipx/ipx.h>
6095759Stanimura#include <netipx/ipx_if.h>
6195759Stanimura#include <netipx/ipx_ip.h>
6211819Sjulian#include <netipx/ipx_pcb.h>
6311819Sjulian#include <netipx/ipx_var.h>
6411819Sjulian
6511819Sjulian/*
6611819Sjulian * IPX protocol implementation.
6711819Sjulian */
6811819Sjulian
6933181Seivindstatic int ipxsendspace = IPXSNDQ;
7019947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW,
7119947Sjhay            &ipxsendspace, 0, "");
7233181Seivindstatic int ipxrecvspace = IPXRCVQ;
7319947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
7419947Sjhay            &ipxrecvspace, 0, "");
7519947Sjhay
7624659Sjhaystatic	int ipx_usr_abort(struct socket *so);
7783366Sjulianstatic	int ipx_attach(struct socket *so, int proto, struct thread *td);
7883366Sjulianstatic	int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
7928270Swollmanstatic	int ipx_connect(struct socket *so, struct sockaddr *nam,
8083366Sjulian			struct thread *td);
8124659Sjhaystatic	int ipx_detach(struct socket *so);
8224659Sjhaystatic	int ipx_disconnect(struct socket *so);
8324659Sjhaystatic	int ipx_send(struct socket *so, int flags, struct mbuf *m,
8428270Swollman		     struct sockaddr *addr, struct mbuf *control,
8583366Sjulian		     struct thread *td);
8624659Sjhaystatic	int ipx_shutdown(struct socket *so);
8783366Sjulianstatic	int ripx_attach(struct socket *so, int proto, struct thread *td);
8825652Sjhaystatic	int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0);
8924659Sjhay
9025652Sjhaystruct	pr_usrreqs ipx_usrreqs = {
9124659Sjhay	ipx_usr_abort, pru_accept_notsupp, ipx_attach, ipx_bind,
9224659Sjhay	ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach,
9324659Sjhay	ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp,
9424659Sjhay	pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown,
95122875Srwatson	ipx_sockaddr, sosend, soreceive, sopoll, pru_sosetlabel_null
9624659Sjhay};
9724659Sjhay
9825652Sjhaystruct	pr_usrreqs ripx_usrreqs = {
9924659Sjhay	ipx_usr_abort, pru_accept_notsupp, ripx_attach, ipx_bind,
10024659Sjhay	ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach,
10124659Sjhay	ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp,
10224659Sjhay	pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown,
103122875Srwatson	ipx_sockaddr, sosend, soreceive, sopoll, pru_sosetlabel_null
10424659Sjhay};
10524659Sjhay
10611819Sjulian/*
10711819Sjulian *  This may also be called for raw listeners.
10811819Sjulian */
10911819Sjulianvoid
11011819Sjulianipx_input(m, ipxp)
11111819Sjulian	struct mbuf *m;
11211819Sjulian	register struct ipxpcb *ipxp;
11311819Sjulian{
11411819Sjulian	register struct ipx *ipx = mtod(m, struct ipx *);
11511819Sjulian	struct ifnet *ifp = m->m_pkthdr.rcvif;
11615245Sjhay	struct sockaddr_ipx ipx_ipx;
11711819Sjulian
11825652Sjhay	if (ipxp == NULL)
11911819Sjulian		panic("No ipxpcb");
12011819Sjulian	/*
12111819Sjulian	 * Construct sockaddr format source address.
12211819Sjulian	 * Stuff source address and datagram in user buffer.
12311819Sjulian	 */
12415245Sjhay	ipx_ipx.sipx_len = sizeof(ipx_ipx);
12515245Sjhay	ipx_ipx.sipx_family = AF_IPX;
12611819Sjulian	ipx_ipx.sipx_addr = ipx->ipx_sna;
12715245Sjhay	ipx_ipx.sipx_zero[0] = '\0';
12815245Sjhay	ipx_ipx.sipx_zero[1] = '\0';
12925652Sjhay	if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) {
13011819Sjulian		register struct ifaddr *ifa;
13111819Sjulian
13271999Sphk		for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL;
13371999Sphk		     ifa = TAILQ_NEXT(ifa, ifa_link)) {
13411819Sjulian			if (ifa->ifa_addr->sa_family == AF_IPX) {
13511819Sjulian				ipx_ipx.sipx_addr.x_net =
13611819Sjulian					IA_SIPX(ifa)->sipx_addr.x_net;
13711819Sjulian				break;
13811819Sjulian			}
13911819Sjulian		}
14011819Sjulian	}
14111819Sjulian	ipxp->ipxp_rpt = ipx->ipx_pt;
14225652Sjhay	if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) {
14325652Sjhay		m->m_len -= sizeof(struct ipx);
14425652Sjhay		m->m_pkthdr.len -= sizeof(struct ipx);
14525652Sjhay		m->m_data += sizeof(struct ipx);
14611819Sjulian	}
14711819Sjulian	if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx,
14825652Sjhay	    m, (struct mbuf *)NULL) == 0)
14911819Sjulian		goto bad;
15011819Sjulian	sorwakeup(ipxp->ipxp_socket);
15111819Sjulian	return;
15211819Sjulianbad:
15311819Sjulian	m_freem(m);
15411819Sjulian}
15511819Sjulian
15611819Sjulianvoid
15711819Sjulianipx_abort(ipxp)
15811819Sjulian	struct ipxpcb *ipxp;
15911819Sjulian{
16011819Sjulian	struct socket *so = ipxp->ipxp_socket;
16111819Sjulian
16211819Sjulian	ipx_pcbdisconnect(ipxp);
16311819Sjulian	soisdisconnected(so);
16411819Sjulian}
16525652Sjhay
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	 */
21511819Sjulian
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			}
29811819Sjulian			/*
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;
34111819Sjulian
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:
36038482Swollman			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);
427130387Srwatson	SOCK_LOCK(so);
42886487Sdillon	sotryfree(so);
42924659Sjhay	return (0);
43024659Sjhay}
43111819Sjulian
43224659Sjhaystatic int
43383366Sjulianipx_attach(so, proto, td)
43424659Sjhay	struct socket *so;
43524659Sjhay	int proto;
43683366Sjulian	struct thread *td;
43724659Sjhay{
43824659Sjhay	int error;
43924659Sjhay	int s;
44024659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
44124659Sjhay
44224659Sjhay	if (ipxp != NULL)
44324659Sjhay		return (EINVAL);
44424659Sjhay	s = splnet();
44583366Sjulian	error = ipx_pcballoc(so, &ipxpcb, td);
44624659Sjhay	splx(s);
44724659Sjhay	if (error == 0)
44819947Sjhay		error = soreserve(so, ipxsendspace, ipxrecvspace);
44924659Sjhay	return (error);
45024659Sjhay}
45111819Sjulian
45224659Sjhaystatic int
45383366Sjulianipx_bind(so, nam, td)
45424659Sjhay	struct socket *so;
45528270Swollman	struct sockaddr *nam;
45683366Sjulian	struct thread *td;
45724659Sjhay{
45824659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
45911819Sjulian
46083366Sjulian	return (ipx_pcbbind(ipxp, nam, td));
46124659Sjhay}
46211819Sjulian
46324659Sjhaystatic int
46483366Sjulianipx_connect(so, nam, td)
46524659Sjhay	struct socket *so;
46628270Swollman	struct sockaddr *nam;
46783366Sjulian	struct thread *td;
46824659Sjhay{
46924659Sjhay	int error;
47024659Sjhay	int s;
47124659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
47211819Sjulian
47324659Sjhay	if (!ipx_nullhost(ipxp->ipxp_faddr))
47424659Sjhay		return (EISCONN);
47524659Sjhay	s = splnet();
47683366Sjulian	error = ipx_pcbconnect(ipxp, nam, td);
47724659Sjhay	splx(s);
47897658Stanimura	if (error == 0)
47924659Sjhay		soisconnected(so);
48024659Sjhay	return (error);
48124659Sjhay}
48211819Sjulian
48324659Sjhaystatic int
48424659Sjhayipx_detach(so)
48524659Sjhay	struct socket *so;
48624659Sjhay{
48724659Sjhay	int s;
48824659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
48911819Sjulian
49024659Sjhay	if (ipxp == NULL)
49124659Sjhay		return (ENOTCONN);
49224659Sjhay	s = splnet();
49324659Sjhay	ipx_pcbdetach(ipxp);
49424659Sjhay	splx(s);
49524659Sjhay	return (0);
49624659Sjhay}
49711819Sjulian
49824659Sjhaystatic int
49924659Sjhayipx_disconnect(so)
50024659Sjhay	struct socket *so;
50124659Sjhay{
50224659Sjhay	int s;
50324659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
50411819Sjulian
50524659Sjhay	if (ipx_nullhost(ipxp->ipxp_faddr))
50624659Sjhay		return (ENOTCONN);
50724659Sjhay	s = splnet();
50824659Sjhay	ipx_pcbdisconnect(ipxp);
50924659Sjhay	splx(s);
51024659Sjhay	soisdisconnected(so);
51124659Sjhay	return (0);
51224659Sjhay}
51311819Sjulian
51424659Sjhayint
51524659Sjhayipx_peeraddr(so, nam)
51624659Sjhay	struct socket *so;
51728270Swollman	struct sockaddr **nam;
51824659Sjhay{
51924659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
52011819Sjulian
52128270Swollman	ipx_setpeeraddr(ipxp, nam); /* XXX what if alloc fails? */
52224659Sjhay	return (0);
52324659Sjhay}
52424659Sjhay
52524659Sjhaystatic int
52683366Sjulianipx_send(so, flags, m, nam, control, td)
52724659Sjhay	struct socket *so;
52824659Sjhay	int flags;
52924659Sjhay	struct mbuf *m;
53028270Swollman	struct sockaddr *nam;
53124659Sjhay	struct mbuf *control;
53283366Sjulian	struct thread *td;
53324659Sjhay{
53424659Sjhay	int error;
53524659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
53624659Sjhay	struct ipx_addr laddr;
53724659Sjhay	int s = 0;
53824659Sjhay
53925652Sjhay	if (nam != NULL) {
54024659Sjhay		laddr = ipxp->ipxp_laddr;
54124659Sjhay		if (!ipx_nullhost(ipxp->ipxp_faddr)) {
54224659Sjhay			error = EISCONN;
54324659Sjhay			goto send_release;
54411819Sjulian		}
54524659Sjhay		/*
54624659Sjhay		 * Must block input while temporarily connected.
54724659Sjhay		 */
54824659Sjhay		s = splnet();
54983366Sjulian		error = ipx_pcbconnect(ipxp, nam, td);
55024659Sjhay		if (error) {
55111819Sjulian			splx(s);
55224659Sjhay			goto send_release;
55311819Sjulian		}
55424659Sjhay	} else {
55524659Sjhay		if (ipx_nullhost(ipxp->ipxp_faddr)) {
55624659Sjhay			error = ENOTCONN;
55724659Sjhay			goto send_release;
55824659Sjhay		}
55911819Sjulian	}
56024659Sjhay	error = ipx_output(ipxp, m);
56124659Sjhay	m = NULL;
56225652Sjhay	if (nam != NULL) {
56324659Sjhay		ipx_pcbdisconnect(ipxp);
56424659Sjhay		splx(s);
56543712Sjhay		ipxp->ipxp_laddr = laddr;
56624659Sjhay	}
56711819Sjulian
56824659Sjhaysend_release:
56911819Sjulian	if (m != NULL)
57011819Sjulian		m_freem(m);
57111819Sjulian	return (error);
57211819Sjulian}
57319947Sjhay
57424659Sjhaystatic int
57524659Sjhayipx_shutdown(so)
57624659Sjhay	struct socket *so;
57724659Sjhay{
57824659Sjhay	socantsendmore(so);
57924659Sjhay	return (0);
58024659Sjhay}
58124659Sjhay
58211819Sjulianint
58324659Sjhayipx_sockaddr(so, nam)
58411819Sjulian	struct socket *so;
58528270Swollman	struct sockaddr **nam;
58611819Sjulian{
58711819Sjulian	struct ipxpcb *ipxp = sotoipxpcb(so);
58811819Sjulian
58928270Swollman	ipx_setsockaddr(ipxp, nam); /* XXX what if alloc fails? */
59024659Sjhay	return (0);
59124659Sjhay}
59211819Sjulian
59324659Sjhaystatic int
59483366Sjulianripx_attach(so, proto, td)
59524659Sjhay	struct socket *so;
59624659Sjhay	int proto;
59783366Sjulian	struct thread *td;
59824659Sjhay{
59924659Sjhay	int error = 0;
60024659Sjhay	int s;
60124659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
60211819Sjulian
60393593Sjhb	if (td != NULL && (error = suser(td)) != 0)
60425345Sjhay		return (error);
60524659Sjhay	s = splnet();
60683366Sjulian	error = ipx_pcballoc(so, &ipxrawpcb, td);
60724659Sjhay	splx(s);
60824659Sjhay	if (error)
60924659Sjhay		return (error);
61024659Sjhay	error = soreserve(so, ipxsendspace, ipxrecvspace);
61124659Sjhay	if (error)
61224659Sjhay		return (error);
61324659Sjhay	ipxp = sotoipxpcb(so);
61424659Sjhay	ipxp->ipxp_faddr.x_host = ipx_broadhost;
61524659Sjhay	ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
61611819Sjulian	return (error);
61711819Sjulian}
618