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