ipx_usrreq.c revision 180816
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: head/sys/netipx/ipx_usrreq.c 180816 2008-07-25 23:54:07Z trhodes $"); 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 97static int ipxsendspace = IPXSNDQ; 98SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 99 &ipxsendspace, 0, "Send buffer space"); 100static int ipxrecvspace = IPXRCVQ; 101SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 102 &ipxrecvspace, 0, "Receive buffer space"); 103 104static void ipx_usr_abort(struct socket *so); 105static int ipx_attach(struct socket *so, int proto, struct thread *td); 106static int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 107static int ipx_connect(struct socket *so, struct sockaddr *nam, 108 struct thread *td); 109static void ipx_detach(struct socket *so); 110static int ipx_disconnect(struct socket *so); 111static int ipx_send(struct socket *so, int flags, struct mbuf *m, 112 struct sockaddr *addr, struct mbuf *control, 113 struct thread *td); 114static int ipx_shutdown(struct socket *so); 115static int ripx_attach(struct socket *so, int proto, struct thread *td); 116static int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 117static void ipx_usr_close(struct socket *so); 118 119struct 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 134struct 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 */ 152void 153ipx_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 */ 199void 200ipx_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 223static int 224ipx_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 343int 344ipx_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 447static void 448ipx_usr_abort(struct socket *so) 449{ 450 451 /* XXXRW: Possibly ipx_disconnect() here? */ 452 soisdisconnected(so); 453} 454 455static int 456ipx_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 473static int 474ipx_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 488static void 489ipx_usr_close(struct socket *so) 490{ 491 492 /* XXXRW: Possibly ipx_disconnect() here? */ 493 soisdisconnected(so); 494} 495 496static int 497ipx_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); 512out: 513 IPX_UNLOCK(ipxp); 514 IPX_LIST_UNLOCK(); 515 return (error); 516} 517 518static void 519ipx_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 532static int 533ipx_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); 548out: 549 IPX_UNLOCK(ipxp); 550 IPX_LIST_UNLOCK(); 551 return (0); 552} 553 554int 555ipx_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 564static int 565ipx_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 616send_release: 617 if (m != NULL) 618 m_freem(m); 619 return (error); 620} 621 622static int 623ipx_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 632int 633ipx_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 642static int 643ripx_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; 671out: 672 IPX_LIST_UNLOCK(); 673 return (error); 674} 675