ipx_usrreq.c revision 194544
1126430Snjl/*- 2126430Snjl * Copyright (c) 1984, 1985, 1986, 1987, 1993 3126430Snjl * The Regents of the University of California. 4126430Snjl * Copyright (c) 2004-2006 Robert N. M. Watson 5126430Snjl * All rights reserved. 6126430Snjl * 7126430Snjl * Redistribution and use in source and binary forms, with or without 8126430Snjl * modification, are permitted provided that the following conditions 9126430Snjl * are met: 10126430Snjl * 1. Redistributions of source code must retain the above copyright 11126430Snjl * notice, this list of conditions and the following disclaimer. 12126430Snjl * 2. Redistributions in binary form must reproduce the above copyright 13126430Snjl * notice, this list of conditions and the following disclaimer in the 14126430Snjl * documentation and/or other materials provided with the distribution. 15126430Snjl * 4. Neither the name of the University nor the names of its contributors 16126430Snjl * may be used to endorse or promote products derived from this software 17126430Snjl * without specific prior written permission. 18126430Snjl * 19126430Snjl * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20126430Snjl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21126430Snjl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22126430Snjl * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23126430Snjl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24126430Snjl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25126430Snjl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26126430Snjl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27126430Snjl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28126430Snjl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29143002Sobrien * SUCH DAMAGE. 30143002Sobrien * 31143002Sobrien * Copyright (c) 1995, Mike Mitchell 32126430Snjl * All rights reserved. 33126430Snjl * 34126430Snjl * Redistribution and use in source and binary forms, with or without 35129879Sphk * modification, are permitted provided that the following conditions 36126430Snjl * are met: 37126430Snjl * 1. Redistributions of source code must retain the above copyright 38126430Snjl * notice, this list of conditions and the following disclaimer. 39126430Snjl * 2. Redistributions in binary form must reproduce the above copyright 40126430Snjl * notice, this list of conditions and the following disclaimer in the 41193530Sjkim * documentation and/or other materials provided with the distribution. 42193530Sjkim * 3. All advertising materials mentioning features or use of this software 43126430Snjl * must display the following acknowledgement: 44126430Snjl * This product includes software developed by the University of 45126430Snjl * California, Berkeley and its contributors. 46126430Snjl * 4. Neither the name of the University nor the names of its contributors 47126430Snjl * may be used to endorse or promote products derived from this software 48126430Snjl * without specific prior written permission. 49126430Snjl * 50126430Snjl * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 51126430Snjl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52126430Snjl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53126430Snjl * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 54126430Snjl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 55126430Snjl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 56126430Snjl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 57126430Snjl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58126430Snjl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 59126430Snjl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60126430Snjl * SUCH DAMAGE. 61126430Snjl * 62126430Snjl * @(#)ipx_usrreq.c 63126430Snjl */ 64126430Snjl 65126430Snjl#include <sys/cdefs.h> 66126430Snjl__FBSDID("$FreeBSD: head/sys/netipx/ipx_usrreq.c 194544 2009-06-20 17:42:53Z rwatson $"); 67126430Snjl 68132526Snjl#include "opt_ipx.h" 69126430Snjl 70126430Snjl#include <sys/param.h> 71126430Snjl#include <sys/kernel.h> 72126430Snjl#include <sys/lock.h> 73126430Snjl#include <sys/mbuf.h> 74153578Sjhb#include <sys/priv.h> 75126430Snjl#include <sys/protosw.h> 76126430Snjl#include <sys/signalvar.h> 77126430Snjl#include <sys/socket.h> 78237197Siwasaki#include <sys/socketvar.h> 79126430Snjl#include <sys/sx.h> 80126430Snjl#include <sys/sysctl.h> 81126430Snjl#include <sys/systm.h> 82126430Snjl 83132526Snjl#include <net/if.h> 84126430Snjl#include <net/route.h> 85126430Snjl 86126430Snjl#include <netinet/in.h> 87203810Sjkim 88126430Snjl#include <netipx/ipx.h> 89126430Snjl#include <netipx/ipx_if.h> 90126430Snjl#include <netipx/ipx_pcb.h> 91126430Snjl#include <netipx/ipx_var.h> 92126430Snjl 93126430Snjl#include <security/mac/mac_framework.h> 94126430Snjl 95126430Snjl/* 96132526Snjl * IPX protocol implementation. 97133625Snjl */ 98203810Sjkim 99126430Snjlstatic int ipxsendspace = IPXSNDQ; 100126430SnjlSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 101133625Snjl &ipxsendspace, 0, "Send buffer space"); 102126430Snjlstatic int ipxrecvspace = IPXRCVQ; 103126430SnjlSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 104126430Snjl &ipxrecvspace, 0, "Receive buffer space"); 105203936Sjkim 106203936Sjkimstatic void ipx_usr_abort(struct socket *so); 107203936Sjkimstatic int ipx_attach(struct socket *so, int proto, struct thread *td); 108203810Sjkimstatic int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 109203810Sjkimstatic int ipx_connect(struct socket *so, struct sockaddr *nam, 110203936Sjkim struct thread *td); 111126430Snjlstatic void ipx_detach(struct socket *so); 112126430Snjlstatic int ipx_disconnect(struct socket *so); 113203936Sjkimstatic int ipx_send(struct socket *so, int flags, struct mbuf *m, 114203936Sjkim struct sockaddr *addr, struct mbuf *control, 115203936Sjkim struct thread *td); 116203936Sjkimstatic int ipx_shutdown(struct socket *so); 117203936Sjkimstatic int ripx_attach(struct socket *so, int proto, struct thread *td); 118126430Snjlstatic int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 119126430Snjlstatic void ipx_usr_close(struct socket *so); 120203936Sjkim 121203936Sjkimstruct pr_usrreqs ipx_usrreqs = { 122203936Sjkim .pru_abort = ipx_usr_abort, 123203936Sjkim .pru_attach = ipx_attach, 124203936Sjkim .pru_bind = ipx_bind, 125203936Sjkim .pru_connect = ipx_connect, 126203936Sjkim .pru_control = ipx_control, 127203936Sjkim .pru_detach = ipx_detach, 128203936Sjkim .pru_disconnect = ipx_disconnect, 129203936Sjkim .pru_peeraddr = ipx_peeraddr, 130203936Sjkim .pru_send = ipx_send, 131203936Sjkim .pru_shutdown = ipx_shutdown, 132203936Sjkim .pru_sockaddr = ipx_sockaddr, 133203936Sjkim .pru_close = ipx_usr_close, 134132526Snjl}; 135258780Seadler 136126430Snjlstruct pr_usrreqs ripx_usrreqs = { 137126430Snjl .pru_abort = ipx_usr_abort, 138203936Sjkim .pru_attach = ripx_attach, 139203936Sjkim .pru_bind = ipx_bind, 140126430Snjl .pru_connect = ipx_connect, 141126430Snjl .pru_control = ipx_control, 142203936Sjkim .pru_detach = ipx_detach, 143203936Sjkim .pru_disconnect = ipx_disconnect, 144203936Sjkim .pru_peeraddr = ipx_peeraddr, 145203936Sjkim .pru_send = ipx_send, 146203936Sjkim .pru_shutdown = ipx_shutdown, 147126430Snjl .pru_sockaddr = ipx_sockaddr, 148126430Snjl .pru_close = ipx_usr_close, 149203936Sjkim}; 150203936Sjkim 151203936Sjkim/* 152258780Seadler * This may also be called for raw listeners. 153126430Snjl */ 154126430Snjlvoid 155153578Sjhbipx_input(struct mbuf *m, struct ipxpcb *ipxp) 156126430Snjl{ 157126430Snjl struct ipx *ipx = mtod(m, struct ipx *); 158126430Snjl struct ifnet *ifp = m->m_pkthdr.rcvif; 159237197Siwasaki struct sockaddr_ipx ipx_ipx; 160126430Snjl 161126430Snjl KASSERT(ipxp != NULL, ("ipx_input: NULL ipxpcb")); 162126430Snjl IPX_LOCK_ASSERT(ipxp); 163126430Snjl /* 164126430Snjl * Construct sockaddr format source address. 165126430Snjl * Stuff source address and datagram in user buffer. 166126430Snjl */ 167126430Snjl ipx_ipx.sipx_len = sizeof(ipx_ipx); 168126430Snjl ipx_ipx.sipx_family = AF_IPX; 169126430Snjl ipx_ipx.sipx_addr = ipx->ipx_sna; 170126430Snjl ipx_ipx.sipx_zero[0] = '\0'; 171126430Snjl ipx_ipx.sipx_zero[1] = '\0'; 172153578Sjhb if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { 173126430Snjl struct ifaddr *ifa; 174128036Snjl 175126430Snjl for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; 176132526Snjl ifa = TAILQ_NEXT(ifa, ifa_link)) { 177132526Snjl if (ifa->ifa_addr->sa_family == AF_IPX) { 178161184Sbruno ipx_ipx.sipx_addr.x_net = 179161184Sbruno IA_SIPX(ifa)->sipx_addr.x_net; 180126430Snjl break; 181197648Sjhb } 182197648Sjhb } 183197648Sjhb } 184197648Sjhb ipxp->ipxp_rpt = ipx->ipx_pt; 185197648Sjhb if ((ipxp->ipxp_flags & IPXP_RAWIN) == 0) { 186133625Snjl m->m_len -= sizeof(struct ipx); 187197648Sjhb m->m_pkthdr.len -= sizeof(struct ipx); 188227293Sed m->m_data += sizeof(struct ipx); 189126430Snjl } 190126430Snjl if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, 191126430Snjl (struct sockaddr *)&ipx_ipx, m, NULL) == 0) 192126430Snjl m_freem(m); 193137438Snjl else 194126430Snjl sorwakeup(ipxp->ipxp_socket); 195137438Snjl} 196126430Snjl 197126430Snjl/* 198126430Snjl * Drop connection, reporting 199126430Snjl * the specified error. 200126430Snjl */ 201161184Sbrunovoid 202161184Sbrunoipx_drop(struct ipxpcb *ipxp, int errno) 203126430Snjl{ 204126430Snjl struct socket *so = ipxp->ipxp_socket; 205126430Snjl 206132256Snjl IPX_LIST_LOCK_ASSERT(); 207126430Snjl IPX_LOCK_ASSERT(ipxp); 208126430Snjl 209126430Snjl /* 210126430Snjl * someday, in the IPX world 211126430Snjl * we will generate error protocol packets 212126430Snjl * announcing that the socket has gone away. 213126430Snjl * 214126430Snjl * XXX Probably never. IPX does not have error packets. 215126430Snjl */ 216153578Sjhb /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 217153578Sjhb tp->t_state = TCPS_CLOSED; 218153578Sjhb tcp_output(tp); 219153578Sjhb }*/ 220153578Sjhb so->so_error = errno; 221153578Sjhb ipx_pcbdisconnect(ipxp); 222153578Sjhb soisdisconnected(so); 223153578Sjhb} 224126430Snjl 225126430Snjlstatic int 226126430Snjlipx_output(struct ipxpcb *ipxp, struct mbuf *m0) 227132526Snjl{ 228132526Snjl struct ipx *ipx; 229126430Snjl struct socket *so; 230132526Snjl int len = 0; 231132526Snjl struct route *ro; 232132526Snjl struct mbuf *m; 233132526Snjl struct mbuf *mprev = NULL; 234132526Snjl 235132526Snjl IPX_LOCK_ASSERT(ipxp); 236132526Snjl 237126430Snjl /* 238132526Snjl * Calculate data length. 239132526Snjl */ 240126430Snjl for (m = m0; m != NULL; m = m->m_next) { 241126430Snjl mprev = m; 242126430Snjl len += m->m_len; 243126430Snjl } 244126430Snjl /* 245126430Snjl * Make sure packet is actually of even length. 246126430Snjl */ 247126430Snjl 248126430Snjl if (len & 1) { 249126430Snjl m = mprev; 250132256Snjl if ((m->m_flags & M_EXT) == 0 && 251132605Snjl (m->m_len + m->m_data < &m->m_dat[MLEN])) { 252132605Snjl mtod(m, char*)[m->m_len++] = 0; 253197648Sjhb } else { 254132605Snjl struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 255126430Snjl 256126430Snjl if (m1 == NULL) { 257126430Snjl m_freem(m0); 258126430Snjl return (ENOBUFS); 259126430Snjl } 260197648Sjhb m1->m_len = 1; 261126430Snjl * mtod(m1, char *) = 0; 262126430Snjl m->m_next = m1; 263126430Snjl } 264126430Snjl m0->m_pkthdr.len++; 265126430Snjl } 266126430Snjl 267126430Snjl /* 268126430Snjl * Fill in mbuf with extended IPX header 269126430Snjl * and addresses and length put into network format. 270126430Snjl */ 271133625Snjl m = m0; 272126430Snjl if (ipxp->ipxp_flags & IPXP_RAWOUT) { 273133625Snjl ipx = mtod(m, struct ipx *); 274126430Snjl } else { 275137438Snjl M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT); 276137438Snjl if (m == NULL) 277137438Snjl return (ENOBUFS); 278137438Snjl ipx = mtod(m, struct ipx *); 279137438Snjl ipx->ipx_tc = 0; 280203936Sjkim ipx->ipx_pt = ipxp->ipxp_dpt; 281137438Snjl ipx->ipx_sna = ipxp->ipxp_laddr; 282126430Snjl ipx->ipx_dna = ipxp->ipxp_faddr; 283126430Snjl len += sizeof(struct ipx); 284126430Snjl } 285126430Snjl 286126430Snjl ipx->ipx_len = htons((u_short)len); 287126430Snjl 288126430Snjl if (ipxp->ipxp_flags & IPXP_CHECKSUM) { 289126430Snjl ipx->ipx_sum = ipx_cksum(m, len); 290126430Snjl } else 291126430Snjl ipx->ipx_sum = 0xffff; 292126430Snjl 293126430Snjl /* 294126430Snjl * Output datagram. 295126430Snjl */ 296126430Snjl so = ipxp->ipxp_socket; 297126430Snjl if (so->so_options & SO_DONTROUTE) 298126430Snjl return (ipx_outputfl(m, (struct route *)NULL, 299126430Snjl (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 300133625Snjl /* 301197438Sjhb * Use cached route for previous datagram if 302126430Snjl * possible. If the previous net was the same 303126430Snjl * and the interface was a broadcast medium, or 304133625Snjl * if the previous destination was identical, 305126430Snjl * then we are ok. 306126430Snjl * 307126430Snjl * NB: We don't handle broadcasts because that 308126430Snjl * would require 3 subroutine calls. 309126430Snjl */ 310237197Siwasaki ro = &ipxp->ipxp_route; 311237197Siwasaki#ifdef ancient_history 312237197Siwasaki /* 313237197Siwasaki * I think that this will all be handled in ipx_pcbconnect! 314237197Siwasaki */ 315237197Siwasaki if (ro->ro_rt != NULL) { 316237197Siwasaki if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 317237197Siwasaki /* 318237197Siwasaki * This assumes we have no GH type routes 319237197Siwasaki */ 320237197Siwasaki if (ro->ro_rt->rt_flags & RTF_HOST) { 321237197Siwasaki if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 322237197Siwasaki goto re_route; 323237197Siwasaki 324237197Siwasaki } 325237197Siwasaki if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 326237197Siwasaki struct ipx_addr *dst = 327237197Siwasaki &satoipx_addr(ro->ro_dst); 328237197Siwasaki dst->x_host = ipx->ipx_dna.x_host; 329237197Siwasaki } 330237197Siwasaki /* 331237197Siwasaki * Otherwise, we go through the same gateway 332237197Siwasaki * and dst is already set up. 333237197Siwasaki */ 334237197Siwasaki } else { 335237197Siwasaki re_route: 336237197Siwasaki RTFREE(ro->ro_rt); 337237197Siwasaki ro->ro_rt = NULL; 338237197Siwasaki } 339237197Siwasaki } 340126430Snjl ipxp->ipxp_lastdst = ipx->ipx_dna; 341126430Snjl#endif /* ancient_history */ 342126430Snjl return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 343126430Snjl} 344126430Snjl 345126430Snjlint 346126430Snjlipx_ctloutput(struct socket *so, struct sockopt *sopt) 347126430Snjl{ 348126430Snjl struct ipxpcb *ipxp = sotoipxpcb(so); 349126430Snjl int mask, error, optval; 350126430Snjl short soptval; 351137438Snjl struct ipx ioptval; 352126430Snjl long seq; 353126430Snjl 354132605Snjl KASSERT(ipxp != NULL, ("ipx_ctloutput: ipxp == NULL")); 355137438Snjl error = 0; 356137438Snjl 357126430Snjl switch (sopt->sopt_dir) { 358137438Snjl case SOPT_GET: 359126430Snjl switch (sopt->sopt_name) { 360126430Snjl case SO_ALL_PACKETS: 361126430Snjl mask = IPXP_ALL_PACKETS; 362137438Snjl goto get_flags; 363137438Snjl 364133625Snjl case SO_HEADERS_ON_INPUT: 365197648Sjhb mask = IPXP_RAWIN; 366126430Snjl goto get_flags; 367133625Snjl 368126430Snjl case SO_IPX_CHECKSUM: 369126430Snjl mask = IPXP_CHECKSUM; 370126430Snjl goto get_flags; 371126430Snjl 372126430Snjl case SO_HEADERS_ON_OUTPUT: 373126430Snjl mask = IPXP_RAWOUT; 374126430Snjl get_flags: 375126430Snjl /* Unlocked read. */ 376126430Snjl soptval = ipxp->ipxp_flags & mask; 377126430Snjl error = sooptcopyout(sopt, &soptval, sizeof soptval); 378126430Snjl break; 379126430Snjl 380126430Snjl case SO_DEFAULT_HEADERS: 381197648Sjhb ioptval.ipx_len = 0; 382133625Snjl ioptval.ipx_sum = 0; 383126430Snjl ioptval.ipx_tc = 0; 384126430Snjl IPX_LOCK(ipxp); 385133625Snjl ioptval.ipx_pt = ipxp->ipxp_dpt; 386126430Snjl ioptval.ipx_dna = ipxp->ipxp_faddr; 387126430Snjl ioptval.ipx_sna = ipxp->ipxp_laddr; 388126430Snjl IPX_UNLOCK(ipxp); 389132605Snjl error = sooptcopyout(sopt, &soptval, sizeof soptval); 390126430Snjl break; 391126430Snjl 392137438Snjl case SO_SEQNO: 393126430Snjl IPX_LIST_LOCK(); 394126430Snjl seq = ipx_pexseq; 395126430Snjl ipx_pexseq++; 396133625Snjl IPX_LIST_UNLOCK(); 397126430Snjl error = sooptcopyout(sopt, &seq, sizeof seq); 398126430Snjl break; 399137438Snjl 400137438Snjl default: 401126430Snjl error = EINVAL; 402126430Snjl } 403126430Snjl break; 404126430Snjl 405126430Snjl case SOPT_SET: 406126430Snjl switch (sopt->sopt_name) { 407126430Snjl case SO_ALL_PACKETS: 408126430Snjl mask = IPXP_ALL_PACKETS; 409126430Snjl goto set_head; 410126430Snjl 411126430Snjl case SO_HEADERS_ON_INPUT: 412126430Snjl mask = IPXP_RAWIN; 413126430Snjl goto set_head; 414126430Snjl 415126430Snjl case SO_IPX_CHECKSUM: 416126430Snjl mask = IPXP_CHECKSUM; 417133625Snjl goto set_head; 418197648Sjhb 419126430Snjl case SO_HEADERS_ON_OUTPUT: 420126430Snjl mask = IPXP_RAWOUT; 421126430Snjl set_head: 422137438Snjl error = sooptcopyin(sopt, &optval, sizeof optval, 423137438Snjl sizeof optval); 424126430Snjl if (error) 425197648Sjhb break; 426133625Snjl IPX_LOCK(ipxp); 427126430Snjl if (optval) 428126430Snjl ipxp->ipxp_flags |= mask; 429126430Snjl else 430126430Snjl ipxp->ipxp_flags &= ~mask; 431126430Snjl IPX_UNLOCK(ipxp); 432126430Snjl break; 433126430Snjl 434126430Snjl case SO_DEFAULT_HEADERS: 435133625Snjl error = sooptcopyin(sopt, &ioptval, sizeof ioptval, 436126430Snjl sizeof ioptval); 437126430Snjl if (error) 438126430Snjl break; 439126430Snjl /* Unlocked write. */ 440126430Snjl ipxp->ipxp_dpt = ioptval.ipx_pt; 441126430Snjl break; 442126430Snjl default: 443126430Snjl error = EINVAL; 444126430Snjl } 445126430Snjl break; 446126430Snjl } 447126430Snjl return (error); 448126430Snjl} 449126430Snjl 450126430Snjlstatic void 451126430Snjlipx_usr_abort(struct socket *so) 452126430Snjl{ 453126430Snjl 454126430Snjl /* XXXRW: Possibly ipx_disconnect() here? */ 455133625Snjl soisdisconnected(so); 456126430Snjl} 457126430Snjl 458126430Snjlstatic int 459126430Snjlipx_attach(struct socket *so, int proto, struct thread *td) 460126430Snjl{ 461126430Snjl#ifdef INVARIANTS 462126430Snjl struct ipxpcb *ipxp = sotoipxpcb(so); 463126430Snjl#endif 464137438Snjl int error; 465126430Snjl 466126430Snjl KASSERT(ipxp == NULL, ("ipx_attach: ipxp != NULL")); 467126430Snjl error = soreserve(so, ipxsendspace, ipxrecvspace); 468133625Snjl if (error != 0) 469161184Sbruno return (error); 470126430Snjl IPX_LIST_LOCK(); 471126430Snjl error = ipx_pcballoc(so, &ipxpcb_list, td); 472161184Sbruno IPX_LIST_UNLOCK(); 473161184Sbruno return (error); 474161184Sbruno} 475161184Sbruno 476161184Sbrunostatic int 477161184Sbrunoipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 478161184Sbruno{ 479161184Sbruno struct ipxpcb *ipxp = sotoipxpcb(so); 480161184Sbruno int error; 481161184Sbruno 482126430Snjl KASSERT(ipxp != NULL, ("ipx_bind: ipxp == NULL")); 483126430Snjl IPX_LIST_LOCK(); 484161184Sbruno IPX_LOCK(ipxp); 485126430Snjl error = ipx_pcbbind(ipxp, nam, td); 486126430Snjl IPX_UNLOCK(ipxp); 487126430Snjl IPX_LIST_UNLOCK(); 488161184Sbruno return (error); 489161184Sbruno} 490161184Sbruno 491161184Sbrunostatic void 492161184Sbrunoipx_usr_close(struct socket *so) 493161184Sbruno{ 494161184Sbruno 495161184Sbruno /* XXXRW: Possibly ipx_disconnect() here? */ 496161184Sbruno soisdisconnected(so); 497161184Sbruno} 498126430Snjl 499126430Snjlstatic int 500126430Snjlipx_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 501126430Snjl{ 502126430Snjl struct ipxpcb *ipxp = sotoipxpcb(so); 503126430Snjl int error; 504126430Snjl 505209064Sjkim KASSERT(ipxp != NULL, ("ipx_connect: ipxp == NULL")); 506126430Snjl IPX_LIST_LOCK(); 507126430Snjl IPX_LOCK(ipxp); 508126430Snjl if (!ipx_nullhost(ipxp->ipxp_faddr)) { 509126430Snjl error = EISCONN; 510126430Snjl goto out; 511126430Snjl } 512126430Snjl error = ipx_pcbconnect(ipxp, nam, td); 513132526Snjl if (error == 0) 514126430Snjl soisconnected(so); 515126430Snjlout: 516126430Snjl IPX_UNLOCK(ipxp); 517126430Snjl IPX_LIST_UNLOCK(); 518126430Snjl return (error); 519126430Snjl} 520126430Snjl 521126430Snjlstatic void 522126430Snjlipx_detach(struct socket *so) 523126430Snjl{ 524126430Snjl struct ipxpcb *ipxp = sotoipxpcb(so); 525137438Snjl 526126430Snjl /* XXXRW: Should assert detached. */ 527126430Snjl KASSERT(ipxp != NULL, ("ipx_detach: ipxp == NULL")); 528137438Snjl IPX_LIST_LOCK(); 529126430Snjl IPX_LOCK(ipxp); 530126430Snjl ipx_pcbdetach(ipxp); 531126430Snjl ipx_pcbfree(ipxp); 532126430Snjl IPX_LIST_UNLOCK(); 533126430Snjl} 534126430Snjl 535126430Snjlstatic int 536126430Snjlipx_disconnect(struct socket *so) 537126430Snjl{ 538126430Snjl struct ipxpcb *ipxp = sotoipxpcb(so); 539126430Snjl int error; 540132526Snjl 541132526Snjl KASSERT(ipxp != NULL, ("ipx_disconnect: ipxp == NULL")); 542126430Snjl IPX_LIST_LOCK(); 543126430Snjl IPX_LOCK(ipxp); 544132526Snjl error = 0; 545132526Snjl if (ipx_nullhost(ipxp->ipxp_faddr)) { 546132526Snjl error = ENOTCONN; 547132526Snjl goto out; 548132526Snjl } 549126430Snjl ipx_pcbdisconnect(ipxp); 550132526Snjl soisdisconnected(so); 551132526Snjlout: 552132526Snjl IPX_UNLOCK(ipxp); 553132526Snjl IPX_LIST_UNLOCK(); 554132526Snjl return (0); 555126430Snjl} 556132526Snjl 557132526Snjlint 558132526Snjlipx_peeraddr(struct socket *so, struct sockaddr **nam) 559132526Snjl{ 560132526Snjl struct ipxpcb *ipxp = sotoipxpcb(so); 561132526Snjl 562126430Snjl KASSERT(ipxp != NULL, ("ipx_peeraddr: ipxp == NULL")); 563132526Snjl ipx_getpeeraddr(ipxp, nam); 564132526Snjl return (0); 565132526Snjl} 566132526Snjl 567132526Snjlstatic int 568132526Snjlipx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 569126430Snjl struct mbuf *control, struct thread *td) 570132526Snjl{ 571132526Snjl int error; 572217566Smdf struct ipxpcb *ipxp = sotoipxpcb(so); 573132526Snjl struct ipx_addr laddr; 574132526Snjl 575126430Snjl KASSERT(ipxp != NULL, ("ipxp_send: ipxp == NULL")); 576126430Snjl /* 577126430Snjl * Attempt to only acquire the necessary locks: if the socket is 578126430Snjl * already connected, we don't need to hold the IPX list lock to be 579126430Snjl * used by ipx_pcbconnect() and ipx_pcbdisconnect(), just the IPX 580126430Snjl * pcb lock. 581161184Sbruno */ 582161184Sbruno#ifdef MAC 583161184Sbruno mac_socket_create_mbuf(so, m); 584126430Snjl#endif 585126430Snjl if (nam != NULL) { 586126430Snjl IPX_LIST_LOCK(); 587161184Sbruno IPX_LOCK(ipxp); 588161184Sbruno laddr = ipxp->ipxp_laddr; 589126430Snjl if (!ipx_nullhost(ipxp->ipxp_faddr)) { 590161184Sbruno IPX_UNLOCK(ipxp); 591126430Snjl IPX_LIST_UNLOCK(); 592132526Snjl error = EISCONN; 593126430Snjl goto send_release; 594126430Snjl } 595126430Snjl /* 596126430Snjl * Must block input while temporarily connected. 597126430Snjl */ 598126430Snjl error = ipx_pcbconnect(ipxp, nam, td); 599197648Sjhb if (error) { 600295938Sjkim IPX_UNLOCK(ipxp); 601295938Sjkim IPX_LIST_UNLOCK(); 602295938Sjkim goto send_release; 603126430Snjl } 604295938Sjkim } else { 605295938Sjkim IPX_LOCK(ipxp); 606126430Snjl if (ipx_nullhost(ipxp->ipxp_faddr)) { 607133625Snjl IPX_UNLOCK(ipxp); 608126430Snjl error = ENOTCONN; 609295935Sjkim goto send_release; 610295935Sjkim } 611126430Snjl } 612126430Snjl error = ipx_output(ipxp, m); 613295935Sjkim m = NULL; 614295935Sjkim if (nam != NULL) { 615295936Sjkim ipx_pcbdisconnect(ipxp); 616126430Snjl ipxp->ipxp_laddr = laddr; 617126430Snjl IPX_UNLOCK(ipxp); 618295935Sjkim IPX_LIST_UNLOCK(); 619204965Sjkim } else 620204965Sjkim IPX_UNLOCK(ipxp); 621295939Sjkim 622197648Sjhbsend_release: 623126430Snjl if (m != NULL) 624126430Snjl m_freem(m); 625126430Snjl return (error); 626126430Snjl} 627126430Snjl 628126430Snjlstatic int 629126430Snjlipx_shutdown(so) 630133625Snjl struct socket *so; 631126430Snjl{ 632126430Snjl 633126430Snjl KASSERT(so->so_pcb != NULL, ("ipx_shutdown: so_pcb == NULL")); 634126430Snjl socantsendmore(so); 635203810Sjkim return (0); 636203810Sjkim} 637203810Sjkim 638126430Snjlint 639203810Sjkimipx_sockaddr(struct socket *so, struct sockaddr **nam) 640126430Snjl{ 641126430Snjl struct ipxpcb *ipxp = sotoipxpcb(so); 642126430Snjl 643126430Snjl KASSERT(ipxp != NULL, ("ipx_sockaddr: ipxp == NULL")); 644126430Snjl ipx_getsockaddr(ipxp, nam); 645126430Snjl return (0); 646126430Snjl} 647126430Snjl 648161184Sbrunostatic int 649161184Sbrunoripx_attach(struct socket *so, int proto, struct thread *td) 650161184Sbruno{ 651161184Sbruno int error = 0; 652161184Sbruno struct ipxpcb *ipxp = sotoipxpcb(so); 653161184Sbruno 654126430Snjl KASSERT(ipxp == NULL, ("ripx_attach: ipxp != NULL")); 655126430Snjl 656126430Snjl if (td != NULL) { 657126430Snjl error = priv_check(td, PRIV_NETIPX_RAW); 658126430Snjl if (error) 659126430Snjl return (error); 660126430Snjl } 661126430Snjl 662126430Snjl /* 663126430Snjl * We hold the IPX list lock for the duration as address parameters 664126430Snjl * of the IPX pcb are changed. Since no one else holds a reference 665126430Snjl * to the ipxpcb yet, we don't need the ipxpcb lock here. 666197648Sjhb */ 667126430Snjl IPX_LIST_LOCK(); 668126430Snjl error = ipx_pcballoc(so, &ipxrawpcb_list, td); 669126430Snjl if (error) 670126430Snjl goto out; 671126430Snjl ipxp = sotoipxpcb(so); 672126430Snjl error = soreserve(so, ipxsendspace, ipxrecvspace); 673126430Snjl if (error) 674126430Snjl goto out; 675203810Sjkim ipxp->ipxp_faddr.x_host = ipx_broadhost; 676203810Sjkim ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT; 677203810Sjkimout: 678203810Sjkim IPX_LIST_UNLOCK(); 679203810Sjkim return (error); 680203810Sjkim} 681203810Sjkim