1 /*-
2  * Copyright (c) 1984, 1985, 1986, 1987, 1993
3  *	The Regents of the University of California.
4  * Copyright (c) 2004-2006 Robert N. M. Watson
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 4. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * Copyright (c) 1995, Mike Mitchell
32  * All rights reserved.
33  *
34  * Redistribution and use in source and binary forms, with or without
35  * modification, are permitted provided that the following conditions
36  * are met:
37  * 1. Redistributions of source code must retain the above copyright
38  *    notice, this list of conditions and the following disclaimer.
39  * 2. Redistributions in binary form must reproduce the above copyright
40  *    notice, this list of conditions and the following disclaimer in the
41  *    documentation and/or other materials provided with the distribution.
42  * 3. All advertising materials mentioning features or use of this software
43  *    must display the following acknowledgement:
44  *	This product includes software developed by the University of
45  *	California, Berkeley and its contributors.
46  * 4. Neither the name of the University nor the names of its contributors
47  *    may be used to endorse or promote products derived from this software
48  *    without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60  * SUCH DAMAGE.
61  *
62  *	@(#)ipx_usrreq.c
63  */
64 
65 #include <sys/cdefs.h>
66 __FBSDID("$FreeBSD: stable/9/sys/netipx/ipx_usrreq.c 194561 2009-06-20 23:38:21Z rwatson $");
67 
68 #include "opt_ipx.h"
69 
70 #include <sys/param.h>
71 #include <sys/kernel.h>
72 #include <sys/lock.h>
73 #include <sys/mbuf.h>
74 #include <sys/priv.h>
75 #include <sys/protosw.h>
76 #include <sys/signalvar.h>
77 #include <sys/socket.h>
78 #include <sys/socketvar.h>
79 #include <sys/sx.h>
80 #include <sys/sysctl.h>
81 #include <sys/systm.h>
82 
83 #include <net/if.h>
84 #include <net/route.h>
85 
86 #include <netinet/in.h>
87 
88 #include <netipx/ipx.h>
89 #include <netipx/ipx_if.h>
90 #include <netipx/ipx_pcb.h>
91 #include <netipx/ipx_var.h>
92 
93 #include <security/mac/mac_framework.h>
94 
95 /*
96  * IPX protocol implementation.
97  */
98 
99 static int ipxsendspace = IPXSNDQ;
100 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW,
101             &ipxsendspace, 0, "Send buffer space");
102 static int ipxrecvspace = IPXRCVQ;
103 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
104             &ipxrecvspace, 0, "Receive buffer space");
105 
106 static	void ipx_usr_abort(struct socket *so);
107 static	int ipx_attach(struct socket *so, int proto, struct thread *td);
108 static	int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
109 static	int ipx_connect(struct socket *so, struct sockaddr *nam,
110 			struct thread *td);
111 static	void ipx_detach(struct socket *so);
112 static	int ipx_disconnect(struct socket *so);
113 static	int ipx_send(struct socket *so, int flags, struct mbuf *m,
114 		     struct sockaddr *addr, struct mbuf *control,
115 		     struct thread *td);
116 static	int ipx_shutdown(struct socket *so);
117 static	int ripx_attach(struct socket *so, int proto, struct thread *td);
118 static	int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0);
119 static	void ipx_usr_close(struct socket *so);
120 
121 struct	pr_usrreqs ipx_usrreqs = {
122 	.pru_abort =		ipx_usr_abort,
123 	.pru_attach =		ipx_attach,
124 	.pru_bind =		ipx_bind,
125 	.pru_connect =		ipx_connect,
126 	.pru_control =		ipx_control,
127 	.pru_detach =		ipx_detach,
128 	.pru_disconnect =	ipx_disconnect,
129 	.pru_peeraddr =		ipx_peeraddr,
130 	.pru_send =		ipx_send,
131 	.pru_shutdown =		ipx_shutdown,
132 	.pru_sockaddr =		ipx_sockaddr,
133 	.pru_close =		ipx_usr_close,
134 };
135 
136 struct	pr_usrreqs ripx_usrreqs = {
137 	.pru_abort =		ipx_usr_abort,
138 	.pru_attach =		ripx_attach,
139 	.pru_bind =		ipx_bind,
140 	.pru_connect =		ipx_connect,
141 	.pru_control =		ipx_control,
142 	.pru_detach =		ipx_detach,
143 	.pru_disconnect =	ipx_disconnect,
144 	.pru_peeraddr =		ipx_peeraddr,
145 	.pru_send =		ipx_send,
146 	.pru_shutdown =		ipx_shutdown,
147 	.pru_sockaddr =		ipx_sockaddr,
148 	.pru_close =		ipx_usr_close,
149 };
150 
151 /*
152  *  This may also be called for raw listeners.
153  */
154 void
ipx_input(struct mbuf * m,struct ipxpcb * ipxp)155 ipx_input(struct mbuf *m, struct ipxpcb *ipxp)
156 {
157 	struct ipx *ipx = mtod(m, struct ipx *);
158 	struct ifnet *ifp = m->m_pkthdr.rcvif;
159 	struct sockaddr_ipx ipx_ipx;
160 
161 	KASSERT(ipxp != NULL, ("ipx_input: NULL ipxpcb"));
162 	IPX_LOCK_ASSERT(ipxp);
163 	/*
164 	 * Construct sockaddr format source address.
165 	 * Stuff source address and datagram in user buffer.
166 	 */
167 	ipx_ipx.sipx_len = sizeof(ipx_ipx);
168 	ipx_ipx.sipx_family = AF_IPX;
169 	ipx_ipx.sipx_addr = ipx->ipx_sna;
170 	ipx_ipx.sipx_zero[0] = '\0';
171 	ipx_ipx.sipx_zero[1] = '\0';
172 	if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) {
173 		struct ifaddr *ifa;
174 
175 		for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL;
176 		     ifa = TAILQ_NEXT(ifa, ifa_link)) {
177 			if (ifa->ifa_addr->sa_family == AF_IPX) {
178 				ipx_ipx.sipx_addr.x_net =
179 					IA_SIPX(ifa)->sipx_addr.x_net;
180 				break;
181 			}
182 		}
183 	}
184 	ipxp->ipxp_rpt = ipx->ipx_pt;
185 	if ((ipxp->ipxp_flags & IPXP_RAWIN) == 0) {
186 		m->m_len -= sizeof(struct ipx);
187 		m->m_pkthdr.len -= sizeof(struct ipx);
188 		m->m_data += sizeof(struct ipx);
189 	}
190 #ifdef MAC
191 	if (mac_socket_check_deliver(ipxp->ipxp_socket, m) != 0) {
192 		m_freem(m);
193 		return;
194 	}
195 #endif
196 	if (sbappendaddr(&ipxp->ipxp_socket->so_rcv,
197 	    (struct sockaddr *)&ipx_ipx, m, NULL) == 0)
198 		m_freem(m);
199 	else
200 		sorwakeup(ipxp->ipxp_socket);
201 }
202 
203 /*
204  * Drop connection, reporting
205  * the specified error.
206  */
207 void
ipx_drop(struct ipxpcb * ipxp,int errno)208 ipx_drop(struct ipxpcb *ipxp, int errno)
209 {
210 	struct socket *so = ipxp->ipxp_socket;
211 
212 	IPX_LIST_LOCK_ASSERT();
213 	IPX_LOCK_ASSERT(ipxp);
214 
215 	/*
216 	 * someday, in the IPX world
217 	 * we will generate error protocol packets
218 	 * announcing that the socket has gone away.
219 	 *
220 	 * XXX Probably never. IPX does not have error packets.
221 	 */
222 	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
223 		tp->t_state = TCPS_CLOSED;
224 		tcp_output(tp);
225 	}*/
226 	so->so_error = errno;
227 	ipx_pcbdisconnect(ipxp);
228 	soisdisconnected(so);
229 }
230 
231 static int
ipx_output(struct ipxpcb * ipxp,struct mbuf * m0)232 ipx_output(struct ipxpcb *ipxp, struct mbuf *m0)
233 {
234 	struct ipx *ipx;
235 	struct socket *so;
236 	int len = 0;
237 	struct route *ro;
238 	struct mbuf *m;
239 	struct mbuf *mprev = NULL;
240 
241 	IPX_LOCK_ASSERT(ipxp);
242 
243 	/*
244 	 * Calculate data length.
245 	 */
246 	for (m = m0; m != NULL; m = m->m_next) {
247 		mprev = m;
248 		len += m->m_len;
249 	}
250 	/*
251 	 * Make sure packet is actually of even length.
252 	 */
253 
254 	if (len & 1) {
255 		m = mprev;
256 		if ((m->m_flags & M_EXT) == 0 &&
257 			(m->m_len + m->m_data < &m->m_dat[MLEN])) {
258 			mtod(m, char*)[m->m_len++] = 0;
259 		} else {
260 			struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
261 
262 			if (m1 == NULL) {
263 				m_freem(m0);
264 				return (ENOBUFS);
265 			}
266 			m1->m_len = 1;
267 			* mtod(m1, char *) = 0;
268 			m->m_next = m1;
269 		}
270 		m0->m_pkthdr.len++;
271 	}
272 
273 	/*
274 	 * Fill in mbuf with extended IPX header
275 	 * and addresses and length put into network format.
276 	 */
277 	m = m0;
278 	if (ipxp->ipxp_flags & IPXP_RAWOUT) {
279 		ipx = mtod(m, struct ipx *);
280 	} else {
281 		M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT);
282 		if (m == NULL)
283 			return (ENOBUFS);
284 		ipx = mtod(m, struct ipx *);
285 		ipx->ipx_tc = 0;
286 		ipx->ipx_pt = ipxp->ipxp_dpt;
287 		ipx->ipx_sna = ipxp->ipxp_laddr;
288 		ipx->ipx_dna = ipxp->ipxp_faddr;
289 		len += sizeof(struct ipx);
290 	}
291 
292 	ipx->ipx_len = htons((u_short)len);
293 
294 	if (ipxp->ipxp_flags & IPXP_CHECKSUM) {
295 		ipx->ipx_sum = ipx_cksum(m, len);
296 	} else
297 		ipx->ipx_sum = 0xffff;
298 
299 	/*
300 	 * Output datagram.
301 	 */
302 	so = ipxp->ipxp_socket;
303 	if (so->so_options & SO_DONTROUTE)
304 		return (ipx_outputfl(m, (struct route *)NULL,
305 		    (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
306 	/*
307 	 * Use cached route for previous datagram if
308 	 * possible.  If the previous net was the same
309 	 * and the interface was a broadcast medium, or
310 	 * if the previous destination was identical,
311 	 * then we are ok.
312 	 *
313 	 * NB: We don't handle broadcasts because that
314 	 *     would require 3 subroutine calls.
315 	 */
316 	ro = &ipxp->ipxp_route;
317 #ifdef ancient_history
318 	/*
319 	 * I think that this will all be handled in ipx_pcbconnect!
320 	 */
321 	if (ro->ro_rt != NULL) {
322 		if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
323 			/*
324 			 * This assumes we have no GH type routes
325 			 */
326 			if (ro->ro_rt->rt_flags & RTF_HOST) {
327 				if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
328 					goto re_route;
329 
330 			}
331 			if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
332 				struct ipx_addr *dst =
333 						&satoipx_addr(ro->ro_dst);
334 				dst->x_host = ipx->ipx_dna.x_host;
335 			}
336 			/*
337 			 * Otherwise, we go through the same gateway
338 			 * and dst is already set up.
339 			 */
340 		} else {
341 		re_route:
342 			RTFREE(ro->ro_rt);
343 			ro->ro_rt = NULL;
344 		}
345 	}
346 	ipxp->ipxp_lastdst = ipx->ipx_dna;
347 #endif /* ancient_history */
348 	return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
349 }
350 
351 int
ipx_ctloutput(struct socket * so,struct sockopt * sopt)352 ipx_ctloutput(struct socket *so, struct sockopt *sopt)
353 {
354 	struct ipxpcb *ipxp = sotoipxpcb(so);
355 	int mask, error, optval;
356 	short soptval;
357 	struct ipx ioptval;
358 	long seq;
359 
360 	KASSERT(ipxp != NULL, ("ipx_ctloutput: ipxp == NULL"));
361 	error = 0;
362 
363 	switch (sopt->sopt_dir) {
364 	case SOPT_GET:
365 		switch (sopt->sopt_name) {
366 		case SO_ALL_PACKETS:
367 			mask = IPXP_ALL_PACKETS;
368 			goto get_flags;
369 
370 		case SO_HEADERS_ON_INPUT:
371 			mask = IPXP_RAWIN;
372 			goto get_flags;
373 
374 		case SO_IPX_CHECKSUM:
375 			mask = IPXP_CHECKSUM;
376 			goto get_flags;
377 
378 		case SO_HEADERS_ON_OUTPUT:
379 			mask = IPXP_RAWOUT;
380 		get_flags:
381 			/* Unlocked read. */
382 			soptval = ipxp->ipxp_flags & mask;
383 			error = sooptcopyout(sopt, &soptval, sizeof soptval);
384 			break;
385 
386 		case SO_DEFAULT_HEADERS:
387 			ioptval.ipx_len = 0;
388 			ioptval.ipx_sum = 0;
389 			ioptval.ipx_tc = 0;
390 			IPX_LOCK(ipxp);
391 			ioptval.ipx_pt = ipxp->ipxp_dpt;
392 			ioptval.ipx_dna = ipxp->ipxp_faddr;
393 			ioptval.ipx_sna = ipxp->ipxp_laddr;
394 			IPX_UNLOCK(ipxp);
395 			error = sooptcopyout(sopt, &soptval, sizeof soptval);
396 			break;
397 
398 		case SO_SEQNO:
399 			IPX_LIST_LOCK();
400 			seq = ipx_pexseq;
401 			ipx_pexseq++;
402 			IPX_LIST_UNLOCK();
403 			error = sooptcopyout(sopt, &seq, sizeof seq);
404 			break;
405 
406 		default:
407 			error = EINVAL;
408 		}
409 		break;
410 
411 	case SOPT_SET:
412 		switch (sopt->sopt_name) {
413 		case SO_ALL_PACKETS:
414 			mask = IPXP_ALL_PACKETS;
415 			goto set_head;
416 
417 		case SO_HEADERS_ON_INPUT:
418 			mask = IPXP_RAWIN;
419 			goto set_head;
420 
421 		case SO_IPX_CHECKSUM:
422 			mask = IPXP_CHECKSUM;
423 			goto set_head;
424 
425 		case SO_HEADERS_ON_OUTPUT:
426 			mask = IPXP_RAWOUT;
427 		set_head:
428 			error = sooptcopyin(sopt, &optval, sizeof optval,
429 					    sizeof optval);
430 			if (error)
431 				break;
432 			IPX_LOCK(ipxp);
433 			if (optval)
434 				ipxp->ipxp_flags |= mask;
435 			else
436 				ipxp->ipxp_flags &= ~mask;
437 			IPX_UNLOCK(ipxp);
438 			break;
439 
440 		case SO_DEFAULT_HEADERS:
441 			error = sooptcopyin(sopt, &ioptval, sizeof ioptval,
442 					    sizeof ioptval);
443 			if (error)
444 				break;
445 			/* Unlocked write. */
446 			ipxp->ipxp_dpt = ioptval.ipx_pt;
447 			break;
448 		default:
449 			error = EINVAL;
450 		}
451 		break;
452 	}
453 	return (error);
454 }
455 
456 static void
ipx_usr_abort(struct socket * so)457 ipx_usr_abort(struct socket *so)
458 {
459 
460 	/* XXXRW: Possibly ipx_disconnect() here? */
461 	soisdisconnected(so);
462 }
463 
464 static int
ipx_attach(struct socket * so,int proto,struct thread * td)465 ipx_attach(struct socket *so, int proto, struct thread *td)
466 {
467 #ifdef INVARIANTS
468 	struct ipxpcb *ipxp = sotoipxpcb(so);
469 #endif
470 	int error;
471 
472 	KASSERT(ipxp == NULL, ("ipx_attach: ipxp != NULL"));
473 	error = soreserve(so, ipxsendspace, ipxrecvspace);
474 	if (error != 0)
475 		return (error);
476 	IPX_LIST_LOCK();
477 	error = ipx_pcballoc(so, &ipxpcb_list, td);
478 	IPX_LIST_UNLOCK();
479 	return (error);
480 }
481 
482 static int
ipx_bind(struct socket * so,struct sockaddr * nam,struct thread * td)483 ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
484 {
485 	struct ipxpcb *ipxp = sotoipxpcb(so);
486 	int error;
487 
488 	KASSERT(ipxp != NULL, ("ipx_bind: ipxp == NULL"));
489 	IPX_LIST_LOCK();
490 	IPX_LOCK(ipxp);
491 	error = ipx_pcbbind(ipxp, nam, td);
492 	IPX_UNLOCK(ipxp);
493 	IPX_LIST_UNLOCK();
494 	return (error);
495 }
496 
497 static void
ipx_usr_close(struct socket * so)498 ipx_usr_close(struct socket *so)
499 {
500 
501 	/* XXXRW: Possibly ipx_disconnect() here? */
502 	soisdisconnected(so);
503 }
504 
505 static int
ipx_connect(struct socket * so,struct sockaddr * nam,struct thread * td)506 ipx_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
507 {
508 	struct ipxpcb *ipxp = sotoipxpcb(so);
509 	int error;
510 
511 	KASSERT(ipxp != NULL, ("ipx_connect: ipxp == NULL"));
512 	IPX_LIST_LOCK();
513 	IPX_LOCK(ipxp);
514 	if (!ipx_nullhost(ipxp->ipxp_faddr)) {
515 		error = EISCONN;
516 		goto out;
517 	}
518 	error = ipx_pcbconnect(ipxp, nam, td);
519 	if (error == 0)
520 		soisconnected(so);
521 out:
522 	IPX_UNLOCK(ipxp);
523 	IPX_LIST_UNLOCK();
524 	return (error);
525 }
526 
527 static void
ipx_detach(struct socket * so)528 ipx_detach(struct socket *so)
529 {
530 	struct ipxpcb *ipxp = sotoipxpcb(so);
531 
532 	/* XXXRW: Should assert detached. */
533 	KASSERT(ipxp != NULL, ("ipx_detach: ipxp == NULL"));
534 	IPX_LIST_LOCK();
535 	IPX_LOCK(ipxp);
536 	ipx_pcbdetach(ipxp);
537 	ipx_pcbfree(ipxp);
538 	IPX_LIST_UNLOCK();
539 }
540 
541 static int
ipx_disconnect(struct socket * so)542 ipx_disconnect(struct socket *so)
543 {
544 	struct ipxpcb *ipxp = sotoipxpcb(so);
545 	int error;
546 
547 	KASSERT(ipxp != NULL, ("ipx_disconnect: ipxp == NULL"));
548 	IPX_LIST_LOCK();
549 	IPX_LOCK(ipxp);
550 	error = 0;
551 	if (ipx_nullhost(ipxp->ipxp_faddr)) {
552 		error = ENOTCONN;
553 		goto out;
554 	}
555 	ipx_pcbdisconnect(ipxp);
556 	soisdisconnected(so);
557 out:
558 	IPX_UNLOCK(ipxp);
559 	IPX_LIST_UNLOCK();
560 	return (0);
561 }
562 
563 int
ipx_peeraddr(struct socket * so,struct sockaddr ** nam)564 ipx_peeraddr(struct socket *so, struct sockaddr **nam)
565 {
566 	struct ipxpcb *ipxp = sotoipxpcb(so);
567 
568 	KASSERT(ipxp != NULL, ("ipx_peeraddr: ipxp == NULL"));
569 	ipx_getpeeraddr(ipxp, nam);
570 	return (0);
571 }
572 
573 static int
ipx_send(struct socket * so,int flags,struct mbuf * m,struct sockaddr * nam,struct mbuf * control,struct thread * td)574 ipx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
575     struct mbuf *control, struct thread *td)
576 {
577 	int error;
578 	struct ipxpcb *ipxp = sotoipxpcb(so);
579 	struct ipx_addr laddr;
580 
581 	KASSERT(ipxp != NULL, ("ipxp_send: ipxp == NULL"));
582 	/*
583 	 * Attempt to only acquire the necessary locks: if the socket is
584 	 * already connected, we don't need to hold the IPX list lock to be
585 	 * used by ipx_pcbconnect() and ipx_pcbdisconnect(), just the IPX
586 	 * pcb lock.
587 	 */
588 #ifdef MAC
589 	mac_socket_create_mbuf(so, m);
590 #endif
591 	if (nam != NULL) {
592 		IPX_LIST_LOCK();
593 		IPX_LOCK(ipxp);
594 		laddr = ipxp->ipxp_laddr;
595 		if (!ipx_nullhost(ipxp->ipxp_faddr)) {
596 			IPX_UNLOCK(ipxp);
597 			IPX_LIST_UNLOCK();
598 			error = EISCONN;
599 			goto send_release;
600 		}
601 		/*
602 		 * Must block input while temporarily connected.
603 		 */
604 		error = ipx_pcbconnect(ipxp, nam, td);
605 		if (error) {
606 			IPX_UNLOCK(ipxp);
607 			IPX_LIST_UNLOCK();
608 			goto send_release;
609 		}
610 	} else {
611 		IPX_LOCK(ipxp);
612 		if (ipx_nullhost(ipxp->ipxp_faddr)) {
613 			IPX_UNLOCK(ipxp);
614 			error = ENOTCONN;
615 			goto send_release;
616 		}
617 	}
618 	error = ipx_output(ipxp, m);
619 	m = NULL;
620 	if (nam != NULL) {
621 		ipx_pcbdisconnect(ipxp);
622 		ipxp->ipxp_laddr = laddr;
623 		IPX_UNLOCK(ipxp);
624 		IPX_LIST_UNLOCK();
625 	} else
626 		IPX_UNLOCK(ipxp);
627 
628 send_release:
629 	if (m != NULL)
630 		m_freem(m);
631 	return (error);
632 }
633 
634 static int
ipx_shutdown(so)635 ipx_shutdown(so)
636 	struct socket *so;
637 {
638 
639 	KASSERT(so->so_pcb != NULL, ("ipx_shutdown: so_pcb == NULL"));
640 	socantsendmore(so);
641 	return (0);
642 }
643 
644 int
ipx_sockaddr(struct socket * so,struct sockaddr ** nam)645 ipx_sockaddr(struct socket *so, struct sockaddr **nam)
646 {
647 	struct ipxpcb *ipxp = sotoipxpcb(so);
648 
649 	KASSERT(ipxp != NULL, ("ipx_sockaddr: ipxp == NULL"));
650 	ipx_getsockaddr(ipxp, nam);
651 	return (0);
652 }
653 
654 static int
ripx_attach(struct socket * so,int proto,struct thread * td)655 ripx_attach(struct socket *so, int proto, struct thread *td)
656 {
657 	int error = 0;
658 	struct ipxpcb *ipxp = sotoipxpcb(so);
659 
660 	KASSERT(ipxp == NULL, ("ripx_attach: ipxp != NULL"));
661 
662 	if (td != NULL) {
663 		error = priv_check(td, PRIV_NETIPX_RAW);
664 		if (error)
665 			return (error);
666 	}
667 
668 	/*
669 	 * We hold the IPX list lock for the duration as address parameters
670 	 * of the IPX pcb are changed.  Since no one else holds a reference
671 	 * to the ipxpcb yet, we don't need the ipxpcb lock here.
672 	 */
673 	IPX_LIST_LOCK();
674 	error = ipx_pcballoc(so, &ipxrawpcb_list, td);
675 	if (error)
676 		goto out;
677 	ipxp = sotoipxpcb(so);
678 	error = soreserve(so, ipxsendspace, ipxrecvspace);
679 	if (error)
680 		goto out;
681 	ipxp->ipxp_faddr.x_host = ipx_broadhost;
682 	ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
683 out:
684 	IPX_LIST_UNLOCK();
685 	return (error);
686 }
687