ipx_usrreq.c revision 185928
1224090Sdougb/*- 2262706Serwin * Copyright (c) 1984, 1985, 1986, 1987, 1993 3224090Sdougb * The Regents of the University of California. 4224090Sdougb * Copyright (c) 2004-2006 Robert N. M. Watson 5224090Sdougb * All rights reserved. 6224090Sdougb * 7224090Sdougb * Redistribution and use in source and binary forms, with or without 8224090Sdougb * modification, are permitted provided that the following conditions 9224090Sdougb * are met: 10224090Sdougb * 1. Redistributions of source code must retain the above copyright 11224090Sdougb * notice, this list of conditions and the following disclaimer. 12224090Sdougb * 2. Redistributions in binary form must reproduce the above copyright 13224090Sdougb * notice, this list of conditions and the following disclaimer in the 14224090Sdougb * documentation and/or other materials provided with the distribution. 15224090Sdougb * 4. Neither the name of the University nor the names of its contributors 16224090Sdougb * may be used to endorse or promote products derived from this software 17234010Sdougb * without specific prior written permission. 18224090Sdougb * 19224090Sdougb * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20224090Sdougb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21224090Sdougb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22224090Sdougb * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23224090Sdougb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24224090Sdougb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25224090Sdougb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26224090Sdougb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27224090Sdougb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28224090Sdougb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29224090Sdougb * SUCH DAMAGE. 30224090Sdougb * 31224090Sdougb * Copyright (c) 1995, Mike Mitchell 32224090Sdougb * All rights reserved. 33224090Sdougb * 34224090Sdougb * Redistribution and use in source and binary forms, with or without 35224090Sdougb * modification, are permitted provided that the following conditions 36224090Sdougb * are met: 37224090Sdougb * 1. Redistributions of source code must retain the above copyright 38224090Sdougb * notice, this list of conditions and the following disclaimer. 39224090Sdougb * 2. Redistributions in binary form must reproduce the above copyright 40224090Sdougb * notice, this list of conditions and the following disclaimer in the 41224090Sdougb * documentation and/or other materials provided with the distribution. 42224090Sdougb * 3. All advertising materials mentioning features or use of this software 43224090Sdougb * must display the following acknowledgement: 44224090Sdougb * This product includes software developed by the University of 45224090Sdougb * California, Berkeley and its contributors. 46224090Sdougb * 4. Neither the name of the University nor the names of its contributors 47224090Sdougb * may be used to endorse or promote products derived from this software 48224090Sdougb * without specific prior written permission. 49224090Sdougb * 50224090Sdougb * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 51224090Sdougb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52224090Sdougb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53224090Sdougb * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 54224090Sdougb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 55224090Sdougb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 56224090Sdougb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 57224090Sdougb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58224090Sdougb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 59224090Sdougb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60224090Sdougb * SUCH DAMAGE. 61224090Sdougb * 62224090Sdougb * @(#)ipx_usrreq.c 63224090Sdougb */ 64224090Sdougb 65224090Sdougb#include <sys/cdefs.h> 66224090Sdougb__FBSDID("$FreeBSD: head/sys/netipx/ipx_usrreq.c 185928 2008-12-11 10:29:35Z rwatson $"); 67224090Sdougb 68224090Sdougb#include "opt_ipx.h" 69224090Sdougb 70224090Sdougb#include <sys/param.h> 71224090Sdougb#include <sys/kernel.h> 72224090Sdougb#include <sys/lock.h> 73224090Sdougb#include <sys/mbuf.h> 74224090Sdougb#include <sys/priv.h> 75224090Sdougb#include <sys/protosw.h> 76224090Sdougb#include <sys/signalvar.h> 77224090Sdougb#include <sys/socket.h> 78224090Sdougb#include <sys/socketvar.h> 79224090Sdougb#include <sys/sx.h> 80224090Sdougb#include <sys/sysctl.h> 81224090Sdougb#include <sys/systm.h> 82224090Sdougb 83224090Sdougb#include <net/if.h> 84224090Sdougb#include <net/route.h> 85224090Sdougb 86224090Sdougb#include <netinet/in.h> 87224090Sdougb 88224090Sdougb#include <netipx/ipx.h> 89224090Sdougb#include <netipx/ipx_if.h> 90224090Sdougb#include <netipx/ipx_pcb.h> 91224090Sdougb#include <netipx/ipx_var.h> 92224090Sdougb 93224090Sdougb/* 94224090Sdougb * IPX protocol implementation. 95224090Sdougb */ 96224090Sdougb 97224090Sdougbstatic int ipxsendspace = IPXSNDQ; 98224090SdougbSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 99224090Sdougb &ipxsendspace, 0, "Send buffer space"); 100224090Sdougbstatic int ipxrecvspace = IPXRCVQ; 101224090SdougbSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 102224090Sdougb &ipxrecvspace, 0, "Receive buffer space"); 103224090Sdougb 104224090Sdougbstatic void ipx_usr_abort(struct socket *so); 105224090Sdougbstatic int ipx_attach(struct socket *so, int proto, struct thread *td); 106224090Sdougbstatic int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 107224090Sdougbstatic int ipx_connect(struct socket *so, struct sockaddr *nam, 108224090Sdougb struct thread *td); 109224090Sdougbstatic void ipx_detach(struct socket *so); 110224090Sdougbstatic int ipx_disconnect(struct socket *so); 111224090Sdougbstatic int ipx_send(struct socket *so, int flags, struct mbuf *m, 112224090Sdougb struct sockaddr *addr, struct mbuf *control, 113224090Sdougb struct thread *td); 114224090Sdougbstatic int ipx_shutdown(struct socket *so); 115224090Sdougbstatic int ripx_attach(struct socket *so, int proto, struct thread *td); 116224090Sdougbstatic int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 117224090Sdougbstatic void ipx_usr_close(struct socket *so); 118224090Sdougb 119224090Sdougbstruct pr_usrreqs ipx_usrreqs = { 120224090Sdougb .pru_abort = ipx_usr_abort, 121224090Sdougb .pru_attach = ipx_attach, 122224090Sdougb .pru_bind = ipx_bind, 123224090Sdougb .pru_connect = ipx_connect, 124245163Serwin .pru_control = ipx_control, 125245163Serwin .pru_detach = ipx_detach, 126245163Serwin .pru_disconnect = ipx_disconnect, 127245163Serwin .pru_peeraddr = ipx_peeraddr, 128224090Sdougb .pru_send = ipx_send, 129245163Serwin .pru_shutdown = ipx_shutdown, 130254402Serwin .pru_sockaddr = ipx_sockaddr, 131254402Serwin .pru_close = ipx_usr_close, 132245163Serwin}; 133245163Serwin 134224090Sdougbstruct pr_usrreqs ripx_usrreqs = { 135224090Sdougb .pru_abort = ipx_usr_abort, 136224090Sdougb .pru_attach = ripx_attach, 137224090Sdougb .pru_bind = ipx_bind, 138224090Sdougb .pru_connect = ipx_connect, 139224090Sdougb .pru_control = ipx_control, 140224090Sdougb .pru_detach = ipx_detach, 141224090Sdougb .pru_disconnect = ipx_disconnect, 142224090Sdougb .pru_peeraddr = ipx_peeraddr, 143224090Sdougb .pru_send = ipx_send, 144224090Sdougb .pru_shutdown = ipx_shutdown, 145224090Sdougb .pru_sockaddr = ipx_sockaddr, 146224090Sdougb .pru_close = ipx_usr_close, 147224090Sdougb}; 148224090Sdougb 149224090Sdougb/* 150224090Sdougb * This may also be called for raw listeners. 151224090Sdougb */ 152224090Sdougbvoid 153224090Sdougbipx_input(struct mbuf *m, struct ipxpcb *ipxp) 154224090Sdougb{ 155224090Sdougb struct ipx *ipx = mtod(m, struct ipx *); 156224090Sdougb struct ifnet *ifp = m->m_pkthdr.rcvif; 157224090Sdougb struct sockaddr_ipx ipx_ipx; 158224090Sdougb 159224090Sdougb KASSERT(ipxp != NULL, ("ipx_input: NULL ipxpcb")); 160224090Sdougb IPX_LOCK_ASSERT(ipxp); 161224090Sdougb /* 162224090Sdougb * Construct sockaddr format source address. 163224090Sdougb * Stuff source address and datagram in user buffer. 164224090Sdougb */ 165224090Sdougb ipx_ipx.sipx_len = sizeof(ipx_ipx); 166224090Sdougb ipx_ipx.sipx_family = AF_IPX; 167224090Sdougb ipx_ipx.sipx_addr = ipx->ipx_sna; 168224090Sdougb ipx_ipx.sipx_zero[0] = '\0'; 169224090Sdougb ipx_ipx.sipx_zero[1] = '\0'; 170224090Sdougb if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { 171224090Sdougb struct ifaddr *ifa; 172224090Sdougb 173224090Sdougb for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; 174224090Sdougb ifa = TAILQ_NEXT(ifa, ifa_link)) { 175224090Sdougb if (ifa->ifa_addr->sa_family == AF_IPX) { 176224090Sdougb ipx_ipx.sipx_addr.x_net = 177245163Serwin IA_SIPX(ifa)->sipx_addr.x_net; 178224090Sdougb break; 179224090Sdougb } 180224090Sdougb } 181224090Sdougb } 182245163Serwin ipxp->ipxp_rpt = ipx->ipx_pt; 183245163Serwin if ((ipxp->ipxp_flags & IPXP_RAWIN) == 0) { 184224090Sdougb m->m_len -= sizeof(struct ipx); 185224090Sdougb m->m_pkthdr.len -= sizeof(struct ipx); 186224090Sdougb m->m_data += sizeof(struct ipx); 187224090Sdougb } 188224090Sdougb if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, 189224090Sdougb (struct sockaddr *)&ipx_ipx, m, NULL) == 0) 190245163Serwin m_freem(m); 191245163Serwin else 192224090Sdougb sorwakeup(ipxp->ipxp_socket); 193245163Serwin} 194245163Serwin 195224090Sdougb/* 196245163Serwin * Drop connection, reporting 197245163Serwin * the specified error. 198224090Sdougb */ 199224090Sdougbvoid 200224090Sdougbipx_drop(struct ipxpcb *ipxp, int errno) 201224090Sdougb{ 202224090Sdougb struct socket *so = ipxp->ipxp_socket; 203224090Sdougb 204224090Sdougb IPX_LIST_LOCK_ASSERT(); 205224090Sdougb IPX_LOCK_ASSERT(ipxp); 206224090Sdougb 207245163Serwin /* 208224090Sdougb * someday, in the IPX world 209224090Sdougb * we will generate error protocol packets 210224090Sdougb * announcing that the socket has gone away. 211224090Sdougb * 212224090Sdougb * XXX Probably never. IPX does not have error packets. 213224090Sdougb */ 214224090Sdougb /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 215224090Sdougb tp->t_state = TCPS_CLOSED; 216224090Sdougb tcp_output(tp); 217224090Sdougb }*/ 218224090Sdougb so->so_error = errno; 219224090Sdougb ipx_pcbdisconnect(ipxp); 220224090Sdougb soisdisconnected(so); 221224090Sdougb} 222224090Sdougb 223224090Sdougbstatic int 224224090Sdougbipx_output(struct ipxpcb *ipxp, struct mbuf *m0) 225224090Sdougb{ 226224090Sdougb struct ipx *ipx; 227224090Sdougb struct socket *so; 228224090Sdougb int len = 0; 229224090Sdougb struct route *ro; 230224090Sdougb struct mbuf *m; 231224090Sdougb struct mbuf *mprev = NULL; 232224090Sdougb 233224090Sdougb IPX_LOCK_ASSERT(ipxp); 234224090Sdougb 235224090Sdougb /* 236224090Sdougb * Calculate data length. 237224090Sdougb */ 238224090Sdougb for (m = m0; m != NULL; m = m->m_next) { 239224090Sdougb mprev = m; 240224090Sdougb len += m->m_len; 241224090Sdougb } 242224090Sdougb /* 243224090Sdougb * Make sure packet is actually of even length. 244224090Sdougb */ 245224090Sdougb 246224090Sdougb if (len & 1) { 247224090Sdougb m = mprev; 248224090Sdougb if ((m->m_flags & M_EXT) == 0 && 249224090Sdougb (m->m_len + m->m_data < &m->m_dat[MLEN])) { 250224090Sdougb mtod(m, char*)[m->m_len++] = 0; 251224090Sdougb } else { 252224090Sdougb struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 253224090Sdougb 254224090Sdougb if (m1 == NULL) { 255224090Sdougb m_freem(m0); 256262706Serwin return (ENOBUFS); 257224090Sdougb } 258224090Sdougb m1->m_len = 1; 259224090Sdougb * mtod(m1, char *) = 0; 260224090Sdougb m->m_next = m1; 261224090Sdougb } 262224090Sdougb m0->m_pkthdr.len++; 263224090Sdougb } 264224090Sdougb 265224090Sdougb /* 266224090Sdougb * Fill in mbuf with extended IPX header 267224090Sdougb * and addresses and length put into network format. 268224090Sdougb */ 269224090Sdougb m = m0; 270224090Sdougb if (ipxp->ipxp_flags & IPXP_RAWOUT) { 271224090Sdougb ipx = mtod(m, struct ipx *); 272224090Sdougb } else { 273224090Sdougb M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT); 274224090Sdougb if (m == NULL) 275262706Serwin return (ENOBUFS); 276262706Serwin ipx = mtod(m, struct ipx *); 277224090Sdougb ipx->ipx_tc = 0; 278224090Sdougb ipx->ipx_pt = ipxp->ipxp_dpt; 279224090Sdougb ipx->ipx_sna = ipxp->ipxp_laddr; 280224090Sdougb ipx->ipx_dna = ipxp->ipxp_faddr; 281245163Serwin len += sizeof(struct ipx); 282245163Serwin } 283224090Sdougb 284224090Sdougb ipx->ipx_len = htons((u_short)len); 285224090Sdougb 286224090Sdougb if (ipxp->ipxp_flags & IPXP_CHECKSUM) { 287224090Sdougb ipx->ipx_sum = ipx_cksum(m, len); 288224090Sdougb } else 289224090Sdougb ipx->ipx_sum = 0xffff; 290224090Sdougb 291224090Sdougb /* 292224090Sdougb * Output datagram. 293224090Sdougb */ 294224090Sdougb so = ipxp->ipxp_socket; 295224090Sdougb if (so->so_options & SO_DONTROUTE) 296224090Sdougb return (ipx_outputfl(m, (struct route *)NULL, 297224090Sdougb (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 298224090Sdougb /* 299262706Serwin * Use cached route for previous datagram if 300262706Serwin * possible. If the previous net was the same 301262706Serwin * and the interface was a broadcast medium, or 302262706Serwin * if the previous destination was identical, 303262706Serwin * then we are ok. 304224090Sdougb * 305224090Sdougb * NB: We don't handle broadcasts because that 306224090Sdougb * would require 3 subroutine calls. 307224090Sdougb */ 308224090Sdougb ro = &ipxp->ipxp_route; 309224090Sdougb#ifdef ancient_history 310224090Sdougb /* 311224090Sdougb * I think that this will all be handled in ipx_pcbconnect! 312224090Sdougb */ 313245163Serwin if (ro->ro_rt != NULL) { 314245163Serwin if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 315224090Sdougb /* 316224090Sdougb * This assumes we have no GH type routes 317224090Sdougb */ 318224090Sdougb if (ro->ro_rt->rt_flags & RTF_HOST) { 319224090Sdougb if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 320224090Sdougb goto re_route; 321224090Sdougb 322224090Sdougb } 323224090Sdougb if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 324224090Sdougb struct ipx_addr *dst = 325224090Sdougb &satoipx_addr(ro->ro_dst); 326224090Sdougb dst->x_host = ipx->ipx_dna.x_host; 327224090Sdougb } 328224090Sdougb /* 329224090Sdougb * Otherwise, we go through the same gateway 330224090Sdougb * and dst is already set up. 331224090Sdougb */ 332224090Sdougb } else { 333224090Sdougb re_route: 334224090Sdougb RTFREE(ro->ro_rt); 335224090Sdougb ro->ro_rt = NULL; 336224090Sdougb } 337224090Sdougb } 338224090Sdougb ipxp->ipxp_lastdst = ipx->ipx_dna; 339224090Sdougb#endif /* ancient_history */ 340224090Sdougb return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 341224090Sdougb} 342224090Sdougb 343224090Sdougbint 344224090Sdougbipx_ctloutput(struct socket *so, struct sockopt *sopt) 345262706Serwin{ 346262706Serwin struct ipxpcb *ipxp = sotoipxpcb(so); 347262706Serwin int mask, error, optval; 348262706Serwin short soptval; 349262706Serwin struct ipx ioptval; 350262706Serwin long seq; 351262706Serwin 352262706Serwin KASSERT(ipxp != NULL, ("ipx_ctloutput: ipxp == NULL")); 353262706Serwin error = 0; 354262706Serwin 355262706Serwin switch (sopt->sopt_dir) { 356262706Serwin case SOPT_GET: 357262706Serwin switch (sopt->sopt_name) { 358262706Serwin case SO_ALL_PACKETS: 359262706Serwin mask = IPXP_ALL_PACKETS; 360224090Sdougb goto get_flags; 361224090Sdougb 362224090Sdougb case SO_HEADERS_ON_INPUT: 363224090Sdougb mask = IPXP_RAWIN; 364224090Sdougb goto get_flags; 365224090Sdougb 366224090Sdougb case SO_IPX_CHECKSUM: 367224090Sdougb mask = IPXP_CHECKSUM; 368224090Sdougb goto get_flags; 369224090Sdougb 370224090Sdougb case SO_HEADERS_ON_OUTPUT: 371224090Sdougb mask = IPXP_RAWOUT; 372224090Sdougb get_flags: 373224090Sdougb /* Unlocked read. */ 374224090Sdougb soptval = ipxp->ipxp_flags & mask; 375224090Sdougb error = sooptcopyout(sopt, &soptval, sizeof soptval); 376224090Sdougb break; 377224090Sdougb 378224090Sdougb case SO_DEFAULT_HEADERS: 379224090Sdougb ioptval.ipx_len = 0; 380224090Sdougb ioptval.ipx_sum = 0; 381224090Sdougb ioptval.ipx_tc = 0; 382224090Sdougb IPX_LOCK(ipxp); 383224090Sdougb ioptval.ipx_pt = ipxp->ipxp_dpt; 384224090Sdougb ioptval.ipx_dna = ipxp->ipxp_faddr; 385224090Sdougb ioptval.ipx_sna = ipxp->ipxp_laddr; 386224090Sdougb IPX_UNLOCK(ipxp); 387224090Sdougb error = sooptcopyout(sopt, &soptval, sizeof soptval); 388224090Sdougb break; 389254897Serwin 390224090Sdougb case SO_SEQNO: 391224090Sdougb IPX_LIST_LOCK(); 392224090Sdougb seq = ipx_pexseq; 393224090Sdougb ipx_pexseq++; 394224090Sdougb IPX_LIST_UNLOCK(); 395224090Sdougb error = sooptcopyout(sopt, &seq, sizeof seq); 396224090Sdougb break; 397224090Sdougb 398224090Sdougb default: 399224090Sdougb error = EINVAL; 400224090Sdougb } 401224090Sdougb break; 402224090Sdougb 403224090Sdougb case SOPT_SET: 404224090Sdougb switch (sopt->sopt_name) { 405224090Sdougb case SO_ALL_PACKETS: 406224090Sdougb mask = IPXP_ALL_PACKETS; 407224090Sdougb goto set_head; 408245163Serwin 409245163Serwin case SO_HEADERS_ON_INPUT: 410224090Sdougb mask = IPXP_RAWIN; 411224090Sdougb goto set_head; 412224090Sdougb 413224090Sdougb case SO_IPX_CHECKSUM: 414224090Sdougb mask = IPXP_CHECKSUM; 415245163Serwin goto set_head; 416245163Serwin 417224090Sdougb case SO_HEADERS_ON_OUTPUT: 418224090Sdougb mask = IPXP_RAWOUT; 419224090Sdougb set_head: 420245163Serwin error = sooptcopyin(sopt, &optval, sizeof optval, 421245163Serwin sizeof optval); 422224090Sdougb if (error) 423224090Sdougb break; 424224090Sdougb IPX_LOCK(ipxp); 425245163Serwin if (optval) 426245163Serwin ipxp->ipxp_flags |= mask; 427245163Serwin else 428224090Sdougb ipxp->ipxp_flags &= ~mask; 429245163Serwin IPX_UNLOCK(ipxp); 430245163Serwin break; 431245163Serwin 432245163Serwin case SO_DEFAULT_HEADERS: 433245163Serwin error = sooptcopyin(sopt, &ioptval, sizeof ioptval, 434245163Serwin sizeof ioptval); 435245163Serwin if (error) 436245163Serwin break; 437245163Serwin /* Unlocked write. */ 438245163Serwin ipxp->ipxp_dpt = ioptval.ipx_pt; 439224090Sdougb break; 440224090Sdougb default: 441224090Sdougb error = EINVAL; 442224090Sdougb } 443245163Serwin break; 444245163Serwin } 445245163Serwin return (error); 446245163Serwin} 447245163Serwin 448245163Serwinstatic void 449224090Sdougbipx_usr_abort(struct socket *so) 450224090Sdougb{ 451224090Sdougb 452224090Sdougb /* XXXRW: Possibly ipx_disconnect() here? */ 453224090Sdougb soisdisconnected(so); 454224090Sdougb} 455224090Sdougb 456224090Sdougbstatic int 457224090Sdougbipx_attach(struct socket *so, int proto, struct thread *td) 458224090Sdougb{ 459#ifdef INVARIANTS 460 struct ipxpcb *ipxp = sotoipxpcb(so); 461#endif 462 int error; 463 464 KASSERT(ipxp == NULL, ("ipx_attach: ipxp != NULL")); 465 error = soreserve(so, ipxsendspace, ipxrecvspace); 466 if (error != 0) 467 return (error); 468 IPX_LIST_LOCK(); 469 error = ipx_pcballoc(so, &ipxpcb_list, td); 470 IPX_LIST_UNLOCK(); 471 return (error); 472} 473 474static int 475ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 476{ 477 struct ipxpcb *ipxp = sotoipxpcb(so); 478 int error; 479 480 KASSERT(ipxp != NULL, ("ipx_bind: ipxp == NULL")); 481 IPX_LIST_LOCK(); 482 IPX_LOCK(ipxp); 483 error = ipx_pcbbind(ipxp, nam, td); 484 IPX_UNLOCK(ipxp); 485 IPX_LIST_UNLOCK(); 486 return (error); 487} 488 489static void 490ipx_usr_close(struct socket *so) 491{ 492 493 /* XXXRW: Possibly ipx_disconnect() here? */ 494 soisdisconnected(so); 495} 496 497static int 498ipx_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 499{ 500 struct ipxpcb *ipxp = sotoipxpcb(so); 501 int error; 502 503 KASSERT(ipxp != NULL, ("ipx_connect: ipxp == NULL")); 504 IPX_LIST_LOCK(); 505 IPX_LOCK(ipxp); 506 if (!ipx_nullhost(ipxp->ipxp_faddr)) { 507 error = EISCONN; 508 goto out; 509 } 510 error = ipx_pcbconnect(ipxp, nam, td); 511 if (error == 0) 512 soisconnected(so); 513out: 514 IPX_UNLOCK(ipxp); 515 IPX_LIST_UNLOCK(); 516 return (error); 517} 518 519static void 520ipx_detach(struct socket *so) 521{ 522 struct ipxpcb *ipxp = sotoipxpcb(so); 523 524 /* XXXRW: Should assert detached. */ 525 KASSERT(ipxp != NULL, ("ipx_detach: ipxp == NULL")); 526 IPX_LIST_LOCK(); 527 IPX_LOCK(ipxp); 528 ipx_pcbdetach(ipxp); 529 ipx_pcbfree(ipxp); 530 IPX_LIST_UNLOCK(); 531} 532 533static int 534ipx_disconnect(struct socket *so) 535{ 536 struct ipxpcb *ipxp = sotoipxpcb(so); 537 int error; 538 539 KASSERT(ipxp != NULL, ("ipx_disconnect: ipxp == NULL")); 540 IPX_LIST_LOCK(); 541 IPX_LOCK(ipxp); 542 error = 0; 543 if (ipx_nullhost(ipxp->ipxp_faddr)) { 544 error = ENOTCONN; 545 goto out; 546 } 547 ipx_pcbdisconnect(ipxp); 548 soisdisconnected(so); 549out: 550 IPX_UNLOCK(ipxp); 551 IPX_LIST_UNLOCK(); 552 return (0); 553} 554 555int 556ipx_peeraddr(struct socket *so, struct sockaddr **nam) 557{ 558 struct ipxpcb *ipxp = sotoipxpcb(so); 559 560 KASSERT(ipxp != NULL, ("ipx_peeraddr: ipxp == NULL")); 561 ipx_getpeeraddr(ipxp, nam); 562 return (0); 563} 564 565static int 566ipx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 567 struct mbuf *control, struct thread *td) 568{ 569 int error; 570 struct ipxpcb *ipxp = sotoipxpcb(so); 571 struct ipx_addr laddr; 572 573 KASSERT(ipxp != NULL, ("ipxp_send: ipxp == NULL")); 574 /* 575 * Attempt to only acquire the necessary locks: if the socket is 576 * already connected, we don't need to hold the IPX list lock to be 577 * used by ipx_pcbconnect() and ipx_pcbdisconnect(), just the IPX 578 * pcb lock. 579 */ 580 if (nam != NULL) { 581 IPX_LIST_LOCK(); 582 IPX_LOCK(ipxp); 583 laddr = ipxp->ipxp_laddr; 584 if (!ipx_nullhost(ipxp->ipxp_faddr)) { 585 IPX_UNLOCK(ipxp); 586 IPX_LIST_UNLOCK(); 587 error = EISCONN; 588 goto send_release; 589 } 590 /* 591 * Must block input while temporarily connected. 592 */ 593 error = ipx_pcbconnect(ipxp, nam, td); 594 if (error) { 595 IPX_UNLOCK(ipxp); 596 IPX_LIST_UNLOCK(); 597 goto send_release; 598 } 599 } else { 600 IPX_LOCK(ipxp); 601 if (ipx_nullhost(ipxp->ipxp_faddr)) { 602 IPX_UNLOCK(ipxp); 603 error = ENOTCONN; 604 goto send_release; 605 } 606 } 607 error = ipx_output(ipxp, m); 608 m = NULL; 609 if (nam != NULL) { 610 ipx_pcbdisconnect(ipxp); 611 ipxp->ipxp_laddr = laddr; 612 IPX_UNLOCK(ipxp); 613 IPX_LIST_UNLOCK(); 614 } else 615 IPX_UNLOCK(ipxp); 616 617send_release: 618 if (m != NULL) 619 m_freem(m); 620 return (error); 621} 622 623static int 624ipx_shutdown(so) 625 struct socket *so; 626{ 627 628 KASSERT(so->so_pcb != NULL, ("ipx_shutdown: so_pcb == NULL")); 629 socantsendmore(so); 630 return (0); 631} 632 633int 634ipx_sockaddr(struct socket *so, struct sockaddr **nam) 635{ 636 struct ipxpcb *ipxp = sotoipxpcb(so); 637 638 KASSERT(ipxp != NULL, ("ipx_sockaddr: ipxp == NULL")); 639 ipx_getsockaddr(ipxp, nam); 640 return (0); 641} 642 643static int 644ripx_attach(struct socket *so, int proto, struct thread *td) 645{ 646 int error = 0; 647 struct ipxpcb *ipxp = sotoipxpcb(so); 648 649 KASSERT(ipxp == NULL, ("ripx_attach: ipxp != NULL")); 650 651 if (td != NULL) { 652 error = priv_check(td, PRIV_NETIPX_RAW); 653 if (error) 654 return (error); 655 } 656 657 /* 658 * We hold the IPX list lock for the duration as address parameters 659 * of the IPX pcb are changed. Since no one else holds a reference 660 * to the ipxpcb yet, we don't need the ipxpcb lock here. 661 */ 662 IPX_LIST_LOCK(); 663 error = ipx_pcballoc(so, &ipxrawpcb_list, td); 664 if (error) 665 goto out; 666 ipxp = sotoipxpcb(so); 667 error = soreserve(so, ipxsendspace, ipxrecvspace); 668 if (error) 669 goto out; 670 ipxp->ipxp_faddr.x_host = ipx_broadhost; 671 ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT; 672out: 673 IPX_LIST_UNLOCK(); 674 return (error); 675} 676