ipx_usrreq.c revision 139588
189857Sobrien/*
289857Sobrien * Copyright (c) 2004 Robert N. M. Watson
3218822Sdim * Copyright (c) 1995, Mike Mitchell
4218822Sdim * Copyright (c) 1984, 1985, 1986, 1987, 1993
5218822Sdim *	The Regents of the University of California.  All rights reserved.
6218822Sdim *
789857Sobrien * Redistribution and use in source and binary forms, with or without
889857Sobrien * modification, are permitted provided that the following conditions
989857Sobrien * are met:
1089857Sobrien * 1. Redistributions of source code must retain the above copyright
1189857Sobrien *    notice, this list of conditions and the following disclaimer.
1289857Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1389857Sobrien *    notice, this list of conditions and the following disclaimer in the
1489857Sobrien *    documentation and/or other materials provided with the distribution.
1589857Sobrien * 3. All advertising materials mentioning features or use of this software
1689857Sobrien *    must display the following acknowledgement:
1789857Sobrien *	This product includes software developed by the University of
1889857Sobrien *	California, Berkeley and its contributors.
1989857Sobrien * 4. Neither the name of the University nor the names of its contributors
2089857Sobrien *    may be used to endorse or promote products derived from this software
2189857Sobrien *    without specific prior written permission.
22218822Sdim *
23218822Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2489857Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2589857Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2689857Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2789857Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2889857Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2989857Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3089857Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3189857Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3289857Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3389857Sobrien * SUCH DAMAGE.
3489857Sobrien *
3589857Sobrien *	@(#)ipx_usrreq.c
3689857Sobrien */
3789857Sobrien
3889857Sobrien#include <sys/cdefs.h>
3989857Sobrien__FBSDID("$FreeBSD: head/sys/netipx/ipx_usrreq.c 139588 2005-01-02 15:29:29Z rwatson $");
4089857Sobrien
4189857Sobrien#include "opt_ipx.h"
4289857Sobrien
4389857Sobrien#include <sys/param.h>
4489857Sobrien#include <sys/kernel.h>
4589857Sobrien#include <sys/lock.h>
4689857Sobrien#include <sys/mbuf.h>
4789857Sobrien#include <sys/protosw.h>
4889857Sobrien#include <sys/signalvar.h>
4989857Sobrien#include <sys/socket.h>
5089857Sobrien#include <sys/socketvar.h>
5189857Sobrien#include <sys/sx.h>
5289857Sobrien#include <sys/sysctl.h>
5389857Sobrien#include <sys/systm.h>
5489857Sobrien
5589857Sobrien#include <net/if.h>
5689857Sobrien#include <net/route.h>
5789857Sobrien
5889857Sobrien#include <netinet/in.h>
5989857Sobrien
6089857Sobrien#include <netipx/ipx.h>
6189857Sobrien#include <netipx/ipx_if.h>
6289857Sobrien#include <netipx/ipx_ip.h>
6389857Sobrien#include <netipx/ipx_pcb.h>
6489857Sobrien#include <netipx/ipx_var.h>
6589857Sobrien
6689857Sobrien/*
6789857Sobrien * IPX protocol implementation.
6889857Sobrien */
6989857Sobrien
7089857Sobrienstatic int ipxsendspace = IPXSNDQ;
7189857SobrienSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW,
7289857Sobrien            &ipxsendspace, 0, "");
7389857Sobrienstatic int ipxrecvspace = IPXRCVQ;
7489857SobrienSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
7589857Sobrien            &ipxrecvspace, 0, "");
7689857Sobrien
7789857Sobrienstatic	int ipx_usr_abort(struct socket *so);
7889857Sobrienstatic	int ipx_attach(struct socket *so, int proto, struct thread *td);
7989857Sobrienstatic	int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
8089857Sobrienstatic	int ipx_connect(struct socket *so, struct sockaddr *nam,
8189857Sobrien			struct thread *td);
8289857Sobrienstatic	int ipx_detach(struct socket *so);
8389857Sobrienstatic	int ipx_disconnect(struct socket *so);
8489857Sobrienstatic	int ipx_send(struct socket *so, int flags, struct mbuf *m,
8589857Sobrien		     struct sockaddr *addr, struct mbuf *control,
8689857Sobrien		     struct thread *td);
8789857Sobrienstatic	int ipx_shutdown(struct socket *so);
8889857Sobrienstatic	int ripx_attach(struct socket *so, int proto, struct thread *td);
8989857Sobrienstatic	int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0);
9089857Sobrien
9189857Sobrienstruct	pr_usrreqs ipx_usrreqs = {
9289857Sobrien	.pru_abort =		ipx_usr_abort,
9389857Sobrien	.pru_attach =		ipx_attach,
9489857Sobrien	.pru_bind =		ipx_bind,
9589857Sobrien	.pru_connect =		ipx_connect,
9689857Sobrien	.pru_control =		ipx_control,
9789857Sobrien	.pru_detach =		ipx_detach,
9889857Sobrien	.pru_disconnect =	ipx_disconnect,
9989857Sobrien	.pru_peeraddr =		ipx_peeraddr,
10089857Sobrien	.pru_send =		ipx_send,
10189857Sobrien	.pru_shutdown =		ipx_shutdown,
10289857Sobrien	.pru_sockaddr =		ipx_sockaddr,
10389857Sobrien};
10489857Sobrien
10589857Sobrienstruct	pr_usrreqs ripx_usrreqs = {
10689857Sobrien	.pru_abort =		ipx_usr_abort,
10789857Sobrien	.pru_attach =		ripx_attach,
10889857Sobrien	.pru_bind =		ipx_bind,
10989857Sobrien	.pru_connect =		ipx_connect,
11089857Sobrien	.pru_control =		ipx_control,
11189857Sobrien	.pru_detach =		ipx_detach,
11289857Sobrien	.pru_disconnect =	ipx_disconnect,
11389857Sobrien	.pru_peeraddr =		ipx_peeraddr,
11489857Sobrien	.pru_send =		ipx_send,
11589857Sobrien	.pru_shutdown =		ipx_shutdown,
11689857Sobrien	.pru_sockaddr =		ipx_sockaddr,
11789857Sobrien};
11889857Sobrien
11989857Sobrien/*
12089857Sobrien *  This may also be called for raw listeners.
12189857Sobrien */
12289857Sobrienvoid
12389857Sobrienipx_input(m, ipxp)
12489857Sobrien	struct mbuf *m;
12589857Sobrien	register struct ipxpcb *ipxp;
12689857Sobrien{
12789857Sobrien	register struct ipx *ipx = mtod(m, struct ipx *);
12889857Sobrien	struct ifnet *ifp = m->m_pkthdr.rcvif;
12989857Sobrien	struct sockaddr_ipx ipx_ipx;
13089857Sobrien
13189857Sobrien	KASSERT(ipxp != NULL, ("ipx_input: NUL ipxpcb"));
13289857Sobrien	/*
13389857Sobrien	 * Construct sockaddr format source address.
13489857Sobrien	 * Stuff source address and datagram in user buffer.
13589857Sobrien	 */
13689857Sobrien	ipx_ipx.sipx_len = sizeof(ipx_ipx);
13789857Sobrien	ipx_ipx.sipx_family = AF_IPX;
13889857Sobrien	ipx_ipx.sipx_addr = ipx->ipx_sna;
13989857Sobrien	ipx_ipx.sipx_zero[0] = '\0';
14089857Sobrien	ipx_ipx.sipx_zero[1] = '\0';
14189857Sobrien	if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) {
14289857Sobrien		register struct ifaddr *ifa;
14389857Sobrien
14489857Sobrien		for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL;
14589857Sobrien		     ifa = TAILQ_NEXT(ifa, ifa_link)) {
14689857Sobrien			if (ifa->ifa_addr->sa_family == AF_IPX) {
14789857Sobrien				ipx_ipx.sipx_addr.x_net =
14889857Sobrien					IA_SIPX(ifa)->sipx_addr.x_net;
14989857Sobrien				break;
15089857Sobrien			}
15189857Sobrien		}
15289857Sobrien	}
15389857Sobrien	ipxp->ipxp_rpt = ipx->ipx_pt;
15489857Sobrien	if ((ipxp->ipxp_flags & IPXP_RAWIN) == 0) {
15589857Sobrien		m->m_len -= sizeof(struct ipx);
15689857Sobrien		m->m_pkthdr.len -= sizeof(struct ipx);
15789857Sobrien		m->m_data += sizeof(struct ipx);
15889857Sobrien	}
15989857Sobrien	if (sbappendaddr(&ipxp->ipxp_socket->so_rcv,
16089857Sobrien	    (struct sockaddr *)&ipx_ipx, m, NULL) == 0)
16189857Sobrien		m_freem(m);
16289857Sobrien	else
16389857Sobrien		sorwakeup(ipxp->ipxp_socket);
16489857Sobrien}
16589857Sobrien
16689857Sobrienvoid
16789857Sobrienipx_abort(ipxp)
16889857Sobrien	struct ipxpcb *ipxp;
16989857Sobrien{
17089857Sobrien	struct socket *so = ipxp->ipxp_socket;
17189857Sobrien
17289857Sobrien	ipx_pcbdisconnect(ipxp);
17389857Sobrien	soisdisconnected(so);
17489857Sobrien}
17589857Sobrien
17689857Sobrien/*
17789857Sobrien * Drop connection, reporting
17889857Sobrien * the specified error.
17989857Sobrien */
18089857Sobrienvoid
18189857Sobrienipx_drop(ipxp, errno)
18289857Sobrien	register struct ipxpcb *ipxp;
18389857Sobrien	int errno;
18489857Sobrien{
18589857Sobrien	struct socket *so = ipxp->ipxp_socket;
18689857Sobrien
18789857Sobrien	/*
18889857Sobrien	 * someday, in the IPX world
18989857Sobrien	 * we will generate error protocol packets
19089857Sobrien	 * announcing that the socket has gone away.
19189857Sobrien	 *
19289857Sobrien	 * XXX Probably never. IPX does not have error packets.
19389857Sobrien	 */
19489857Sobrien	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
19589857Sobrien		tp->t_state = TCPS_CLOSED;
19689857Sobrien		tcp_output(tp);
19789857Sobrien	}*/
19889857Sobrien	so->so_error = errno;
19989857Sobrien	ipx_pcbdisconnect(ipxp);
20089857Sobrien	soisdisconnected(so);
20189857Sobrien}
20289857Sobrien
20389857Sobrienstatic int
20489857Sobrienipx_output(ipxp, m0)
20589857Sobrien	struct ipxpcb *ipxp;
20689857Sobrien	struct mbuf *m0;
20789857Sobrien{
20889857Sobrien	register struct ipx *ipx;
20989857Sobrien	register struct socket *so;
21089857Sobrien	register int len = 0;
21189857Sobrien	register struct route *ro;
21289857Sobrien	struct mbuf *m;
21389857Sobrien	struct mbuf *mprev = NULL;
21489857Sobrien
21589857Sobrien	/*
21689857Sobrien	 * Calculate data length.
21789857Sobrien	 */
21889857Sobrien	for (m = m0; m != NULL; m = m->m_next) {
21989857Sobrien		mprev = m;
22089857Sobrien		len += m->m_len;
22189857Sobrien	}
22289857Sobrien	/*
22389857Sobrien	 * Make sure packet is actually of even length.
22489857Sobrien	 */
22589857Sobrien
22689857Sobrien	if (len & 1) {
22789857Sobrien		m = mprev;
22889857Sobrien		if ((m->m_flags & M_EXT) == 0 &&
22989857Sobrien			(m->m_len + m->m_data < &m->m_dat[MLEN])) {
23089857Sobrien			mtod(m, char*)[m->m_len++] = 0;
23189857Sobrien		} else {
23289857Sobrien			struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
23389857Sobrien
23489857Sobrien			if (m1 == NULL) {
23589857Sobrien				m_freem(m0);
23689857Sobrien				return (ENOBUFS);
23789857Sobrien			}
23889857Sobrien			m1->m_len = 1;
23989857Sobrien			* mtod(m1, char *) = 0;
24089857Sobrien			m->m_next = m1;
24189857Sobrien		}
24289857Sobrien		m0->m_pkthdr.len++;
24389857Sobrien	}
24489857Sobrien
24589857Sobrien	/*
24689857Sobrien	 * Fill in mbuf with extended IPX header
24789857Sobrien	 * and addresses and length put into network format.
24889857Sobrien	 */
24989857Sobrien	m = m0;
25089857Sobrien	if (ipxp->ipxp_flags & IPXP_RAWOUT) {
25189857Sobrien		ipx = mtod(m, struct ipx *);
25289857Sobrien	} else {
25389857Sobrien		M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT);
25489857Sobrien		if (m == NULL)
25589857Sobrien			return (ENOBUFS);
25689857Sobrien		ipx = mtod(m, struct ipx *);
25789857Sobrien		ipx->ipx_tc = 0;
25889857Sobrien		ipx->ipx_pt = ipxp->ipxp_dpt;
25989857Sobrien		ipx->ipx_sna = ipxp->ipxp_laddr;
26089857Sobrien		ipx->ipx_dna = ipxp->ipxp_faddr;
26189857Sobrien		len += sizeof(struct ipx);
26289857Sobrien	}
26389857Sobrien
26489857Sobrien	ipx->ipx_len = htons((u_short)len);
26589857Sobrien
26689857Sobrien	if (ipxp->ipxp_flags & IPXP_CHECKSUM) {
26789857Sobrien		ipx->ipx_sum = ipx_cksum(m, len);
26889857Sobrien	} else
26989857Sobrien		ipx->ipx_sum = 0xffff;
27089857Sobrien
27189857Sobrien	/*
27289857Sobrien	 * Output datagram.
27389857Sobrien	 */
27489857Sobrien	so = ipxp->ipxp_socket;
27589857Sobrien	if (so->so_options & SO_DONTROUTE)
27689857Sobrien		return (ipx_outputfl(m, (struct route *)NULL,
27789857Sobrien		    (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
27889857Sobrien	/*
27989857Sobrien	 * Use cached route for previous datagram if
28089857Sobrien	 * possible.  If the previous net was the same
28189857Sobrien	 * and the interface was a broadcast medium, or
28289857Sobrien	 * if the previous destination was identical,
28389857Sobrien	 * then we are ok.
28489857Sobrien	 *
28589857Sobrien	 * NB: We don't handle broadcasts because that
28689857Sobrien	 *     would require 3 subroutine calls.
28789857Sobrien	 */
28889857Sobrien	ro = &ipxp->ipxp_route;
28989857Sobrien#ifdef ancient_history
29089857Sobrien	/*
29189857Sobrien	 * I think that this will all be handled in ipx_pcbconnect!
29289857Sobrien	 */
29389857Sobrien	if (ro->ro_rt != NULL) {
29489857Sobrien		if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
29589857Sobrien			/*
29689857Sobrien			 * This assumes we have no GH type routes
29789857Sobrien			 */
29889857Sobrien			if (ro->ro_rt->rt_flags & RTF_HOST) {
29989857Sobrien				if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
30089857Sobrien					goto re_route;
30189857Sobrien
30289857Sobrien			}
30389857Sobrien			if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
30489857Sobrien				register struct ipx_addr *dst =
30589857Sobrien						&satoipx_addr(ro->ro_dst);
30689857Sobrien				dst->x_host = ipx->ipx_dna.x_host;
30789857Sobrien			}
30889857Sobrien			/*
30989857Sobrien			 * Otherwise, we go through the same gateway
31089857Sobrien			 * and dst is already set up.
31189857Sobrien			 */
31289857Sobrien		} else {
31389857Sobrien		re_route:
31489857Sobrien			RTFREE(ro->ro_rt);
31589857Sobrien			ro->ro_rt = NULL;
31689857Sobrien		}
31789857Sobrien	}
31889857Sobrien	ipxp->ipxp_lastdst = ipx->ipx_dna;
31989857Sobrien#endif /* ancient_history */
32089857Sobrien	return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
32189857Sobrien}
32289857Sobrien
32389857Sobrienint
32489857Sobrienipx_ctloutput(so, sopt)
32589857Sobrien	struct socket *so;
32689857Sobrien	struct sockopt *sopt;
32789857Sobrien{
32889857Sobrien	struct ipxpcb *ipxp = sotoipxpcb(so);
32989857Sobrien	int mask, error, optval;
33089857Sobrien	short soptval;
33189857Sobrien	struct ipx ioptval;
33289857Sobrien
33389857Sobrien	error = 0;
33489857Sobrien	if (ipxp == NULL)
33589857Sobrien		return (EINVAL);
33689857Sobrien
33789857Sobrien	switch (sopt->sopt_dir) {
33889857Sobrien	case SOPT_GET:
33989857Sobrien		switch (sopt->sopt_name) {
34089857Sobrien		case SO_ALL_PACKETS:
34189857Sobrien			mask = IPXP_ALL_PACKETS;
34289857Sobrien			goto get_flags;
34389857Sobrien
34489857Sobrien		case SO_HEADERS_ON_INPUT:
34589857Sobrien			mask = IPXP_RAWIN;
34689857Sobrien			goto get_flags;
34789857Sobrien
34889857Sobrien		case SO_IPX_CHECKSUM:
34989857Sobrien			mask = IPXP_CHECKSUM;
35089857Sobrien			goto get_flags;
35189857Sobrien
35289857Sobrien		case SO_HEADERS_ON_OUTPUT:
35389857Sobrien			mask = IPXP_RAWOUT;
35489857Sobrien		get_flags:
35589857Sobrien			soptval = ipxp->ipxp_flags & mask;
35689857Sobrien			error = sooptcopyout(sopt, &soptval, sizeof soptval);
35789857Sobrien			break;
35889857Sobrien
35989857Sobrien		case SO_DEFAULT_HEADERS:
36089857Sobrien			ioptval.ipx_len = 0;
36189857Sobrien			ioptval.ipx_sum = 0;
36289857Sobrien			ioptval.ipx_tc = 0;
36389857Sobrien			ioptval.ipx_pt = ipxp->ipxp_dpt;
36489857Sobrien			ioptval.ipx_dna = ipxp->ipxp_faddr;
36589857Sobrien			ioptval.ipx_sna = ipxp->ipxp_laddr;
36689857Sobrien			error = sooptcopyout(sopt, &soptval, sizeof soptval);
36789857Sobrien			break;
36889857Sobrien
36989857Sobrien		case SO_SEQNO:
37089857Sobrien			error = sooptcopyout(sopt, &ipx_pexseq,
37189857Sobrien					     sizeof ipx_pexseq);
37289857Sobrien			ipx_pexseq++;
37389857Sobrien			break;
37489857Sobrien
37589857Sobrien		default:
37689857Sobrien			error = EINVAL;
37789857Sobrien		}
37889857Sobrien		break;
37989857Sobrien
38089857Sobrien	case SOPT_SET:
38189857Sobrien		switch (sopt->sopt_name) {
38289857Sobrien		case SO_ALL_PACKETS:
38389857Sobrien			mask = IPXP_ALL_PACKETS;
38489857Sobrien			goto set_head;
38589857Sobrien
38689857Sobrien		case SO_HEADERS_ON_INPUT:
38789857Sobrien			mask = IPXP_RAWIN;
38889857Sobrien			goto set_head;
38989857Sobrien
39089857Sobrien		case SO_IPX_CHECKSUM:
39189857Sobrien			mask = IPXP_CHECKSUM;
39289857Sobrien
39389857Sobrien		case SO_HEADERS_ON_OUTPUT:
39489857Sobrien			mask = IPXP_RAWOUT;
39589857Sobrien		set_head:
39689857Sobrien			error = sooptcopyin(sopt, &optval, sizeof optval,
39789857Sobrien					    sizeof optval);
39889857Sobrien			if (error)
39989857Sobrien				break;
40089857Sobrien			if (optval)
40189857Sobrien				ipxp->ipxp_flags |= mask;
40289857Sobrien			else
40389857Sobrien				ipxp->ipxp_flags &= ~mask;
40489857Sobrien			break;
40589857Sobrien
40689857Sobrien		case SO_DEFAULT_HEADERS:
40789857Sobrien			error = sooptcopyin(sopt, &ioptval, sizeof ioptval,
40889857Sobrien					    sizeof ioptval);
40989857Sobrien			if (error)
41089857Sobrien				break;
41189857Sobrien			ipxp->ipxp_dpt = ioptval.ipx_pt;
41289857Sobrien			break;
41389857Sobrien#ifdef IPXIP
41489857Sobrien		case SO_IPXIP_ROUTE:
41589857Sobrien			error = ipxip_route(so, sopt);
41689857Sobrien			break;
41789857Sobrien#endif /* IPXIP */
41889857Sobrien		default:
41989857Sobrien			error = EINVAL;
42089857Sobrien		}
42189857Sobrien		break;
42289857Sobrien	}
42389857Sobrien	return (error);
42489857Sobrien}
42589857Sobrien
42689857Sobrienstatic int
42789857Sobrienipx_usr_abort(so)
42889857Sobrien	struct socket *so;
42989857Sobrien{
43089857Sobrien	int s;
43189857Sobrien	struct ipxpcb *ipxp = sotoipxpcb(so);
43289857Sobrien
43389857Sobrien	s = splnet();
43489857Sobrien	ipx_pcbdetach(ipxp);
43589857Sobrien	splx(s);
43689857Sobrien	soisdisconnected(so);
43789857Sobrien	ACCEPT_LOCK();
43889857Sobrien	SOCK_LOCK(so);
43989857Sobrien	sotryfree(so);
44089857Sobrien	return (0);
44189857Sobrien}
442218822Sdim
44389857Sobrienstatic int
44489857Sobrienipx_attach(so, proto, td)
44589857Sobrien	struct socket *so;
44689857Sobrien	int proto;
447218822Sdim	struct thread *td;
448218822Sdim{
44989857Sobrien	int error;
45089857Sobrien	int s;
45189857Sobrien	struct ipxpcb *ipxp = sotoipxpcb(so);
45289857Sobrien
45389857Sobrien	if (ipxp != NULL)
454218822Sdim		return (EINVAL);
45589857Sobrien	s = splnet();
45689857Sobrien	error = ipx_pcballoc(so, &ipxpcb_list, td);
45789857Sobrien	splx(s);
45889857Sobrien	if (error == 0)
45989857Sobrien		error = soreserve(so, ipxsendspace, ipxrecvspace);
46089857Sobrien	return (error);
46189857Sobrien}
462218822Sdim
463218822Sdimstatic int
464218822Sdimipx_bind(so, nam, td)
46589857Sobrien	struct socket *so;
46689857Sobrien	struct sockaddr *nam;
46789857Sobrien	struct thread *td;
46889857Sobrien{
469218822Sdim	struct ipxpcb *ipxp = sotoipxpcb(so);
470218822Sdim
471218822Sdim	return (ipx_pcbbind(ipxp, nam, td));
472218822Sdim}
47389857Sobrien
47489857Sobrienstatic int
47589857Sobrienipx_connect(so, nam, td)
47689857Sobrien	struct socket *so;
477218822Sdim	struct sockaddr *nam;
478218822Sdim	struct thread *td;
47989857Sobrien{
48089857Sobrien	int error;
48189857Sobrien	int s;
482218822Sdim	struct ipxpcb *ipxp = sotoipxpcb(so);
483218822Sdim
484218822Sdim	if (!ipx_nullhost(ipxp->ipxp_faddr))
48589857Sobrien		return (EISCONN);
48689857Sobrien	s = splnet();
48789857Sobrien	error = ipx_pcbconnect(ipxp, nam, td);
48889857Sobrien	splx(s);
48989857Sobrien	if (error == 0)
49089857Sobrien		soisconnected(so);
49189857Sobrien	return (error);
49289857Sobrien}
49389857Sobrien
49489857Sobrienstatic int
49589857Sobrienipx_detach(so)
49689857Sobrien	struct socket *so;
49789857Sobrien{
49889857Sobrien	int s;
499218822Sdim	struct ipxpcb *ipxp = sotoipxpcb(so);
500218822Sdim
501218822Sdim	if (ipxp == NULL)
502218822Sdim		return (ENOTCONN);
50389857Sobrien	s = splnet();
50489857Sobrien	ipx_pcbdetach(ipxp);
50589857Sobrien	splx(s);
50689857Sobrien	return (0);
507218822Sdim}
508218822Sdim
50989857Sobrienstatic int
51089857Sobrienipx_disconnect(so)
51189857Sobrien	struct socket *so;
51289857Sobrien{
51389857Sobrien	int s;
51489857Sobrien	struct ipxpcb *ipxp = sotoipxpcb(so);
51589857Sobrien
51689857Sobrien	if (ipx_nullhost(ipxp->ipxp_faddr))
51789857Sobrien		return (ENOTCONN);
51889857Sobrien	s = splnet();
51989857Sobrien	ipx_pcbdisconnect(ipxp);
52089857Sobrien	splx(s);
52189857Sobrien	soisdisconnected(so);
52289857Sobrien	return (0);
52389857Sobrien}
524104834Sobrien
525104834Sobrienint
526104834Sobrienipx_peeraddr(so, nam)
527104834Sobrien	struct socket *so;
528104834Sobrien	struct sockaddr **nam;
529104834Sobrien{
530104834Sobrien	struct ipxpcb *ipxp = sotoipxpcb(so);
531104834Sobrien
532104834Sobrien	ipx_setpeeraddr(ipxp, nam);
533104834Sobrien	return (0);
53489857Sobrien}
535218822Sdim
536218822Sdimstatic int
537218822Sdimipx_send(so, flags, m, nam, control, td)
53889857Sobrien	struct socket *so;
539218822Sdim	int flags;
540218822Sdim	struct mbuf *m;
541218822Sdim	struct sockaddr *nam;
542218822Sdim	struct mbuf *control;
543218822Sdim	struct thread *td;
544218822Sdim{
545218822Sdim	int error;
54689857Sobrien	struct ipxpcb *ipxp = sotoipxpcb(so);
547218822Sdim	struct ipx_addr laddr;
548218822Sdim	int s = 0;
54989857Sobrien
550218822Sdim	if (nam != NULL) {
55189857Sobrien		laddr = ipxp->ipxp_laddr;
55289857Sobrien		if (!ipx_nullhost(ipxp->ipxp_faddr)) {
55389857Sobrien			error = EISCONN;
55489857Sobrien			goto send_release;
55589857Sobrien		}
55689857Sobrien		/*
55789857Sobrien		 * Must block input while temporarily connected.
55889857Sobrien		 */
55989857Sobrien		s = splnet();
56089857Sobrien		error = ipx_pcbconnect(ipxp, nam, td);
56189857Sobrien		if (error) {
56289857Sobrien			splx(s);
56389857Sobrien			goto send_release;
56489857Sobrien		}
56589857Sobrien	} else {
566		if (ipx_nullhost(ipxp->ipxp_faddr)) {
567			error = ENOTCONN;
568			goto send_release;
569		}
570	}
571	error = ipx_output(ipxp, m);
572	m = NULL;
573	if (nam != NULL) {
574		ipx_pcbdisconnect(ipxp);
575		splx(s);
576		ipxp->ipxp_laddr = laddr;
577	}
578
579send_release:
580	if (m != NULL)
581		m_freem(m);
582	return (error);
583}
584
585static int
586ipx_shutdown(so)
587	struct socket *so;
588{
589	socantsendmore(so);
590	return (0);
591}
592
593int
594ipx_sockaddr(so, nam)
595	struct socket *so;
596	struct sockaddr **nam;
597{
598	struct ipxpcb *ipxp = sotoipxpcb(so);
599
600	ipx_setsockaddr(ipxp, nam);
601	return (0);
602}
603
604static int
605ripx_attach(so, proto, td)
606	struct socket *so;
607	int proto;
608	struct thread *td;
609{
610	int error = 0;
611	int s;
612	struct ipxpcb *ipxp = sotoipxpcb(so);
613
614	if (td != NULL && (error = suser(td)) != 0)
615		return (error);
616	s = splnet();
617	error = ipx_pcballoc(so, &ipxrawpcb_list, td);
618	splx(s);
619	if (error)
620		return (error);
621	error = soreserve(so, ipxsendspace, ipxrecvspace);
622	if (error)
623		return (error);
624	ipxp = sotoipxpcb(so);
625	ipxp->ipxp_faddr.x_host = ipx_broadhost;
626	ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
627	return (error);
628}
629