ipx_usrreq.c revision 139930
1157184Sache/*- 2157184Sache * Copyright (c) 2004-2005 Robert N. M. Watson 3157184Sache * Copyright (c) 1995, Mike Mitchell 4157184Sache * Copyright (c) 1984, 1985, 1986, 1987, 1993 5157184Sache * The Regents of the University of California. All rights reserved. 6157184Sache * 7157184Sache * Redistribution and use in source and binary forms, with or without 8157184Sache * modification, are permitted provided that the following conditions 9157184Sache * are met: 10157184Sache * 1. Redistributions of source code must retain the above copyright 11157184Sache * notice, this list of conditions and the following disclaimer. 12157184Sache * 2. Redistributions in binary form must reproduce the above copyright 13157184Sache * notice, this list of conditions and the following disclaimer in the 14157184Sache * documentation and/or other materials provided with the distribution. 15157184Sache * 3. All advertising materials mentioning features or use of this software 16157184Sache * must display the following acknowledgement: 17157184Sache * This product includes software developed by the University of 18157184Sache * California, Berkeley and its contributors. 19157184Sache * 4. Neither the name of the University nor the names of its contributors 20157184Sache * may be used to endorse or promote products derived from this software 21157184Sache * without specific prior written permission. 22157184Sache * 23157184Sache * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24157184Sache * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25157184Sache * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26157184Sache * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27157184Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28157184Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29157184Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30157184Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31157184Sache * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32157184Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33157184Sache * SUCH DAMAGE. 34157184Sache * 35157184Sache * @(#)ipx_usrreq.c 36157184Sache */ 37157184Sache 38157184Sache#include <sys/cdefs.h> 39157184Sache__FBSDID("$FreeBSD: head/sys/netipx/ipx_usrreq.c 139930 2005-01-09 05:15:59Z rwatson $"); 40157184Sache 41157184Sache#include "opt_ipx.h" 42157184Sache 43157184Sache#include <sys/param.h> 44157184Sache#include <sys/kernel.h> 45157184Sache#include <sys/lock.h> 46157184Sache#include <sys/mbuf.h> 47157184Sache#include <sys/protosw.h> 48157184Sache#include <sys/signalvar.h> 49157184Sache#include <sys/socket.h> 50157184Sache#include <sys/socketvar.h> 51157184Sache#include <sys/sx.h> 52157184Sache#include <sys/sysctl.h> 53157184Sache#include <sys/systm.h> 54157184Sache 55157184Sache#include <net/if.h> 56157184Sache#include <net/route.h> 57157184Sache 58157184Sache#include <netinet/in.h> 59157184Sache 60157184Sache#include <netipx/ipx.h> 61157184Sache#include <netipx/ipx_if.h> 62157184Sache#include <netipx/ipx_ip.h> 63157184Sache#include <netipx/ipx_pcb.h> 64157184Sache#include <netipx/ipx_var.h> 65157184Sache 66157184Sache/* 67157184Sache * IPX protocol implementation. 68157184Sache */ 69157184Sache 70157184Sachestatic int ipxsendspace = IPXSNDQ; 71157184SacheSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 72157184Sache &ipxsendspace, 0, ""); 73157184Sachestatic int ipxrecvspace = IPXRCVQ; 74157184SacheSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 75157184Sache &ipxrecvspace, 0, ""); 76157184Sache 77157184Sachestatic int ipx_usr_abort(struct socket *so); 78157184Sachestatic int ipx_attach(struct socket *so, int proto, struct thread *td); 79157184Sachestatic int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 80157184Sachestatic int ipx_connect(struct socket *so, struct sockaddr *nam, 81157184Sache struct thread *td); 82157184Sachestatic int ipx_detach(struct socket *so); 83157184Sachestatic int ipx_disconnect(struct socket *so); 84157184Sachestatic int ipx_send(struct socket *so, int flags, struct mbuf *m, 85157184Sache struct sockaddr *addr, struct mbuf *control, 86157184Sache struct thread *td); 87157184Sachestatic int ipx_shutdown(struct socket *so); 88157184Sachestatic int ripx_attach(struct socket *so, int proto, struct thread *td); 89157184Sachestatic int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 90157184Sache 91157184Sachestruct pr_usrreqs ipx_usrreqs = { 92157184Sache .pru_abort = ipx_usr_abort, 93157184Sache .pru_attach = ipx_attach, 94157184Sache .pru_bind = ipx_bind, 95157184Sache .pru_connect = ipx_connect, 96157184Sache .pru_control = ipx_control, 97157184Sache .pru_detach = ipx_detach, 98157184Sache .pru_disconnect = ipx_disconnect, 99157184Sache .pru_peeraddr = ipx_peeraddr, 100157184Sache .pru_send = ipx_send, 101157184Sache .pru_shutdown = ipx_shutdown, 102157184Sache .pru_sockaddr = ipx_sockaddr, 103157184Sache}; 104157184Sache 105157184Sachestruct pr_usrreqs ripx_usrreqs = { 106157184Sache .pru_abort = ipx_usr_abort, 107157184Sache .pru_attach = ripx_attach, 108157184Sache .pru_bind = ipx_bind, 109157184Sache .pru_connect = ipx_connect, 110157184Sache .pru_control = ipx_control, 111157184Sache .pru_detach = ipx_detach, 112157184Sache .pru_disconnect = ipx_disconnect, 113157184Sache .pru_peeraddr = ipx_peeraddr, 114157184Sache .pru_send = ipx_send, 115157184Sache .pru_shutdown = ipx_shutdown, 116157184Sache .pru_sockaddr = ipx_sockaddr, 117157184Sache}; 118157184Sache 119157184Sache/* 120157184Sache * This may also be called for raw listeners. 121157184Sache */ 122157184Sachevoid 123157184Sacheipx_input(m, ipxp) 124157184Sache struct mbuf *m; 125157184Sache register struct ipxpcb *ipxp; 126157184Sache{ 127157184Sache register struct ipx *ipx = mtod(m, struct ipx *); 128157184Sache struct ifnet *ifp = m->m_pkthdr.rcvif; 129157184Sache struct sockaddr_ipx ipx_ipx; 130157184Sache 131157184Sache KASSERT(ipxp != NULL, ("ipx_input: NULL ipxpcb")); 132157184Sache IPX_LOCK_ASSERT(ipxp); 133157184Sache /* 134157184Sache * Construct sockaddr format source address. 135157184Sache * Stuff source address and datagram in user buffer. 136157184Sache */ 137157184Sache ipx_ipx.sipx_len = sizeof(ipx_ipx); 138157184Sache ipx_ipx.sipx_family = AF_IPX; 139157184Sache ipx_ipx.sipx_addr = ipx->ipx_sna; 140157184Sache ipx_ipx.sipx_zero[0] = '\0'; 141157184Sache ipx_ipx.sipx_zero[1] = '\0'; 142157184Sache if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { 143157184Sache register struct ifaddr *ifa; 144157184Sache 145157184Sache for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; 146157184Sache ifa = TAILQ_NEXT(ifa, ifa_link)) { 147157184Sache if (ifa->ifa_addr->sa_family == AF_IPX) { 148157184Sache ipx_ipx.sipx_addr.x_net = 149157184Sache IA_SIPX(ifa)->sipx_addr.x_net; 150157184Sache break; 151157184Sache } 152157184Sache } 153157184Sache } 154157184Sache ipxp->ipxp_rpt = ipx->ipx_pt; 155157184Sache if ((ipxp->ipxp_flags & IPXP_RAWIN) == 0) { 156157184Sache m->m_len -= sizeof(struct ipx); 157157184Sache m->m_pkthdr.len -= sizeof(struct ipx); 158157184Sache m->m_data += sizeof(struct ipx); 159157184Sache } 160157184Sache if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, 161157184Sache (struct sockaddr *)&ipx_ipx, m, NULL) == 0) 162157184Sache m_freem(m); 163157184Sache else 164157184Sache sorwakeup(ipxp->ipxp_socket); 165157184Sache} 166157184Sache 167157184Sache/* 168157184Sache * Drop connection, reporting 169157184Sache * the specified error. 170157184Sache */ 171157184Sachevoid 172157184Sacheipx_drop(ipxp, errno) 173157184Sache register struct ipxpcb *ipxp; 174157184Sache int errno; 175157184Sache{ 176157184Sache struct socket *so = ipxp->ipxp_socket; 177157184Sache 178157184Sache IPX_LIST_LOCK_ASSERT(); 179157184Sache IPX_LOCK_ASSERT(ipxp); 180157184Sache 181157184Sache /* 182157184Sache * someday, in the IPX world 183157184Sache * we will generate error protocol packets 184157184Sache * announcing that the socket has gone away. 185157184Sache * 186157184Sache * XXX Probably never. IPX does not have error packets. 187157184Sache */ 188157184Sache /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 189157184Sache tp->t_state = TCPS_CLOSED; 190157184Sache tcp_output(tp); 191157184Sache }*/ 192157184Sache so->so_error = errno; 193157184Sache ipx_pcbdisconnect(ipxp); 194157184Sache soisdisconnected(so); 195157184Sache} 196157184Sache 197157184Sachestatic int 198157184Sacheipx_output(ipxp, m0) 199157184Sache struct ipxpcb *ipxp; 200157184Sache struct mbuf *m0; 201157184Sache{ 202157184Sache register struct ipx *ipx; 203157184Sache register struct socket *so; 204157184Sache register int len = 0; 205157184Sache register struct route *ro; 206157184Sache struct mbuf *m; 207157184Sache struct mbuf *mprev = NULL; 208157184Sache 209157184Sache IPX_LOCK_ASSERT(ipxp); 210157184Sache 211157184Sache /* 212157184Sache * Calculate data length. 213157184Sache */ 214157184Sache for (m = m0; m != NULL; m = m->m_next) { 215157184Sache mprev = m; 216157184Sache len += m->m_len; 217157184Sache } 218157184Sache /* 219157184Sache * Make sure packet is actually of even length. 220157184Sache */ 221157184Sache 222157184Sache if (len & 1) { 223157184Sache m = mprev; 224157184Sache if ((m->m_flags & M_EXT) == 0 && 225157184Sache (m->m_len + m->m_data < &m->m_dat[MLEN])) { 226157184Sache mtod(m, char*)[m->m_len++] = 0; 227157184Sache } else { 228157184Sache struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 229157184Sache 230157184Sache if (m1 == NULL) { 231157184Sache m_freem(m0); 232157184Sache return (ENOBUFS); 233157184Sache } 234157184Sache m1->m_len = 1; 235157184Sache * mtod(m1, char *) = 0; 236157184Sache m->m_next = m1; 237157184Sache } 238157184Sache m0->m_pkthdr.len++; 239157184Sache } 240157184Sache 241157184Sache /* 242157184Sache * Fill in mbuf with extended IPX header 243157184Sache * and addresses and length put into network format. 244157184Sache */ 245157184Sache m = m0; 246157184Sache if (ipxp->ipxp_flags & IPXP_RAWOUT) { 247157184Sache ipx = mtod(m, struct ipx *); 248157184Sache } else { 249157184Sache M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT); 250157184Sache if (m == NULL) 251157184Sache return (ENOBUFS); 252157184Sache ipx = mtod(m, struct ipx *); 253157184Sache ipx->ipx_tc = 0; 254157184Sache ipx->ipx_pt = ipxp->ipxp_dpt; 255157184Sache ipx->ipx_sna = ipxp->ipxp_laddr; 256157184Sache ipx->ipx_dna = ipxp->ipxp_faddr; 257157184Sache len += sizeof(struct ipx); 258157184Sache } 259157184Sache 260157184Sache ipx->ipx_len = htons((u_short)len); 261157184Sache 262157184Sache if (ipxp->ipxp_flags & IPXP_CHECKSUM) { 263157184Sache ipx->ipx_sum = ipx_cksum(m, len); 264157184Sache } else 265157184Sache ipx->ipx_sum = 0xffff; 266157184Sache 267157184Sache /* 268157184Sache * Output datagram. 269157184Sache */ 270157184Sache so = ipxp->ipxp_socket; 271157184Sache if (so->so_options & SO_DONTROUTE) 272157184Sache return (ipx_outputfl(m, (struct route *)NULL, 273157184Sache (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 274157184Sache /* 275157184Sache * Use cached route for previous datagram if 276157184Sache * possible. If the previous net was the same 277157184Sache * and the interface was a broadcast medium, or 278157184Sache * if the previous destination was identical, 279157184Sache * then we are ok. 280157184Sache * 281157184Sache * NB: We don't handle broadcasts because that 282157184Sache * would require 3 subroutine calls. 283157184Sache */ 284157184Sache ro = &ipxp->ipxp_route; 285157184Sache#ifdef ancient_history 286157184Sache /* 287157184Sache * I think that this will all be handled in ipx_pcbconnect! 288157184Sache */ 289157184Sache if (ro->ro_rt != NULL) { 290157184Sache if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 291157184Sache /* 292157184Sache * This assumes we have no GH type routes 293157184Sache */ 294157184Sache if (ro->ro_rt->rt_flags & RTF_HOST) { 295157184Sache if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 296157184Sache goto re_route; 297157184Sache 298157184Sache } 299157184Sache if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 300157184Sache register struct ipx_addr *dst = 301157184Sache &satoipx_addr(ro->ro_dst); 302157184Sache dst->x_host = ipx->ipx_dna.x_host; 303157184Sache } 304157184Sache /* 305157184Sache * Otherwise, we go through the same gateway 306157184Sache * and dst is already set up. 307157184Sache */ 308157184Sache } else { 309157184Sache re_route: 310157184Sache RTFREE(ro->ro_rt); 311157184Sache ro->ro_rt = NULL; 312157184Sache } 313157184Sache } 314157184Sache ipxp->ipxp_lastdst = ipx->ipx_dna; 315157184Sache#endif /* ancient_history */ 316157184Sache return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 317157184Sache} 318157184Sache 319157184Sacheint 320157184Sacheipx_ctloutput(so, sopt) 321157184Sache struct socket *so; 322157184Sache struct sockopt *sopt; 323157184Sache{ 324157184Sache struct ipxpcb *ipxp = sotoipxpcb(so); 325157184Sache int mask, error, optval; 326157184Sache short soptval; 327157184Sache struct ipx ioptval; 328157184Sache long seq; 329157184Sache 330157184Sache error = 0; 331157184Sache if (ipxp == NULL) 332157184Sache return (EINVAL); 333157184Sache 334157184Sache switch (sopt->sopt_dir) { 335157184Sache case SOPT_GET: 336157184Sache switch (sopt->sopt_name) { 337157184Sache case SO_ALL_PACKETS: 338157184Sache mask = IPXP_ALL_PACKETS; 339157184Sache goto get_flags; 340157184Sache 341157184Sache case SO_HEADERS_ON_INPUT: 342157184Sache mask = IPXP_RAWIN; 343157184Sache goto get_flags; 344157184Sache 345157184Sache case SO_IPX_CHECKSUM: 346157184Sache mask = IPXP_CHECKSUM; 347157184Sache goto get_flags; 348157184Sache 349157184Sache case SO_HEADERS_ON_OUTPUT: 350157184Sache mask = IPXP_RAWOUT; 351157184Sache get_flags: 352157184Sache /* Unlocked read. */ 353157184Sache soptval = ipxp->ipxp_flags & mask; 354157184Sache error = sooptcopyout(sopt, &soptval, sizeof soptval); 355157184Sache break; 356157184Sache 357157184Sache case SO_DEFAULT_HEADERS: 358157184Sache ioptval.ipx_len = 0; 359157184Sache ioptval.ipx_sum = 0; 360157184Sache ioptval.ipx_tc = 0; 361157184Sache IPX_LOCK(ipxp); 362157184Sache ioptval.ipx_pt = ipxp->ipxp_dpt; 363157184Sache ioptval.ipx_dna = ipxp->ipxp_faddr; 364157184Sache ioptval.ipx_sna = ipxp->ipxp_laddr; 365157184Sache IPX_UNLOCK(ipxp); 366157184Sache error = sooptcopyout(sopt, &soptval, sizeof soptval); 367157184Sache break; 368157184Sache 369157184Sache case SO_SEQNO: 370157184Sache IPX_LIST_LOCK(); 371157184Sache seq = ipx_pexseq; 372157184Sache ipx_pexseq++; 373157184Sache IPX_LIST_UNLOCK(); 374157184Sache error = sooptcopyout(sopt, &seq, sizeof seq); 375157184Sache break; 376 377 default: 378 error = EINVAL; 379 } 380 break; 381 382 case SOPT_SET: 383 switch (sopt->sopt_name) { 384 case SO_ALL_PACKETS: 385 mask = IPXP_ALL_PACKETS; 386 goto set_head; 387 388 case SO_HEADERS_ON_INPUT: 389 mask = IPXP_RAWIN; 390 goto set_head; 391 392 case SO_IPX_CHECKSUM: 393 mask = IPXP_CHECKSUM; 394 395 case SO_HEADERS_ON_OUTPUT: 396 mask = IPXP_RAWOUT; 397 set_head: 398 error = sooptcopyin(sopt, &optval, sizeof optval, 399 sizeof optval); 400 if (error) 401 break; 402 IPX_LOCK(ipxp); 403 if (optval) 404 ipxp->ipxp_flags |= mask; 405 else 406 ipxp->ipxp_flags &= ~mask; 407 IPX_UNLOCK(ipxp); 408 break; 409 410 case SO_DEFAULT_HEADERS: 411 error = sooptcopyin(sopt, &ioptval, sizeof ioptval, 412 sizeof ioptval); 413 if (error) 414 break; 415 /* Unlocked write. */ 416 ipxp->ipxp_dpt = ioptval.ipx_pt; 417 break; 418#ifdef IPXIP 419 case SO_IPXIP_ROUTE: 420 error = ipxip_route(so, sopt); 421 break; 422#endif /* IPXIP */ 423 default: 424 error = EINVAL; 425 } 426 break; 427 } 428 return (error); 429} 430 431static int 432ipx_usr_abort(so) 433 struct socket *so; 434{ 435 struct ipxpcb *ipxp = sotoipxpcb(so); 436 437 IPX_LIST_LOCK(); 438 IPX_LOCK(ipxp); 439 ipx_pcbdetach(ipxp); 440 IPX_LIST_UNLOCK(); 441 soisdisconnected(so); 442 ACCEPT_LOCK(); 443 SOCK_LOCK(so); 444 sotryfree(so); 445 return (0); 446} 447 448static int 449ipx_attach(so, proto, td) 450 struct socket *so; 451 int proto; 452 struct thread *td; 453{ 454 struct ipxpcb *ipxp = sotoipxpcb(so); 455 int error; 456 457 if (ipxp != NULL) 458 return (EINVAL); 459 IPX_LIST_LOCK(); 460 error = ipx_pcballoc(so, &ipxpcb_list, td); 461 IPX_LIST_UNLOCK(); 462 if (error == 0) 463 error = soreserve(so, ipxsendspace, ipxrecvspace); 464 return (error); 465} 466 467static int 468ipx_bind(so, nam, td) 469 struct socket *so; 470 struct sockaddr *nam; 471 struct thread *td; 472{ 473 struct ipxpcb *ipxp = sotoipxpcb(so); 474 int error; 475 476 IPX_LIST_LOCK(); 477 IPX_LOCK(ipxp); 478 error = ipx_pcbbind(ipxp, nam, td); 479 IPX_UNLOCK(ipxp); 480 IPX_LIST_UNLOCK(); 481 return (error); 482} 483 484static int 485ipx_connect(so, nam, td) 486 struct socket *so; 487 struct sockaddr *nam; 488 struct thread *td; 489{ 490 struct ipxpcb *ipxp = sotoipxpcb(so); 491 int error; 492 493 IPX_LIST_LOCK(); 494 IPX_LOCK(ipxp); 495 if (!ipx_nullhost(ipxp->ipxp_faddr)) { 496 error = EISCONN; 497 goto out; 498 } 499 error = ipx_pcbconnect(ipxp, nam, td); 500 if (error == 0) 501 soisconnected(so); 502out: 503 IPX_UNLOCK(ipxp); 504 IPX_LIST_UNLOCK(); 505 return (error); 506} 507 508static int 509ipx_detach(so) 510 struct socket *so; 511{ 512 struct ipxpcb *ipxp = sotoipxpcb(so); 513 514 if (ipxp == NULL) 515 return (ENOTCONN); 516 IPX_LIST_LOCK(); 517 IPX_LOCK(ipxp); 518 ipx_pcbdetach(ipxp); 519 IPX_LIST_UNLOCK(); 520 return (0); 521} 522 523static int 524ipx_disconnect(so) 525 struct socket *so; 526{ 527 struct ipxpcb *ipxp = sotoipxpcb(so); 528 int error; 529 530 IPX_LIST_LOCK(); 531 IPX_LOCK(ipxp); 532 error = 0; 533 if (ipx_nullhost(ipxp->ipxp_faddr)) { 534 error = ENOTCONN; 535 goto out; 536 } 537 ipx_pcbdisconnect(ipxp); 538 soisdisconnected(so); 539out: 540 IPX_UNLOCK(ipxp); 541 IPX_LIST_UNLOCK(); 542 return (0); 543} 544 545int 546ipx_peeraddr(so, nam) 547 struct socket *so; 548 struct sockaddr **nam; 549{ 550 struct ipxpcb *ipxp = sotoipxpcb(so); 551 552 ipx_setpeeraddr(ipxp, nam); 553 return (0); 554} 555 556static int 557ipx_send(so, flags, m, nam, control, td) 558 struct socket *so; 559 int flags; 560 struct mbuf *m; 561 struct sockaddr *nam; 562 struct mbuf *control; 563 struct thread *td; 564{ 565 int error; 566 struct ipxpcb *ipxp = sotoipxpcb(so); 567 struct ipx_addr laddr; 568 569 /* 570 * Attempt to only acquire the necessary locks: if the socket is 571 * already connected, we don't need to hold the IPX list lock to be 572 * used by ipx_pcbconnect() and ipx_pcbdisconnect(), just the IPX 573 * pcb lock. 574 */ 575 if (nam != NULL) { 576 IPX_LIST_LOCK(); 577 IPX_LOCK(ipxp); 578 laddr = ipxp->ipxp_laddr; 579 if (!ipx_nullhost(ipxp->ipxp_faddr)) { 580 IPX_UNLOCK(ipxp); 581 IPX_LIST_UNLOCK(); 582 error = EISCONN; 583 goto send_release; 584 } 585 /* 586 * Must block input while temporarily connected. 587 */ 588 error = ipx_pcbconnect(ipxp, nam, td); 589 if (error) { 590 IPX_UNLOCK(ipxp); 591 IPX_LIST_UNLOCK(); 592 goto send_release; 593 } 594 } else { 595 IPX_LOCK(ipxp); 596 if (ipx_nullhost(ipxp->ipxp_faddr)) { 597 IPX_UNLOCK(ipxp); 598 error = ENOTCONN; 599 goto send_release; 600 } 601 } 602 error = ipx_output(ipxp, m); 603 m = NULL; 604 if (nam != NULL) { 605 ipx_pcbdisconnect(ipxp); 606 ipxp->ipxp_laddr = laddr; 607 IPX_UNLOCK(ipxp); 608 IPX_LIST_UNLOCK(); 609 } else 610 IPX_UNLOCK(ipxp); 611 612send_release: 613 if (m != NULL) 614 m_freem(m); 615 return (error); 616} 617 618static int 619ipx_shutdown(so) 620 struct socket *so; 621{ 622 socantsendmore(so); 623 return (0); 624} 625 626int 627ipx_sockaddr(so, nam) 628 struct socket *so; 629 struct sockaddr **nam; 630{ 631 struct ipxpcb *ipxp = sotoipxpcb(so); 632 633 ipx_setsockaddr(ipxp, nam); 634 return (0); 635} 636 637static int 638ripx_attach(so, proto, td) 639 struct socket *so; 640 int proto; 641 struct thread *td; 642{ 643 int error = 0; 644 struct ipxpcb *ipxp = sotoipxpcb(so); 645 646 if (td != NULL && (error = suser(td)) != 0) 647 return (error); 648 /* 649 * We hold the IPX list lock for the duration as address parameters 650 * of the IPX pcb are changed. Since no one else holds a reference 651 * to the ipxpcb yet, we don't need the ipxpcb lock here. 652 */ 653 IPX_LIST_LOCK(); 654 error = ipx_pcballoc(so, &ipxrawpcb_list, td); 655 if (error) 656 goto out; 657 ipxp = sotoipxpcb(so); 658 error = soreserve(so, ipxsendspace, ipxrecvspace); 659 if (error) 660 goto out; 661 ipxp->ipxp_faddr.x_host = ipx_broadhost; 662 ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT; 663out: 664 IPX_LIST_UNLOCK(); 665 return (error); 666} 667