ipx_usrreq.c revision 272461
1139804Simp/*- 265534Salfred * Copyright (c) 1984, 1985, 1986, 1987, 1993 365534Salfred * The Regents of the University of California. 461837Salfred * Copyright (c) 2004-2006 Robert N. M. Watson 561837Salfred * All rights reserved. 661837Salfred * 761837Salfred * Redistribution and use in source and binary forms, with or without 861837Salfred * modification, are permitted provided that the following conditions 961837Salfred * are met: 1061837Salfred * 1. Redistributions of source code must retain the above copyright 1161837Salfred * notice, this list of conditions and the following disclaimer. 1261837Salfred * 2. Redistributions in binary form must reproduce the above copyright 1361837Salfred * notice, this list of conditions and the following disclaimer in the 1461837Salfred * documentation and/or other materials provided with the distribution. 1561837Salfred * 4. Neither the name of the University nor the names of its contributors 1661837Salfred * may be used to endorse or promote products derived from this software 1761837Salfred * without specific prior written permission. 1861837Salfred * 1961837Salfred * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2061837Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2161837Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2261837Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2361837Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2461837Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2561837Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2661837Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2761837Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28116182Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29116182Sobrien * SUCH DAMAGE. 30116182Sobrien * 3161837Salfred * Copyright (c) 1995, Mike Mitchell 3261837Salfred * All rights reserved. 3377598Sjesper * 3461837Salfred * Redistribution and use in source and binary forms, with or without 3561837Salfred * modification, are permitted provided that the following conditions 3661837Salfred * are met: 3761837Salfred * 1. Redistributions of source code must retain the above copyright 38129920Srwatson * notice, this list of conditions and the following disclaimer. 3961837Salfred * 2. Redistributions in binary form must reproduce the above copyright 4061837Salfred * notice, this list of conditions and the following disclaimer in the 41129876Sphk * documentation and/or other materials provided with the distribution. 42129920Srwatson * 3. All advertising materials mentioning features or use of this software 4361837Salfred * must display the following acknowledgement: 4465534Salfred * This product includes software developed by the University of 4561837Salfred * California, Berkeley and its contributors. 4661837Salfred * 4. Neither the name of the University nor the names of its contributors 4761837Salfred * may be used to endorse or promote products derived from this software 4861837Salfred * without specific prior written permission. 49129920Srwatson * 50129920Srwatson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 51129920Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52129920Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53129920Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 54129920Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5561837Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5661837Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5761837Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5861837Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5961837Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6065534Salfred * SUCH DAMAGE. 6165534Salfred * 6265534Salfred * @(#)ipx_usrreq.c 6365534Salfred */ 6465534Salfred 6565534Salfred#include <sys/cdefs.h> 6665534Salfred__FBSDID("$FreeBSD: releng/10.1/sys/netipx/ipx_usrreq.c 243882 2012-12-05 08:04:20Z glebius $"); 6761837Salfred 6861837Salfred#include "opt_ipx.h" 6961837Salfred 7061837Salfred#include <sys/param.h> 7161837Salfred#include <sys/kernel.h> 7261837Salfred#include <sys/lock.h> 7361837Salfred#include <sys/mbuf.h> 7461837Salfred#include <sys/priv.h> 7561837Salfred#include <sys/protosw.h> 7661837Salfred#include <sys/signalvar.h> 7761837Salfred#include <sys/socket.h> 78129920Srwatson#include <sys/socketvar.h> 7961837Salfred#include <sys/sx.h> 8061837Salfred#include <sys/sysctl.h> 8161837Salfred#include <sys/systm.h> 82129920Srwatson 8361837Salfred#include <net/if.h> 8461837Salfred#include <net/route.h> 8561837Salfred 86129920Srwatson#include <netinet/in.h> 8761837Salfred 8861837Salfred#include <netipx/ipx.h> 8961837Salfred#include <netipx/ipx_if.h> 9061837Salfred#include <netipx/ipx_pcb.h> 9161837Salfred#include <netipx/ipx_var.h> 9261837Salfred 9361837Salfred#include <security/mac/mac_framework.h> 94129920Srwatson 9561837Salfred/* 9661837Salfred * IPX protocol implementation. 9761837Salfred */ 9861837Salfred 9961837Salfredstatic int ipxsendspace = IPXSNDQ; 10061837SalfredSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 10161837Salfred &ipxsendspace, 0, "Send buffer space"); 10261837Salfredstatic int ipxrecvspace = IPXRCVQ; 10361837SalfredSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 10461837Salfred &ipxrecvspace, 0, "Receive buffer space"); 10561837Salfred 10661837Salfredstatic void ipx_usr_abort(struct socket *so); 10761837Salfredstatic int ipx_attach(struct socket *so, int proto, struct thread *td); 10861837Salfredstatic int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 10961837Salfredstatic int ipx_connect(struct socket *so, struct sockaddr *nam, 11061837Salfred struct thread *td); 11161837Salfredstatic void ipx_detach(struct socket *so); 11261837Salfredstatic int ipx_disconnect(struct socket *so); 11361837Salfredstatic int ipx_send(struct socket *so, int flags, struct mbuf *m, 11461837Salfred struct sockaddr *addr, struct mbuf *control, 11561837Salfred struct thread *td); 116129920Srwatsonstatic int ipx_shutdown(struct socket *so); 11761837Salfredstatic int ripx_attach(struct socket *so, int proto, struct thread *td); 11861837Salfredstatic int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 119129920Srwatsonstatic void ipx_usr_close(struct socket *so); 120129920Srwatson 12161837Salfredstruct pr_usrreqs ipx_usrreqs = { 122129920Srwatson .pru_abort = ipx_usr_abort, 12361837Salfred .pru_attach = ipx_attach, 12461837Salfred .pru_bind = ipx_bind, 12561837Salfred .pru_connect = ipx_connect, 12661837Salfred .pru_control = ipx_control, 12761837Salfred .pru_detach = ipx_detach, 12861837Salfred .pru_disconnect = ipx_disconnect, 12961837Salfred .pru_peeraddr = ipx_peeraddr, 130129920Srwatson .pru_send = ipx_send, 13161837Salfred .pru_shutdown = ipx_shutdown, 13261837Salfred .pru_sockaddr = ipx_sockaddr, 13361837Salfred .pru_close = ipx_usr_close, 134111119Simp}; 13561837Salfred 13661837Salfredstruct pr_usrreqs ripx_usrreqs = { 13761837Salfred .pru_abort = ipx_usr_abort, 13861837Salfred .pru_attach = ripx_attach, 13961837Salfred .pru_bind = ipx_bind, 14063645Salfred .pru_connect = ipx_connect, 14163645Salfred .pru_control = ipx_control, 14263645Salfred .pru_detach = ipx_detach, 14363645Salfred .pru_disconnect = ipx_disconnect, 14463645Salfred .pru_peeraddr = ipx_peeraddr, 14563645Salfred .pru_send = ipx_send, 14665534Salfred .pru_shutdown = ipx_shutdown, 14765534Salfred .pru_sockaddr = ipx_sockaddr, 14865534Salfred .pru_close = ipx_usr_close, 14965534Salfred}; 15061837Salfred 15161837Salfred/* 15261837Salfred * This may also be called for raw listeners. 15361837Salfred */ 15461837Salfredvoid 15561837Salfredipx_input(struct mbuf *m, struct ipxpcb *ipxp) 15661837Salfred{ 15761837Salfred struct ipx *ipx = mtod(m, struct ipx *); 15861837Salfred struct ifnet *ifp = m->m_pkthdr.rcvif; 15961837Salfred struct sockaddr_ipx ipx_ipx; 16061837Salfred 16161837Salfred KASSERT(ipxp != NULL, ("ipx_input: NULL ipxpcb")); 16261837Salfred 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