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