]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netipx/ipx_usrreq.c
Invoke the MAC Framework's mac_socket_create_mbuf() entry point when
[FreeBSD/FreeBSD.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         if (sbappendaddr(&ipxp->ipxp_socket->so_rcv,
191             (struct sockaddr *)&ipx_ipx, m, NULL) == 0)
192                 m_freem(m);
193         else
194                 sorwakeup(ipxp->ipxp_socket);
195 }
196
197 /*
198  * Drop connection, reporting
199  * the specified error.
200  */
201 void
202 ipx_drop(struct ipxpcb *ipxp, int errno)
203 {
204         struct socket *so = ipxp->ipxp_socket;
205
206         IPX_LIST_LOCK_ASSERT();
207         IPX_LOCK_ASSERT(ipxp);
208
209         /*
210          * someday, in the IPX world
211          * we will generate error protocol packets
212          * announcing that the socket has gone away.
213          *
214          * XXX Probably never. IPX does not have error packets.
215          */
216         /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
217                 tp->t_state = TCPS_CLOSED;
218                 tcp_output(tp);
219         }*/
220         so->so_error = errno;
221         ipx_pcbdisconnect(ipxp);
222         soisdisconnected(so);
223 }
224
225 static int
226 ipx_output(struct ipxpcb *ipxp, struct mbuf *m0)
227 {
228         struct ipx *ipx;
229         struct socket *so;
230         int len = 0;
231         struct route *ro;
232         struct mbuf *m;
233         struct mbuf *mprev = NULL;
234
235         IPX_LOCK_ASSERT(ipxp);
236
237         /*
238          * Calculate data length.
239          */
240         for (m = m0; m != NULL; m = m->m_next) {
241                 mprev = m;
242                 len += m->m_len;
243         }
244         /*
245          * Make sure packet is actually of even length.
246          */
247
248         if (len & 1) {
249                 m = mprev;
250                 if ((m->m_flags & M_EXT) == 0 &&
251                         (m->m_len + m->m_data < &m->m_dat[MLEN])) {
252                         mtod(m, char*)[m->m_len++] = 0;
253                 } else {
254                         struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
255
256                         if (m1 == NULL) {
257                                 m_freem(m0);
258                                 return (ENOBUFS);
259                         }
260                         m1->m_len = 1;
261                         * mtod(m1, char *) = 0;
262                         m->m_next = m1;
263                 }
264                 m0->m_pkthdr.len++;
265         }
266
267         /*
268          * Fill in mbuf with extended IPX header
269          * and addresses and length put into network format.
270          */
271         m = m0;
272         if (ipxp->ipxp_flags & IPXP_RAWOUT) {
273                 ipx = mtod(m, struct ipx *);
274         } else {
275                 M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT);
276                 if (m == NULL)
277                         return (ENOBUFS);
278                 ipx = mtod(m, struct ipx *);
279                 ipx->ipx_tc = 0;
280                 ipx->ipx_pt = ipxp->ipxp_dpt;
281                 ipx->ipx_sna = ipxp->ipxp_laddr;
282                 ipx->ipx_dna = ipxp->ipxp_faddr;
283                 len += sizeof(struct ipx);
284         }
285
286         ipx->ipx_len = htons((u_short)len);
287
288         if (ipxp->ipxp_flags & IPXP_CHECKSUM) {
289                 ipx->ipx_sum = ipx_cksum(m, len);
290         } else
291                 ipx->ipx_sum = 0xffff;
292
293         /*
294          * Output datagram.
295          */
296         so = ipxp->ipxp_socket;
297         if (so->so_options & SO_DONTROUTE)
298                 return (ipx_outputfl(m, (struct route *)NULL,
299                     (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
300         /*
301          * Use cached route for previous datagram if
302          * possible.  If the previous net was the same
303          * and the interface was a broadcast medium, or
304          * if the previous destination was identical,
305          * then we are ok.
306          *
307          * NB: We don't handle broadcasts because that
308          *     would require 3 subroutine calls.
309          */
310         ro = &ipxp->ipxp_route;
311 #ifdef ancient_history
312         /*
313          * I think that this will all be handled in ipx_pcbconnect!
314          */
315         if (ro->ro_rt != NULL) {
316                 if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
317                         /*
318                          * This assumes we have no GH type routes
319                          */
320                         if (ro->ro_rt->rt_flags & RTF_HOST) {
321                                 if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
322                                         goto re_route;
323
324                         }
325                         if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
326                                 struct ipx_addr *dst =
327                                                 &satoipx_addr(ro->ro_dst);
328                                 dst->x_host = ipx->ipx_dna.x_host;
329                         }
330                         /*
331                          * Otherwise, we go through the same gateway
332                          * and dst is already set up.
333                          */
334                 } else {
335                 re_route:
336                         RTFREE(ro->ro_rt);
337                         ro->ro_rt = NULL;
338                 }
339         }
340         ipxp->ipxp_lastdst = ipx->ipx_dna;
341 #endif /* ancient_history */
342         return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
343 }
344
345 int
346 ipx_ctloutput(struct socket *so, struct sockopt *sopt)
347 {
348         struct ipxpcb *ipxp = sotoipxpcb(so);
349         int mask, error, optval;
350         short soptval;
351         struct ipx ioptval;
352         long seq;
353
354         KASSERT(ipxp != NULL, ("ipx_ctloutput: ipxp == NULL"));
355         error = 0;
356
357         switch (sopt->sopt_dir) {
358         case SOPT_GET:
359                 switch (sopt->sopt_name) {
360                 case SO_ALL_PACKETS:
361                         mask = IPXP_ALL_PACKETS;
362                         goto get_flags;
363
364                 case SO_HEADERS_ON_INPUT:
365                         mask = IPXP_RAWIN;
366                         goto get_flags;
367
368                 case SO_IPX_CHECKSUM:
369                         mask = IPXP_CHECKSUM;
370                         goto get_flags;
371
372                 case SO_HEADERS_ON_OUTPUT:
373                         mask = IPXP_RAWOUT;
374                 get_flags:
375                         /* Unlocked read. */
376                         soptval = ipxp->ipxp_flags & mask;
377                         error = sooptcopyout(sopt, &soptval, sizeof soptval);
378                         break;
379
380                 case SO_DEFAULT_HEADERS:
381                         ioptval.ipx_len = 0;
382                         ioptval.ipx_sum = 0;
383                         ioptval.ipx_tc = 0;
384                         IPX_LOCK(ipxp);
385                         ioptval.ipx_pt = ipxp->ipxp_dpt;
386                         ioptval.ipx_dna = ipxp->ipxp_faddr;
387                         ioptval.ipx_sna = ipxp->ipxp_laddr;
388                         IPX_UNLOCK(ipxp);
389                         error = sooptcopyout(sopt, &soptval, sizeof soptval);
390                         break;
391
392                 case SO_SEQNO:
393                         IPX_LIST_LOCK();
394                         seq = ipx_pexseq;
395                         ipx_pexseq++;
396                         IPX_LIST_UNLOCK();
397                         error = sooptcopyout(sopt, &seq, sizeof seq);
398                         break;
399
400                 default:
401                         error = EINVAL;
402                 }
403                 break;
404
405         case SOPT_SET:
406                 switch (sopt->sopt_name) {
407                 case SO_ALL_PACKETS:
408                         mask = IPXP_ALL_PACKETS;
409                         goto set_head;
410
411                 case SO_HEADERS_ON_INPUT:
412                         mask = IPXP_RAWIN;
413                         goto set_head;
414
415                 case SO_IPX_CHECKSUM:
416                         mask = IPXP_CHECKSUM;
417                         goto set_head;
418
419                 case SO_HEADERS_ON_OUTPUT:
420                         mask = IPXP_RAWOUT;
421                 set_head:
422                         error = sooptcopyin(sopt, &optval, sizeof optval,
423                                             sizeof optval);
424                         if (error)
425                                 break;
426                         IPX_LOCK(ipxp);
427                         if (optval)
428                                 ipxp->ipxp_flags |= mask;
429                         else
430                                 ipxp->ipxp_flags &= ~mask;
431                         IPX_UNLOCK(ipxp);
432                         break;
433
434                 case SO_DEFAULT_HEADERS:
435                         error = sooptcopyin(sopt, &ioptval, sizeof ioptval,
436                                             sizeof ioptval);
437                         if (error)
438                                 break;
439                         /* Unlocked write. */
440                         ipxp->ipxp_dpt = ioptval.ipx_pt;
441                         break;
442                 default:
443                         error = EINVAL;
444                 }
445                 break;
446         }
447         return (error);
448 }
449
450 static void
451 ipx_usr_abort(struct socket *so)
452 {
453
454         /* XXXRW: Possibly ipx_disconnect() here? */
455         soisdisconnected(so);
456 }
457
458 static int
459 ipx_attach(struct socket *so, int proto, struct thread *td)
460 {
461 #ifdef INVARIANTS
462         struct ipxpcb *ipxp = sotoipxpcb(so);
463 #endif
464         int error;
465
466         KASSERT(ipxp == NULL, ("ipx_attach: ipxp != NULL"));
467         error = soreserve(so, ipxsendspace, ipxrecvspace);
468         if (error != 0)
469                 return (error);
470         IPX_LIST_LOCK();
471         error = ipx_pcballoc(so, &ipxpcb_list, td);
472         IPX_LIST_UNLOCK();
473         return (error);
474 }
475
476 static int
477 ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
478 {
479         struct ipxpcb *ipxp = sotoipxpcb(so);
480         int error;
481
482         KASSERT(ipxp != NULL, ("ipx_bind: ipxp == NULL"));
483         IPX_LIST_LOCK();
484         IPX_LOCK(ipxp);
485         error = ipx_pcbbind(ipxp, nam, td);
486         IPX_UNLOCK(ipxp);
487         IPX_LIST_UNLOCK();
488         return (error);
489 }
490
491 static void
492 ipx_usr_close(struct socket *so)
493 {
494
495         /* XXXRW: Possibly ipx_disconnect() here? */
496         soisdisconnected(so);
497 }
498
499 static int
500 ipx_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
501 {
502         struct ipxpcb *ipxp = sotoipxpcb(so);
503         int error;
504
505         KASSERT(ipxp != NULL, ("ipx_connect: ipxp == NULL"));
506         IPX_LIST_LOCK();
507         IPX_LOCK(ipxp);
508         if (!ipx_nullhost(ipxp->ipxp_faddr)) {
509                 error = EISCONN;
510                 goto out;
511         }
512         error = ipx_pcbconnect(ipxp, nam, td);
513         if (error == 0)
514                 soisconnected(so);
515 out:
516         IPX_UNLOCK(ipxp);
517         IPX_LIST_UNLOCK();
518         return (error);
519 }
520
521 static void
522 ipx_detach(struct socket *so)
523 {
524         struct ipxpcb *ipxp = sotoipxpcb(so);
525
526         /* XXXRW: Should assert detached. */
527         KASSERT(ipxp != NULL, ("ipx_detach: ipxp == NULL"));
528         IPX_LIST_LOCK();
529         IPX_LOCK(ipxp);
530         ipx_pcbdetach(ipxp);
531         ipx_pcbfree(ipxp);
532         IPX_LIST_UNLOCK();
533 }
534
535 static int
536 ipx_disconnect(struct socket *so)
537 {
538         struct ipxpcb *ipxp = sotoipxpcb(so);
539         int error;
540
541         KASSERT(ipxp != NULL, ("ipx_disconnect: ipxp == NULL"));
542         IPX_LIST_LOCK();
543         IPX_LOCK(ipxp);
544         error = 0;
545         if (ipx_nullhost(ipxp->ipxp_faddr)) {
546                 error = ENOTCONN;
547                 goto out;
548         }
549         ipx_pcbdisconnect(ipxp);
550         soisdisconnected(so);
551 out:
552         IPX_UNLOCK(ipxp);
553         IPX_LIST_UNLOCK();
554         return (0);
555 }
556
557 int
558 ipx_peeraddr(struct socket *so, struct sockaddr **nam)
559 {
560         struct ipxpcb *ipxp = sotoipxpcb(so);
561
562         KASSERT(ipxp != NULL, ("ipx_peeraddr: ipxp == NULL"));
563         ipx_getpeeraddr(ipxp, nam);
564         return (0);
565 }
566
567 static int
568 ipx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
569     struct mbuf *control, struct thread *td)
570 {
571         int error;
572         struct ipxpcb *ipxp = sotoipxpcb(so);
573         struct ipx_addr laddr;
574
575         KASSERT(ipxp != NULL, ("ipxp_send: ipxp == NULL"));
576         /*
577          * Attempt to only acquire the necessary locks: if the socket is
578          * already connected, we don't need to hold the IPX list lock to be
579          * used by ipx_pcbconnect() and ipx_pcbdisconnect(), just the IPX
580          * pcb lock.
581          */
582 #ifdef MAC
583         mac_socket_create_mbuf(so, m);
584 #endif
585         if (nam != NULL) {
586                 IPX_LIST_LOCK();
587                 IPX_LOCK(ipxp);
588                 laddr = ipxp->ipxp_laddr;
589                 if (!ipx_nullhost(ipxp->ipxp_faddr)) {
590                         IPX_UNLOCK(ipxp);
591                         IPX_LIST_UNLOCK();
592                         error = EISCONN;
593                         goto send_release;
594                 }
595                 /*
596                  * Must block input while temporarily connected.
597                  */
598                 error = ipx_pcbconnect(ipxp, nam, td);
599                 if (error) {
600                         IPX_UNLOCK(ipxp);
601                         IPX_LIST_UNLOCK();
602                         goto send_release;
603                 }
604         } else {
605                 IPX_LOCK(ipxp);
606                 if (ipx_nullhost(ipxp->ipxp_faddr)) {
607                         IPX_UNLOCK(ipxp);
608                         error = ENOTCONN;
609                         goto send_release;
610                 }
611         }
612         error = ipx_output(ipxp, m);
613         m = NULL;
614         if (nam != NULL) {
615                 ipx_pcbdisconnect(ipxp);
616                 ipxp->ipxp_laddr = laddr;
617                 IPX_UNLOCK(ipxp);
618                 IPX_LIST_UNLOCK();
619         } else
620                 IPX_UNLOCK(ipxp);
621
622 send_release:
623         if (m != NULL)
624                 m_freem(m);
625         return (error);
626 }
627
628 static int
629 ipx_shutdown(so)
630         struct socket *so;
631 {
632
633         KASSERT(so->so_pcb != NULL, ("ipx_shutdown: so_pcb == NULL"));
634         socantsendmore(so);
635         return (0);
636 }
637
638 int
639 ipx_sockaddr(struct socket *so, struct sockaddr **nam)
640 {
641         struct ipxpcb *ipxp = sotoipxpcb(so);
642
643         KASSERT(ipxp != NULL, ("ipx_sockaddr: ipxp == NULL"));
644         ipx_getsockaddr(ipxp, nam);
645         return (0);
646 }
647
648 static int
649 ripx_attach(struct socket *so, int proto, struct thread *td)
650 {
651         int error = 0;
652         struct ipxpcb *ipxp = sotoipxpcb(so);
653
654         KASSERT(ipxp == NULL, ("ripx_attach: ipxp != NULL"));
655
656         if (td != NULL) {
657                 error = priv_check(td, PRIV_NETIPX_RAW);
658                 if (error)
659                         return (error);
660         }
661
662         /*
663          * We hold the IPX list lock for the duration as address parameters
664          * of the IPX pcb are changed.  Since no one else holds a reference
665          * to the ipxpcb yet, we don't need the ipxpcb lock here.
666          */
667         IPX_LIST_LOCK();
668         error = ipx_pcballoc(so, &ipxrawpcb_list, td);
669         if (error)
670                 goto out;
671         ipxp = sotoipxpcb(so);
672         error = soreserve(so, ipxsendspace, ipxrecvspace);
673         if (error)
674                 goto out;
675         ipxp->ipxp_faddr.x_host = ipx_broadhost;
676         ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
677 out:
678         IPX_LIST_UNLOCK();
679         return (error);
680 }