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