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