ipx_usrreq.c revision 130387
111819Sjulian/* 211819Sjulian * Copyright (c) 1995, Mike Mitchell 311819Sjulian * Copyright (c) 1984, 1985, 1986, 1987, 1993 411819Sjulian * The Regents of the University of California. All rights reserved. 511819Sjulian * 611819Sjulian * Redistribution and use in source and binary forms, with or without 711819Sjulian * modification, are permitted provided that the following conditions 811819Sjulian * are met: 911819Sjulian * 1. Redistributions of source code must retain the above copyright 1011819Sjulian * notice, this list of conditions and the following disclaimer. 1111819Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1211819Sjulian * notice, this list of conditions and the following disclaimer in the 1311819Sjulian * documentation and/or other materials provided with the distribution. 1411819Sjulian * 3. All advertising materials mentioning features or use of this software 1511819Sjulian * must display the following acknowledgement: 1611819Sjulian * This product includes software developed by the University of 1711819Sjulian * California, Berkeley and its contributors. 1811819Sjulian * 4. Neither the name of the University nor the names of its contributors 1911819Sjulian * may be used to endorse or promote products derived from this software 2011819Sjulian * without specific prior written permission. 2111819Sjulian * 2211819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2311819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2411819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2511819Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2611819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2711819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2811819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2911819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3011819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3111819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3211819Sjulian * SUCH DAMAGE. 3311819Sjulian * 3412057Sjulian * @(#)ipx_usrreq.c 3511819Sjulian */ 3611819Sjulian 37116189Sobrien#include <sys/cdefs.h> 38116189Sobrien__FBSDID("$FreeBSD: head/sys/netipx/ipx_usrreq.c 130387 2004-06-12 20:47:32Z rwatson $"); 39116189Sobrien 4031742Seivind#include "opt_ipx.h" 4131742Seivind 4211819Sjulian#include <sys/param.h> 4319947Sjhay#include <sys/kernel.h> 4495759Stanimura#include <sys/lock.h> 4511819Sjulian#include <sys/mbuf.h> 4611819Sjulian#include <sys/protosw.h> 4795759Stanimura#include <sys/signalvar.h> 4811819Sjulian#include <sys/socket.h> 4911819Sjulian#include <sys/socketvar.h> 5095759Stanimura#include <sys/sx.h> 5119947Sjhay#include <sys/sysctl.h> 5295759Stanimura#include <sys/systm.h> 5311819Sjulian 5411819Sjulian#include <net/if.h> 5511819Sjulian#include <net/route.h> 5611819Sjulian 5711947Sjulian#include <netinet/in.h> 5811947Sjulian 5911819Sjulian#include <netipx/ipx.h> 6095759Stanimura#include <netipx/ipx_if.h> 6195759Stanimura#include <netipx/ipx_ip.h> 6211819Sjulian#include <netipx/ipx_pcb.h> 6311819Sjulian#include <netipx/ipx_var.h> 6411819Sjulian 6511819Sjulian/* 6611819Sjulian * IPX protocol implementation. 6711819Sjulian */ 6811819Sjulian 6933181Seivindstatic int ipxsendspace = IPXSNDQ; 7019947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 7119947Sjhay &ipxsendspace, 0, ""); 7233181Seivindstatic int ipxrecvspace = IPXRCVQ; 7319947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 7419947Sjhay &ipxrecvspace, 0, ""); 7519947Sjhay 7624659Sjhaystatic int ipx_usr_abort(struct socket *so); 7783366Sjulianstatic int ipx_attach(struct socket *so, int proto, struct thread *td); 7883366Sjulianstatic int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 7928270Swollmanstatic int ipx_connect(struct socket *so, struct sockaddr *nam, 8083366Sjulian struct thread *td); 8124659Sjhaystatic int ipx_detach(struct socket *so); 8224659Sjhaystatic int ipx_disconnect(struct socket *so); 8324659Sjhaystatic int ipx_send(struct socket *so, int flags, struct mbuf *m, 8428270Swollman struct sockaddr *addr, struct mbuf *control, 8583366Sjulian struct thread *td); 8624659Sjhaystatic int ipx_shutdown(struct socket *so); 8783366Sjulianstatic int ripx_attach(struct socket *so, int proto, struct thread *td); 8825652Sjhaystatic int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 8924659Sjhay 9025652Sjhaystruct pr_usrreqs ipx_usrreqs = { 9124659Sjhay ipx_usr_abort, pru_accept_notsupp, ipx_attach, ipx_bind, 9224659Sjhay ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach, 9324659Sjhay ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp, 9424659Sjhay pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown, 95122875Srwatson ipx_sockaddr, sosend, soreceive, sopoll, pru_sosetlabel_null 9624659Sjhay}; 9724659Sjhay 9825652Sjhaystruct pr_usrreqs ripx_usrreqs = { 9924659Sjhay ipx_usr_abort, pru_accept_notsupp, ripx_attach, ipx_bind, 10024659Sjhay ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach, 10124659Sjhay ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp, 10224659Sjhay pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown, 103122875Srwatson ipx_sockaddr, sosend, soreceive, sopoll, pru_sosetlabel_null 10424659Sjhay}; 10524659Sjhay 10611819Sjulian/* 10711819Sjulian * This may also be called for raw listeners. 10811819Sjulian */ 10911819Sjulianvoid 11011819Sjulianipx_input(m, ipxp) 11111819Sjulian struct mbuf *m; 11211819Sjulian register struct ipxpcb *ipxp; 11311819Sjulian{ 11411819Sjulian register struct ipx *ipx = mtod(m, struct ipx *); 11511819Sjulian struct ifnet *ifp = m->m_pkthdr.rcvif; 11615245Sjhay struct sockaddr_ipx ipx_ipx; 11711819Sjulian 11825652Sjhay if (ipxp == NULL) 11911819Sjulian panic("No ipxpcb"); 12011819Sjulian /* 12111819Sjulian * Construct sockaddr format source address. 12211819Sjulian * Stuff source address and datagram in user buffer. 12311819Sjulian */ 12415245Sjhay ipx_ipx.sipx_len = sizeof(ipx_ipx); 12515245Sjhay ipx_ipx.sipx_family = AF_IPX; 12611819Sjulian ipx_ipx.sipx_addr = ipx->ipx_sna; 12715245Sjhay ipx_ipx.sipx_zero[0] = '\0'; 12815245Sjhay ipx_ipx.sipx_zero[1] = '\0'; 12925652Sjhay if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { 13011819Sjulian register struct ifaddr *ifa; 13111819Sjulian 13271999Sphk for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; 13371999Sphk ifa = TAILQ_NEXT(ifa, ifa_link)) { 13411819Sjulian if (ifa->ifa_addr->sa_family == AF_IPX) { 13511819Sjulian ipx_ipx.sipx_addr.x_net = 13611819Sjulian IA_SIPX(ifa)->sipx_addr.x_net; 13711819Sjulian break; 13811819Sjulian } 13911819Sjulian } 14011819Sjulian } 14111819Sjulian ipxp->ipxp_rpt = ipx->ipx_pt; 14225652Sjhay if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) { 14325652Sjhay m->m_len -= sizeof(struct ipx); 14425652Sjhay m->m_pkthdr.len -= sizeof(struct ipx); 14525652Sjhay m->m_data += sizeof(struct ipx); 14611819Sjulian } 14711819Sjulian if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx, 14825652Sjhay m, (struct mbuf *)NULL) == 0) 14911819Sjulian goto bad; 15011819Sjulian sorwakeup(ipxp->ipxp_socket); 15111819Sjulian return; 15211819Sjulianbad: 15311819Sjulian m_freem(m); 15411819Sjulian} 15511819Sjulian 15611819Sjulianvoid 15711819Sjulianipx_abort(ipxp) 15811819Sjulian struct ipxpcb *ipxp; 15911819Sjulian{ 16011819Sjulian struct socket *so = ipxp->ipxp_socket; 16111819Sjulian 16211819Sjulian ipx_pcbdisconnect(ipxp); 16311819Sjulian soisdisconnected(so); 16411819Sjulian} 16525652Sjhay 16611819Sjulian/* 16711819Sjulian * Drop connection, reporting 16811819Sjulian * the specified error. 16911819Sjulian */ 17011819Sjulianvoid 17111819Sjulianipx_drop(ipxp, errno) 17211819Sjulian register struct ipxpcb *ipxp; 17311819Sjulian int errno; 17411819Sjulian{ 17511819Sjulian struct socket *so = ipxp->ipxp_socket; 17611819Sjulian 17711819Sjulian /* 17825652Sjhay * someday, in the IPX world 17911819Sjulian * we will generate error protocol packets 18011819Sjulian * announcing that the socket has gone away. 18125652Sjhay * 18225652Sjhay * XXX Probably never. IPX does not have error packets. 18311819Sjulian */ 18411819Sjulian /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 18511819Sjulian tp->t_state = TCPS_CLOSED; 18625652Sjhay tcp_output(tp); 18711819Sjulian }*/ 18811819Sjulian so->so_error = errno; 18911819Sjulian ipx_pcbdisconnect(ipxp); 19011819Sjulian soisdisconnected(so); 19111819Sjulian} 19211819Sjulian 19325652Sjhaystatic int 19411819Sjulianipx_output(ipxp, m0) 19511819Sjulian struct ipxpcb *ipxp; 19611819Sjulian struct mbuf *m0; 19711819Sjulian{ 19811819Sjulian register struct ipx *ipx; 19911819Sjulian register struct socket *so; 20011819Sjulian register int len = 0; 20111819Sjulian register struct route *ro; 20254799Sgreen struct mbuf *m; 20311819Sjulian struct mbuf *mprev = NULL; 20411819Sjulian 20511819Sjulian /* 20611819Sjulian * Calculate data length. 20711819Sjulian */ 20825652Sjhay for (m = m0; m != NULL; m = m->m_next) { 20911819Sjulian mprev = m; 21011819Sjulian len += m->m_len; 21111819Sjulian } 21211819Sjulian /* 21311819Sjulian * Make sure packet is actually of even length. 21411819Sjulian */ 21511819Sjulian 21611819Sjulian if (len & 1) { 21711819Sjulian m = mprev; 21811819Sjulian if ((m->m_flags & M_EXT) == 0 && 21911819Sjulian (m->m_len + m->m_data < &m->m_dat[MLEN])) { 22050519Sjhay mtod(m, char*)[m->m_len++] = 0; 22111819Sjulian } else { 222111119Simp struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 22311819Sjulian 22425652Sjhay if (m1 == NULL) { 22511819Sjulian m_freem(m0); 22611819Sjulian return (ENOBUFS); 22711819Sjulian } 22811819Sjulian m1->m_len = 1; 22911819Sjulian * mtod(m1, char *) = 0; 23011819Sjulian m->m_next = m1; 23111819Sjulian } 23211819Sjulian m0->m_pkthdr.len++; 23311819Sjulian } 23411819Sjulian 23511819Sjulian /* 23611819Sjulian * Fill in mbuf with extended IPX header 23711819Sjulian * and addresses and length put into network format. 23811819Sjulian */ 23911819Sjulian m = m0; 24011819Sjulian if (ipxp->ipxp_flags & IPXP_RAWOUT) { 24111819Sjulian ipx = mtod(m, struct ipx *); 24211819Sjulian } else { 243111119Simp M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT); 24425652Sjhay if (m == NULL) 24511819Sjulian return (ENOBUFS); 24611819Sjulian ipx = mtod(m, struct ipx *); 24711819Sjulian ipx->ipx_tc = 0; 24811819Sjulian ipx->ipx_pt = ipxp->ipxp_dpt; 24911819Sjulian ipx->ipx_sna = ipxp->ipxp_laddr; 25011819Sjulian ipx->ipx_dna = ipxp->ipxp_faddr; 25125652Sjhay len += sizeof(struct ipx); 25211819Sjulian } 25311819Sjulian 25411819Sjulian ipx->ipx_len = htons((u_short)len); 25511819Sjulian 25650519Sjhay if (ipxp->ipxp_flags & IPXP_CHECKSUM) { 25711819Sjulian ipx->ipx_sum = ipx_cksum(m, len); 25811819Sjulian } else 25911819Sjulian ipx->ipx_sum = 0xffff; 26011819Sjulian 26111819Sjulian /* 26211819Sjulian * Output datagram. 26311819Sjulian */ 26411819Sjulian so = ipxp->ipxp_socket; 26597658Stanimura if (so->so_options & SO_DONTROUTE) 26625652Sjhay return (ipx_outputfl(m, (struct route *)NULL, 26797658Stanimura (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 26811819Sjulian /* 26911819Sjulian * Use cached route for previous datagram if 27011819Sjulian * possible. If the previous net was the same 27111819Sjulian * and the interface was a broadcast medium, or 27211819Sjulian * if the previous destination was identical, 27311819Sjulian * then we are ok. 27411819Sjulian * 27511819Sjulian * NB: We don't handle broadcasts because that 27611819Sjulian * would require 3 subroutine calls. 27711819Sjulian */ 27811819Sjulian ro = &ipxp->ipxp_route; 27911819Sjulian#ifdef ancient_history 28011819Sjulian /* 28111819Sjulian * I think that this will all be handled in ipx_pcbconnect! 28211819Sjulian */ 28325652Sjhay if (ro->ro_rt != NULL) { 28411819Sjulian if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 28511819Sjulian /* 28611819Sjulian * This assumes we have no GH type routes 28711819Sjulian */ 28811819Sjulian if (ro->ro_rt->rt_flags & RTF_HOST) { 28911819Sjulian if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 29011819Sjulian goto re_route; 29111819Sjulian 29211819Sjulian } 29311819Sjulian if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 29411819Sjulian register struct ipx_addr *dst = 29511819Sjulian &satoipx_addr(ro->ro_dst); 29611819Sjulian dst->x_host = ipx->ipx_dna.x_host; 29711819Sjulian } 29811819Sjulian /* 29911819Sjulian * Otherwise, we go through the same gateway 30011819Sjulian * and dst is already set up. 30111819Sjulian */ 30211819Sjulian } else { 30311819Sjulian re_route: 30411819Sjulian RTFREE(ro->ro_rt); 30525652Sjhay ro->ro_rt = NULL; 30611819Sjulian } 30711819Sjulian } 30811819Sjulian ipxp->ipxp_lastdst = ipx->ipx_dna; 30911819Sjulian#endif /* ancient_history */ 31097658Stanimura return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 31111819Sjulian} 31219947Sjhay 31311819Sjulianint 31438482Swollmanipx_ctloutput(so, sopt) 31511819Sjulian struct socket *so; 31638482Swollman struct sockopt *sopt; 31711819Sjulian{ 31811819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 31938482Swollman int mask, error, optval; 32038482Swollman short soptval; 32138482Swollman struct ipx ioptval; 32211819Sjulian 32338482Swollman error = 0; 32411819Sjulian if (ipxp == NULL) 32511819Sjulian return (EINVAL); 32611819Sjulian 32738482Swollman switch (sopt->sopt_dir) { 32838482Swollman case SOPT_GET: 32938482Swollman switch (sopt->sopt_name) { 33011819Sjulian case SO_ALL_PACKETS: 33111819Sjulian mask = IPXP_ALL_PACKETS; 33211819Sjulian goto get_flags; 33311819Sjulian 33411819Sjulian case SO_HEADERS_ON_INPUT: 33511819Sjulian mask = IPXP_RAWIN; 33611819Sjulian goto get_flags; 33750519Sjhay 33850519Sjhay case SO_IPX_CHECKSUM: 33950519Sjhay mask = IPXP_CHECKSUM; 34050519Sjhay goto get_flags; 34111819Sjulian 34211819Sjulian case SO_HEADERS_ON_OUTPUT: 34311819Sjulian mask = IPXP_RAWOUT; 34411819Sjulian get_flags: 34538482Swollman soptval = ipxp->ipxp_flags & mask; 34638482Swollman error = sooptcopyout(sopt, &soptval, sizeof soptval); 34711819Sjulian break; 34811819Sjulian 34911819Sjulian case SO_DEFAULT_HEADERS: 35038482Swollman ioptval.ipx_len = 0; 35138482Swollman ioptval.ipx_sum = 0; 35238482Swollman ioptval.ipx_tc = 0; 35338482Swollman ioptval.ipx_pt = ipxp->ipxp_dpt; 35438482Swollman ioptval.ipx_dna = ipxp->ipxp_faddr; 35538482Swollman ioptval.ipx_sna = ipxp->ipxp_laddr; 35638482Swollman error = sooptcopyout(sopt, &soptval, sizeof soptval); 35711819Sjulian break; 35811819Sjulian 35911819Sjulian case SO_SEQNO: 36038482Swollman error = sooptcopyout(sopt, &ipx_pexseq, 36138482Swollman sizeof ipx_pexseq); 36238482Swollman ipx_pexseq++; 36311819Sjulian break; 36411819Sjulian 36511819Sjulian default: 36611819Sjulian error = EINVAL; 36711819Sjulian } 36811819Sjulian break; 36911819Sjulian 37038482Swollman case SOPT_SET: 37138482Swollman switch (sopt->sopt_name) { 37211819Sjulian case SO_ALL_PACKETS: 37311819Sjulian mask = IPXP_ALL_PACKETS; 37411819Sjulian goto set_head; 37511819Sjulian 37611819Sjulian case SO_HEADERS_ON_INPUT: 37711819Sjulian mask = IPXP_RAWIN; 37811819Sjulian goto set_head; 37911819Sjulian 38050519Sjhay case SO_IPX_CHECKSUM: 38150519Sjhay mask = IPXP_CHECKSUM; 38250519Sjhay 38311819Sjulian case SO_HEADERS_ON_OUTPUT: 38411819Sjulian mask = IPXP_RAWOUT; 38511819Sjulian set_head: 38638482Swollman error = sooptcopyin(sopt, &optval, sizeof optval, 38738482Swollman sizeof optval); 38838482Swollman if (error) 38938482Swollman break; 39038482Swollman if (optval) 39138482Swollman ipxp->ipxp_flags |= mask; 39238482Swollman else 39338482Swollman ipxp->ipxp_flags &= ~mask; 39411819Sjulian break; 39511819Sjulian 39611819Sjulian case SO_DEFAULT_HEADERS: 39738482Swollman error = sooptcopyin(sopt, &ioptval, sizeof ioptval, 39838482Swollman sizeof ioptval); 39938482Swollman if (error) 40038482Swollman break; 40138482Swollman ipxp->ipxp_dpt = ioptval.ipx_pt; 40211819Sjulian break; 40311819Sjulian#ifdef IPXIP 40411819Sjulian case SO_IPXIP_ROUTE: 40538482Swollman error = ipxip_route(so, sopt); 40611819Sjulian break; 40711819Sjulian#endif /* IPXIP */ 40811819Sjulian default: 40911819Sjulian error = EINVAL; 41011819Sjulian } 41111819Sjulian break; 41211819Sjulian } 41311819Sjulian return (error); 41411819Sjulian} 41511819Sjulian 41624659Sjhaystatic int 41724659Sjhayipx_usr_abort(so) 41811819Sjulian struct socket *so; 41911819Sjulian{ 42024659Sjhay int s; 42111819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 42211819Sjulian 42324659Sjhay s = splnet(); 42424659Sjhay ipx_pcbdetach(ipxp); 42524659Sjhay splx(s); 426130387Srwatson soisdisconnected(so); 427130387Srwatson SOCK_LOCK(so); 42886487Sdillon sotryfree(so); 42924659Sjhay return (0); 43024659Sjhay} 43111819Sjulian 43224659Sjhaystatic int 43383366Sjulianipx_attach(so, proto, td) 43424659Sjhay struct socket *so; 43524659Sjhay int proto; 43683366Sjulian struct thread *td; 43724659Sjhay{ 43824659Sjhay int error; 43924659Sjhay int s; 44024659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 44124659Sjhay 44224659Sjhay if (ipxp != NULL) 44324659Sjhay return (EINVAL); 44424659Sjhay s = splnet(); 44583366Sjulian error = ipx_pcballoc(so, &ipxpcb, td); 44624659Sjhay splx(s); 44724659Sjhay if (error == 0) 44819947Sjhay error = soreserve(so, ipxsendspace, ipxrecvspace); 44924659Sjhay return (error); 45024659Sjhay} 45111819Sjulian 45224659Sjhaystatic int 45383366Sjulianipx_bind(so, nam, td) 45424659Sjhay struct socket *so; 45528270Swollman struct sockaddr *nam; 45683366Sjulian struct thread *td; 45724659Sjhay{ 45824659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 45911819Sjulian 46083366Sjulian return (ipx_pcbbind(ipxp, nam, td)); 46124659Sjhay} 46211819Sjulian 46324659Sjhaystatic int 46483366Sjulianipx_connect(so, nam, td) 46524659Sjhay struct socket *so; 46628270Swollman struct sockaddr *nam; 46783366Sjulian struct thread *td; 46824659Sjhay{ 46924659Sjhay int error; 47024659Sjhay int s; 47124659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 47211819Sjulian 47324659Sjhay if (!ipx_nullhost(ipxp->ipxp_faddr)) 47424659Sjhay return (EISCONN); 47524659Sjhay s = splnet(); 47683366Sjulian error = ipx_pcbconnect(ipxp, nam, td); 47724659Sjhay splx(s); 47897658Stanimura if (error == 0) 47924659Sjhay soisconnected(so); 48024659Sjhay return (error); 48124659Sjhay} 48211819Sjulian 48324659Sjhaystatic int 48424659Sjhayipx_detach(so) 48524659Sjhay struct socket *so; 48624659Sjhay{ 48724659Sjhay int s; 48824659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 48911819Sjulian 49024659Sjhay if (ipxp == NULL) 49124659Sjhay return (ENOTCONN); 49224659Sjhay s = splnet(); 49324659Sjhay ipx_pcbdetach(ipxp); 49424659Sjhay splx(s); 49524659Sjhay return (0); 49624659Sjhay} 49711819Sjulian 49824659Sjhaystatic int 49924659Sjhayipx_disconnect(so) 50024659Sjhay struct socket *so; 50124659Sjhay{ 50224659Sjhay int s; 50324659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 50411819Sjulian 50524659Sjhay if (ipx_nullhost(ipxp->ipxp_faddr)) 50624659Sjhay return (ENOTCONN); 50724659Sjhay s = splnet(); 50824659Sjhay ipx_pcbdisconnect(ipxp); 50924659Sjhay splx(s); 51024659Sjhay soisdisconnected(so); 51124659Sjhay return (0); 51224659Sjhay} 51311819Sjulian 51424659Sjhayint 51524659Sjhayipx_peeraddr(so, nam) 51624659Sjhay struct socket *so; 51728270Swollman struct sockaddr **nam; 51824659Sjhay{ 51924659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 52011819Sjulian 52128270Swollman ipx_setpeeraddr(ipxp, nam); /* XXX what if alloc fails? */ 52224659Sjhay return (0); 52324659Sjhay} 52424659Sjhay 52524659Sjhaystatic int 52683366Sjulianipx_send(so, flags, m, nam, control, td) 52724659Sjhay struct socket *so; 52824659Sjhay int flags; 52924659Sjhay struct mbuf *m; 53028270Swollman struct sockaddr *nam; 53124659Sjhay struct mbuf *control; 53283366Sjulian struct thread *td; 53324659Sjhay{ 53424659Sjhay int error; 53524659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 53624659Sjhay struct ipx_addr laddr; 53724659Sjhay int s = 0; 53824659Sjhay 53925652Sjhay if (nam != NULL) { 54024659Sjhay laddr = ipxp->ipxp_laddr; 54124659Sjhay if (!ipx_nullhost(ipxp->ipxp_faddr)) { 54224659Sjhay error = EISCONN; 54324659Sjhay goto send_release; 54411819Sjulian } 54524659Sjhay /* 54624659Sjhay * Must block input while temporarily connected. 54724659Sjhay */ 54824659Sjhay s = splnet(); 54983366Sjulian error = ipx_pcbconnect(ipxp, nam, td); 55024659Sjhay if (error) { 55111819Sjulian splx(s); 55224659Sjhay goto send_release; 55311819Sjulian } 55424659Sjhay } else { 55524659Sjhay if (ipx_nullhost(ipxp->ipxp_faddr)) { 55624659Sjhay error = ENOTCONN; 55724659Sjhay goto send_release; 55824659Sjhay } 55911819Sjulian } 56024659Sjhay error = ipx_output(ipxp, m); 56124659Sjhay m = NULL; 56225652Sjhay if (nam != NULL) { 56324659Sjhay ipx_pcbdisconnect(ipxp); 56424659Sjhay splx(s); 56543712Sjhay ipxp->ipxp_laddr = laddr; 56624659Sjhay } 56711819Sjulian 56824659Sjhaysend_release: 56911819Sjulian if (m != NULL) 57011819Sjulian m_freem(m); 57111819Sjulian return (error); 57211819Sjulian} 57319947Sjhay 57424659Sjhaystatic int 57524659Sjhayipx_shutdown(so) 57624659Sjhay struct socket *so; 57724659Sjhay{ 57824659Sjhay socantsendmore(so); 57924659Sjhay return (0); 58024659Sjhay} 58124659Sjhay 58211819Sjulianint 58324659Sjhayipx_sockaddr(so, nam) 58411819Sjulian struct socket *so; 58528270Swollman struct sockaddr **nam; 58611819Sjulian{ 58711819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 58811819Sjulian 58928270Swollman ipx_setsockaddr(ipxp, nam); /* XXX what if alloc fails? */ 59024659Sjhay return (0); 59124659Sjhay} 59211819Sjulian 59324659Sjhaystatic int 59483366Sjulianripx_attach(so, proto, td) 59524659Sjhay struct socket *so; 59624659Sjhay int proto; 59783366Sjulian struct thread *td; 59824659Sjhay{ 59924659Sjhay int error = 0; 60024659Sjhay int s; 60124659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 60211819Sjulian 60393593Sjhb if (td != NULL && (error = suser(td)) != 0) 60425345Sjhay return (error); 60524659Sjhay s = splnet(); 60683366Sjulian error = ipx_pcballoc(so, &ipxrawpcb, td); 60724659Sjhay splx(s); 60824659Sjhay if (error) 60924659Sjhay return (error); 61024659Sjhay error = soreserve(so, ipxsendspace, ipxrecvspace); 61124659Sjhay if (error) 61224659Sjhay return (error); 61324659Sjhay ipxp = sotoipxpcb(so); 61424659Sjhay ipxp->ipxp_faddr.x_host = ipx_broadhost; 61524659Sjhay ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT; 61611819Sjulian return (error); 61711819Sjulian} 618