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