ipx_usrreq.c revision 83366
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
3512057Sjulian *
3650477Speter * $FreeBSD: head/sys/netipx/ipx_usrreq.c 83366 2001-09-12 08:38:13Z julian $
3711819Sjulian */
3811819Sjulian
3931742Seivind#include "opt_ipx.h"
4031742Seivind
4111819Sjulian#include <sys/param.h>
4211819Sjulian#include <sys/systm.h>
4319947Sjhay#include <sys/kernel.h>
4411819Sjulian#include <sys/mbuf.h>
4511819Sjulian#include <sys/protosw.h>
4611819Sjulian#include <sys/socket.h>
4711819Sjulian#include <sys/socketvar.h>
4819947Sjhay#include <sys/sysctl.h>
4911819Sjulian
5011819Sjulian#include <net/if.h>
5111819Sjulian#include <net/route.h>
5211819Sjulian
5311947Sjulian#include <netinet/in.h>
5411947Sjulian
5511819Sjulian#include <netipx/ipx.h>
5611819Sjulian#include <netipx/ipx_pcb.h>
5711819Sjulian#include <netipx/ipx_if.h>
5811819Sjulian#include <netipx/ipx_var.h>
5911947Sjulian#include <netipx/ipx_ip.h>
6011819Sjulian
6111819Sjulian/*
6211819Sjulian * IPX protocol implementation.
6311819Sjulian */
6411819Sjulian
6533181Seivindstatic int ipxsendspace = IPXSNDQ;
6619947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW,
6719947Sjhay            &ipxsendspace, 0, "");
6833181Seivindstatic int ipxrecvspace = IPXRCVQ;
6919947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
7019947Sjhay            &ipxrecvspace, 0, "");
7119947Sjhay
7224659Sjhaystatic	int ipx_usr_abort(struct socket *so);
7383366Sjulianstatic	int ipx_attach(struct socket *so, int proto, struct thread *td);
7483366Sjulianstatic	int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
7528270Swollmanstatic	int ipx_connect(struct socket *so, struct sockaddr *nam,
7683366Sjulian			struct thread *td);
7724659Sjhaystatic	int ipx_detach(struct socket *so);
7824659Sjhaystatic	int ipx_disconnect(struct socket *so);
7924659Sjhaystatic	int ipx_send(struct socket *so, int flags, struct mbuf *m,
8028270Swollman		     struct sockaddr *addr, struct mbuf *control,
8183366Sjulian		     struct thread *td);
8224659Sjhaystatic	int ipx_shutdown(struct socket *so);
8383366Sjulianstatic	int ripx_attach(struct socket *so, int proto, struct thread *td);
8425652Sjhaystatic	int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0);
8524659Sjhay
8625652Sjhaystruct	pr_usrreqs ipx_usrreqs = {
8724659Sjhay	ipx_usr_abort, pru_accept_notsupp, ipx_attach, ipx_bind,
8824659Sjhay	ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach,
8924659Sjhay	ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp,
9024659Sjhay	pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown,
9129366Speter	ipx_sockaddr, sosend, soreceive, sopoll
9224659Sjhay};
9324659Sjhay
9425652Sjhaystruct	pr_usrreqs ripx_usrreqs = {
9524659Sjhay	ipx_usr_abort, pru_accept_notsupp, ripx_attach, ipx_bind,
9624659Sjhay	ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach,
9724659Sjhay	ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp,
9824659Sjhay	pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown,
9929366Speter	ipx_sockaddr, sosend, soreceive, sopoll
10024659Sjhay};
10124659Sjhay
10211819Sjulian/*
10311819Sjulian *  This may also be called for raw listeners.
10411819Sjulian */
10511819Sjulianvoid
10611819Sjulianipx_input(m, ipxp)
10711819Sjulian	struct mbuf *m;
10811819Sjulian	register struct ipxpcb *ipxp;
10911819Sjulian{
11011819Sjulian	register struct ipx *ipx = mtod(m, struct ipx *);
11111819Sjulian	struct ifnet *ifp = m->m_pkthdr.rcvif;
11215245Sjhay	struct sockaddr_ipx ipx_ipx;
11311819Sjulian
11425652Sjhay	if (ipxp == NULL)
11511819Sjulian		panic("No ipxpcb");
11611819Sjulian	/*
11711819Sjulian	 * Construct sockaddr format source address.
11811819Sjulian	 * Stuff source address and datagram in user buffer.
11911819Sjulian	 */
12015245Sjhay	ipx_ipx.sipx_len = sizeof(ipx_ipx);
12115245Sjhay	ipx_ipx.sipx_family = AF_IPX;
12211819Sjulian	ipx_ipx.sipx_addr = ipx->ipx_sna;
12315245Sjhay	ipx_ipx.sipx_zero[0] = '\0';
12415245Sjhay	ipx_ipx.sipx_zero[1] = '\0';
12525652Sjhay	if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) {
12611819Sjulian		register struct ifaddr *ifa;
12711819Sjulian
12871999Sphk		for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL;
12971999Sphk		     ifa = TAILQ_NEXT(ifa, ifa_link)) {
13011819Sjulian			if (ifa->ifa_addr->sa_family == AF_IPX) {
13111819Sjulian				ipx_ipx.sipx_addr.x_net =
13211819Sjulian					IA_SIPX(ifa)->sipx_addr.x_net;
13311819Sjulian				break;
13411819Sjulian			}
13511819Sjulian		}
13611819Sjulian	}
13711819Sjulian	ipxp->ipxp_rpt = ipx->ipx_pt;
13825652Sjhay	if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) {
13925652Sjhay		m->m_len -= sizeof(struct ipx);
14025652Sjhay		m->m_pkthdr.len -= sizeof(struct ipx);
14125652Sjhay		m->m_data += sizeof(struct ipx);
14211819Sjulian	}
14311819Sjulian	if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx,
14425652Sjhay	    m, (struct mbuf *)NULL) == 0)
14511819Sjulian		goto bad;
14611819Sjulian	sorwakeup(ipxp->ipxp_socket);
14711819Sjulian	return;
14811819Sjulianbad:
14911819Sjulian	m_freem(m);
15011819Sjulian}
15111819Sjulian
15211819Sjulianvoid
15311819Sjulianipx_abort(ipxp)
15411819Sjulian	struct ipxpcb *ipxp;
15511819Sjulian{
15611819Sjulian	struct socket *so = ipxp->ipxp_socket;
15711819Sjulian
15811819Sjulian	ipx_pcbdisconnect(ipxp);
15911819Sjulian	soisdisconnected(so);
16011819Sjulian}
16125652Sjhay
16211819Sjulian/*
16311819Sjulian * Drop connection, reporting
16411819Sjulian * the specified error.
16511819Sjulian */
16611819Sjulianvoid
16711819Sjulianipx_drop(ipxp, errno)
16811819Sjulian	register struct ipxpcb *ipxp;
16911819Sjulian	int errno;
17011819Sjulian{
17111819Sjulian	struct socket *so = ipxp->ipxp_socket;
17211819Sjulian
17311819Sjulian	/*
17425652Sjhay	 * someday, in the IPX world
17511819Sjulian	 * we will generate error protocol packets
17611819Sjulian	 * announcing that the socket has gone away.
17725652Sjhay	 *
17825652Sjhay	 * XXX Probably never. IPX does not have error packets.
17911819Sjulian	 */
18011819Sjulian	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
18111819Sjulian		tp->t_state = TCPS_CLOSED;
18225652Sjhay		tcp_output(tp);
18311819Sjulian	}*/
18411819Sjulian	so->so_error = errno;
18511819Sjulian	ipx_pcbdisconnect(ipxp);
18611819Sjulian	soisdisconnected(so);
18711819Sjulian}
18811819Sjulian
18925652Sjhaystatic int
19011819Sjulianipx_output(ipxp, m0)
19111819Sjulian	struct ipxpcb *ipxp;
19211819Sjulian	struct mbuf *m0;
19311819Sjulian{
19411819Sjulian	register struct ipx *ipx;
19511819Sjulian	register struct socket *so;
19611819Sjulian	register int len = 0;
19711819Sjulian	register struct route *ro;
19854799Sgreen	struct mbuf *m;
19911819Sjulian	struct mbuf *mprev = NULL;
20011819Sjulian
20111819Sjulian	/*
20211819Sjulian	 * Calculate data length.
20311819Sjulian	 */
20425652Sjhay	for (m = m0; m != NULL; m = m->m_next) {
20511819Sjulian		mprev = m;
20611819Sjulian		len += m->m_len;
20711819Sjulian	}
20811819Sjulian	/*
20911819Sjulian	 * Make sure packet is actually of even length.
21011819Sjulian	 */
21111819Sjulian
21211819Sjulian	if (len & 1) {
21311819Sjulian		m = mprev;
21411819Sjulian		if ((m->m_flags & M_EXT) == 0 &&
21511819Sjulian			(m->m_len + m->m_data < &m->m_dat[MLEN])) {
21650519Sjhay			mtod(m, char*)[m->m_len++] = 0;
21711819Sjulian		} else {
21811819Sjulian			struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
21911819Sjulian
22025652Sjhay			if (m1 == NULL) {
22111819Sjulian				m_freem(m0);
22211819Sjulian				return (ENOBUFS);
22311819Sjulian			}
22411819Sjulian			m1->m_len = 1;
22511819Sjulian			* mtod(m1, char *) = 0;
22611819Sjulian			m->m_next = m1;
22711819Sjulian		}
22811819Sjulian		m0->m_pkthdr.len++;
22911819Sjulian	}
23011819Sjulian
23111819Sjulian	/*
23211819Sjulian	 * Fill in mbuf with extended IPX header
23311819Sjulian	 * and addresses and length put into network format.
23411819Sjulian	 */
23511819Sjulian	m = m0;
23611819Sjulian	if (ipxp->ipxp_flags & IPXP_RAWOUT) {
23711819Sjulian		ipx = mtod(m, struct ipx *);
23811819Sjulian	} else {
23925652Sjhay		M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT);
24025652Sjhay		if (m == NULL)
24111819Sjulian			return (ENOBUFS);
24211819Sjulian		ipx = mtod(m, struct ipx *);
24311819Sjulian		ipx->ipx_tc = 0;
24411819Sjulian		ipx->ipx_pt = ipxp->ipxp_dpt;
24511819Sjulian		ipx->ipx_sna = ipxp->ipxp_laddr;
24611819Sjulian		ipx->ipx_dna = ipxp->ipxp_faddr;
24725652Sjhay		len += sizeof(struct ipx);
24811819Sjulian	}
24911819Sjulian
25011819Sjulian	ipx->ipx_len = htons((u_short)len);
25111819Sjulian
25250519Sjhay	if (ipxp->ipxp_flags & IPXP_CHECKSUM) {
25311819Sjulian		ipx->ipx_sum = ipx_cksum(m, len);
25411819Sjulian	} else
25511819Sjulian		ipx->ipx_sum = 0xffff;
25611819Sjulian
25711819Sjulian	/*
25811819Sjulian	 * Output datagram.
25911819Sjulian	 */
26011819Sjulian	so = ipxp->ipxp_socket;
26111819Sjulian	if (so->so_options & SO_DONTROUTE)
26225652Sjhay		return (ipx_outputfl(m, (struct route *)NULL,
26311819Sjulian		    (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
26411819Sjulian	/*
26511819Sjulian	 * Use cached route for previous datagram if
26611819Sjulian	 * possible.  If the previous net was the same
26711819Sjulian	 * and the interface was a broadcast medium, or
26811819Sjulian	 * if the previous destination was identical,
26911819Sjulian	 * then we are ok.
27011819Sjulian	 *
27111819Sjulian	 * NB: We don't handle broadcasts because that
27211819Sjulian	 *     would require 3 subroutine calls.
27311819Sjulian	 */
27411819Sjulian	ro = &ipxp->ipxp_route;
27511819Sjulian#ifdef ancient_history
27611819Sjulian	/*
27711819Sjulian	 * I think that this will all be handled in ipx_pcbconnect!
27811819Sjulian	 */
27925652Sjhay	if (ro->ro_rt != NULL) {
28011819Sjulian		if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
28111819Sjulian			/*
28211819Sjulian			 * This assumes we have no GH type routes
28311819Sjulian			 */
28411819Sjulian			if (ro->ro_rt->rt_flags & RTF_HOST) {
28511819Sjulian				if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
28611819Sjulian					goto re_route;
28711819Sjulian
28811819Sjulian			}
28911819Sjulian			if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
29011819Sjulian				register struct ipx_addr *dst =
29111819Sjulian						&satoipx_addr(ro->ro_dst);
29211819Sjulian				dst->x_host = ipx->ipx_dna.x_host;
29311819Sjulian			}
29411819Sjulian			/*
29511819Sjulian			 * Otherwise, we go through the same gateway
29611819Sjulian			 * and dst is already set up.
29711819Sjulian			 */
29811819Sjulian		} else {
29911819Sjulian		re_route:
30011819Sjulian			RTFREE(ro->ro_rt);
30125652Sjhay			ro->ro_rt = NULL;
30211819Sjulian		}
30311819Sjulian	}
30411819Sjulian	ipxp->ipxp_lastdst = ipx->ipx_dna;
30511819Sjulian#endif /* ancient_history */
30611819Sjulian	return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
30711819Sjulian}
30819947Sjhay
30911819Sjulianint
31038482Swollmanipx_ctloutput(so, sopt)
31111819Sjulian	struct socket *so;
31238482Swollman	struct sockopt *sopt;
31311819Sjulian{
31411819Sjulian	struct ipxpcb *ipxp = sotoipxpcb(so);
31538482Swollman	int mask, error, optval;
31638482Swollman	short soptval;
31738482Swollman	struct ipx ioptval;
31811819Sjulian
31938482Swollman	error = 0;
32011819Sjulian	if (ipxp == NULL)
32111819Sjulian		return (EINVAL);
32211819Sjulian
32338482Swollman	switch (sopt->sopt_dir) {
32438482Swollman	case SOPT_GET:
32538482Swollman		switch (sopt->sopt_name) {
32611819Sjulian		case SO_ALL_PACKETS:
32711819Sjulian			mask = IPXP_ALL_PACKETS;
32811819Sjulian			goto get_flags;
32911819Sjulian
33011819Sjulian		case SO_HEADERS_ON_INPUT:
33111819Sjulian			mask = IPXP_RAWIN;
33211819Sjulian			goto get_flags;
33350519Sjhay
33450519Sjhay		case SO_IPX_CHECKSUM:
33550519Sjhay			mask = IPXP_CHECKSUM;
33650519Sjhay			goto get_flags;
33711819Sjulian
33811819Sjulian		case SO_HEADERS_ON_OUTPUT:
33911819Sjulian			mask = IPXP_RAWOUT;
34011819Sjulian		get_flags:
34138482Swollman			soptval = ipxp->ipxp_flags & mask;
34238482Swollman			error = sooptcopyout(sopt, &soptval, sizeof soptval);
34311819Sjulian			break;
34411819Sjulian
34511819Sjulian		case SO_DEFAULT_HEADERS:
34638482Swollman			ioptval.ipx_len = 0;
34738482Swollman			ioptval.ipx_sum = 0;
34838482Swollman			ioptval.ipx_tc = 0;
34938482Swollman			ioptval.ipx_pt = ipxp->ipxp_dpt;
35038482Swollman			ioptval.ipx_dna = ipxp->ipxp_faddr;
35138482Swollman			ioptval.ipx_sna = ipxp->ipxp_laddr;
35238482Swollman			error = sooptcopyout(sopt, &soptval, sizeof soptval);
35311819Sjulian			break;
35411819Sjulian
35511819Sjulian		case SO_SEQNO:
35638482Swollman			error = sooptcopyout(sopt, &ipx_pexseq,
35738482Swollman					     sizeof ipx_pexseq);
35838482Swollman			ipx_pexseq++;
35911819Sjulian			break;
36011819Sjulian
36111819Sjulian		default:
36211819Sjulian			error = EINVAL;
36311819Sjulian		}
36411819Sjulian		break;
36511819Sjulian
36638482Swollman	case SOPT_SET:
36738482Swollman		switch (sopt->sopt_name) {
36811819Sjulian		case SO_ALL_PACKETS:
36911819Sjulian			mask = IPXP_ALL_PACKETS;
37011819Sjulian			goto set_head;
37111819Sjulian
37211819Sjulian		case SO_HEADERS_ON_INPUT:
37311819Sjulian			mask = IPXP_RAWIN;
37411819Sjulian			goto set_head;
37511819Sjulian
37650519Sjhay		case SO_IPX_CHECKSUM:
37750519Sjhay			mask = IPXP_CHECKSUM;
37850519Sjhay
37911819Sjulian		case SO_HEADERS_ON_OUTPUT:
38011819Sjulian			mask = IPXP_RAWOUT;
38111819Sjulian		set_head:
38238482Swollman			error = sooptcopyin(sopt, &optval, sizeof optval,
38338482Swollman					    sizeof optval);
38438482Swollman			if (error)
38538482Swollman				break;
38638482Swollman			if (optval)
38738482Swollman				ipxp->ipxp_flags |= mask;
38838482Swollman			else
38938482Swollman				ipxp->ipxp_flags &= ~mask;
39011819Sjulian			break;
39111819Sjulian
39211819Sjulian		case SO_DEFAULT_HEADERS:
39338482Swollman			error = sooptcopyin(sopt, &ioptval, sizeof ioptval,
39438482Swollman					    sizeof ioptval);
39538482Swollman			if (error)
39638482Swollman				break;
39738482Swollman			ipxp->ipxp_dpt = ioptval.ipx_pt;
39811819Sjulian			break;
39911819Sjulian#ifdef IPXIP
40011819Sjulian		case SO_IPXIP_ROUTE:
40138482Swollman			error = ipxip_route(so, sopt);
40211819Sjulian			break;
40311819Sjulian#endif /* IPXIP */
40431742Seivind#ifdef IPTUNNEL
40531742Seivind#if 0
40631742Seivind		case SO_IPXTUNNEL_ROUTE:
40738482Swollman			error = ipxtun_route(so, sopt);
40811819Sjulian			break;
40911819Sjulian#endif
41031742Seivind#endif
41111819Sjulian		default:
41211819Sjulian			error = EINVAL;
41311819Sjulian		}
41411819Sjulian		break;
41511819Sjulian	}
41611819Sjulian	return (error);
41711819Sjulian}
41811819Sjulian
41924659Sjhaystatic int
42024659Sjhayipx_usr_abort(so)
42111819Sjulian	struct socket *so;
42211819Sjulian{
42324659Sjhay	int s;
42411819Sjulian	struct ipxpcb *ipxp = sotoipxpcb(so);
42511819Sjulian
42624659Sjhay	s = splnet();
42724659Sjhay	ipx_pcbdetach(ipxp);
42824659Sjhay	splx(s);
42924659Sjhay	sofree(so);
43024659Sjhay	soisdisconnected(so);
43124659Sjhay	return (0);
43224659Sjhay}
43311819Sjulian
43424659Sjhaystatic int
43583366Sjulianipx_attach(so, proto, td)
43624659Sjhay	struct socket *so;
43724659Sjhay	int proto;
43883366Sjulian	struct thread *td;
43924659Sjhay{
44024659Sjhay	int error;
44124659Sjhay	int s;
44224659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
44324659Sjhay
44424659Sjhay	if (ipxp != NULL)
44524659Sjhay		return (EINVAL);
44624659Sjhay	s = splnet();
44783366Sjulian	error = ipx_pcballoc(so, &ipxpcb, td);
44824659Sjhay	splx(s);
44924659Sjhay	if (error == 0)
45019947Sjhay		error = soreserve(so, ipxsendspace, ipxrecvspace);
45124659Sjhay	return (error);
45224659Sjhay}
45311819Sjulian
45424659Sjhaystatic int
45583366Sjulianipx_bind(so, nam, td)
45624659Sjhay	struct socket *so;
45728270Swollman	struct sockaddr *nam;
45883366Sjulian	struct thread *td;
45924659Sjhay{
46024659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
46111819Sjulian
46283366Sjulian	return (ipx_pcbbind(ipxp, nam, td));
46324659Sjhay}
46411819Sjulian
46524659Sjhaystatic int
46683366Sjulianipx_connect(so, nam, td)
46724659Sjhay	struct socket *so;
46828270Swollman	struct sockaddr *nam;
46983366Sjulian	struct thread *td;
47024659Sjhay{
47124659Sjhay	int error;
47224659Sjhay	int s;
47324659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
47411819Sjulian
47524659Sjhay	if (!ipx_nullhost(ipxp->ipxp_faddr))
47624659Sjhay		return (EISCONN);
47724659Sjhay	s = splnet();
47883366Sjulian	error = ipx_pcbconnect(ipxp, nam, td);
47924659Sjhay	splx(s);
48024659Sjhay	if (error == 0)
48124659Sjhay		soisconnected(so);
48224659Sjhay	return (error);
48324659Sjhay}
48411819Sjulian
48524659Sjhaystatic int
48624659Sjhayipx_detach(so)
48724659Sjhay	struct socket *so;
48824659Sjhay{
48924659Sjhay	int s;
49024659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
49111819Sjulian
49224659Sjhay	if (ipxp == NULL)
49324659Sjhay		return (ENOTCONN);
49424659Sjhay	s = splnet();
49524659Sjhay	ipx_pcbdetach(ipxp);
49624659Sjhay	splx(s);
49724659Sjhay	return (0);
49824659Sjhay}
49911819Sjulian
50024659Sjhaystatic int
50124659Sjhayipx_disconnect(so)
50224659Sjhay	struct socket *so;
50324659Sjhay{
50424659Sjhay	int s;
50524659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
50611819Sjulian
50724659Sjhay	if (ipx_nullhost(ipxp->ipxp_faddr))
50824659Sjhay		return (ENOTCONN);
50924659Sjhay	s = splnet();
51024659Sjhay	ipx_pcbdisconnect(ipxp);
51124659Sjhay	splx(s);
51224659Sjhay	soisdisconnected(so);
51324659Sjhay	return (0);
51424659Sjhay}
51511819Sjulian
51624659Sjhayint
51724659Sjhayipx_peeraddr(so, nam)
51824659Sjhay	struct socket *so;
51928270Swollman	struct sockaddr **nam;
52024659Sjhay{
52124659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
52211819Sjulian
52328270Swollman	ipx_setpeeraddr(ipxp, nam); /* XXX what if alloc fails? */
52424659Sjhay	return (0);
52524659Sjhay}
52624659Sjhay
52724659Sjhaystatic int
52883366Sjulianipx_send(so, flags, m, nam, control, td)
52924659Sjhay	struct socket *so;
53024659Sjhay	int flags;
53124659Sjhay	struct mbuf *m;
53228270Swollman	struct sockaddr *nam;
53324659Sjhay	struct mbuf *control;
53483366Sjulian	struct thread *td;
53524659Sjhay{
53624659Sjhay	int error;
53724659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
53824659Sjhay	struct ipx_addr laddr;
53924659Sjhay	int s = 0;
54024659Sjhay
54125652Sjhay	if (nam != NULL) {
54224659Sjhay		laddr = ipxp->ipxp_laddr;
54324659Sjhay		if (!ipx_nullhost(ipxp->ipxp_faddr)) {
54424659Sjhay			error = EISCONN;
54524659Sjhay			goto send_release;
54611819Sjulian		}
54724659Sjhay		/*
54824659Sjhay		 * Must block input while temporarily connected.
54924659Sjhay		 */
55024659Sjhay		s = splnet();
55183366Sjulian		error = ipx_pcbconnect(ipxp, nam, td);
55224659Sjhay		if (error) {
55311819Sjulian			splx(s);
55424659Sjhay			goto send_release;
55511819Sjulian		}
55624659Sjhay	} else {
55724659Sjhay		if (ipx_nullhost(ipxp->ipxp_faddr)) {
55824659Sjhay			error = ENOTCONN;
55924659Sjhay			goto send_release;
56024659Sjhay		}
56111819Sjulian	}
56224659Sjhay	error = ipx_output(ipxp, m);
56324659Sjhay	m = NULL;
56425652Sjhay	if (nam != NULL) {
56524659Sjhay		ipx_pcbdisconnect(ipxp);
56624659Sjhay		splx(s);
56743712Sjhay		ipxp->ipxp_laddr = laddr;
56824659Sjhay	}
56911819Sjulian
57024659Sjhaysend_release:
57111819Sjulian	if (m != NULL)
57211819Sjulian		m_freem(m);
57311819Sjulian	return (error);
57411819Sjulian}
57519947Sjhay
57624659Sjhaystatic int
57724659Sjhayipx_shutdown(so)
57824659Sjhay	struct socket *so;
57924659Sjhay{
58024659Sjhay	socantsendmore(so);
58124659Sjhay	return (0);
58224659Sjhay}
58324659Sjhay
58411819Sjulianint
58524659Sjhayipx_sockaddr(so, nam)
58611819Sjulian	struct socket *so;
58728270Swollman	struct sockaddr **nam;
58811819Sjulian{
58911819Sjulian	struct ipxpcb *ipxp = sotoipxpcb(so);
59011819Sjulian
59128270Swollman	ipx_setsockaddr(ipxp, nam); /* XXX what if alloc fails? */
59224659Sjhay	return (0);
59324659Sjhay}
59411819Sjulian
59524659Sjhaystatic int
59683366Sjulianripx_attach(so, proto, td)
59724659Sjhay	struct socket *so;
59824659Sjhay	int proto;
59983366Sjulian	struct thread *td;
60024659Sjhay{
60124659Sjhay	int error = 0;
60224659Sjhay	int s;
60324659Sjhay	struct ipxpcb *ipxp = sotoipxpcb(so);
60411819Sjulian
60583366Sjulian	if (td != NULL && (error = suser_td(td)) != 0)
60625345Sjhay		return (error);
60724659Sjhay	s = splnet();
60883366Sjulian	error = ipx_pcballoc(so, &ipxrawpcb, td);
60924659Sjhay	splx(s);
61024659Sjhay	if (error)
61124659Sjhay		return (error);
61224659Sjhay	error = soreserve(so, ipxsendspace, ipxrecvspace);
61324659Sjhay	if (error)
61424659Sjhay		return (error);
61524659Sjhay	ipxp = sotoipxpcb(so);
61624659Sjhay	ipxp->ipxp_faddr.x_host = ipx_broadhost;
61724659Sjhay	ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
61811819Sjulian	return (error);
61911819Sjulian}
620