]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netipx/ipx_usrreq.c
This commit was generated by cvs2svn to compensate for changes in r165071,
[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) 1995, Mike Mitchell
5  * Copyright (c) 2004-2006 Robert N. M. Watson
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *      @(#)ipx_usrreq.c
37  */
38
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41
42 #include "opt_ipx.h"
43
44 #include <sys/param.h>
45 #include <sys/kernel.h>
46 #include <sys/lock.h>
47 #include <sys/mbuf.h>
48 #include <sys/priv.h>
49 #include <sys/protosw.h>
50 #include <sys/signalvar.h>
51 #include <sys/socket.h>
52 #include <sys/socketvar.h>
53 #include <sys/sx.h>
54 #include <sys/sysctl.h>
55 #include <sys/systm.h>
56
57 #include <net/if.h>
58 #include <net/route.h>
59
60 #include <netinet/in.h>
61
62 #include <netipx/ipx.h>
63 #include <netipx/ipx_if.h>
64 #include <netipx/ipx_ip.h>
65 #include <netipx/ipx_pcb.h>
66 #include <netipx/ipx_var.h>
67
68 /*
69  * IPX protocol implementation.
70  */
71
72 static int ipxsendspace = IPXSNDQ;
73 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW,
74             &ipxsendspace, 0, "");
75 static int ipxrecvspace = IPXRCVQ;
76 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
77             &ipxrecvspace, 0, "");
78
79 static  void ipx_usr_abort(struct socket *so);
80 static  int ipx_attach(struct socket *so, int proto, struct thread *td);
81 static  int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
82 static  int ipx_connect(struct socket *so, struct sockaddr *nam,
83                         struct thread *td);
84 static  void ipx_detach(struct socket *so);
85 static  int ipx_disconnect(struct socket *so);
86 static  int ipx_send(struct socket *so, int flags, struct mbuf *m,
87                      struct sockaddr *addr, struct mbuf *control,
88                      struct thread *td);
89 static  int ipx_shutdown(struct socket *so);
90 static  int ripx_attach(struct socket *so, int proto, struct thread *td);
91 static  int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0);
92 static  void ipx_usr_close(struct socket *so);
93
94 struct  pr_usrreqs ipx_usrreqs = {
95         .pru_abort =            ipx_usr_abort,
96         .pru_attach =           ipx_attach,
97         .pru_bind =             ipx_bind,
98         .pru_connect =          ipx_connect,
99         .pru_control =          ipx_control,
100         .pru_detach =           ipx_detach,
101         .pru_disconnect =       ipx_disconnect,
102         .pru_peeraddr =         ipx_peeraddr,
103         .pru_send =             ipx_send,
104         .pru_shutdown =         ipx_shutdown,
105         .pru_sockaddr =         ipx_sockaddr,
106         .pru_close =            ipx_usr_close,
107 };
108
109 struct  pr_usrreqs ripx_usrreqs = {
110         .pru_abort =            ipx_usr_abort,
111         .pru_attach =           ripx_attach,
112         .pru_bind =             ipx_bind,
113         .pru_connect =          ipx_connect,
114         .pru_control =          ipx_control,
115         .pru_detach =           ipx_detach,
116         .pru_disconnect =       ipx_disconnect,
117         .pru_peeraddr =         ipx_peeraddr,
118         .pru_send =             ipx_send,
119         .pru_shutdown =         ipx_shutdown,
120         .pru_sockaddr =         ipx_sockaddr,
121         .pru_close =            ipx_usr_close,
122 };
123
124 /*
125  *  This may also be called for raw listeners.
126  */
127 void
128 ipx_input(m, ipxp)
129         struct mbuf *m;
130         register struct ipxpcb *ipxp;
131 {
132         register struct ipx *ipx = mtod(m, struct ipx *);
133         struct ifnet *ifp = m->m_pkthdr.rcvif;
134         struct sockaddr_ipx ipx_ipx;
135
136         KASSERT(ipxp != NULL, ("ipx_input: NULL ipxpcb"));
137         IPX_LOCK_ASSERT(ipxp);
138         /*
139          * Construct sockaddr format source address.
140          * Stuff source address and datagram in user buffer.
141          */
142         ipx_ipx.sipx_len = sizeof(ipx_ipx);
143         ipx_ipx.sipx_family = AF_IPX;
144         ipx_ipx.sipx_addr = ipx->ipx_sna;
145         ipx_ipx.sipx_zero[0] = '\0';
146         ipx_ipx.sipx_zero[1] = '\0';
147         if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) {
148                 register struct ifaddr *ifa;
149
150                 for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL;
151                      ifa = TAILQ_NEXT(ifa, ifa_link)) {
152                         if (ifa->ifa_addr->sa_family == AF_IPX) {
153                                 ipx_ipx.sipx_addr.x_net =
154                                         IA_SIPX(ifa)->sipx_addr.x_net;
155                                 break;
156                         }
157                 }
158         }
159         ipxp->ipxp_rpt = ipx->ipx_pt;
160         if ((ipxp->ipxp_flags & IPXP_RAWIN) == 0) {
161                 m->m_len -= sizeof(struct ipx);
162                 m->m_pkthdr.len -= sizeof(struct ipx);
163                 m->m_data += sizeof(struct ipx);
164         }
165         if (sbappendaddr(&ipxp->ipxp_socket->so_rcv,
166             (struct sockaddr *)&ipx_ipx, m, NULL) == 0)
167                 m_freem(m);
168         else
169                 sorwakeup(ipxp->ipxp_socket);
170 }
171
172 /*
173  * Drop connection, reporting
174  * the specified error.
175  */
176 void
177 ipx_drop(ipxp, errno)
178         register struct ipxpcb *ipxp;
179         int errno;
180 {
181         struct socket *so = ipxp->ipxp_socket;
182
183         IPX_LIST_LOCK_ASSERT();
184         IPX_LOCK_ASSERT(ipxp);
185
186         /*
187          * someday, in the IPX world
188          * we will generate error protocol packets
189          * announcing that the socket has gone away.
190          *
191          * XXX Probably never. IPX does not have error packets.
192          */
193         /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
194                 tp->t_state = TCPS_CLOSED;
195                 tcp_output(tp);
196         }*/
197         so->so_error = errno;
198         ipx_pcbdisconnect(ipxp);
199         soisdisconnected(so);
200 }
201
202 static int
203 ipx_output(ipxp, m0)
204         struct ipxpcb *ipxp;
205         struct mbuf *m0;
206 {
207         register struct ipx *ipx;
208         register struct socket *so;
209         register int len = 0;
210         register struct route *ro;
211         struct mbuf *m;
212         struct mbuf *mprev = NULL;
213
214         IPX_LOCK_ASSERT(ipxp);
215
216         /*
217          * Calculate data length.
218          */
219         for (m = m0; m != NULL; m = m->m_next) {
220                 mprev = m;
221                 len += m->m_len;
222         }
223         /*
224          * Make sure packet is actually of even length.
225          */
226
227         if (len & 1) {
228                 m = mprev;
229                 if ((m->m_flags & M_EXT) == 0 &&
230                         (m->m_len + m->m_data < &m->m_dat[MLEN])) {
231                         mtod(m, char*)[m->m_len++] = 0;
232                 } else {
233                         struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
234
235                         if (m1 == NULL) {
236                                 m_freem(m0);
237                                 return (ENOBUFS);
238                         }
239                         m1->m_len = 1;
240                         * mtod(m1, char *) = 0;
241                         m->m_next = m1;
242                 }
243                 m0->m_pkthdr.len++;
244         }
245
246         /*
247          * Fill in mbuf with extended IPX header
248          * and addresses and length put into network format.
249          */
250         m = m0;
251         if (ipxp->ipxp_flags & IPXP_RAWOUT) {
252                 ipx = mtod(m, struct ipx *);
253         } else {
254                 M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT);
255                 if (m == NULL)
256                         return (ENOBUFS);
257                 ipx = mtod(m, struct ipx *);
258                 ipx->ipx_tc = 0;
259                 ipx->ipx_pt = ipxp->ipxp_dpt;
260                 ipx->ipx_sna = ipxp->ipxp_laddr;
261                 ipx->ipx_dna = ipxp->ipxp_faddr;
262                 len += sizeof(struct ipx);
263         }
264
265         ipx->ipx_len = htons((u_short)len);
266
267         if (ipxp->ipxp_flags & IPXP_CHECKSUM) {
268                 ipx->ipx_sum = ipx_cksum(m, len);
269         } else
270                 ipx->ipx_sum = 0xffff;
271
272         /*
273          * Output datagram.
274          */
275         so = ipxp->ipxp_socket;
276         if (so->so_options & SO_DONTROUTE)
277                 return (ipx_outputfl(m, (struct route *)NULL,
278                     (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
279         /*
280          * Use cached route for previous datagram if
281          * possible.  If the previous net was the same
282          * and the interface was a broadcast medium, or
283          * if the previous destination was identical,
284          * then we are ok.
285          *
286          * NB: We don't handle broadcasts because that
287          *     would require 3 subroutine calls.
288          */
289         ro = &ipxp->ipxp_route;
290 #ifdef ancient_history
291         /*
292          * I think that this will all be handled in ipx_pcbconnect!
293          */
294         if (ro->ro_rt != NULL) {
295                 if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
296                         /*
297                          * This assumes we have no GH type routes
298                          */
299                         if (ro->ro_rt->rt_flags & RTF_HOST) {
300                                 if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
301                                         goto re_route;
302
303                         }
304                         if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
305                                 register struct ipx_addr *dst =
306                                                 &satoipx_addr(ro->ro_dst);
307                                 dst->x_host = ipx->ipx_dna.x_host;
308                         }
309                         /*
310                          * Otherwise, we go through the same gateway
311                          * and dst is already set up.
312                          */
313                 } else {
314                 re_route:
315                         RTFREE(ro->ro_rt);
316                         ro->ro_rt = NULL;
317                 }
318         }
319         ipxp->ipxp_lastdst = ipx->ipx_dna;
320 #endif /* ancient_history */
321         return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
322 }
323
324 int
325 ipx_ctloutput(so, sopt)
326         struct socket *so;
327         struct sockopt *sopt;
328 {
329         struct ipxpcb *ipxp = sotoipxpcb(so);
330         int mask, error, optval;
331         short soptval;
332         struct ipx ioptval;
333         long seq;
334
335         KASSERT(ipxp != NULL, ("ipx_ctloutput: ipxp == NULL"));
336         error = 0;
337
338         switch (sopt->sopt_dir) {
339         case SOPT_GET:
340                 switch (sopt->sopt_name) {
341                 case SO_ALL_PACKETS:
342                         mask = IPXP_ALL_PACKETS;
343                         goto get_flags;
344
345                 case SO_HEADERS_ON_INPUT:
346                         mask = IPXP_RAWIN;
347                         goto get_flags;
348
349                 case SO_IPX_CHECKSUM:
350                         mask = IPXP_CHECKSUM;
351                         goto get_flags;
352
353                 case SO_HEADERS_ON_OUTPUT:
354                         mask = IPXP_RAWOUT;
355                 get_flags:
356                         /* Unlocked read. */
357                         soptval = ipxp->ipxp_flags & mask;
358                         error = sooptcopyout(sopt, &soptval, sizeof soptval);
359                         break;
360
361                 case SO_DEFAULT_HEADERS:
362                         ioptval.ipx_len = 0;
363                         ioptval.ipx_sum = 0;
364                         ioptval.ipx_tc = 0;
365                         IPX_LOCK(ipxp);
366                         ioptval.ipx_pt = ipxp->ipxp_dpt;
367                         ioptval.ipx_dna = ipxp->ipxp_faddr;
368                         ioptval.ipx_sna = ipxp->ipxp_laddr;
369                         IPX_UNLOCK(ipxp);
370                         error = sooptcopyout(sopt, &soptval, sizeof soptval);
371                         break;
372
373                 case SO_SEQNO:
374                         IPX_LIST_LOCK();
375                         seq = ipx_pexseq;
376                         ipx_pexseq++;
377                         IPX_LIST_UNLOCK();
378                         error = sooptcopyout(sopt, &seq, sizeof seq);
379                         break;
380
381                 default:
382                         error = EINVAL;
383                 }
384                 break;
385
386         case SOPT_SET:
387                 switch (sopt->sopt_name) {
388                 case SO_ALL_PACKETS:
389                         mask = IPXP_ALL_PACKETS;
390                         goto set_head;
391
392                 case SO_HEADERS_ON_INPUT:
393                         mask = IPXP_RAWIN;
394                         goto set_head;
395
396                 case SO_IPX_CHECKSUM:
397                         mask = IPXP_CHECKSUM;
398
399                 case SO_HEADERS_ON_OUTPUT:
400                         mask = IPXP_RAWOUT;
401                 set_head:
402                         error = sooptcopyin(sopt, &optval, sizeof optval,
403                                             sizeof optval);
404                         if (error)
405                                 break;
406                         IPX_LOCK(ipxp);
407                         if (optval)
408                                 ipxp->ipxp_flags |= mask;
409                         else
410                                 ipxp->ipxp_flags &= ~mask;
411                         IPX_UNLOCK(ipxp);
412                         break;
413
414                 case SO_DEFAULT_HEADERS:
415                         error = sooptcopyin(sopt, &ioptval, sizeof ioptval,
416                                             sizeof ioptval);
417                         if (error)
418                                 break;
419                         /* Unlocked write. */
420                         ipxp->ipxp_dpt = ioptval.ipx_pt;
421                         break;
422 #ifdef IPXIP
423                 case SO_IPXIP_ROUTE:
424                         error = ipxip_route(so, sopt);
425                         break;
426 #endif /* IPXIP */
427                 default:
428                         error = EINVAL;
429                 }
430                 break;
431         }
432         return (error);
433 }
434
435 static void
436 ipx_usr_abort(so)
437         struct socket *so;
438 {
439
440         /* XXXRW: Possibly ipx_disconnect() here? */
441         soisdisconnected(so);
442 }
443
444 static int
445 ipx_attach(so, proto, td)
446         struct socket *so;
447         int proto;
448         struct thread *td;
449 {
450 #ifdef INVARIANTS
451         struct ipxpcb *ipxp = sotoipxpcb(so);
452 #endif
453         int error;
454
455         KASSERT(ipxp == NULL, ("ipx_attach: ipxp != NULL"));
456         error = soreserve(so, ipxsendspace, ipxrecvspace);
457         if (error != 0)
458                 return (error);
459         IPX_LIST_LOCK();
460         error = ipx_pcballoc(so, &ipxpcb_list, td);
461         IPX_LIST_UNLOCK();
462         return (error);
463 }
464
465 static int
466 ipx_bind(so, nam, td)
467         struct socket *so;
468         struct sockaddr *nam;
469         struct thread *td;
470 {
471         struct ipxpcb *ipxp = sotoipxpcb(so);
472         int error;
473
474         KASSERT(ipxp != NULL, ("ipx_bind: ipxp == NULL"));
475         IPX_LIST_LOCK();
476         IPX_LOCK(ipxp);
477         error = ipx_pcbbind(ipxp, nam, td);
478         IPX_UNLOCK(ipxp);
479         IPX_LIST_UNLOCK();
480         return (error);
481 }
482
483 static void
484 ipx_usr_close(so)
485         struct socket *so;
486 {
487
488         /* XXXRW: Possibly ipx_disconnect() here? */
489         soisdisconnected(so);
490 }
491
492 static int
493 ipx_connect(so, nam, td)
494         struct socket *so;
495         struct sockaddr *nam;
496         struct thread *td;
497 {
498         struct ipxpcb *ipxp = sotoipxpcb(so);
499         int error;
500
501         KASSERT(ipxp != NULL, ("ipx_connect: ipxp == NULL"));
502         IPX_LIST_LOCK();
503         IPX_LOCK(ipxp);
504         if (!ipx_nullhost(ipxp->ipxp_faddr)) {
505                 error = EISCONN;
506                 goto out;
507         }
508         error = ipx_pcbconnect(ipxp, nam, td);
509         if (error == 0)
510                 soisconnected(so);
511 out:
512         IPX_UNLOCK(ipxp);
513         IPX_LIST_UNLOCK();
514         return (error);
515 }
516
517 static void
518 ipx_detach(so)
519         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(so)
534         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(so, nam)
557         struct socket *so;
558         struct sockaddr **nam;
559 {
560         struct ipxpcb *ipxp = sotoipxpcb(so);
561
562         KASSERT(ipxp != NULL, ("ipx_peeraddr: ipxp == NULL"));
563         ipx_setpeeraddr(ipxp, nam);
564         return (0);
565 }
566
567 static int
568 ipx_send(so, flags, m, nam, control, td)
569         struct socket *so;
570         int flags;
571         struct mbuf *m;
572         struct sockaddr *nam;
573         struct mbuf *control;
574         struct thread *td;
575 {
576         int error;
577         struct ipxpcb *ipxp = sotoipxpcb(so);
578         struct ipx_addr laddr;
579
580         KASSERT(ipxp != NULL, ("ipxp_send: ipxp == NULL"));
581         /*
582          * Attempt to only acquire the necessary locks: if the socket is
583          * already connected, we don't need to hold the IPX list lock to be
584          * used by ipx_pcbconnect() and ipx_pcbdisconnect(), just the IPX
585          * pcb lock.
586          */
587         if (nam != NULL) {
588                 IPX_LIST_LOCK();
589                 IPX_LOCK(ipxp);
590                 laddr = ipxp->ipxp_laddr;
591                 if (!ipx_nullhost(ipxp->ipxp_faddr)) {
592                         IPX_UNLOCK(ipxp);
593                         IPX_LIST_UNLOCK();
594                         error = EISCONN;
595                         goto send_release;
596                 }
597                 /*
598                  * Must block input while temporarily connected.
599                  */
600                 error = ipx_pcbconnect(ipxp, nam, td);
601                 if (error) {
602                         IPX_UNLOCK(ipxp);
603                         IPX_LIST_UNLOCK();
604                         goto send_release;
605                 }
606         } else {
607                 IPX_LOCK(ipxp);
608                 if (ipx_nullhost(ipxp->ipxp_faddr)) {
609                         IPX_UNLOCK(ipxp);
610                         error = ENOTCONN;
611                         goto send_release;
612                 }
613         }
614         error = ipx_output(ipxp, m);
615         m = NULL;
616         if (nam != NULL) {
617                 ipx_pcbdisconnect(ipxp);
618                 ipxp->ipxp_laddr = laddr;
619                 IPX_UNLOCK(ipxp);
620                 IPX_LIST_UNLOCK();
621         } else
622                 IPX_UNLOCK(ipxp);
623
624 send_release:
625         if (m != NULL)
626                 m_freem(m);
627         return (error);
628 }
629
630 static int
631 ipx_shutdown(so)
632         struct socket *so;
633 {
634
635         KASSERT(so->so_pcb != NULL, ("ipx_shutdown: so_pcb == NULL"));
636         socantsendmore(so);
637         return (0);
638 }
639
640 int
641 ipx_sockaddr(so, nam)
642         struct socket *so;
643         struct sockaddr **nam;
644 {
645         struct ipxpcb *ipxp = sotoipxpcb(so);
646
647         KASSERT(ipxp != NULL, ("ipx_sockaddr: ipxp == NULL"));
648         ipx_setsockaddr(ipxp, nam);
649         return (0);
650 }
651
652 static int
653 ripx_attach(so, proto, td)
654         struct socket *so;
655         int proto;
656         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 }