]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/netipx/ipx_usrreq.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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                         goto set_head;
416
417                 case SO_HEADERS_ON_OUTPUT:
418                         mask = IPXP_RAWOUT;
419                 set_head:
420                         error = sooptcopyin(sopt, &optval, sizeof optval,
421                                             sizeof optval);
422                         if (error)
423                                 break;
424                         IPX_LOCK(ipxp);
425                         if (optval)
426                                 ipxp->ipxp_flags |= mask;
427                         else
428                                 ipxp->ipxp_flags &= ~mask;
429                         IPX_UNLOCK(ipxp);
430                         break;
431
432                 case SO_DEFAULT_HEADERS:
433                         error = sooptcopyin(sopt, &ioptval, sizeof ioptval,
434                                             sizeof ioptval);
435                         if (error)
436                                 break;
437                         /* Unlocked write. */
438                         ipxp->ipxp_dpt = ioptval.ipx_pt;
439                         break;
440                 default:
441                         error = EINVAL;
442                 }
443                 break;
444         }
445         return (error);
446 }
447
448 static void
449 ipx_usr_abort(struct socket *so)
450 {
451
452         /* XXXRW: Possibly ipx_disconnect() here? */
453         soisdisconnected(so);
454 }
455
456 static int
457 ipx_attach(struct socket *so, int proto, struct thread *td)
458 {
459 #ifdef INVARIANTS
460         struct ipxpcb *ipxp = sotoipxpcb(so);
461 #endif
462         int error;
463
464         KASSERT(ipxp == NULL, ("ipx_attach: ipxp != NULL"));
465         error = soreserve(so, ipxsendspace, ipxrecvspace);
466         if (error != 0)
467                 return (error);
468         IPX_LIST_LOCK();
469         error = ipx_pcballoc(so, &ipxpcb_list, td);
470         IPX_LIST_UNLOCK();
471         return (error);
472 }
473
474 static int
475 ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
476 {
477         struct ipxpcb *ipxp = sotoipxpcb(so);
478         int error;
479
480         KASSERT(ipxp != NULL, ("ipx_bind: ipxp == NULL"));
481         IPX_LIST_LOCK();
482         IPX_LOCK(ipxp);
483         error = ipx_pcbbind(ipxp, nam, td);
484         IPX_UNLOCK(ipxp);
485         IPX_LIST_UNLOCK();
486         return (error);
487 }
488
489 static void
490 ipx_usr_close(struct socket *so)
491 {
492
493         /* XXXRW: Possibly ipx_disconnect() here? */
494         soisdisconnected(so);
495 }
496
497 static int
498 ipx_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
499 {
500         struct ipxpcb *ipxp = sotoipxpcb(so);
501         int error;
502
503         KASSERT(ipxp != NULL, ("ipx_connect: ipxp == NULL"));
504         IPX_LIST_LOCK();
505         IPX_LOCK(ipxp);
506         if (!ipx_nullhost(ipxp->ipxp_faddr)) {
507                 error = EISCONN;
508                 goto out;
509         }
510         error = ipx_pcbconnect(ipxp, nam, td);
511         if (error == 0)
512                 soisconnected(so);
513 out:
514         IPX_UNLOCK(ipxp);
515         IPX_LIST_UNLOCK();
516         return (error);
517 }
518
519 static void
520 ipx_detach(struct socket *so)
521 {
522         struct ipxpcb *ipxp = sotoipxpcb(so);
523
524         /* XXXRW: Should assert detached. */
525         KASSERT(ipxp != NULL, ("ipx_detach: ipxp == NULL"));
526         IPX_LIST_LOCK();
527         IPX_LOCK(ipxp);
528         ipx_pcbdetach(ipxp);
529         ipx_pcbfree(ipxp);
530         IPX_LIST_UNLOCK();
531 }
532
533 static int
534 ipx_disconnect(struct socket *so)
535 {
536         struct ipxpcb *ipxp = sotoipxpcb(so);
537         int error;
538
539         KASSERT(ipxp != NULL, ("ipx_disconnect: ipxp == NULL"));
540         IPX_LIST_LOCK();
541         IPX_LOCK(ipxp);
542         error = 0;
543         if (ipx_nullhost(ipxp->ipxp_faddr)) {
544                 error = ENOTCONN;
545                 goto out;
546         }
547         ipx_pcbdisconnect(ipxp);
548         soisdisconnected(so);
549 out:
550         IPX_UNLOCK(ipxp);
551         IPX_LIST_UNLOCK();
552         return (0);
553 }
554
555 int
556 ipx_peeraddr(struct socket *so, struct sockaddr **nam)
557 {
558         struct ipxpcb *ipxp = sotoipxpcb(so);
559
560         KASSERT(ipxp != NULL, ("ipx_peeraddr: ipxp == NULL"));
561         ipx_getpeeraddr(ipxp, nam);
562         return (0);
563 }
564
565 static int
566 ipx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
567     struct mbuf *control, struct thread *td)
568 {
569         int error;
570         struct ipxpcb *ipxp = sotoipxpcb(so);
571         struct ipx_addr laddr;
572
573         KASSERT(ipxp != NULL, ("ipxp_send: ipxp == NULL"));
574         /*
575          * Attempt to only acquire the necessary locks: if the socket is
576          * already connected, we don't need to hold the IPX list lock to be
577          * used by ipx_pcbconnect() and ipx_pcbdisconnect(), just the IPX
578          * pcb lock.
579          */
580         if (nam != NULL) {
581                 IPX_LIST_LOCK();
582                 IPX_LOCK(ipxp);
583                 laddr = ipxp->ipxp_laddr;
584                 if (!ipx_nullhost(ipxp->ipxp_faddr)) {
585                         IPX_UNLOCK(ipxp);
586                         IPX_LIST_UNLOCK();
587                         error = EISCONN;
588                         goto send_release;
589                 }
590                 /*
591                  * Must block input while temporarily connected.
592                  */
593                 error = ipx_pcbconnect(ipxp, nam, td);
594                 if (error) {
595                         IPX_UNLOCK(ipxp);
596                         IPX_LIST_UNLOCK();
597                         goto send_release;
598                 }
599         } else {
600                 IPX_LOCK(ipxp);
601                 if (ipx_nullhost(ipxp->ipxp_faddr)) {
602                         IPX_UNLOCK(ipxp);
603                         error = ENOTCONN;
604                         goto send_release;
605                 }
606         }
607         error = ipx_output(ipxp, m);
608         m = NULL;
609         if (nam != NULL) {
610                 ipx_pcbdisconnect(ipxp);
611                 ipxp->ipxp_laddr = laddr;
612                 IPX_UNLOCK(ipxp);
613                 IPX_LIST_UNLOCK();
614         } else
615                 IPX_UNLOCK(ipxp);
616
617 send_release:
618         if (m != NULL)
619                 m_freem(m);
620         return (error);
621 }
622
623 static int
624 ipx_shutdown(so)
625         struct socket *so;
626 {
627
628         KASSERT(so->so_pcb != NULL, ("ipx_shutdown: so_pcb == NULL"));
629         socantsendmore(so);
630         return (0);
631 }
632
633 int
634 ipx_sockaddr(struct socket *so, struct sockaddr **nam)
635 {
636         struct ipxpcb *ipxp = sotoipxpcb(so);
637
638         KASSERT(ipxp != NULL, ("ipx_sockaddr: ipxp == NULL"));
639         ipx_getsockaddr(ipxp, nam);
640         return (0);
641 }
642
643 static int
644 ripx_attach(struct socket *so, int proto, struct thread *td)
645 {
646         int error = 0;
647         struct ipxpcb *ipxp = sotoipxpcb(so);
648
649         KASSERT(ipxp == NULL, ("ripx_attach: ipxp != NULL"));
650
651         if (td != NULL) {
652                 error = priv_check(td, PRIV_NETIPX_RAW);
653                 if (error)
654                         return (error);
655         }
656
657         /*
658          * We hold the IPX list lock for the duration as address parameters
659          * of the IPX pcb are changed.  Since no one else holds a reference
660          * to the ipxpcb yet, we don't need the ipxpcb lock here.
661          */
662         IPX_LIST_LOCK();
663         error = ipx_pcballoc(so, &ipxrawpcb_list, td);
664         if (error)
665                 goto out;
666         ipxp = sotoipxpcb(so);
667         error = soreserve(so, ipxsendspace, ipxrecvspace);
668         if (error)
669                 goto out;
670         ipxp->ipxp_faddr.x_host = ipx_broadhost;
671         ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
672 out:
673         IPX_LIST_UNLOCK();
674         return (error);
675 }