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$"); 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 93194544Srwatson#include <security/mac/mac_framework.h> 94194544Srwatson 9511819Sjulian/* 9611819Sjulian * IPX protocol implementation. 9711819Sjulian */ 9811819Sjulian 9933181Seivindstatic int ipxsendspace = IPXSNDQ; 10019947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 101180816Strhodes &ipxsendspace, 0, "Send buffer space"); 10233181Seivindstatic int ipxrecvspace = IPXRCVQ; 10319947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 104180816Strhodes &ipxrecvspace, 0, "Receive buffer space"); 10519947Sjhay 106157366Srwatsonstatic void ipx_usr_abort(struct socket *so); 10783366Sjulianstatic int ipx_attach(struct socket *so, int proto, struct thread *td); 10883366Sjulianstatic int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 10928270Swollmanstatic int ipx_connect(struct socket *so, struct sockaddr *nam, 11083366Sjulian struct thread *td); 111157370Srwatsonstatic void ipx_detach(struct socket *so); 11224659Sjhaystatic int ipx_disconnect(struct socket *so); 11324659Sjhaystatic int ipx_send(struct socket *so, int flags, struct mbuf *m, 114139584Srwatson struct sockaddr *addr, struct mbuf *control, 11583366Sjulian struct thread *td); 11624659Sjhaystatic int ipx_shutdown(struct socket *so); 11783366Sjulianstatic int ripx_attach(struct socket *so, int proto, struct thread *td); 11825652Sjhaystatic int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 119160549Srwatsonstatic void ipx_usr_close(struct socket *so); 12024659Sjhay 12125652Sjhaystruct pr_usrreqs ipx_usrreqs = { 122137386Sphk .pru_abort = ipx_usr_abort, 123137386Sphk .pru_attach = ipx_attach, 124137386Sphk .pru_bind = ipx_bind, 125137386Sphk .pru_connect = ipx_connect, 126137386Sphk .pru_control = ipx_control, 127137386Sphk .pru_detach = ipx_detach, 128137386Sphk .pru_disconnect = ipx_disconnect, 129137386Sphk .pru_peeraddr = ipx_peeraddr, 130137386Sphk .pru_send = ipx_send, 131137386Sphk .pru_shutdown = ipx_shutdown, 132137386Sphk .pru_sockaddr = ipx_sockaddr, 133160549Srwatson .pru_close = ipx_usr_close, 13424659Sjhay}; 13524659Sjhay 13625652Sjhaystruct pr_usrreqs ripx_usrreqs = { 137137386Sphk .pru_abort = ipx_usr_abort, 138137386Sphk .pru_attach = ripx_attach, 139137386Sphk .pru_bind = ipx_bind, 140137386Sphk .pru_connect = ipx_connect, 141137386Sphk .pru_control = ipx_control, 142137386Sphk .pru_detach = ipx_detach, 143137386Sphk .pru_disconnect = ipx_disconnect, 144137386Sphk .pru_peeraddr = ipx_peeraddr, 145137386Sphk .pru_send = ipx_send, 146137386Sphk .pru_shutdown = ipx_shutdown, 147137386Sphk .pru_sockaddr = ipx_sockaddr, 148160549Srwatson .pru_close = ipx_usr_close, 14924659Sjhay}; 15024659Sjhay 15111819Sjulian/* 15211819Sjulian * This may also be called for raw listeners. 15311819Sjulian */ 15411819Sjulianvoid 155169463Srwatsonipx_input(struct mbuf *m, struct ipxpcb *ipxp) 15611819Sjulian{ 157169463Srwatson struct ipx *ipx = mtod(m, struct ipx *); 15811819Sjulian struct ifnet *ifp = m->m_pkthdr.rcvif; 15915245Sjhay struct sockaddr_ipx ipx_ipx; 16011819Sjulian 161139623Srwatson KASSERT(ipxp != NULL, ("ipx_input: NULL ipxpcb")); 162139929Srwatson IPX_LOCK_ASSERT(ipxp); 16311819Sjulian /* 16411819Sjulian * Construct sockaddr format source address. 16511819Sjulian * Stuff source address and datagram in user buffer. 16611819Sjulian */ 16715245Sjhay ipx_ipx.sipx_len = sizeof(ipx_ipx); 16815245Sjhay ipx_ipx.sipx_family = AF_IPX; 16911819Sjulian ipx_ipx.sipx_addr = ipx->ipx_sna; 17015245Sjhay ipx_ipx.sipx_zero[0] = '\0'; 17115245Sjhay ipx_ipx.sipx_zero[1] = '\0'; 17225652Sjhay if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { 173169463Srwatson struct ifaddr *ifa; 17411819Sjulian 175139584Srwatson for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; 17671999Sphk ifa = TAILQ_NEXT(ifa, ifa_link)) { 17711819Sjulian if (ifa->ifa_addr->sa_family == AF_IPX) { 17811819Sjulian ipx_ipx.sipx_addr.x_net = 17911819Sjulian IA_SIPX(ifa)->sipx_addr.x_net; 18011819Sjulian break; 18111819Sjulian } 18211819Sjulian } 18311819Sjulian } 18411819Sjulian ipxp->ipxp_rpt = ipx->ipx_pt; 185139588Srwatson if ((ipxp->ipxp_flags & IPXP_RAWIN) == 0) { 18625652Sjhay m->m_len -= sizeof(struct ipx); 18725652Sjhay m->m_pkthdr.len -= sizeof(struct ipx); 18825652Sjhay m->m_data += sizeof(struct ipx); 18911819Sjulian } 190194561Srwatson#ifdef MAC 191194561Srwatson if (mac_socket_check_deliver(ipxp->ipxp_socket, m) != 0) { 192194561Srwatson m_freem(m); 193194561Srwatson return; 194194561Srwatson } 195194561Srwatson#endif 196139588Srwatson if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, 197139588Srwatson (struct sockaddr *)&ipx_ipx, m, NULL) == 0) 198139588Srwatson m_freem(m); 199139588Srwatson else 200139588Srwatson sorwakeup(ipxp->ipxp_socket); 20111819Sjulian} 20211819Sjulian 20311819Sjulian/* 20411819Sjulian * Drop connection, reporting 20511819Sjulian * the specified error. 20611819Sjulian */ 20711819Sjulianvoid 208169463Srwatsonipx_drop(struct ipxpcb *ipxp, int errno) 20911819Sjulian{ 21011819Sjulian struct socket *so = ipxp->ipxp_socket; 21111819Sjulian 212139929Srwatson IPX_LIST_LOCK_ASSERT(); 213139929Srwatson IPX_LOCK_ASSERT(ipxp); 214139929Srwatson 21511819Sjulian /* 21625652Sjhay * someday, in the IPX world 21711819Sjulian * we will generate error protocol packets 21811819Sjulian * announcing that the socket has gone away. 21925652Sjhay * 22025652Sjhay * XXX Probably never. IPX does not have error packets. 22111819Sjulian */ 22211819Sjulian /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 22311819Sjulian tp->t_state = TCPS_CLOSED; 22425652Sjhay tcp_output(tp); 22511819Sjulian }*/ 22611819Sjulian so->so_error = errno; 22711819Sjulian ipx_pcbdisconnect(ipxp); 22811819Sjulian soisdisconnected(so); 22911819Sjulian} 23011819Sjulian 23125652Sjhaystatic int 232169463Srwatsonipx_output(struct ipxpcb *ipxp, struct mbuf *m0) 23311819Sjulian{ 234169463Srwatson struct ipx *ipx; 235169463Srwatson struct socket *so; 236169463Srwatson int len = 0; 237169463Srwatson struct route *ro; 23854799Sgreen struct mbuf *m; 23911819Sjulian struct mbuf *mprev = NULL; 24011819Sjulian 241139929Srwatson IPX_LOCK_ASSERT(ipxp); 242139929Srwatson 24311819Sjulian /* 24411819Sjulian * Calculate data length. 24511819Sjulian */ 24625652Sjhay for (m = m0; m != NULL; m = m->m_next) { 24711819Sjulian mprev = m; 24811819Sjulian len += m->m_len; 24911819Sjulian } 25011819Sjulian /* 25111819Sjulian * Make sure packet is actually of even length. 25211819Sjulian */ 253139584Srwatson 25411819Sjulian if (len & 1) { 25511819Sjulian m = mprev; 25611819Sjulian if ((m->m_flags & M_EXT) == 0 && 25711819Sjulian (m->m_len + m->m_data < &m->m_dat[MLEN])) { 25850519Sjhay mtod(m, char*)[m->m_len++] = 0; 25911819Sjulian } else { 260243882Sglebius struct mbuf *m1 = m_get(M_NOWAIT, MT_DATA); 26111819Sjulian 26225652Sjhay if (m1 == NULL) { 26311819Sjulian m_freem(m0); 26411819Sjulian return (ENOBUFS); 26511819Sjulian } 26611819Sjulian m1->m_len = 1; 26711819Sjulian * mtod(m1, char *) = 0; 26811819Sjulian m->m_next = m1; 26911819Sjulian } 27011819Sjulian m0->m_pkthdr.len++; 27111819Sjulian } 27211819Sjulian 27311819Sjulian /* 27411819Sjulian * Fill in mbuf with extended IPX header 27511819Sjulian * and addresses and length put into network format. 27611819Sjulian */ 27711819Sjulian m = m0; 27811819Sjulian if (ipxp->ipxp_flags & IPXP_RAWOUT) { 27911819Sjulian ipx = mtod(m, struct ipx *); 28011819Sjulian } else { 281243882Sglebius M_PREPEND(m, sizeof(struct ipx), M_NOWAIT); 28225652Sjhay if (m == NULL) 28311819Sjulian return (ENOBUFS); 28411819Sjulian ipx = mtod(m, struct ipx *); 28511819Sjulian ipx->ipx_tc = 0; 28611819Sjulian ipx->ipx_pt = ipxp->ipxp_dpt; 28711819Sjulian ipx->ipx_sna = ipxp->ipxp_laddr; 28811819Sjulian ipx->ipx_dna = ipxp->ipxp_faddr; 28925652Sjhay len += sizeof(struct ipx); 29011819Sjulian } 29111819Sjulian 29211819Sjulian ipx->ipx_len = htons((u_short)len); 29311819Sjulian 29450519Sjhay if (ipxp->ipxp_flags & IPXP_CHECKSUM) { 29511819Sjulian ipx->ipx_sum = ipx_cksum(m, len); 29611819Sjulian } else 29711819Sjulian ipx->ipx_sum = 0xffff; 29811819Sjulian 29911819Sjulian /* 30011819Sjulian * Output datagram. 30111819Sjulian */ 30211819Sjulian so = ipxp->ipxp_socket; 30397658Stanimura if (so->so_options & SO_DONTROUTE) 30425652Sjhay return (ipx_outputfl(m, (struct route *)NULL, 30597658Stanimura (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 30611819Sjulian /* 30711819Sjulian * Use cached route for previous datagram if 30811819Sjulian * possible. If the previous net was the same 30911819Sjulian * and the interface was a broadcast medium, or 31011819Sjulian * if the previous destination was identical, 31111819Sjulian * then we are ok. 31211819Sjulian * 31311819Sjulian * NB: We don't handle broadcasts because that 31411819Sjulian * would require 3 subroutine calls. 31511819Sjulian */ 31611819Sjulian ro = &ipxp->ipxp_route; 31711819Sjulian#ifdef ancient_history 31811819Sjulian /* 31911819Sjulian * I think that this will all be handled in ipx_pcbconnect! 32011819Sjulian */ 32125652Sjhay if (ro->ro_rt != NULL) { 32211819Sjulian if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 32311819Sjulian /* 32411819Sjulian * This assumes we have no GH type routes 32511819Sjulian */ 32611819Sjulian if (ro->ro_rt->rt_flags & RTF_HOST) { 32711819Sjulian if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 32811819Sjulian goto re_route; 32911819Sjulian 33011819Sjulian } 33111819Sjulian if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 332169463Srwatson struct ipx_addr *dst = 33311819Sjulian &satoipx_addr(ro->ro_dst); 33411819Sjulian dst->x_host = ipx->ipx_dna.x_host; 33511819Sjulian } 336139584Srwatson /* 33711819Sjulian * Otherwise, we go through the same gateway 33811819Sjulian * and dst is already set up. 33911819Sjulian */ 34011819Sjulian } else { 34111819Sjulian re_route: 34211819Sjulian RTFREE(ro->ro_rt); 34325652Sjhay ro->ro_rt = NULL; 34411819Sjulian } 34511819Sjulian } 34611819Sjulian ipxp->ipxp_lastdst = ipx->ipx_dna; 34711819Sjulian#endif /* ancient_history */ 34897658Stanimura return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 34911819Sjulian} 35019947Sjhay 35111819Sjulianint 352169463Srwatsonipx_ctloutput(struct socket *so, struct sockopt *sopt) 35311819Sjulian{ 35411819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 35538482Swollman int mask, error, optval; 35638482Swollman short soptval; 35738482Swollman struct ipx ioptval; 358139930Srwatson long seq; 35911819Sjulian 360157128Srwatson KASSERT(ipxp != NULL, ("ipx_ctloutput: ipxp == NULL")); 36138482Swollman error = 0; 36211819Sjulian 36338482Swollman switch (sopt->sopt_dir) { 36438482Swollman case SOPT_GET: 36538482Swollman switch (sopt->sopt_name) { 36611819Sjulian case SO_ALL_PACKETS: 36711819Sjulian mask = IPXP_ALL_PACKETS; 36811819Sjulian goto get_flags; 36911819Sjulian 37011819Sjulian case SO_HEADERS_ON_INPUT: 37111819Sjulian mask = IPXP_RAWIN; 37211819Sjulian goto get_flags; 37350519Sjhay 37450519Sjhay case SO_IPX_CHECKSUM: 37550519Sjhay mask = IPXP_CHECKSUM; 37650519Sjhay goto get_flags; 377139584Srwatson 37811819Sjulian case SO_HEADERS_ON_OUTPUT: 37911819Sjulian mask = IPXP_RAWOUT; 38011819Sjulian get_flags: 381139930Srwatson /* Unlocked read. */ 38238482Swollman soptval = ipxp->ipxp_flags & mask; 38338482Swollman error = sooptcopyout(sopt, &soptval, sizeof soptval); 38411819Sjulian break; 38511819Sjulian 38611819Sjulian case SO_DEFAULT_HEADERS: 38738482Swollman ioptval.ipx_len = 0; 38838482Swollman ioptval.ipx_sum = 0; 38938482Swollman ioptval.ipx_tc = 0; 390139930Srwatson IPX_LOCK(ipxp); 39138482Swollman ioptval.ipx_pt = ipxp->ipxp_dpt; 39238482Swollman ioptval.ipx_dna = ipxp->ipxp_faddr; 39338482Swollman ioptval.ipx_sna = ipxp->ipxp_laddr; 394139930Srwatson IPX_UNLOCK(ipxp); 39538482Swollman error = sooptcopyout(sopt, &soptval, sizeof soptval); 39611819Sjulian break; 39711819Sjulian 39811819Sjulian case SO_SEQNO: 399139930Srwatson IPX_LIST_LOCK(); 400139930Srwatson seq = ipx_pexseq; 40138482Swollman ipx_pexseq++; 402139930Srwatson IPX_LIST_UNLOCK(); 403139930Srwatson error = sooptcopyout(sopt, &seq, sizeof seq); 40411819Sjulian break; 40511819Sjulian 40611819Sjulian default: 40711819Sjulian error = EINVAL; 40811819Sjulian } 40911819Sjulian break; 41011819Sjulian 41138482Swollman case SOPT_SET: 41238482Swollman switch (sopt->sopt_name) { 41311819Sjulian case SO_ALL_PACKETS: 41411819Sjulian mask = IPXP_ALL_PACKETS; 41511819Sjulian goto set_head; 41611819Sjulian 41711819Sjulian case SO_HEADERS_ON_INPUT: 41811819Sjulian mask = IPXP_RAWIN; 41911819Sjulian goto set_head; 42011819Sjulian 42150519Sjhay case SO_IPX_CHECKSUM: 42250519Sjhay mask = IPXP_CHECKSUM; 423185928Srwatson goto set_head; 42450519Sjhay 42511819Sjulian case SO_HEADERS_ON_OUTPUT: 42611819Sjulian mask = IPXP_RAWOUT; 42711819Sjulian set_head: 42838482Swollman error = sooptcopyin(sopt, &optval, sizeof optval, 42938482Swollman sizeof optval); 43038482Swollman if (error) 43138482Swollman break; 432139930Srwatson IPX_LOCK(ipxp); 43338482Swollman if (optval) 43438482Swollman ipxp->ipxp_flags |= mask; 43538482Swollman else 43638482Swollman ipxp->ipxp_flags &= ~mask; 437139930Srwatson IPX_UNLOCK(ipxp); 43811819Sjulian break; 43911819Sjulian 44011819Sjulian case SO_DEFAULT_HEADERS: 44138482Swollman error = sooptcopyin(sopt, &ioptval, sizeof ioptval, 44238482Swollman sizeof ioptval); 44338482Swollman if (error) 44438482Swollman break; 445139930Srwatson /* Unlocked write. */ 44638482Swollman ipxp->ipxp_dpt = ioptval.ipx_pt; 44711819Sjulian break; 44811819Sjulian default: 44911819Sjulian error = EINVAL; 45011819Sjulian } 45111819Sjulian break; 45211819Sjulian } 45311819Sjulian return (error); 45411819Sjulian} 45511819Sjulian 456157366Srwatsonstatic void 457169463Srwatsonipx_usr_abort(struct socket *so) 45811819Sjulian{ 45911819Sjulian 460160549Srwatson /* XXXRW: Possibly ipx_disconnect() here? */ 461130387Srwatson soisdisconnected(so); 46224659Sjhay} 46311819Sjulian 46424659Sjhaystatic int 465169463Srwatsonipx_attach(struct socket *so, int proto, struct thread *td) 46624659Sjhay{ 467157672Scognet#ifdef INVARIANTS 468139929Srwatson struct ipxpcb *ipxp = sotoipxpcb(so); 469157672Scognet#endif 47024659Sjhay int error; 47124659Sjhay 472157128Srwatson KASSERT(ipxp == NULL, ("ipx_attach: ipxp != NULL")); 473157128Srwatson error = soreserve(so, ipxsendspace, ipxrecvspace); 474157128Srwatson if (error != 0) 475157128Srwatson return (error); 476139929Srwatson IPX_LIST_LOCK(); 477139444Srwatson error = ipx_pcballoc(so, &ipxpcb_list, td); 478139929Srwatson IPX_LIST_UNLOCK(); 47924659Sjhay return (error); 48024659Sjhay} 48111819Sjulian 48224659Sjhaystatic int 483169463Srwatsonipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 48424659Sjhay{ 48524659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 486139929Srwatson int error; 48711819Sjulian 488157128Srwatson KASSERT(ipxp != NULL, ("ipx_bind: ipxp == NULL")); 489139929Srwatson IPX_LIST_LOCK(); 490139929Srwatson IPX_LOCK(ipxp); 491139929Srwatson error = ipx_pcbbind(ipxp, nam, td); 492139929Srwatson IPX_UNLOCK(ipxp); 493139929Srwatson IPX_LIST_UNLOCK(); 494139929Srwatson return (error); 49524659Sjhay} 49611819Sjulian 497160549Srwatsonstatic void 498169463Srwatsonipx_usr_close(struct socket *so) 499160549Srwatson{ 500160549Srwatson 501160549Srwatson /* XXXRW: Possibly ipx_disconnect() here? */ 502160549Srwatson soisdisconnected(so); 503160549Srwatson} 504160549Srwatson 50524659Sjhaystatic int 506169463Srwatsonipx_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 50724659Sjhay{ 508139929Srwatson struct ipxpcb *ipxp = sotoipxpcb(so); 50924659Sjhay int error; 51011819Sjulian 511157128Srwatson KASSERT(ipxp != NULL, ("ipx_connect: ipxp == NULL")); 512139929Srwatson IPX_LIST_LOCK(); 513139929Srwatson IPX_LOCK(ipxp); 514139929Srwatson if (!ipx_nullhost(ipxp->ipxp_faddr)) { 515139929Srwatson error = EISCONN; 516139929Srwatson goto out; 517139929Srwatson } 51883366Sjulian error = ipx_pcbconnect(ipxp, nam, td); 51997658Stanimura if (error == 0) 52024659Sjhay soisconnected(so); 521139929Srwatsonout: 522139929Srwatson IPX_UNLOCK(ipxp); 523139929Srwatson IPX_LIST_UNLOCK(); 52424659Sjhay return (error); 52524659Sjhay} 52611819Sjulian 527157370Srwatsonstatic void 528169463Srwatsonipx_detach(struct socket *so) 52924659Sjhay{ 53024659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 53111819Sjulian 532160549Srwatson /* XXXRW: Should assert detached. */ 533157128Srwatson KASSERT(ipxp != NULL, ("ipx_detach: ipxp == NULL")); 534139929Srwatson IPX_LIST_LOCK(); 535139929Srwatson IPX_LOCK(ipxp); 53624659Sjhay ipx_pcbdetach(ipxp); 537157128Srwatson ipx_pcbfree(ipxp); 538139929Srwatson IPX_LIST_UNLOCK(); 53924659Sjhay} 54011819Sjulian 54124659Sjhaystatic int 542169463Srwatsonipx_disconnect(struct socket *so) 54324659Sjhay{ 54424659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 545139929Srwatson int error; 54611819Sjulian 547157128Srwatson KASSERT(ipxp != NULL, ("ipx_disconnect: ipxp == NULL")); 548139929Srwatson IPX_LIST_LOCK(); 549139929Srwatson IPX_LOCK(ipxp); 550139929Srwatson error = 0; 551139929Srwatson if (ipx_nullhost(ipxp->ipxp_faddr)) { 552139929Srwatson error = ENOTCONN; 553139929Srwatson goto out; 554139929Srwatson } 55524659Sjhay ipx_pcbdisconnect(ipxp); 55624659Sjhay soisdisconnected(so); 557139929Srwatsonout: 558139929Srwatson IPX_UNLOCK(ipxp); 559139929Srwatson IPX_LIST_UNLOCK(); 56024659Sjhay return (0); 56124659Sjhay} 56211819Sjulian 56324659Sjhayint 564169463Srwatsonipx_peeraddr(struct socket *so, struct sockaddr **nam) 56524659Sjhay{ 56624659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 56711819Sjulian 568157128Srwatson KASSERT(ipxp != NULL, ("ipx_peeraddr: ipxp == NULL")); 569169462Srwatson ipx_getpeeraddr(ipxp, nam); 57024659Sjhay return (0); 57124659Sjhay} 57224659Sjhay 57324659Sjhaystatic int 574169463Srwatsonipx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 575169463Srwatson struct mbuf *control, struct thread *td) 57624659Sjhay{ 57724659Sjhay int error; 57824659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 57924659Sjhay struct ipx_addr laddr; 58024659Sjhay 581157128Srwatson KASSERT(ipxp != NULL, ("ipxp_send: ipxp == NULL")); 582139929Srwatson /* 583139929Srwatson * Attempt to only acquire the necessary locks: if the socket is 584139929Srwatson * already connected, we don't need to hold the IPX list lock to be 585139929Srwatson * used by ipx_pcbconnect() and ipx_pcbdisconnect(), just the IPX 586139929Srwatson * pcb lock. 587139929Srwatson */ 588194544Srwatson#ifdef MAC 589194544Srwatson mac_socket_create_mbuf(so, m); 590194544Srwatson#endif 59125652Sjhay if (nam != NULL) { 592139929Srwatson IPX_LIST_LOCK(); 593139929Srwatson IPX_LOCK(ipxp); 59424659Sjhay laddr = ipxp->ipxp_laddr; 59524659Sjhay if (!ipx_nullhost(ipxp->ipxp_faddr)) { 596139929Srwatson IPX_UNLOCK(ipxp); 597139929Srwatson IPX_LIST_UNLOCK(); 59824659Sjhay error = EISCONN; 59924659Sjhay goto send_release; 60011819Sjulian } 60124659Sjhay /* 60224659Sjhay * Must block input while temporarily connected. 60324659Sjhay */ 60483366Sjulian error = ipx_pcbconnect(ipxp, nam, td); 60524659Sjhay if (error) { 606139929Srwatson IPX_UNLOCK(ipxp); 607139929Srwatson IPX_LIST_UNLOCK(); 60824659Sjhay goto send_release; 60911819Sjulian } 61024659Sjhay } else { 611139929Srwatson IPX_LOCK(ipxp); 61224659Sjhay if (ipx_nullhost(ipxp->ipxp_faddr)) { 613139929Srwatson IPX_UNLOCK(ipxp); 61424659Sjhay error = ENOTCONN; 61524659Sjhay goto send_release; 61624659Sjhay } 61711819Sjulian } 61824659Sjhay error = ipx_output(ipxp, m); 61924659Sjhay m = NULL; 62025652Sjhay if (nam != NULL) { 62124659Sjhay ipx_pcbdisconnect(ipxp); 62243712Sjhay ipxp->ipxp_laddr = laddr; 623139929Srwatson IPX_UNLOCK(ipxp); 624139929Srwatson IPX_LIST_UNLOCK(); 625139929Srwatson } else 626139929Srwatson IPX_UNLOCK(ipxp); 62711819Sjulian 62824659Sjhaysend_release: 62911819Sjulian if (m != NULL) 63011819Sjulian m_freem(m); 63111819Sjulian return (error); 63211819Sjulian} 63319947Sjhay 63424659Sjhaystatic int 63524659Sjhayipx_shutdown(so) 63624659Sjhay struct socket *so; 63724659Sjhay{ 638157128Srwatson 639157128Srwatson KASSERT(so->so_pcb != NULL, ("ipx_shutdown: so_pcb == NULL")); 64024659Sjhay socantsendmore(so); 64124659Sjhay return (0); 64224659Sjhay} 64324659Sjhay 64411819Sjulianint 645169463Srwatsonipx_sockaddr(struct socket *so, struct sockaddr **nam) 64611819Sjulian{ 64711819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 64811819Sjulian 649157128Srwatson KASSERT(ipxp != NULL, ("ipx_sockaddr: ipxp == NULL")); 650169462Srwatson ipx_getsockaddr(ipxp, nam); 65124659Sjhay return (0); 65224659Sjhay} 65311819Sjulian 65424659Sjhaystatic int 655169463Srwatsonripx_attach(struct socket *so, int proto, struct thread *td) 65624659Sjhay{ 65724659Sjhay int error = 0; 65824659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 65911819Sjulian 660157128Srwatson KASSERT(ipxp == NULL, ("ripx_attach: ipxp != NULL")); 661164033Srwatson 662164033Srwatson if (td != NULL) { 663164033Srwatson error = priv_check(td, PRIV_NETIPX_RAW); 664164033Srwatson if (error) 665164033Srwatson return (error); 666164033Srwatson } 667164033Srwatson 668139929Srwatson /* 669139929Srwatson * We hold the IPX list lock for the duration as address parameters 670139929Srwatson * of the IPX pcb are changed. Since no one else holds a reference 671139929Srwatson * to the ipxpcb yet, we don't need the ipxpcb lock here. 672139929Srwatson */ 673139929Srwatson IPX_LIST_LOCK(); 674139444Srwatson error = ipx_pcballoc(so, &ipxrawpcb_list, td); 67524659Sjhay if (error) 676139929Srwatson goto out; 677139929Srwatson ipxp = sotoipxpcb(so); 67824659Sjhay error = soreserve(so, ipxsendspace, ipxrecvspace); 67924659Sjhay if (error) 680139929Srwatson goto out; 68124659Sjhay ipxp->ipxp_faddr.x_host = ipx_broadhost; 68224659Sjhay ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT; 683139929Srwatsonout: 684139929Srwatson IPX_LIST_UNLOCK(); 68511819Sjulian return (error); 68611819Sjulian} 687