ipx_usrreq.c revision 116189
123599Smarkm/*
223599Smarkm * Copyright (c) 1995, Mike Mitchell
323599Smarkm * Copyright (c) 1984, 1985, 1986, 1987, 1993
423599Smarkm *	The Regents of the University of California.  All rights reserved.
523599Smarkm *
623599Smarkm * Redistribution and use in source and binary forms, with or without
723599Smarkm * modification, are permitted provided that the following conditions
823599Smarkm * are met:
923599Smarkm * 1. Redistributions of source code must retain the above copyright
1023599Smarkm *    notice, this list of conditions and the following disclaimer.
1123599Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1223599Smarkm *    notice, this list of conditions and the following disclaimer in the
1323599Smarkm *    documentation and/or other materials provided with the distribution.
1423599Smarkm * 3. All advertising materials mentioning features or use of this software
1523599Smarkm *    must display the following acknowledgement:
1623599Smarkm *	This product includes software developed by the University of
1723599Smarkm *	California, Berkeley and its contributors.
1823599Smarkm * 4. Neither the name of the University nor the names of its contributors
1923599Smarkm *    may be used to endorse or promote products derived from this software
2023599Smarkm *    without specific prior written permission.
2123599Smarkm *
2223599Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2323599Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2423599Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2523599Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2623599Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2723599Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2823599Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2923599Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3039838Ssos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3139838Ssos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3223599Smarkm * SUCH DAMAGE.
3323599Smarkm *
3423599Smarkm *	@(#)ipx_usrreq.c
3523599Smarkm */
3623599Smarkm
3723599Smarkm#include <sys/cdefs.h>
3823599Smarkm__FBSDID("$FreeBSD: head/sys/netipx/ipx_usrreq.c 116189 2003-06-11 05:37:42Z obrien $");
3923599Smarkm
4023599Smarkm#include "opt_ipx.h"
4135050Sahasty
4237611Sahasty#include <sys/param.h>
4337611Sahasty#include <sys/kernel.h>
4423599Smarkm#include <sys/lock.h>
4524246Sfsmp#include <sys/mbuf.h>
4624246Sfsmp#include <sys/protosw.h>
4724246Sfsmp#include <sys/signalvar.h>
4824246Sfsmp#include <sys/socket.h>
4924246Sfsmp#include <sys/socketvar.h>
5024246Sfsmp#include <sys/sx.h>
5124246Sfsmp#include <sys/sysctl.h>
5224246Sfsmp#include <sys/systm.h>
5324246Sfsmp
5423599Smarkm#include <net/if.h>
5524246Sfsmp#include <net/route.h>
5624246Sfsmp
5724528Sfsmp#include <netinet/in.h>
5824528Sfsmp
5924528Sfsmp#include <netipx/ipx.h>
6024528Sfsmp#include <netipx/ipx_if.h>
6124528Sfsmp#include <netipx/ipx_ip.h>
6238707Ssos#include <netipx/ipx_pcb.h>
6324528Sfsmp#include <netipx/ipx_var.h>
6424528Sfsmp
6524246Sfsmp/*
6624528Sfsmp * IPX protocol implementation.
6724528Sfsmp */
6824528Sfsmp
6924528Sfsmpstatic int ipxsendspace = IPXSNDQ;
7037611SahastySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW,
7124528Sfsmp            &ipxsendspace, 0, "");
7224528Sfsmpstatic int ipxrecvspace = IPXRCVQ;
7324528SfsmpSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
7424528Sfsmp            &ipxrecvspace, 0, "");
7524528Sfsmp
7624528Sfsmpstatic	int ipx_usr_abort(struct socket *so);
7724246Sfsmpstatic	int ipx_attach(struct socket *so, int proto, struct thread *td);
7824246Sfsmpstatic	int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
7924246Sfsmpstatic	int ipx_connect(struct socket *so, struct sockaddr *nam,
8024246Sfsmp			struct thread *td);
8124246Sfsmpstatic	int ipx_detach(struct socket *so);
8224246Sfsmpstatic	int ipx_disconnect(struct socket *so);
8324246Sfsmpstatic	int ipx_send(struct socket *so, int flags, struct mbuf *m,
8424246Sfsmp		     struct sockaddr *addr, struct mbuf *control,
8524246Sfsmp		     struct thread *td);
8624246Sfsmpstatic	int ipx_shutdown(struct socket *so);
8724528Sfsmpstatic	int ripx_attach(struct socket *so, int proto, struct thread *td);
8824528Sfsmpstatic	int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0);
8924528Sfsmp
9024528Sfsmpstruct	pr_usrreqs ipx_usrreqs = {
9124528Sfsmp	ipx_usr_abort, pru_accept_notsupp, ipx_attach, ipx_bind,
9224528Sfsmp	ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach,
9324528Sfsmp	ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp,
9424528Sfsmp	pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown,
9524246Sfsmp	ipx_sockaddr, sosend, soreceive, sopoll
9624246Sfsmp};
9724246Sfsmp
9824246Sfsmpstruct	pr_usrreqs ripx_usrreqs = {
9924246Sfsmp	ipx_usr_abort, pru_accept_notsupp, ripx_attach, ipx_bind,
10024528Sfsmp	ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach,
10124528Sfsmp	ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp,
10224528Sfsmp	pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown,
10324528Sfsmp	ipx_sockaddr, sosend, soreceive, sopoll
10424528Sfsmp};
10524528Sfsmp
10624528Sfsmp/*
10724528Sfsmp *  This may also be called for raw listeners.
10824528Sfsmp */
10924246Sfsmpvoid
11024246Sfsmpipx_input(m, ipxp)
11124246Sfsmp	struct mbuf *m;
11224246Sfsmp	register struct ipxpcb *ipxp;
11324246Sfsmp{
11424246Sfsmp	register struct ipx *ipx = mtod(m, struct ipx *);
11524246Sfsmp	struct ifnet *ifp = m->m_pkthdr.rcvif;
11624246Sfsmp	struct sockaddr_ipx ipx_ipx;
11724246Sfsmp
11824246Sfsmp	if (ipxp == NULL)
11924528Sfsmp		panic("No ipxpcb");
12024528Sfsmp	/*
12124528Sfsmp	 * Construct sockaddr format source address.
12224528Sfsmp	 * Stuff source address and datagram in user buffer.
12324528Sfsmp	 */
12424528Sfsmp	ipx_ipx.sipx_len = sizeof(ipx_ipx);
12524528Sfsmp	ipx_ipx.sipx_family = AF_IPX;
12624246Sfsmp	ipx_ipx.sipx_addr = ipx->ipx_sna;
12724246Sfsmp	ipx_ipx.sipx_zero[0] = '\0';
12824246Sfsmp	ipx_ipx.sipx_zero[1] = '\0';
12924246Sfsmp	if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) {
13024246Sfsmp		register struct ifaddr *ifa;
13138707Ssos
13238707Ssos		for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL;
13338707Ssos		     ifa = TAILQ_NEXT(ifa, ifa_link)) {
13438707Ssos			if (ifa->ifa_addr->sa_family == AF_IPX) {
13538707Ssos				ipx_ipx.sipx_addr.x_net =
13638707Ssos					IA_SIPX(ifa)->sipx_addr.x_net;
13738707Ssos				break;
13838707Ssos			}
13924246Sfsmp		}
14024246Sfsmp	}
14124246Sfsmp	ipxp->ipxp_rpt = ipx->ipx_pt;
14224246Sfsmp	if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) {
14324246Sfsmp		m->m_len -= sizeof(struct ipx);
14424246Sfsmp		m->m_pkthdr.len -= sizeof(struct ipx);
14524246Sfsmp		m->m_data += sizeof(struct ipx);
14624246Sfsmp	}
14724246Sfsmp	if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx,
14824528Sfsmp	    m, (struct mbuf *)NULL) == 0)
14924528Sfsmp		goto bad;
15024528Sfsmp	sorwakeup(ipxp->ipxp_socket);
15124528Sfsmp	return;
15224528Sfsmpbad:
15324528Sfsmp	m_freem(m);
15424528Sfsmp}
15524528Sfsmp
15624246Sfsmpvoid
15724246Sfsmpipx_abort(ipxp)
15824528Sfsmp	struct ipxpcb *ipxp;
15924528Sfsmp{
16024528Sfsmp	struct socket *so = ipxp->ipxp_socket;
16124528Sfsmp
16238707Ssos	ipx_pcbdisconnect(ipxp);
16338707Ssos	soisdisconnected(so);
16438707Ssos}
16538707Ssos
16624528Sfsmp/*
16724246Sfsmp * Drop connection, reporting
16824246Sfsmp * the specified error.
16924246Sfsmp */
17024246Sfsmpvoid
17124246Sfsmpipx_drop(ipxp, errno)
17225329Sfsmp	register struct ipxpcb *ipxp;
17324528Sfsmp	int errno;
17424528Sfsmp{
17524528Sfsmp	struct socket *so = ipxp->ipxp_socket;
17624528Sfsmp
17725329Sfsmp	/*
17825329Sfsmp	 * someday, in the IPX world
17925329Sfsmp	 * we will generate error protocol packets
18025329Sfsmp	 * announcing that the socket has gone away.
18125329Sfsmp	 *
18224246Sfsmp	 * XXX Probably never. IPX does not have error packets.
18324528Sfsmp	 */
18424528Sfsmp	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
18524528Sfsmp		tp->t_state = TCPS_CLOSED;
18624528Sfsmp		tcp_output(tp);
18724528Sfsmp	}*/
18824246Sfsmp	so->so_error = errno;
18924246Sfsmp	ipx_pcbdisconnect(ipxp);
19024246Sfsmp	soisdisconnected(so);
19124246Sfsmp}
19238707Ssos
19338707Ssosstatic int
19438707Ssosipx_output(ipxp, m0)
19538707Ssos	struct ipxpcb *ipxp;
19638707Ssos	struct mbuf *m0;
19738707Ssos{
19824246Sfsmp	register struct ipx *ipx;
19924246Sfsmp	register struct socket *so;
20024528Sfsmp	register int len = 0;
20124528Sfsmp	register struct route *ro;
20224528Sfsmp	struct mbuf *m;
20324528Sfsmp	struct mbuf *mprev = NULL;
20424528Sfsmp
20524528Sfsmp	/*
20624528Sfsmp	 * Calculate data length.
20724528Sfsmp	 */
20824528Sfsmp	for (m = m0; m != NULL; m = m->m_next) {
20924528Sfsmp		mprev = m;
21024528Sfsmp		len += m->m_len;
21124528Sfsmp	}
21224528Sfsmp	/*
21324528Sfsmp	 * Make sure packet is actually of even length.
21424528Sfsmp	 */
21524528Sfsmp
21624528Sfsmp	if (len & 1) {
21724528Sfsmp		m = mprev;
21824528Sfsmp		if ((m->m_flags & M_EXT) == 0 &&
21924528Sfsmp			(m->m_len + m->m_data < &m->m_dat[MLEN])) {
22024528Sfsmp			mtod(m, char*)[m->m_len++] = 0;
22124528Sfsmp		} else {
22224528Sfsmp			struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
22324528Sfsmp
22424246Sfsmp			if (m1 == NULL) {
22524246Sfsmp				m_freem(m0);
22629233Smarkm				return (ENOBUFS);
22729233Smarkm			}
22829233Smarkm			m1->m_len = 1;
22929233Smarkm			* mtod(m1, char *) = 0;
23029233Smarkm			m->m_next = m1;
23129233Smarkm		}
23229233Smarkm		m0->m_pkthdr.len++;
23329233Smarkm	}
23429233Smarkm
23529233Smarkm	/*
23629233Smarkm	 * Fill in mbuf with extended IPX header
23729233Smarkm	 * and addresses and length put into network format.
23824528Sfsmp	 */
23924528Sfsmp	m = m0;
24024246Sfsmp	if (ipxp->ipxp_flags & IPXP_RAWOUT) {
24124528Sfsmp		ipx = mtod(m, struct ipx *);
24224528Sfsmp	} else {
24324528Sfsmp		M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT);
24424528Sfsmp		if (m == NULL)
24524528Sfsmp			return (ENOBUFS);
24624246Sfsmp		ipx = mtod(m, struct ipx *);
24724246Sfsmp		ipx->ipx_tc = 0;
24824246Sfsmp		ipx->ipx_pt = ipxp->ipxp_dpt;
24924246Sfsmp		ipx->ipx_sna = ipxp->ipxp_laddr;
25024246Sfsmp		ipx->ipx_dna = ipxp->ipxp_faddr;
25124246Sfsmp		len += sizeof(struct ipx);
25224246Sfsmp	}
25323599Smarkm
25424528Sfsmp	ipx->ipx_len = htons((u_short)len);
25524246Sfsmp
25624246Sfsmp	if (ipxp->ipxp_flags & IPXP_CHECKSUM) {
25724528Sfsmp		ipx->ipx_sum = ipx_cksum(m, len);
25824528Sfsmp	} else
25924528Sfsmp		ipx->ipx_sum = 0xffff;
26024087Sfsmp
26124087Sfsmp	/*
26224087Sfsmp	 * Output datagram.
26324087Sfsmp	 */
26424087Sfsmp	so = ipxp->ipxp_socket;
26524087Sfsmp	if (so->so_options & SO_DONTROUTE)
26624087Sfsmp		return (ipx_outputfl(m, (struct route *)NULL,
26724087Sfsmp		    (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
26824087Sfsmp	/*
26924087Sfsmp	 * Use cached route for previous datagram if
27024087Sfsmp	 * possible.  If the previous net was the same
27124087Sfsmp	 * and the interface was a broadcast medium, or
27224087Sfsmp	 * if the previous destination was identical,
27324087Sfsmp	 * then we are ok.
27424087Sfsmp	 *
27524087Sfsmp	 * NB: We don't handle broadcasts because that
27624087Sfsmp	 *     would require 3 subroutine calls.
27724087Sfsmp	 */
27824087Sfsmp	ro = &ipxp->ipxp_route;
27924087Sfsmp#ifdef ancient_history
28024087Sfsmp	/*
28124087Sfsmp	 * I think that this will all be handled in ipx_pcbconnect!
28224087Sfsmp	 */
28324087Sfsmp	if (ro->ro_rt != NULL) {
28424087Sfsmp		if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
28524087Sfsmp			/*
28624087Sfsmp			 * This assumes we have no GH type routes
28724087Sfsmp			 */
28824087Sfsmp			if (ro->ro_rt->rt_flags & RTF_HOST) {
28924087Sfsmp				if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
29024087Sfsmp					goto re_route;
29124087Sfsmp
29224087Sfsmp			}
29324087Sfsmp			if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
29424087Sfsmp				register struct ipx_addr *dst =
29524087Sfsmp						&satoipx_addr(ro->ro_dst);
29624087Sfsmp				dst->x_host = ipx->ipx_dna.x_host;
29724087Sfsmp			}
29824087Sfsmp			/*
29924087Sfsmp			 * Otherwise, we go through the same gateway
30024087Sfsmp			 * and dst is already set up.
30124087Sfsmp			 */
30224087Sfsmp		} else {
30324087Sfsmp		re_route:
30424087Sfsmp			RTFREE(ro->ro_rt);
30524087Sfsmp			ro->ro_rt = NULL;
30624087Sfsmp		}
30724087Sfsmp	}
30824087Sfsmp	ipxp->ipxp_lastdst = ipx->ipx_dna;
30924087Sfsmp#endif /* ancient_history */
31024087Sfsmp	return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
31124087Sfsmp}
31223599Smarkm
31324528Sfsmpint
31423599Smarkmipx_ctloutput(so, sopt)
31523599Smarkm	struct socket *so;
31623599Smarkm	struct sockopt *sopt;
31723599Smarkm{
31824528Sfsmp	struct ipxpcb *ipxp = sotoipxpcb(so);
31924528Sfsmp	int mask, error, optval;
32024246Sfsmp	short soptval;
32124528Sfsmp	struct ipx ioptval;
32224528Sfsmp
32324528Sfsmp	error = 0;
32424528Sfsmp	if (ipxp == NULL)
32524528Sfsmp		return (EINVAL);
32633850Sahasty
32723599Smarkm	switch (sopt->sopt_dir) {
32823599Smarkm	case SOPT_GET:
32924528Sfsmp		switch (sopt->sopt_name) {
33024528Sfsmp		case SO_ALL_PACKETS:
33124528Sfsmp			mask = IPXP_ALL_PACKETS;
33224528Sfsmp			goto get_flags;
33333025Sahasty
33424528Sfsmp		case SO_HEADERS_ON_INPUT:
33533025Sahasty			mask = IPXP_RAWIN;
33633025Sahasty			goto get_flags;
33733025Sahasty
33833025Sahasty		case SO_IPX_CHECKSUM:
33933025Sahasty			mask = IPXP_CHECKSUM;
34024528Sfsmp			goto get_flags;
34124528Sfsmp
34224528Sfsmp		case SO_HEADERS_ON_OUTPUT:
34324246Sfsmp			mask = IPXP_RAWOUT;
34424246Sfsmp		get_flags:
34539041Ssos			soptval = ipxp->ipxp_flags & mask;
34624528Sfsmp			error = sooptcopyout(sopt, &soptval, sizeof soptval);
34739838Ssos			break;
34839838Ssos
34930856Seivind		case SO_DEFAULT_HEADERS:
35030856Seivind			ioptval.ipx_len = 0;
35124528Sfsmp			ioptval.ipx_sum = 0;
35224528Sfsmp			ioptval.ipx_tc = 0;
35324528Sfsmp			ioptval.ipx_pt = ipxp->ipxp_dpt;
35424528Sfsmp			ioptval.ipx_dna = ipxp->ipxp_faddr;
35524246Sfsmp			ioptval.ipx_sna = ipxp->ipxp_laddr;
35623599Smarkm			error = sooptcopyout(sopt, &soptval, sizeof soptval);
35724528Sfsmp			break;
35824528Sfsmp
35924528Sfsmp		case SO_SEQNO:
36024528Sfsmp			error = sooptcopyout(sopt, &ipx_pexseq,
36124528Sfsmp					     sizeof ipx_pexseq);
36238706Ssos			ipx_pexseq++;
36338706Ssos			break;
36438706Ssos
36529233Smarkm		default:
36638706Ssos			error = EINVAL;
36730856Seivind		}
36838706Ssos		break;
36930856Seivind
37024528Sfsmp	case SOPT_SET:
37124528Sfsmp		switch (sopt->sopt_name) {
37225329Sfsmp		case SO_ALL_PACKETS:
37325329Sfsmp			mask = IPXP_ALL_PACKETS;
37423599Smarkm			goto set_head;
37523599Smarkm
37623599Smarkm		case SO_HEADERS_ON_INPUT:
37724528Sfsmp			mask = IPXP_RAWIN;
37829233Smarkm			goto set_head;
37929233Smarkm
38029233Smarkm		case SO_IPX_CHECKSUM:
38129233Smarkm			mask = IPXP_CHECKSUM;
38229233Smarkm
38329233Smarkm		case SO_HEADERS_ON_OUTPUT:
38424528Sfsmp			mask = IPXP_RAWOUT;
38524246Sfsmp		set_head:
38623599Smarkm			error = sooptcopyin(sopt, &optval, sizeof optval,
38723599Smarkm					    sizeof optval);
38823599Smarkm			if (error)
38923599Smarkm				break;
39023599Smarkm			if (optval)
39136090Sahasty				ipxp->ipxp_flags |= mask;
39223599Smarkm			else
39323599Smarkm				ipxp->ipxp_flags &= ~mask;
39423599Smarkm			break;
39523599Smarkm
39623599Smarkm		case SO_DEFAULT_HEADERS:
39723599Smarkm			error = sooptcopyin(sopt, &ioptval, sizeof ioptval,
39823599Smarkm					    sizeof ioptval);
39923599Smarkm			if (error)
40023599Smarkm				break;
40123599Smarkm			ipxp->ipxp_dpt = ioptval.ipx_pt;
40223599Smarkm			break;
40338706Ssos#ifdef IPXIP
40438706Ssos		case SO_IPXIP_ROUTE:
40538706Ssos			error = ipxip_route(so, sopt);
40638706Ssos			break;
40738706Ssos#endif /* IPXIP */
40825329Sfsmp		default:
40925329Sfsmp			error = EINVAL;
41023599Smarkm		}
41123599Smarkm		break;
41223599Smarkm	}
41323599Smarkm	return (error);
41423599Smarkm}
41523599Smarkm
41623599Smarkmstatic int
41723599Smarkmipx_usr_abort(so)
41823599Smarkm	struct socket *so;
41923599Smarkm{
42023935Sfsmp	int s;
42129233Smarkm	struct ipxpcb *ipxp = sotoipxpcb(so);
42223599Smarkm
42323599Smarkm	s = splnet();
42423599Smarkm	ipx_pcbdetach(ipxp);
42523599Smarkm	splx(s);
42623599Smarkm	sotryfree(so);
42723599Smarkm	soisdisconnected(so);
42823599Smarkm	return (0);
42923599Smarkm}
43023599Smarkm
43123599Smarkmstatic int
43223599Smarkmipx_attach(so, proto, td)
43323599Smarkm	struct socket *so;
43439041Ssos	int proto;
43539041Ssos	struct thread *td;
43639041Ssos{
43723599Smarkm	int error;
43823599Smarkm	int s;
43923599Smarkm	struct ipxpcb *ipxp = sotoipxpcb(so);
44023599Smarkm
44123599Smarkm	if (ipxp != NULL)
44223599Smarkm		return (EINVAL);
44323599Smarkm	s = splnet();
44423599Smarkm	error = ipx_pcballoc(so, &ipxpcb, td);
44523599Smarkm	splx(s);
44623599Smarkm	if (error == 0)
44723599Smarkm		error = soreserve(so, ipxsendspace, ipxrecvspace);
44823599Smarkm	return (error);
44923599Smarkm}
45023599Smarkm
45123599Smarkmstatic int
45223599Smarkmipx_bind(so, nam, td)
45323599Smarkm	struct socket *so;
45423599Smarkm	struct sockaddr *nam;
45523599Smarkm	struct thread *td;
45623599Smarkm{
45723599Smarkm	struct ipxpcb *ipxp = sotoipxpcb(so);
45823599Smarkm
45923599Smarkm	return (ipx_pcbbind(ipxp, nam, td));
46023599Smarkm}
46124528Sfsmp
46224528Sfsmpstatic int
46324528Sfsmpipx_connect(so, nam, td)
46423599Smarkm	struct socket *so;
46523599Smarkm	struct sockaddr *nam;
46624246Sfsmp	struct thread *td;
46724528Sfsmp{
46824528Sfsmp	int error;
46924528Sfsmp	int s;
47024528Sfsmp	struct ipxpcb *ipxp = sotoipxpcb(so);
47125329Sfsmp
47225329Sfsmp	if (!ipx_nullhost(ipxp->ipxp_faddr))
47325329Sfsmp		return (EISCONN);
47425329Sfsmp	s = splnet();
47525329Sfsmp	error = ipx_pcbconnect(ipxp, nam, td);
47625329Sfsmp	splx(s);
47725329Sfsmp	if (error == 0)
47825329Sfsmp		soisconnected(so);
47925329Sfsmp	return (error);
48025329Sfsmp}
48125329Sfsmp
48236090Sahastystatic int
48336090Sahastyipx_detach(so)
48436090Sahasty	struct socket *so;
48537611Sahasty{
48639841Ssos	int s;
48739841Ssos	struct ipxpcb *ipxp = sotoipxpcb(so);
48839841Ssos
48924528Sfsmp	if (ipxp == NULL)
49023599Smarkm		return (ENOTCONN);
49124528Sfsmp	s = splnet();
49224528Sfsmp	ipx_pcbdetach(ipxp);
49336090Sahasty	splx(s);
49436090Sahasty	return (0);
49536090Sahasty}
49636090Sahasty
49736090Sahastystatic int
49836090Sahastyipx_disconnect(so)
49936090Sahasty	struct socket *so;
50036090Sahasty{
501	int s;
502	struct ipxpcb *ipxp = sotoipxpcb(so);
503
504	if (ipx_nullhost(ipxp->ipxp_faddr))
505		return (ENOTCONN);
506	s = splnet();
507	ipx_pcbdisconnect(ipxp);
508	splx(s);
509	soisdisconnected(so);
510	return (0);
511}
512
513int
514ipx_peeraddr(so, nam)
515	struct socket *so;
516	struct sockaddr **nam;
517{
518	struct ipxpcb *ipxp = sotoipxpcb(so);
519
520	ipx_setpeeraddr(ipxp, nam); /* XXX what if alloc fails? */
521	return (0);
522}
523
524static int
525ipx_send(so, flags, m, nam, control, td)
526	struct socket *so;
527	int flags;
528	struct mbuf *m;
529	struct sockaddr *nam;
530	struct mbuf *control;
531	struct thread *td;
532{
533	int error;
534	struct ipxpcb *ipxp = sotoipxpcb(so);
535	struct ipx_addr laddr;
536	int s = 0;
537
538	if (nam != NULL) {
539		laddr = ipxp->ipxp_laddr;
540		if (!ipx_nullhost(ipxp->ipxp_faddr)) {
541			error = EISCONN;
542			goto send_release;
543		}
544		/*
545		 * Must block input while temporarily connected.
546		 */
547		s = splnet();
548		error = ipx_pcbconnect(ipxp, nam, td);
549		if (error) {
550			splx(s);
551			goto send_release;
552		}
553	} else {
554		if (ipx_nullhost(ipxp->ipxp_faddr)) {
555			error = ENOTCONN;
556			goto send_release;
557		}
558	}
559	error = ipx_output(ipxp, m);
560	m = NULL;
561	if (nam != NULL) {
562		ipx_pcbdisconnect(ipxp);
563		splx(s);
564		ipxp->ipxp_laddr = laddr;
565	}
566
567send_release:
568	if (m != NULL)
569		m_freem(m);
570	return (error);
571}
572
573static int
574ipx_shutdown(so)
575	struct socket *so;
576{
577	socantsendmore(so);
578	return (0);
579}
580
581int
582ipx_sockaddr(so, nam)
583	struct socket *so;
584	struct sockaddr **nam;
585{
586	struct ipxpcb *ipxp = sotoipxpcb(so);
587
588	ipx_setsockaddr(ipxp, nam); /* XXX what if alloc fails? */
589	return (0);
590}
591
592static int
593ripx_attach(so, proto, td)
594	struct socket *so;
595	int proto;
596	struct thread *td;
597{
598	int error = 0;
599	int s;
600	struct ipxpcb *ipxp = sotoipxpcb(so);
601
602	if (td != NULL && (error = suser(td)) != 0)
603		return (error);
604	s = splnet();
605	error = ipx_pcballoc(so, &ipxrawpcb, td);
606	splx(s);
607	if (error)
608		return (error);
609	error = soreserve(so, ipxsendspace, ipxrecvspace);
610	if (error)
611		return (error);
612	ipxp = sotoipxpcb(so);
613	ipxp->ipxp_faddr.x_host = ipx_broadhost;
614	ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
615	return (error);
616}
617