ipx_usrreq.c revision 185928
1139823Simp/*- 2157128Srwatson * Copyright (c) 1984, 1985, 1986, 1987, 1993 3157128Srwatson * The Regents of the University of California. 4157128Srwatson * Copyright (c) 2004-2006 Robert N. M. Watson 5157128Srwatson * All rights reserved. 611819Sjulian * 711819Sjulian * Redistribution and use in source and binary forms, with or without 811819Sjulian * modification, are permitted provided that the following conditions 911819Sjulian * are met: 1011819Sjulian * 1. Redistributions of source code must retain the above copyright 1111819Sjulian * notice, this list of conditions and the following disclaimer. 1211819Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1311819Sjulian * notice, this list of conditions and the following disclaimer in the 1411819Sjulian * documentation and/or other materials provided with the distribution. 15165899Srwatson * 4. Neither the name of the University nor the names of its contributors 16165899Srwatson * may be used to endorse or promote products derived from this software 17165899Srwatson * without specific prior written permission. 18165899Srwatson * 19165899Srwatson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20165899Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21165899Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22165899Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23165899Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24165899Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25165899Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26165899Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27165899Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28165899Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29165899Srwatson * SUCH DAMAGE. 30165899Srwatson * 31165899Srwatson * Copyright (c) 1995, Mike Mitchell 32165899Srwatson * All rights reserved. 33165899Srwatson * 34165899Srwatson * Redistribution and use in source and binary forms, with or without 35165899Srwatson * modification, are permitted provided that the following conditions 36165899Srwatson * are met: 37165899Srwatson * 1. Redistributions of source code must retain the above copyright 38165899Srwatson * notice, this list of conditions and the following disclaimer. 39165899Srwatson * 2. Redistributions in binary form must reproduce the above copyright 40165899Srwatson * notice, this list of conditions and the following disclaimer in the 41165899Srwatson * documentation and/or other materials provided with the distribution. 4211819Sjulian * 3. All advertising materials mentioning features or use of this software 4311819Sjulian * must display the following acknowledgement: 4411819Sjulian * This product includes software developed by the University of 4511819Sjulian * California, Berkeley and its contributors. 4611819Sjulian * 4. Neither the name of the University nor the names of its contributors 4711819Sjulian * may be used to endorse or promote products derived from this software 4811819Sjulian * without specific prior written permission. 4911819Sjulian * 5011819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5111819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5211819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5311819Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5411819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5511819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5611819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5711819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5811819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5911819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6011819Sjulian * SUCH DAMAGE. 6111819Sjulian * 6212057Sjulian * @(#)ipx_usrreq.c 6311819Sjulian */ 6411819Sjulian 65116189Sobrien#include <sys/cdefs.h> 66116189Sobrien__FBSDID("$FreeBSD: head/sys/netipx/ipx_usrreq.c 185928 2008-12-11 10:29:35Z rwatson $"); 67116189Sobrien 6831742Seivind#include "opt_ipx.h" 6931742Seivind 7011819Sjulian#include <sys/param.h> 7119947Sjhay#include <sys/kernel.h> 7295759Stanimura#include <sys/lock.h> 7311819Sjulian#include <sys/mbuf.h> 74164033Srwatson#include <sys/priv.h> 7511819Sjulian#include <sys/protosw.h> 7695759Stanimura#include <sys/signalvar.h> 7711819Sjulian#include <sys/socket.h> 7811819Sjulian#include <sys/socketvar.h> 7995759Stanimura#include <sys/sx.h> 8019947Sjhay#include <sys/sysctl.h> 8195759Stanimura#include <sys/systm.h> 8211819Sjulian 8311819Sjulian#include <net/if.h> 8411819Sjulian#include <net/route.h> 8511819Sjulian 8611947Sjulian#include <netinet/in.h> 8711947Sjulian 8811819Sjulian#include <netipx/ipx.h> 8995759Stanimura#include <netipx/ipx_if.h> 9011819Sjulian#include <netipx/ipx_pcb.h> 9111819Sjulian#include <netipx/ipx_var.h> 9211819Sjulian 9311819Sjulian/* 9411819Sjulian * IPX protocol implementation. 9511819Sjulian */ 9611819Sjulian 9733181Seivindstatic int ipxsendspace = IPXSNDQ; 9819947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 99180816Strhodes &ipxsendspace, 0, "Send buffer space"); 10033181Seivindstatic int ipxrecvspace = IPXRCVQ; 10119947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 102180816Strhodes &ipxrecvspace, 0, "Receive buffer space"); 10319947Sjhay 104157366Srwatsonstatic void ipx_usr_abort(struct socket *so); 10583366Sjulianstatic int ipx_attach(struct socket *so, int proto, struct thread *td); 10683366Sjulianstatic int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 10728270Swollmanstatic int ipx_connect(struct socket *so, struct sockaddr *nam, 10883366Sjulian struct thread *td); 109157370Srwatsonstatic void ipx_detach(struct socket *so); 11024659Sjhaystatic int ipx_disconnect(struct socket *so); 11124659Sjhaystatic int ipx_send(struct socket *so, int flags, struct mbuf *m, 112139584Srwatson struct sockaddr *addr, struct mbuf *control, 11383366Sjulian struct thread *td); 11424659Sjhaystatic int ipx_shutdown(struct socket *so); 11583366Sjulianstatic int ripx_attach(struct socket *so, int proto, struct thread *td); 11625652Sjhaystatic int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 117160549Srwatsonstatic void ipx_usr_close(struct socket *so); 11824659Sjhay 11925652Sjhaystruct pr_usrreqs ipx_usrreqs = { 120137386Sphk .pru_abort = ipx_usr_abort, 121137386Sphk .pru_attach = ipx_attach, 122137386Sphk .pru_bind = ipx_bind, 123137386Sphk .pru_connect = ipx_connect, 124137386Sphk .pru_control = ipx_control, 125137386Sphk .pru_detach = ipx_detach, 126137386Sphk .pru_disconnect = ipx_disconnect, 127137386Sphk .pru_peeraddr = ipx_peeraddr, 128137386Sphk .pru_send = ipx_send, 129137386Sphk .pru_shutdown = ipx_shutdown, 130137386Sphk .pru_sockaddr = ipx_sockaddr, 131160549Srwatson .pru_close = ipx_usr_close, 13224659Sjhay}; 13324659Sjhay 13425652Sjhaystruct pr_usrreqs ripx_usrreqs = { 135137386Sphk .pru_abort = ipx_usr_abort, 136137386Sphk .pru_attach = ripx_attach, 137137386Sphk .pru_bind = ipx_bind, 138137386Sphk .pru_connect = ipx_connect, 139137386Sphk .pru_control = ipx_control, 140137386Sphk .pru_detach = ipx_detach, 141137386Sphk .pru_disconnect = ipx_disconnect, 142137386Sphk .pru_peeraddr = ipx_peeraddr, 143137386Sphk .pru_send = ipx_send, 144137386Sphk .pru_shutdown = ipx_shutdown, 145137386Sphk .pru_sockaddr = ipx_sockaddr, 146160549Srwatson .pru_close = ipx_usr_close, 14724659Sjhay}; 14824659Sjhay 14911819Sjulian/* 15011819Sjulian * This may also be called for raw listeners. 15111819Sjulian */ 15211819Sjulianvoid 153169463Srwatsonipx_input(struct mbuf *m, struct ipxpcb *ipxp) 15411819Sjulian{ 155169463Srwatson struct ipx *ipx = mtod(m, struct ipx *); 15611819Sjulian struct ifnet *ifp = m->m_pkthdr.rcvif; 15715245Sjhay struct sockaddr_ipx ipx_ipx; 15811819Sjulian 159139623Srwatson KASSERT(ipxp != NULL, ("ipx_input: NULL ipxpcb")); 160139929Srwatson IPX_LOCK_ASSERT(ipxp); 16111819Sjulian /* 16211819Sjulian * Construct sockaddr format source address. 16311819Sjulian * Stuff source address and datagram in user buffer. 16411819Sjulian */ 16515245Sjhay ipx_ipx.sipx_len = sizeof(ipx_ipx); 16615245Sjhay ipx_ipx.sipx_family = AF_IPX; 16711819Sjulian ipx_ipx.sipx_addr = ipx->ipx_sna; 16815245Sjhay ipx_ipx.sipx_zero[0] = '\0'; 16915245Sjhay ipx_ipx.sipx_zero[1] = '\0'; 17025652Sjhay if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { 171169463Srwatson struct ifaddr *ifa; 17211819Sjulian 173139584Srwatson for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; 17471999Sphk ifa = TAILQ_NEXT(ifa, ifa_link)) { 17511819Sjulian if (ifa->ifa_addr->sa_family == AF_IPX) { 17611819Sjulian ipx_ipx.sipx_addr.x_net = 17711819Sjulian IA_SIPX(ifa)->sipx_addr.x_net; 17811819Sjulian break; 17911819Sjulian } 18011819Sjulian } 18111819Sjulian } 18211819Sjulian ipxp->ipxp_rpt = ipx->ipx_pt; 183139588Srwatson if ((ipxp->ipxp_flags & IPXP_RAWIN) == 0) { 18425652Sjhay m->m_len -= sizeof(struct ipx); 18525652Sjhay m->m_pkthdr.len -= sizeof(struct ipx); 18625652Sjhay m->m_data += sizeof(struct ipx); 18711819Sjulian } 188139588Srwatson if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, 189139588Srwatson (struct sockaddr *)&ipx_ipx, m, NULL) == 0) 190139588Srwatson m_freem(m); 191139588Srwatson else 192139588Srwatson sorwakeup(ipxp->ipxp_socket); 19311819Sjulian} 19411819Sjulian 19511819Sjulian/* 19611819Sjulian * Drop connection, reporting 19711819Sjulian * the specified error. 19811819Sjulian */ 19911819Sjulianvoid 200169463Srwatsonipx_drop(struct ipxpcb *ipxp, int errno) 20111819Sjulian{ 20211819Sjulian struct socket *so = ipxp->ipxp_socket; 20311819Sjulian 204139929Srwatson IPX_LIST_LOCK_ASSERT(); 205139929Srwatson IPX_LOCK_ASSERT(ipxp); 206139929Srwatson 20711819Sjulian /* 20825652Sjhay * someday, in the IPX world 20911819Sjulian * we will generate error protocol packets 21011819Sjulian * announcing that the socket has gone away. 21125652Sjhay * 21225652Sjhay * XXX Probably never. IPX does not have error packets. 21311819Sjulian */ 21411819Sjulian /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 21511819Sjulian tp->t_state = TCPS_CLOSED; 21625652Sjhay tcp_output(tp); 21711819Sjulian }*/ 21811819Sjulian so->so_error = errno; 21911819Sjulian ipx_pcbdisconnect(ipxp); 22011819Sjulian soisdisconnected(so); 22111819Sjulian} 22211819Sjulian 22325652Sjhaystatic int 224169463Srwatsonipx_output(struct ipxpcb *ipxp, struct mbuf *m0) 22511819Sjulian{ 226169463Srwatson struct ipx *ipx; 227169463Srwatson struct socket *so; 228169463Srwatson int len = 0; 229169463Srwatson struct route *ro; 23054799Sgreen struct mbuf *m; 23111819Sjulian struct mbuf *mprev = NULL; 23211819Sjulian 233139929Srwatson IPX_LOCK_ASSERT(ipxp); 234139929Srwatson 23511819Sjulian /* 23611819Sjulian * Calculate data length. 23711819Sjulian */ 23825652Sjhay for (m = m0; m != NULL; m = m->m_next) { 23911819Sjulian mprev = m; 24011819Sjulian len += m->m_len; 24111819Sjulian } 24211819Sjulian /* 24311819Sjulian * Make sure packet is actually of even length. 24411819Sjulian */ 245139584Srwatson 24611819Sjulian if (len & 1) { 24711819Sjulian m = mprev; 24811819Sjulian if ((m->m_flags & M_EXT) == 0 && 24911819Sjulian (m->m_len + m->m_data < &m->m_dat[MLEN])) { 25050519Sjhay mtod(m, char*)[m->m_len++] = 0; 25111819Sjulian } else { 252111119Simp struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 25311819Sjulian 25425652Sjhay if (m1 == NULL) { 25511819Sjulian m_freem(m0); 25611819Sjulian return (ENOBUFS); 25711819Sjulian } 25811819Sjulian m1->m_len = 1; 25911819Sjulian * mtod(m1, char *) = 0; 26011819Sjulian m->m_next = m1; 26111819Sjulian } 26211819Sjulian m0->m_pkthdr.len++; 26311819Sjulian } 26411819Sjulian 26511819Sjulian /* 26611819Sjulian * Fill in mbuf with extended IPX header 26711819Sjulian * and addresses and length put into network format. 26811819Sjulian */ 26911819Sjulian m = m0; 27011819Sjulian if (ipxp->ipxp_flags & IPXP_RAWOUT) { 27111819Sjulian ipx = mtod(m, struct ipx *); 27211819Sjulian } else { 273111119Simp M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT); 27425652Sjhay if (m == NULL) 27511819Sjulian return (ENOBUFS); 27611819Sjulian ipx = mtod(m, struct ipx *); 27711819Sjulian ipx->ipx_tc = 0; 27811819Sjulian ipx->ipx_pt = ipxp->ipxp_dpt; 27911819Sjulian ipx->ipx_sna = ipxp->ipxp_laddr; 28011819Sjulian ipx->ipx_dna = ipxp->ipxp_faddr; 28125652Sjhay len += sizeof(struct ipx); 28211819Sjulian } 28311819Sjulian 28411819Sjulian ipx->ipx_len = htons((u_short)len); 28511819Sjulian 28650519Sjhay if (ipxp->ipxp_flags & IPXP_CHECKSUM) { 28711819Sjulian ipx->ipx_sum = ipx_cksum(m, len); 28811819Sjulian } else 28911819Sjulian ipx->ipx_sum = 0xffff; 29011819Sjulian 29111819Sjulian /* 29211819Sjulian * Output datagram. 29311819Sjulian */ 29411819Sjulian so = ipxp->ipxp_socket; 29597658Stanimura if (so->so_options & SO_DONTROUTE) 29625652Sjhay return (ipx_outputfl(m, (struct route *)NULL, 29797658Stanimura (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 29811819Sjulian /* 29911819Sjulian * Use cached route for previous datagram if 30011819Sjulian * possible. If the previous net was the same 30111819Sjulian * and the interface was a broadcast medium, or 30211819Sjulian * if the previous destination was identical, 30311819Sjulian * then we are ok. 30411819Sjulian * 30511819Sjulian * NB: We don't handle broadcasts because that 30611819Sjulian * would require 3 subroutine calls. 30711819Sjulian */ 30811819Sjulian ro = &ipxp->ipxp_route; 30911819Sjulian#ifdef ancient_history 31011819Sjulian /* 31111819Sjulian * I think that this will all be handled in ipx_pcbconnect! 31211819Sjulian */ 31325652Sjhay if (ro->ro_rt != NULL) { 31411819Sjulian if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 31511819Sjulian /* 31611819Sjulian * This assumes we have no GH type routes 31711819Sjulian */ 31811819Sjulian if (ro->ro_rt->rt_flags & RTF_HOST) { 31911819Sjulian if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 32011819Sjulian goto re_route; 32111819Sjulian 32211819Sjulian } 32311819Sjulian if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 324169463Srwatson struct ipx_addr *dst = 32511819Sjulian &satoipx_addr(ro->ro_dst); 32611819Sjulian dst->x_host = ipx->ipx_dna.x_host; 32711819Sjulian } 328139584Srwatson /* 32911819Sjulian * Otherwise, we go through the same gateway 33011819Sjulian * and dst is already set up. 33111819Sjulian */ 33211819Sjulian } else { 33311819Sjulian re_route: 33411819Sjulian RTFREE(ro->ro_rt); 33525652Sjhay ro->ro_rt = NULL; 33611819Sjulian } 33711819Sjulian } 33811819Sjulian ipxp->ipxp_lastdst = ipx->ipx_dna; 33911819Sjulian#endif /* ancient_history */ 34097658Stanimura return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 34111819Sjulian} 34219947Sjhay 34311819Sjulianint 344169463Srwatsonipx_ctloutput(struct socket *so, struct sockopt *sopt) 34511819Sjulian{ 34611819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 34738482Swollman int mask, error, optval; 34838482Swollman short soptval; 34938482Swollman struct ipx ioptval; 350139930Srwatson long seq; 35111819Sjulian 352157128Srwatson KASSERT(ipxp != NULL, ("ipx_ctloutput: ipxp == NULL")); 35338482Swollman error = 0; 35411819Sjulian 35538482Swollman switch (sopt->sopt_dir) { 35638482Swollman case SOPT_GET: 35738482Swollman switch (sopt->sopt_name) { 35811819Sjulian case SO_ALL_PACKETS: 35911819Sjulian mask = IPXP_ALL_PACKETS; 36011819Sjulian goto get_flags; 36111819Sjulian 36211819Sjulian case SO_HEADERS_ON_INPUT: 36311819Sjulian mask = IPXP_RAWIN; 36411819Sjulian goto get_flags; 36550519Sjhay 36650519Sjhay case SO_IPX_CHECKSUM: 36750519Sjhay mask = IPXP_CHECKSUM; 36850519Sjhay goto get_flags; 369139584Srwatson 37011819Sjulian case SO_HEADERS_ON_OUTPUT: 37111819Sjulian mask = IPXP_RAWOUT; 37211819Sjulian get_flags: 373139930Srwatson /* Unlocked read. */ 37438482Swollman soptval = ipxp->ipxp_flags & mask; 37538482Swollman error = sooptcopyout(sopt, &soptval, sizeof soptval); 37611819Sjulian break; 37711819Sjulian 37811819Sjulian case SO_DEFAULT_HEADERS: 37938482Swollman ioptval.ipx_len = 0; 38038482Swollman ioptval.ipx_sum = 0; 38138482Swollman ioptval.ipx_tc = 0; 382139930Srwatson IPX_LOCK(ipxp); 38338482Swollman ioptval.ipx_pt = ipxp->ipxp_dpt; 38438482Swollman ioptval.ipx_dna = ipxp->ipxp_faddr; 38538482Swollman ioptval.ipx_sna = ipxp->ipxp_laddr; 386139930Srwatson IPX_UNLOCK(ipxp); 38738482Swollman error = sooptcopyout(sopt, &soptval, sizeof soptval); 38811819Sjulian break; 38911819Sjulian 39011819Sjulian case SO_SEQNO: 391139930Srwatson IPX_LIST_LOCK(); 392139930Srwatson seq = ipx_pexseq; 39338482Swollman ipx_pexseq++; 394139930Srwatson IPX_LIST_UNLOCK(); 395139930Srwatson error = sooptcopyout(sopt, &seq, sizeof seq); 39611819Sjulian break; 39711819Sjulian 39811819Sjulian default: 39911819Sjulian error = EINVAL; 40011819Sjulian } 40111819Sjulian break; 40211819Sjulian 40338482Swollman case SOPT_SET: 40438482Swollman switch (sopt->sopt_name) { 40511819Sjulian case SO_ALL_PACKETS: 40611819Sjulian mask = IPXP_ALL_PACKETS; 40711819Sjulian goto set_head; 40811819Sjulian 40911819Sjulian case SO_HEADERS_ON_INPUT: 41011819Sjulian mask = IPXP_RAWIN; 41111819Sjulian goto set_head; 41211819Sjulian 41350519Sjhay case SO_IPX_CHECKSUM: 41450519Sjhay mask = IPXP_CHECKSUM; 415185928Srwatson goto set_head; 41650519Sjhay 41711819Sjulian case SO_HEADERS_ON_OUTPUT: 41811819Sjulian mask = IPXP_RAWOUT; 41911819Sjulian set_head: 42038482Swollman error = sooptcopyin(sopt, &optval, sizeof optval, 42138482Swollman sizeof optval); 42238482Swollman if (error) 42338482Swollman break; 424139930Srwatson IPX_LOCK(ipxp); 42538482Swollman if (optval) 42638482Swollman ipxp->ipxp_flags |= mask; 42738482Swollman else 42838482Swollman ipxp->ipxp_flags &= ~mask; 429139930Srwatson IPX_UNLOCK(ipxp); 43011819Sjulian break; 43111819Sjulian 43211819Sjulian case SO_DEFAULT_HEADERS: 43338482Swollman error = sooptcopyin(sopt, &ioptval, sizeof ioptval, 43438482Swollman sizeof ioptval); 43538482Swollman if (error) 43638482Swollman break; 437139930Srwatson /* Unlocked write. */ 43838482Swollman ipxp->ipxp_dpt = ioptval.ipx_pt; 43911819Sjulian break; 44011819Sjulian default: 44111819Sjulian error = EINVAL; 44211819Sjulian } 44311819Sjulian break; 44411819Sjulian } 44511819Sjulian return (error); 44611819Sjulian} 44711819Sjulian 448157366Srwatsonstatic void 449169463Srwatsonipx_usr_abort(struct socket *so) 45011819Sjulian{ 45111819Sjulian 452160549Srwatson /* XXXRW: Possibly ipx_disconnect() here? */ 453130387Srwatson soisdisconnected(so); 45424659Sjhay} 45511819Sjulian 45624659Sjhaystatic int 457169463Srwatsonipx_attach(struct socket *so, int proto, struct thread *td) 45824659Sjhay{ 459157672Scognet#ifdef INVARIANTS 460139929Srwatson struct ipxpcb *ipxp = sotoipxpcb(so); 461157672Scognet#endif 46224659Sjhay int error; 46324659Sjhay 464157128Srwatson KASSERT(ipxp == NULL, ("ipx_attach: ipxp != NULL")); 465157128Srwatson error = soreserve(so, ipxsendspace, ipxrecvspace); 466157128Srwatson if (error != 0) 467157128Srwatson return (error); 468139929Srwatson IPX_LIST_LOCK(); 469139444Srwatson error = ipx_pcballoc(so, &ipxpcb_list, td); 470139929Srwatson IPX_LIST_UNLOCK(); 47124659Sjhay return (error); 47224659Sjhay} 47311819Sjulian 47424659Sjhaystatic int 475169463Srwatsonipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 47624659Sjhay{ 47724659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 478139929Srwatson int error; 47911819Sjulian 480157128Srwatson KASSERT(ipxp != NULL, ("ipx_bind: ipxp == NULL")); 481139929Srwatson IPX_LIST_LOCK(); 482139929Srwatson IPX_LOCK(ipxp); 483139929Srwatson error = ipx_pcbbind(ipxp, nam, td); 484139929Srwatson IPX_UNLOCK(ipxp); 485139929Srwatson IPX_LIST_UNLOCK(); 486139929Srwatson return (error); 48724659Sjhay} 48811819Sjulian 489160549Srwatsonstatic void 490169463Srwatsonipx_usr_close(struct socket *so) 491160549Srwatson{ 492160549Srwatson 493160549Srwatson /* XXXRW: Possibly ipx_disconnect() here? */ 494160549Srwatson soisdisconnected(so); 495160549Srwatson} 496160549Srwatson 49724659Sjhaystatic int 498169463Srwatsonipx_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 49924659Sjhay{ 500139929Srwatson struct ipxpcb *ipxp = sotoipxpcb(so); 50124659Sjhay int error; 50211819Sjulian 503157128Srwatson KASSERT(ipxp != NULL, ("ipx_connect: ipxp == NULL")); 504139929Srwatson IPX_LIST_LOCK(); 505139929Srwatson IPX_LOCK(ipxp); 506139929Srwatson if (!ipx_nullhost(ipxp->ipxp_faddr)) { 507139929Srwatson error = EISCONN; 508139929Srwatson goto out; 509139929Srwatson } 51083366Sjulian error = ipx_pcbconnect(ipxp, nam, td); 51197658Stanimura if (error == 0) 51224659Sjhay soisconnected(so); 513139929Srwatsonout: 514139929Srwatson IPX_UNLOCK(ipxp); 515139929Srwatson IPX_LIST_UNLOCK(); 51624659Sjhay return (error); 51724659Sjhay} 51811819Sjulian 519157370Srwatsonstatic void 520169463Srwatsonipx_detach(struct socket *so) 52124659Sjhay{ 52224659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 52311819Sjulian 524160549Srwatson /* XXXRW: Should assert detached. */ 525157128Srwatson KASSERT(ipxp != NULL, ("ipx_detach: ipxp == NULL")); 526139929Srwatson IPX_LIST_LOCK(); 527139929Srwatson IPX_LOCK(ipxp); 52824659Sjhay ipx_pcbdetach(ipxp); 529157128Srwatson ipx_pcbfree(ipxp); 530139929Srwatson IPX_LIST_UNLOCK(); 53124659Sjhay} 53211819Sjulian 53324659Sjhaystatic int 534169463Srwatsonipx_disconnect(struct socket *so) 53524659Sjhay{ 53624659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 537139929Srwatson int error; 53811819Sjulian 539157128Srwatson KASSERT(ipxp != NULL, ("ipx_disconnect: ipxp == NULL")); 540139929Srwatson IPX_LIST_LOCK(); 541139929Srwatson IPX_LOCK(ipxp); 542139929Srwatson error = 0; 543139929Srwatson if (ipx_nullhost(ipxp->ipxp_faddr)) { 544139929Srwatson error = ENOTCONN; 545139929Srwatson goto out; 546139929Srwatson } 54724659Sjhay ipx_pcbdisconnect(ipxp); 54824659Sjhay soisdisconnected(so); 549139929Srwatsonout: 550139929Srwatson IPX_UNLOCK(ipxp); 551139929Srwatson IPX_LIST_UNLOCK(); 55224659Sjhay return (0); 55324659Sjhay} 55411819Sjulian 55524659Sjhayint 556169463Srwatsonipx_peeraddr(struct socket *so, struct sockaddr **nam) 55724659Sjhay{ 55824659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 55911819Sjulian 560157128Srwatson KASSERT(ipxp != NULL, ("ipx_peeraddr: ipxp == NULL")); 561169462Srwatson ipx_getpeeraddr(ipxp, nam); 56224659Sjhay return (0); 56324659Sjhay} 56424659Sjhay 56524659Sjhaystatic int 566169463Srwatsonipx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 567169463Srwatson struct mbuf *control, struct thread *td) 56824659Sjhay{ 56924659Sjhay int error; 57024659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 57124659Sjhay struct ipx_addr laddr; 57224659Sjhay 573157128Srwatson KASSERT(ipxp != NULL, ("ipxp_send: ipxp == NULL")); 574139929Srwatson /* 575139929Srwatson * Attempt to only acquire the necessary locks: if the socket is 576139929Srwatson * already connected, we don't need to hold the IPX list lock to be 577139929Srwatson * used by ipx_pcbconnect() and ipx_pcbdisconnect(), just the IPX 578139929Srwatson * pcb lock. 579139929Srwatson */ 58025652Sjhay if (nam != NULL) { 581139929Srwatson IPX_LIST_LOCK(); 582139929Srwatson IPX_LOCK(ipxp); 58324659Sjhay laddr = ipxp->ipxp_laddr; 58424659Sjhay if (!ipx_nullhost(ipxp->ipxp_faddr)) { 585139929Srwatson IPX_UNLOCK(ipxp); 586139929Srwatson IPX_LIST_UNLOCK(); 58724659Sjhay error = EISCONN; 58824659Sjhay goto send_release; 58911819Sjulian } 59024659Sjhay /* 59124659Sjhay * Must block input while temporarily connected. 59224659Sjhay */ 59383366Sjulian error = ipx_pcbconnect(ipxp, nam, td); 59424659Sjhay if (error) { 595139929Srwatson IPX_UNLOCK(ipxp); 596139929Srwatson IPX_LIST_UNLOCK(); 59724659Sjhay goto send_release; 59811819Sjulian } 59924659Sjhay } else { 600139929Srwatson IPX_LOCK(ipxp); 60124659Sjhay if (ipx_nullhost(ipxp->ipxp_faddr)) { 602139929Srwatson IPX_UNLOCK(ipxp); 60324659Sjhay error = ENOTCONN; 60424659Sjhay goto send_release; 60524659Sjhay } 60611819Sjulian } 60724659Sjhay error = ipx_output(ipxp, m); 60824659Sjhay m = NULL; 60925652Sjhay if (nam != NULL) { 61024659Sjhay ipx_pcbdisconnect(ipxp); 61143712Sjhay ipxp->ipxp_laddr = laddr; 612139929Srwatson IPX_UNLOCK(ipxp); 613139929Srwatson IPX_LIST_UNLOCK(); 614139929Srwatson } else 615139929Srwatson IPX_UNLOCK(ipxp); 61611819Sjulian 61724659Sjhaysend_release: 61811819Sjulian if (m != NULL) 61911819Sjulian m_freem(m); 62011819Sjulian return (error); 62111819Sjulian} 62219947Sjhay 62324659Sjhaystatic int 62424659Sjhayipx_shutdown(so) 62524659Sjhay struct socket *so; 62624659Sjhay{ 627157128Srwatson 628157128Srwatson KASSERT(so->so_pcb != NULL, ("ipx_shutdown: so_pcb == NULL")); 62924659Sjhay socantsendmore(so); 63024659Sjhay return (0); 63124659Sjhay} 63224659Sjhay 63311819Sjulianint 634169463Srwatsonipx_sockaddr(struct socket *so, struct sockaddr **nam) 63511819Sjulian{ 63611819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 63711819Sjulian 638157128Srwatson KASSERT(ipxp != NULL, ("ipx_sockaddr: ipxp == NULL")); 639169462Srwatson ipx_getsockaddr(ipxp, nam); 64024659Sjhay return (0); 64124659Sjhay} 64211819Sjulian 64324659Sjhaystatic int 644169463Srwatsonripx_attach(struct socket *so, int proto, struct thread *td) 64524659Sjhay{ 64624659Sjhay int error = 0; 64724659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 64811819Sjulian 649157128Srwatson KASSERT(ipxp == NULL, ("ripx_attach: ipxp != NULL")); 650164033Srwatson 651164033Srwatson if (td != NULL) { 652164033Srwatson error = priv_check(td, PRIV_NETIPX_RAW); 653164033Srwatson if (error) 654164033Srwatson return (error); 655164033Srwatson } 656164033Srwatson 657139929Srwatson /* 658139929Srwatson * We hold the IPX list lock for the duration as address parameters 659139929Srwatson * of the IPX pcb are changed. Since no one else holds a reference 660139929Srwatson * to the ipxpcb yet, we don't need the ipxpcb lock here. 661139929Srwatson */ 662139929Srwatson IPX_LIST_LOCK(); 663139444Srwatson error = ipx_pcballoc(so, &ipxrawpcb_list, td); 66424659Sjhay if (error) 665139929Srwatson goto out; 666139929Srwatson ipxp = sotoipxpcb(so); 66724659Sjhay error = soreserve(so, ipxsendspace, ipxrecvspace); 66824659Sjhay if (error) 669139929Srwatson goto out; 67024659Sjhay ipxp->ipxp_faddr.x_host = ipx_broadhost; 67124659Sjhay ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT; 672139929Srwatsonout: 673139929Srwatson IPX_LIST_UNLOCK(); 67411819Sjulian return (error); 67511819Sjulian} 676