ipx_usrreq.c revision 139444
1184610Salfred/*
2184610Salfred * Copyright (c) 2004, Robert N. M. Watson
3184610Salfred * Copyright (c) 1995, Mike Mitchell
4184610Salfred * Copyright (c) 1984, 1985, 1986, 1987, 1993
5184610Salfred *	The Regents of the University of California.  All rights reserved.
6184610Salfred *
7184610Salfred * Redistribution and use in source and binary forms, with or without
8184610Salfred * modification, are permitted provided that the following conditions
9184610Salfred * are met:
10184610Salfred * 1. Redistributions of source code must retain the above copyright
11184610Salfred *    notice, this list of conditions and the following disclaimer.
12184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
13184610Salfred *    notice, this list of conditions and the following disclaimer in the
14184610Salfred *    documentation and/or other materials provided with the distribution.
15184610Salfred * 3. All advertising materials mentioning features or use of this software
16184610Salfred *    must display the following acknowledgement:
17184610Salfred *	This product includes software developed by the University of
18184610Salfred *	California, Berkeley and its contributors.
19184610Salfred * 4. Neither the name of the University nor the names of its contributors
20184610Salfred *    may be used to endorse or promote products derived from this software
21184610Salfred *    without specific prior written permission.
22184610Salfred *
23184610Salfred * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33184610Salfred * SUCH DAMAGE.
34184610Salfred *
35184610Salfred *	@(#)ipx_usrreq.c
36184610Salfred */
37184610Salfred
38184610Salfred#include <sys/cdefs.h>
39184610Salfred__FBSDID("$FreeBSD: head/sys/netipx/ipx_usrreq.c 139444 2004-12-30 17:49:40Z rwatson $");
40184610Salfred
41184610Salfred#include "opt_ipx.h"
42184610Salfred
43184610Salfred#include <sys/param.h>
44184610Salfred#include <sys/kernel.h>
45184610Salfred#include <sys/lock.h>
46184610Salfred#include <sys/mbuf.h>
47184610Salfred#include <sys/protosw.h>
48184610Salfred#include <sys/signalvar.h>
49184610Salfred#include <sys/socket.h>
50184610Salfred#include <sys/socketvar.h>
51194677Sthompsa#include <sys/sx.h>
52194677Sthompsa#include <sys/sysctl.h>
53194677Sthompsa#include <sys/systm.h>
54194677Sthompsa
55194677Sthompsa#include <net/if.h>
56194677Sthompsa#include <net/route.h>
57194677Sthompsa
58194677Sthompsa#include <netinet/in.h>
59194677Sthompsa
60194677Sthompsa#include <netipx/ipx.h>
61194677Sthompsa#include <netipx/ipx_if.h>
62194677Sthompsa#include <netipx/ipx_ip.h>
63194677Sthompsa#include <netipx/ipx_pcb.h>
64194677Sthompsa#include <netipx/ipx_var.h>
65194677Sthompsa
66194677Sthompsa/*
67194677Sthompsa * IPX protocol implementation.
68194677Sthompsa */
69194677Sthompsa
70194677Sthompsastatic int ipxsendspace = IPXSNDQ;
71188942SthompsaSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW,
72194677Sthompsa            &ipxsendspace, 0, "");
73184610Salfredstatic int ipxrecvspace = IPXRCVQ;
74188942SthompsaSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
75188942Sthompsa            &ipxrecvspace, 0, "");
76188942Sthompsa
77188942Sthompsastatic	int ipx_usr_abort(struct socket *so);
78188942Sthompsastatic	int ipx_attach(struct socket *so, int proto, struct thread *td);
79184610Salfredstatic	int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
80188942Sthompsastatic	int ipx_connect(struct socket *so, struct sockaddr *nam,
81188942Sthompsa			struct thread *td);
82188942Sthompsastatic	int ipx_detach(struct socket *so);
83188942Sthompsastatic	int ipx_disconnect(struct socket *so);
84198151Sthompsastatic	int ipx_send(struct socket *so, int flags, struct mbuf *m,
85184610Salfred		     struct sockaddr *addr, struct mbuf *control,
86184610Salfred		     struct thread *td);
87184610Salfredstatic	int ipx_shutdown(struct socket *so);
88184610Salfredstatic	int ripx_attach(struct socket *so, int proto, struct thread *td);
89184610Salfredstatic	int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0);
90184610Salfred
91184610Salfredstruct	pr_usrreqs ipx_usrreqs = {
92184610Salfred	.pru_abort =		ipx_usr_abort,
93184610Salfred	.pru_attach =		ipx_attach,
94184610Salfred	.pru_bind =		ipx_bind,
95184610Salfred	.pru_connect =		ipx_connect,
96184610Salfred	.pru_control =		ipx_control,
97184610Salfred	.pru_detach =		ipx_detach,
98184610Salfred	.pru_disconnect =	ipx_disconnect,
99184610Salfred	.pru_peeraddr =		ipx_peeraddr,
100184610Salfred	.pru_send =		ipx_send,
101184610Salfred	.pru_shutdown =		ipx_shutdown,
102184610Salfred	.pru_sockaddr =		ipx_sockaddr,
103184610Salfred};
104184610Salfred
105184610Salfredstruct	pr_usrreqs ripx_usrreqs = {
106184610Salfred	.pru_abort =		ipx_usr_abort,
107184610Salfred	.pru_attach =		ripx_attach,
108184610Salfred	.pru_bind =		ipx_bind,
109184610Salfred	.pru_connect =		ipx_connect,
110184610Salfred	.pru_control =		ipx_control,
111184610Salfred	.pru_detach =		ipx_detach,
112184610Salfred	.pru_disconnect =	ipx_disconnect,
113184610Salfred	.pru_peeraddr =		ipx_peeraddr,
114184610Salfred	.pru_send =		ipx_send,
115184610Salfred	.pru_shutdown =		ipx_shutdown,
116184610Salfred	.pru_sockaddr =		ipx_sockaddr,
117184610Salfred};
118198501Sthompsa
119198501Sthompsa/*
120184610Salfred *  This may also be called for raw listeners.
121184610Salfred */
122184610Salfredvoid
123184610Salfredipx_input(m, ipxp)
124184610Salfred	struct mbuf *m;
125184610Salfred	register struct ipxpcb *ipxp;
126184610Salfred{
127184610Salfred	register struct ipx *ipx = mtod(m, struct ipx *);
128184610Salfred	struct ifnet *ifp = m->m_pkthdr.rcvif;
129184610Salfred	struct sockaddr_ipx ipx_ipx;
130184610Salfred
131184610Salfred	if (ipxp == NULL)
132184610Salfred		panic("No ipxpcb");
133184610Salfred	/*
134184610Salfred	 * Construct sockaddr format source address.
135184610Salfred	 * Stuff source address and datagram in user buffer.
136184610Salfred	 */
137184610Salfred	ipx_ipx.sipx_len = sizeof(ipx_ipx);
138184610Salfred	ipx_ipx.sipx_family = AF_IPX;
139184610Salfred	ipx_ipx.sipx_addr = ipx->ipx_sna;
140184610Salfred	ipx_ipx.sipx_zero[0] = '\0';
141184610Salfred	ipx_ipx.sipx_zero[1] = '\0';
142184610Salfred	if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) {
143184610Salfred		register struct ifaddr *ifa;
144184610Salfred
145184610Salfred		for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL;
146184610Salfred		     ifa = TAILQ_NEXT(ifa, ifa_link)) {
147184610Salfred			if (ifa->ifa_addr->sa_family == AF_IPX) {
148184610Salfred				ipx_ipx.sipx_addr.x_net =
149184610Salfred					IA_SIPX(ifa)->sipx_addr.x_net;
150184610Salfred				break;
151184610Salfred			}
152184610Salfred		}
153184610Salfred	}
154184610Salfred	ipxp->ipxp_rpt = ipx->ipx_pt;
155184610Salfred	if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) {
156184610Salfred		m->m_len -= sizeof(struct ipx);
157184610Salfred		m->m_pkthdr.len -= sizeof(struct ipx);
158184610Salfred		m->m_data += sizeof(struct ipx);
159184610Salfred	}
160184610Salfred	if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx,
161184610Salfred	    m, (struct mbuf *)NULL) == 0)
162184610Salfred		goto bad;
163184610Salfred	sorwakeup(ipxp->ipxp_socket);
164184610Salfred	return;
165184610Salfredbad:
166184610Salfred	m_freem(m);
167184610Salfred}
168184610Salfred
169184610Salfredvoid
170184610Salfredipx_abort(ipxp)
171184610Salfred	struct ipxpcb *ipxp;
172184610Salfred{
173184610Salfred	struct socket *so = ipxp->ipxp_socket;
174184610Salfred
175184610Salfred	ipx_pcbdisconnect(ipxp);
176184610Salfred	soisdisconnected(so);
177184610Salfred}
178184610Salfred
179184610Salfred/*
180184610Salfred * Drop connection, reporting
181184610Salfred * the specified error.
182184610Salfred */
183184610Salfredvoid
184184610Salfredipx_drop(ipxp, errno)
185184610Salfred	register struct ipxpcb *ipxp;
186184610Salfred	int errno;
187184610Salfred{
188184610Salfred	struct socket *so = ipxp->ipxp_socket;
189184610Salfred
190184610Salfred	/*
191184610Salfred	 * someday, in the IPX world
192184610Salfred	 * we will generate error protocol packets
193184610Salfred	 * announcing that the socket has gone away.
194184610Salfred	 *
195184610Salfred	 * XXX Probably never. IPX does not have error packets.
196184610Salfred	 */
197184610Salfred	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
198184610Salfred		tp->t_state = TCPS_CLOSED;
199184610Salfred		tcp_output(tp);
200184610Salfred	}*/
201184610Salfred	so->so_error = errno;
202184610Salfred	ipx_pcbdisconnect(ipxp);
203184610Salfred	soisdisconnected(so);
204195958Salfred}
205195958Salfred
206195958Salfredstatic int
207195958Salfredipx_output(ipxp, m0)
208195958Salfred	struct ipxpcb *ipxp;
209195958Salfred	struct mbuf *m0;
210195958Salfred{
211195958Salfred	register struct ipx *ipx;
212195958Salfred	register struct socket *so;
213184610Salfred	register int len = 0;
214184610Salfred	register struct route *ro;
215184610Salfred	struct mbuf *m;
216184610Salfred	struct mbuf *mprev = NULL;
217184610Salfred
218184610Salfred	/*
219184610Salfred	 * Calculate data length.
220184610Salfred	 */
221184610Salfred	for (m = m0; m != NULL; m = m->m_next) {
222184610Salfred		mprev = m;
223184610Salfred		len += m->m_len;
224184610Salfred	}
225184610Salfred	/*
226184610Salfred	 * Make sure packet is actually of even length.
227184610Salfred	 */
228184610Salfred
229184610Salfred	if (len & 1) {
230184610Salfred		m = mprev;
231184610Salfred		if ((m->m_flags & M_EXT) == 0 &&
232184610Salfred			(m->m_len + m->m_data < &m->m_dat[MLEN])) {
233184610Salfred			mtod(m, char*)[m->m_len++] = 0;
234184610Salfred		} else {
235184610Salfred			struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
236184610Salfred
237184610Salfred			if (m1 == NULL) {
238184610Salfred				m_freem(m0);
239184610Salfred				return (ENOBUFS);
240184610Salfred			}
241184610Salfred			m1->m_len = 1;
242184610Salfred			* mtod(m1, char *) = 0;
243184610Salfred			m->m_next = m1;
244184610Salfred		}
245184610Salfred		m0->m_pkthdr.len++;
246184610Salfred	}
247184610Salfred
248184610Salfred	/*
249184610Salfred	 * Fill in mbuf with extended IPX header
250184610Salfred	 * and addresses and length put into network format.
251184610Salfred	 */
252184610Salfred	m = m0;
253184610Salfred	if (ipxp->ipxp_flags & IPXP_RAWOUT) {
254184610Salfred		ipx = mtod(m, struct ipx *);
255184610Salfred	} else {
256184610Salfred		M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT);
257184610Salfred		if (m == NULL)
258184610Salfred			return (ENOBUFS);
259184610Salfred		ipx = mtod(m, struct ipx *);
260184610Salfred		ipx->ipx_tc = 0;
261184610Salfred		ipx->ipx_pt = ipxp->ipxp_dpt;
262184610Salfred		ipx->ipx_sna = ipxp->ipxp_laddr;
263184610Salfred		ipx->ipx_dna = ipxp->ipxp_faddr;
264184610Salfred		len += sizeof(struct ipx);
265184610Salfred	}
266184610Salfred
267184610Salfred	ipx->ipx_len = htons((u_short)len);
268184610Salfred
269184610Salfred	if (ipxp->ipxp_flags & IPXP_CHECKSUM) {
270184610Salfred		ipx->ipx_sum = ipx_cksum(m, len);
271184610Salfred	} else
272184610Salfred		ipx->ipx_sum = 0xffff;
273184610Salfred
274184610Salfred	/*
275184610Salfred	 * Output datagram.
276184610Salfred	 */
277187170Sthompsa	so = ipxp->ipxp_socket;
278187170Sthompsa	if (so->so_options & SO_DONTROUTE)
279187170Sthompsa		return (ipx_outputfl(m, (struct route *)NULL,
280187170Sthompsa		    (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
281187170Sthompsa	/*
282184610Salfred	 * Use cached route for previous datagram if
283194228Sthompsa	 * possible.  If the previous net was the same
284184610Salfred	 * and the interface was a broadcast medium, or
285184610Salfred	 * if the previous destination was identical,
286184610Salfred	 * then we are ok.
287184610Salfred	 *
288184610Salfred	 * NB: We don't handle broadcasts because that
289184610Salfred	 *     would require 3 subroutine calls.
290184610Salfred	 */
291184610Salfred	ro = &ipxp->ipxp_route;
292184610Salfred#ifdef ancient_history
293184610Salfred	/*
294184610Salfred	 * I think that this will all be handled in ipx_pcbconnect!
295184610Salfred	 */
296184610Salfred	if (ro->ro_rt != NULL) {
297184610Salfred		if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
298184610Salfred			/*
299184610Salfred			 * This assumes we have no GH type routes
300184610Salfred			 */
301184610Salfred			if (ro->ro_rt->rt_flags & RTF_HOST) {
302184610Salfred				if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
303184610Salfred					goto re_route;
304184610Salfred
305184610Salfred			}
306184610Salfred			if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
307184610Salfred				register struct ipx_addr *dst =
308184610Salfred						&satoipx_addr(ro->ro_dst);
309184610Salfred				dst->x_host = ipx->ipx_dna.x_host;
310184610Salfred			}
311184610Salfred			/*
312184610Salfred			 * Otherwise, we go through the same gateway
313184610Salfred			 * and dst is already set up.
314184610Salfred			 */
315184610Salfred		} else {
316184610Salfred		re_route:
317184610Salfred			RTFREE(ro->ro_rt);
318184610Salfred			ro->ro_rt = NULL;
319184610Salfred		}
320184610Salfred	}
321184610Salfred	ipxp->ipxp_lastdst = ipx->ipx_dna;
322184610Salfred#endif /* ancient_history */
323184610Salfred	return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
324184610Salfred}
325184610Salfred
326184610Salfredint
327184610Salfredipx_ctloutput(so, sopt)
328184610Salfred	struct socket *so;
329184610Salfred	struct sockopt *sopt;
330184610Salfred{
331184610Salfred	struct ipxpcb *ipxp = sotoipxpcb(so);
332184610Salfred	int mask, error, optval;
333184610Salfred	short soptval;
334184610Salfred	struct ipx ioptval;
335184610Salfred
336184610Salfred	error = 0;
337184610Salfred	if (ipxp == NULL)
338184610Salfred		return (EINVAL);
339184610Salfred
340184610Salfred	switch (sopt->sopt_dir) {
341184610Salfred	case SOPT_GET:
342184610Salfred		switch (sopt->sopt_name) {
343184610Salfred		case SO_ALL_PACKETS:
344184610Salfred			mask = IPXP_ALL_PACKETS;
345184610Salfred			goto get_flags;
346184610Salfred
347187186Sthompsa		case SO_HEADERS_ON_INPUT:
348187186Sthompsa			mask = IPXP_RAWIN;
349187186Sthompsa			goto get_flags;
350184610Salfred
351184610Salfred		case SO_IPX_CHECKSUM:
352184610Salfred			mask = IPXP_CHECKSUM;
353184610Salfred			goto get_flags;
354184610Salfred
355190183Sthompsa		case SO_HEADERS_ON_OUTPUT:
356184610Salfred			mask = IPXP_RAWOUT;
357184610Salfred		get_flags:
358190183Sthompsa			soptval = ipxp->ipxp_flags & mask;
359184610Salfred			error = sooptcopyout(sopt, &soptval, sizeof soptval);
360184610Salfred			break;
361184610Salfred
362184610Salfred		case SO_DEFAULT_HEADERS:
363184610Salfred			ioptval.ipx_len = 0;
364184610Salfred			ioptval.ipx_sum = 0;
365184610Salfred			ioptval.ipx_tc = 0;
366198501Sthompsa			ioptval.ipx_pt = ipxp->ipxp_dpt;
367198501Sthompsa			ioptval.ipx_dna = ipxp->ipxp_faddr;
368198501Sthompsa			ioptval.ipx_sna = ipxp->ipxp_laddr;
369198501Sthompsa			error = sooptcopyout(sopt, &soptval, sizeof soptval);
370198501Sthompsa			break;
371198501Sthompsa
372198501Sthompsa		case SO_SEQNO:
373198501Sthompsa			error = sooptcopyout(sopt, &ipx_pexseq,
374198501Sthompsa					     sizeof ipx_pexseq);
375198501Sthompsa			ipx_pexseq++;
376198501Sthompsa			break;
377198501Sthompsa
378198501Sthompsa		default:
379184610Salfred			error = EINVAL;
380184610Salfred		}
381184610Salfred		break;
382184610Salfred
383184610Salfred	case SOPT_SET:
384184610Salfred		switch (sopt->sopt_name) {
385184610Salfred		case SO_ALL_PACKETS:
386184610Salfred			mask = IPXP_ALL_PACKETS;
387184610Salfred			goto set_head;
388184610Salfred
389184610Salfred		case SO_HEADERS_ON_INPUT:
390184610Salfred			mask = IPXP_RAWIN;
391184610Salfred			goto set_head;
392184610Salfred
393184610Salfred		case SO_IPX_CHECKSUM:
394184610Salfred			mask = IPXP_CHECKSUM;
395184610Salfred
396184610Salfred		case SO_HEADERS_ON_OUTPUT:
397184610Salfred			mask = IPXP_RAWOUT;
398184610Salfred		set_head:
399184610Salfred			error = sooptcopyin(sopt, &optval, sizeof optval,
400184610Salfred					    sizeof optval);
401184610Salfred			if (error)
402184610Salfred				break;
403184610Salfred			if (optval)
404184610Salfred				ipxp->ipxp_flags |= mask;
405184610Salfred			else
406184610Salfred				ipxp->ipxp_flags &= ~mask;
407184610Salfred			break;
408184610Salfred
409184610Salfred		case SO_DEFAULT_HEADERS:
410184610Salfred			error = sooptcopyin(sopt, &ioptval, sizeof ioptval,
411184610Salfred					    sizeof ioptval);
412184610Salfred			if (error)
413184610Salfred				break;
414184824Sthompsa			ipxp->ipxp_dpt = ioptval.ipx_pt;
415184610Salfred			break;
416184610Salfred#ifdef IPXIP
417184610Salfred		case SO_IPXIP_ROUTE:
418184610Salfred			error = ipxip_route(so, sopt);
419184824Sthompsa			break;
420184610Salfred#endif /* IPXIP */
421184610Salfred		default:
422184610Salfred			error = EINVAL;
423184610Salfred		}
424184610Salfred		break;
425184610Salfred	}
426184610Salfred	return (error);
427184610Salfred}
428184610Salfred
429184610Salfredstatic int
430184610Salfredipx_usr_abort(so)
431184610Salfred	struct socket *so;
432184610Salfred{
433184610Salfred	int s;
434184610Salfred	struct ipxpcb *ipxp = sotoipxpcb(so);
435184610Salfred
436184610Salfred	s = splnet();
437184610Salfred	ipx_pcbdetach(ipxp);
438184610Salfred	splx(s);
439184610Salfred	soisdisconnected(so);
440184610Salfred	ACCEPT_LOCK();
441184610Salfred	SOCK_LOCK(so);
442194228Sthompsa	sotryfree(so);
443184610Salfred	return (0);
444184610Salfred}
445184610Salfred
446184610Salfredstatic int
447184610Salfredipx_attach(so, proto, td)
448184610Salfred	struct socket *so;
449184610Salfred	int proto;
450184610Salfred	struct thread *td;
451184610Salfred{
452184610Salfred	int error;
453184610Salfred	int s;
454184610Salfred	struct ipxpcb *ipxp = sotoipxpcb(so);
455184610Salfred
456184610Salfred	if (ipxp != NULL)
457184610Salfred		return (EINVAL);
458184610Salfred	s = splnet();
459184610Salfred	error = ipx_pcballoc(so, &ipxpcb_list, td);
460184610Salfred	splx(s);
461184610Salfred	if (error == 0)
462184610Salfred		error = soreserve(so, ipxsendspace, ipxrecvspace);
463184610Salfred	return (error);
464184610Salfred}
465184610Salfred
466184610Salfredstatic int
467184610Salfredipx_bind(so, nam, td)
468184610Salfred	struct socket *so;
469184610Salfred	struct sockaddr *nam;
470188942Sthompsa	struct thread *td;
471{
472	struct ipxpcb *ipxp = sotoipxpcb(so);
473
474	return (ipx_pcbbind(ipxp, nam, td));
475}
476
477static int
478ipx_connect(so, nam, td)
479	struct socket *so;
480	struct sockaddr *nam;
481	struct thread *td;
482{
483	int error;
484	int s;
485	struct ipxpcb *ipxp = sotoipxpcb(so);
486
487	if (!ipx_nullhost(ipxp->ipxp_faddr))
488		return (EISCONN);
489	s = splnet();
490	error = ipx_pcbconnect(ipxp, nam, td);
491	splx(s);
492	if (error == 0)
493		soisconnected(so);
494	return (error);
495}
496
497static int
498ipx_detach(so)
499	struct socket *so;
500{
501	int s;
502	struct ipxpcb *ipxp = sotoipxpcb(so);
503
504	if (ipxp == NULL)
505		return (ENOTCONN);
506	s = splnet();
507	ipx_pcbdetach(ipxp);
508	splx(s);
509	return (0);
510}
511
512static int
513ipx_disconnect(so)
514	struct socket *so;
515{
516	int s;
517	struct ipxpcb *ipxp = sotoipxpcb(so);
518
519	if (ipx_nullhost(ipxp->ipxp_faddr))
520		return (ENOTCONN);
521	s = splnet();
522	ipx_pcbdisconnect(ipxp);
523	splx(s);
524	soisdisconnected(so);
525	return (0);
526}
527
528int
529ipx_peeraddr(so, nam)
530	struct socket *so;
531	struct sockaddr **nam;
532{
533	struct ipxpcb *ipxp = sotoipxpcb(so);
534
535	ipx_setpeeraddr(ipxp, nam); /* XXX what if alloc fails? */
536	return (0);
537}
538
539static int
540ipx_send(so, flags, m, nam, control, td)
541	struct socket *so;
542	int flags;
543	struct mbuf *m;
544	struct sockaddr *nam;
545	struct mbuf *control;
546	struct thread *td;
547{
548	int error;
549	struct ipxpcb *ipxp = sotoipxpcb(so);
550	struct ipx_addr laddr;
551	int s = 0;
552
553	if (nam != NULL) {
554		laddr = ipxp->ipxp_laddr;
555		if (!ipx_nullhost(ipxp->ipxp_faddr)) {
556			error = EISCONN;
557			goto send_release;
558		}
559		/*
560		 * Must block input while temporarily connected.
561		 */
562		s = splnet();
563		error = ipx_pcbconnect(ipxp, nam, td);
564		if (error) {
565			splx(s);
566			goto send_release;
567		}
568	} else {
569		if (ipx_nullhost(ipxp->ipxp_faddr)) {
570			error = ENOTCONN;
571			goto send_release;
572		}
573	}
574	error = ipx_output(ipxp, m);
575	m = NULL;
576	if (nam != NULL) {
577		ipx_pcbdisconnect(ipxp);
578		splx(s);
579		ipxp->ipxp_laddr = laddr;
580	}
581
582send_release:
583	if (m != NULL)
584		m_freem(m);
585	return (error);
586}
587
588static int
589ipx_shutdown(so)
590	struct socket *so;
591{
592	socantsendmore(so);
593	return (0);
594}
595
596int
597ipx_sockaddr(so, nam)
598	struct socket *so;
599	struct sockaddr **nam;
600{
601	struct ipxpcb *ipxp = sotoipxpcb(so);
602
603	ipx_setsockaddr(ipxp, nam); /* XXX what if alloc fails? */
604	return (0);
605}
606
607static int
608ripx_attach(so, proto, td)
609	struct socket *so;
610	int proto;
611	struct thread *td;
612{
613	int error = 0;
614	int s;
615	struct ipxpcb *ipxp = sotoipxpcb(so);
616
617	if (td != NULL && (error = suser(td)) != 0)
618		return (error);
619	s = splnet();
620	error = ipx_pcballoc(so, &ipxrawpcb_list, td);
621	splx(s);
622	if (error)
623		return (error);
624	error = soreserve(so, ipxsendspace, ipxrecvspace);
625	if (error)
626		return (error);
627	ipxp = sotoipxpcb(so);
628	ipxp->ipxp_faddr.x_host = ipx_broadhost;
629	ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
630	return (error);
631}
632