]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/netipx/ipx_usrreq.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / netipx / ipx_usrreq.c
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$");
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
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
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
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_NOWAIT, 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_NOWAIT);
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
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
457 ipx_usr_abort(struct socket *so)
458 {
459
460         /* XXXRW: Possibly ipx_disconnect() here? */
461         soisdisconnected(so);
462 }
463
464 static int
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
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
498 ipx_usr_close(struct socket *so)
499 {
500
501         /* XXXRW: Possibly ipx_disconnect() here? */
502         soisdisconnected(so);
503 }
504
505 static int
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
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
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
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
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
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
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
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 }