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