ipx_usrreq.c revision 185928
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 185928 2008-12-11 10:29:35Z rwatson $"); 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 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 448static void 449ipx_usr_abort(struct socket *so) 450{ 451 452 /* XXXRW: Possibly ipx_disconnect() here? */ 453 soisdisconnected(so); 454} 455 456static int 457ipx_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 474static int 475ipx_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 489static void 490ipx_usr_close(struct socket *so) 491{ 492 493 /* XXXRW: Possibly ipx_disconnect() here? */ 494 soisdisconnected(so); 495} 496 497static int 498ipx_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); 513out: 514 IPX_UNLOCK(ipxp); 515 IPX_LIST_UNLOCK(); 516 return (error); 517} 518 519static void 520ipx_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 533static int 534ipx_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); 549out: 550 IPX_UNLOCK(ipxp); 551 IPX_LIST_UNLOCK(); 552 return (0); 553} 554 555int 556ipx_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 565static int 566ipx_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 617send_release: 618 if (m != NULL) 619 m_freem(m); 620 return (error); 621} 622 623static int 624ipx_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 633int 634ipx_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 643static int 644ripx_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; 672out: 673 IPX_LIST_UNLOCK(); 674 return (error); 675} 676