ipx_usrreq.c revision 137386
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 137386 2004-11-08 14:44:54Z phk $"); 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 = { 91137386Sphk .pru_abort = ipx_usr_abort, 92137386Sphk .pru_attach = ipx_attach, 93137386Sphk .pru_bind = ipx_bind, 94137386Sphk .pru_connect = ipx_connect, 95137386Sphk .pru_control = ipx_control, 96137386Sphk .pru_detach = ipx_detach, 97137386Sphk .pru_disconnect = ipx_disconnect, 98137386Sphk .pru_peeraddr = ipx_peeraddr, 99137386Sphk .pru_send = ipx_send, 100137386Sphk .pru_shutdown = ipx_shutdown, 101137386Sphk .pru_sockaddr = ipx_sockaddr, 10224659Sjhay}; 10324659Sjhay 10425652Sjhaystruct pr_usrreqs ripx_usrreqs = { 105137386Sphk .pru_abort = ipx_usr_abort, 106137386Sphk .pru_attach = ripx_attach, 107137386Sphk .pru_bind = ipx_bind, 108137386Sphk .pru_connect = ipx_connect, 109137386Sphk .pru_control = ipx_control, 110137386Sphk .pru_detach = ipx_detach, 111137386Sphk .pru_disconnect = ipx_disconnect, 112137386Sphk .pru_peeraddr = ipx_peeraddr, 113137386Sphk .pru_send = ipx_send, 114137386Sphk .pru_shutdown = ipx_shutdown, 115137386Sphk .pru_sockaddr = ipx_sockaddr, 11624659Sjhay}; 11724659Sjhay 11811819Sjulian/* 11911819Sjulian * This may also be called for raw listeners. 12011819Sjulian */ 12111819Sjulianvoid 12211819Sjulianipx_input(m, ipxp) 12311819Sjulian struct mbuf *m; 12411819Sjulian register struct ipxpcb *ipxp; 12511819Sjulian{ 12611819Sjulian register struct ipx *ipx = mtod(m, struct ipx *); 12711819Sjulian struct ifnet *ifp = m->m_pkthdr.rcvif; 12815245Sjhay struct sockaddr_ipx ipx_ipx; 12911819Sjulian 13025652Sjhay if (ipxp == NULL) 13111819Sjulian panic("No ipxpcb"); 13211819Sjulian /* 13311819Sjulian * Construct sockaddr format source address. 13411819Sjulian * Stuff source address and datagram in user buffer. 13511819Sjulian */ 13615245Sjhay ipx_ipx.sipx_len = sizeof(ipx_ipx); 13715245Sjhay ipx_ipx.sipx_family = AF_IPX; 13811819Sjulian ipx_ipx.sipx_addr = ipx->ipx_sna; 13915245Sjhay ipx_ipx.sipx_zero[0] = '\0'; 14015245Sjhay ipx_ipx.sipx_zero[1] = '\0'; 14125652Sjhay if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { 14211819Sjulian register struct ifaddr *ifa; 14311819Sjulian 14471999Sphk for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; 14571999Sphk ifa = TAILQ_NEXT(ifa, ifa_link)) { 14611819Sjulian if (ifa->ifa_addr->sa_family == AF_IPX) { 14711819Sjulian ipx_ipx.sipx_addr.x_net = 14811819Sjulian IA_SIPX(ifa)->sipx_addr.x_net; 14911819Sjulian break; 15011819Sjulian } 15111819Sjulian } 15211819Sjulian } 15311819Sjulian ipxp->ipxp_rpt = ipx->ipx_pt; 15425652Sjhay if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) { 15525652Sjhay m->m_len -= sizeof(struct ipx); 15625652Sjhay m->m_pkthdr.len -= sizeof(struct ipx); 15725652Sjhay m->m_data += sizeof(struct ipx); 15811819Sjulian } 15911819Sjulian if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx, 16025652Sjhay m, (struct mbuf *)NULL) == 0) 16111819Sjulian goto bad; 16211819Sjulian sorwakeup(ipxp->ipxp_socket); 16311819Sjulian return; 16411819Sjulianbad: 16511819Sjulian m_freem(m); 16611819Sjulian} 16711819Sjulian 16811819Sjulianvoid 16911819Sjulianipx_abort(ipxp) 17011819Sjulian struct ipxpcb *ipxp; 17111819Sjulian{ 17211819Sjulian struct socket *so = ipxp->ipxp_socket; 17311819Sjulian 17411819Sjulian ipx_pcbdisconnect(ipxp); 17511819Sjulian soisdisconnected(so); 17611819Sjulian} 17725652Sjhay 17811819Sjulian/* 17911819Sjulian * Drop connection, reporting 18011819Sjulian * the specified error. 18111819Sjulian */ 18211819Sjulianvoid 18311819Sjulianipx_drop(ipxp, errno) 18411819Sjulian register struct ipxpcb *ipxp; 18511819Sjulian int errno; 18611819Sjulian{ 18711819Sjulian struct socket *so = ipxp->ipxp_socket; 18811819Sjulian 18911819Sjulian /* 19025652Sjhay * someday, in the IPX world 19111819Sjulian * we will generate error protocol packets 19211819Sjulian * announcing that the socket has gone away. 19325652Sjhay * 19425652Sjhay * XXX Probably never. IPX does not have error packets. 19511819Sjulian */ 19611819Sjulian /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 19711819Sjulian tp->t_state = TCPS_CLOSED; 19825652Sjhay tcp_output(tp); 19911819Sjulian }*/ 20011819Sjulian so->so_error = errno; 20111819Sjulian ipx_pcbdisconnect(ipxp); 20211819Sjulian soisdisconnected(so); 20311819Sjulian} 20411819Sjulian 20525652Sjhaystatic int 20611819Sjulianipx_output(ipxp, m0) 20711819Sjulian struct ipxpcb *ipxp; 20811819Sjulian struct mbuf *m0; 20911819Sjulian{ 21011819Sjulian register struct ipx *ipx; 21111819Sjulian register struct socket *so; 21211819Sjulian register int len = 0; 21311819Sjulian register struct route *ro; 21454799Sgreen struct mbuf *m; 21511819Sjulian struct mbuf *mprev = NULL; 21611819Sjulian 21711819Sjulian /* 21811819Sjulian * Calculate data length. 21911819Sjulian */ 22025652Sjhay for (m = m0; m != NULL; m = m->m_next) { 22111819Sjulian mprev = m; 22211819Sjulian len += m->m_len; 22311819Sjulian } 22411819Sjulian /* 22511819Sjulian * Make sure packet is actually of even length. 22611819Sjulian */ 22711819Sjulian 22811819Sjulian if (len & 1) { 22911819Sjulian m = mprev; 23011819Sjulian if ((m->m_flags & M_EXT) == 0 && 23111819Sjulian (m->m_len + m->m_data < &m->m_dat[MLEN])) { 23250519Sjhay mtod(m, char*)[m->m_len++] = 0; 23311819Sjulian } else { 234111119Simp struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 23511819Sjulian 23625652Sjhay if (m1 == NULL) { 23711819Sjulian m_freem(m0); 23811819Sjulian return (ENOBUFS); 23911819Sjulian } 24011819Sjulian m1->m_len = 1; 24111819Sjulian * mtod(m1, char *) = 0; 24211819Sjulian m->m_next = m1; 24311819Sjulian } 24411819Sjulian m0->m_pkthdr.len++; 24511819Sjulian } 24611819Sjulian 24711819Sjulian /* 24811819Sjulian * Fill in mbuf with extended IPX header 24911819Sjulian * and addresses and length put into network format. 25011819Sjulian */ 25111819Sjulian m = m0; 25211819Sjulian if (ipxp->ipxp_flags & IPXP_RAWOUT) { 25311819Sjulian ipx = mtod(m, struct ipx *); 25411819Sjulian } else { 255111119Simp M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT); 25625652Sjhay if (m == NULL) 25711819Sjulian return (ENOBUFS); 25811819Sjulian ipx = mtod(m, struct ipx *); 25911819Sjulian ipx->ipx_tc = 0; 26011819Sjulian ipx->ipx_pt = ipxp->ipxp_dpt; 26111819Sjulian ipx->ipx_sna = ipxp->ipxp_laddr; 26211819Sjulian ipx->ipx_dna = ipxp->ipxp_faddr; 26325652Sjhay len += sizeof(struct ipx); 26411819Sjulian } 26511819Sjulian 26611819Sjulian ipx->ipx_len = htons((u_short)len); 26711819Sjulian 26850519Sjhay if (ipxp->ipxp_flags & IPXP_CHECKSUM) { 26911819Sjulian ipx->ipx_sum = ipx_cksum(m, len); 27011819Sjulian } else 27111819Sjulian ipx->ipx_sum = 0xffff; 27211819Sjulian 27311819Sjulian /* 27411819Sjulian * Output datagram. 27511819Sjulian */ 27611819Sjulian so = ipxp->ipxp_socket; 27797658Stanimura if (so->so_options & SO_DONTROUTE) 27825652Sjhay return (ipx_outputfl(m, (struct route *)NULL, 27997658Stanimura (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 28011819Sjulian /* 28111819Sjulian * Use cached route for previous datagram if 28211819Sjulian * possible. If the previous net was the same 28311819Sjulian * and the interface was a broadcast medium, or 28411819Sjulian * if the previous destination was identical, 28511819Sjulian * then we are ok. 28611819Sjulian * 28711819Sjulian * NB: We don't handle broadcasts because that 28811819Sjulian * would require 3 subroutine calls. 28911819Sjulian */ 29011819Sjulian ro = &ipxp->ipxp_route; 29111819Sjulian#ifdef ancient_history 29211819Sjulian /* 29311819Sjulian * I think that this will all be handled in ipx_pcbconnect! 29411819Sjulian */ 29525652Sjhay if (ro->ro_rt != NULL) { 29611819Sjulian if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 29711819Sjulian /* 29811819Sjulian * This assumes we have no GH type routes 29911819Sjulian */ 30011819Sjulian if (ro->ro_rt->rt_flags & RTF_HOST) { 30111819Sjulian if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 30211819Sjulian goto re_route; 30311819Sjulian 30411819Sjulian } 30511819Sjulian if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 30611819Sjulian register struct ipx_addr *dst = 30711819Sjulian &satoipx_addr(ro->ro_dst); 30811819Sjulian dst->x_host = ipx->ipx_dna.x_host; 30911819Sjulian } 31011819Sjulian /* 31111819Sjulian * Otherwise, we go through the same gateway 31211819Sjulian * and dst is already set up. 31311819Sjulian */ 31411819Sjulian } else { 31511819Sjulian re_route: 31611819Sjulian RTFREE(ro->ro_rt); 31725652Sjhay ro->ro_rt = NULL; 31811819Sjulian } 31911819Sjulian } 32011819Sjulian ipxp->ipxp_lastdst = ipx->ipx_dna; 32111819Sjulian#endif /* ancient_history */ 32297658Stanimura return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 32311819Sjulian} 32419947Sjhay 32511819Sjulianint 32638482Swollmanipx_ctloutput(so, sopt) 32711819Sjulian struct socket *so; 32838482Swollman struct sockopt *sopt; 32911819Sjulian{ 33011819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 33138482Swollman int mask, error, optval; 33238482Swollman short soptval; 33338482Swollman struct ipx ioptval; 33411819Sjulian 33538482Swollman error = 0; 33611819Sjulian if (ipxp == NULL) 33711819Sjulian return (EINVAL); 33811819Sjulian 33938482Swollman switch (sopt->sopt_dir) { 34038482Swollman case SOPT_GET: 34138482Swollman switch (sopt->sopt_name) { 34211819Sjulian case SO_ALL_PACKETS: 34311819Sjulian mask = IPXP_ALL_PACKETS; 34411819Sjulian goto get_flags; 34511819Sjulian 34611819Sjulian case SO_HEADERS_ON_INPUT: 34711819Sjulian mask = IPXP_RAWIN; 34811819Sjulian goto get_flags; 34950519Sjhay 35050519Sjhay case SO_IPX_CHECKSUM: 35150519Sjhay mask = IPXP_CHECKSUM; 35250519Sjhay goto get_flags; 35311819Sjulian 35411819Sjulian case SO_HEADERS_ON_OUTPUT: 35511819Sjulian mask = IPXP_RAWOUT; 35611819Sjulian get_flags: 35738482Swollman soptval = ipxp->ipxp_flags & mask; 35838482Swollman error = sooptcopyout(sopt, &soptval, sizeof soptval); 35911819Sjulian break; 36011819Sjulian 36111819Sjulian case SO_DEFAULT_HEADERS: 36238482Swollman ioptval.ipx_len = 0; 36338482Swollman ioptval.ipx_sum = 0; 36438482Swollman ioptval.ipx_tc = 0; 36538482Swollman ioptval.ipx_pt = ipxp->ipxp_dpt; 36638482Swollman ioptval.ipx_dna = ipxp->ipxp_faddr; 36738482Swollman ioptval.ipx_sna = ipxp->ipxp_laddr; 36838482Swollman error = sooptcopyout(sopt, &soptval, sizeof soptval); 36911819Sjulian break; 37011819Sjulian 37111819Sjulian case SO_SEQNO: 37238482Swollman error = sooptcopyout(sopt, &ipx_pexseq, 37338482Swollman sizeof ipx_pexseq); 37438482Swollman ipx_pexseq++; 37511819Sjulian break; 37611819Sjulian 37711819Sjulian default: 37811819Sjulian error = EINVAL; 37911819Sjulian } 38011819Sjulian break; 38111819Sjulian 38238482Swollman case SOPT_SET: 38338482Swollman switch (sopt->sopt_name) { 38411819Sjulian case SO_ALL_PACKETS: 38511819Sjulian mask = IPXP_ALL_PACKETS; 38611819Sjulian goto set_head; 38711819Sjulian 38811819Sjulian case SO_HEADERS_ON_INPUT: 38911819Sjulian mask = IPXP_RAWIN; 39011819Sjulian goto set_head; 39111819Sjulian 39250519Sjhay case SO_IPX_CHECKSUM: 39350519Sjhay mask = IPXP_CHECKSUM; 39450519Sjhay 39511819Sjulian case SO_HEADERS_ON_OUTPUT: 39611819Sjulian mask = IPXP_RAWOUT; 39711819Sjulian set_head: 39838482Swollman error = sooptcopyin(sopt, &optval, sizeof optval, 39938482Swollman sizeof optval); 40038482Swollman if (error) 40138482Swollman break; 40238482Swollman if (optval) 40338482Swollman ipxp->ipxp_flags |= mask; 40438482Swollman else 40538482Swollman ipxp->ipxp_flags &= ~mask; 40611819Sjulian break; 40711819Sjulian 40811819Sjulian case SO_DEFAULT_HEADERS: 40938482Swollman error = sooptcopyin(sopt, &ioptval, sizeof ioptval, 41038482Swollman sizeof ioptval); 41138482Swollman if (error) 41238482Swollman break; 41338482Swollman ipxp->ipxp_dpt = ioptval.ipx_pt; 41411819Sjulian break; 41511819Sjulian#ifdef IPXIP 41611819Sjulian case SO_IPXIP_ROUTE: 41738482Swollman error = ipxip_route(so, sopt); 41811819Sjulian break; 41911819Sjulian#endif /* IPXIP */ 42011819Sjulian default: 42111819Sjulian error = EINVAL; 42211819Sjulian } 42311819Sjulian break; 42411819Sjulian } 42511819Sjulian return (error); 42611819Sjulian} 42711819Sjulian 42824659Sjhaystatic int 42924659Sjhayipx_usr_abort(so) 43011819Sjulian struct socket *so; 43111819Sjulian{ 43224659Sjhay int s; 43311819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 43411819Sjulian 43524659Sjhay s = splnet(); 43624659Sjhay ipx_pcbdetach(ipxp); 43724659Sjhay splx(s); 438130387Srwatson soisdisconnected(so); 439136682Srwatson ACCEPT_LOCK(); 440130387Srwatson SOCK_LOCK(so); 44186487Sdillon sotryfree(so); 44224659Sjhay return (0); 44324659Sjhay} 44411819Sjulian 44524659Sjhaystatic int 44683366Sjulianipx_attach(so, proto, td) 44724659Sjhay struct socket *so; 44824659Sjhay int proto; 44983366Sjulian struct thread *td; 45024659Sjhay{ 45124659Sjhay int error; 45224659Sjhay int s; 45324659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 45424659Sjhay 45524659Sjhay if (ipxp != NULL) 45624659Sjhay return (EINVAL); 45724659Sjhay s = splnet(); 45883366Sjulian error = ipx_pcballoc(so, &ipxpcb, td); 45924659Sjhay splx(s); 46024659Sjhay if (error == 0) 46119947Sjhay error = soreserve(so, ipxsendspace, ipxrecvspace); 46224659Sjhay return (error); 46324659Sjhay} 46411819Sjulian 46524659Sjhaystatic int 46683366Sjulianipx_bind(so, nam, td) 46724659Sjhay struct socket *so; 46828270Swollman struct sockaddr *nam; 46983366Sjulian struct thread *td; 47024659Sjhay{ 47124659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 47211819Sjulian 47383366Sjulian return (ipx_pcbbind(ipxp, nam, td)); 47424659Sjhay} 47511819Sjulian 47624659Sjhaystatic int 47783366Sjulianipx_connect(so, nam, td) 47824659Sjhay struct socket *so; 47928270Swollman struct sockaddr *nam; 48083366Sjulian struct thread *td; 48124659Sjhay{ 48224659Sjhay int error; 48324659Sjhay int s; 48424659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 48511819Sjulian 48624659Sjhay if (!ipx_nullhost(ipxp->ipxp_faddr)) 48724659Sjhay return (EISCONN); 48824659Sjhay s = splnet(); 48983366Sjulian error = ipx_pcbconnect(ipxp, nam, td); 49024659Sjhay splx(s); 49197658Stanimura if (error == 0) 49224659Sjhay soisconnected(so); 49324659Sjhay return (error); 49424659Sjhay} 49511819Sjulian 49624659Sjhaystatic int 49724659Sjhayipx_detach(so) 49824659Sjhay struct socket *so; 49924659Sjhay{ 50024659Sjhay int s; 50124659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 50211819Sjulian 50324659Sjhay if (ipxp == NULL) 50424659Sjhay return (ENOTCONN); 50524659Sjhay s = splnet(); 50624659Sjhay ipx_pcbdetach(ipxp); 50724659Sjhay splx(s); 50824659Sjhay return (0); 50924659Sjhay} 51011819Sjulian 51124659Sjhaystatic int 51224659Sjhayipx_disconnect(so) 51324659Sjhay struct socket *so; 51424659Sjhay{ 51524659Sjhay int s; 51624659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 51711819Sjulian 51824659Sjhay if (ipx_nullhost(ipxp->ipxp_faddr)) 51924659Sjhay return (ENOTCONN); 52024659Sjhay s = splnet(); 52124659Sjhay ipx_pcbdisconnect(ipxp); 52224659Sjhay splx(s); 52324659Sjhay soisdisconnected(so); 52424659Sjhay return (0); 52524659Sjhay} 52611819Sjulian 52724659Sjhayint 52824659Sjhayipx_peeraddr(so, nam) 52924659Sjhay struct socket *so; 53028270Swollman struct sockaddr **nam; 53124659Sjhay{ 53224659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 53311819Sjulian 53428270Swollman ipx_setpeeraddr(ipxp, nam); /* XXX what if alloc fails? */ 53524659Sjhay return (0); 53624659Sjhay} 53724659Sjhay 53824659Sjhaystatic int 53983366Sjulianipx_send(so, flags, m, nam, control, td) 54024659Sjhay struct socket *so; 54124659Sjhay int flags; 54224659Sjhay struct mbuf *m; 54328270Swollman struct sockaddr *nam; 54424659Sjhay struct mbuf *control; 54583366Sjulian struct thread *td; 54624659Sjhay{ 54724659Sjhay int error; 54824659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 54924659Sjhay struct ipx_addr laddr; 55024659Sjhay int s = 0; 55124659Sjhay 55225652Sjhay if (nam != NULL) { 55324659Sjhay laddr = ipxp->ipxp_laddr; 55424659Sjhay if (!ipx_nullhost(ipxp->ipxp_faddr)) { 55524659Sjhay error = EISCONN; 55624659Sjhay goto send_release; 55711819Sjulian } 55824659Sjhay /* 55924659Sjhay * Must block input while temporarily connected. 56024659Sjhay */ 56124659Sjhay s = splnet(); 56283366Sjulian error = ipx_pcbconnect(ipxp, nam, td); 56324659Sjhay if (error) { 56411819Sjulian splx(s); 56524659Sjhay goto send_release; 56611819Sjulian } 56724659Sjhay } else { 56824659Sjhay if (ipx_nullhost(ipxp->ipxp_faddr)) { 56924659Sjhay error = ENOTCONN; 57024659Sjhay goto send_release; 57124659Sjhay } 57211819Sjulian } 57324659Sjhay error = ipx_output(ipxp, m); 57424659Sjhay m = NULL; 57525652Sjhay if (nam != NULL) { 57624659Sjhay ipx_pcbdisconnect(ipxp); 57724659Sjhay splx(s); 57843712Sjhay ipxp->ipxp_laddr = laddr; 57924659Sjhay } 58011819Sjulian 58124659Sjhaysend_release: 58211819Sjulian if (m != NULL) 58311819Sjulian m_freem(m); 58411819Sjulian return (error); 58511819Sjulian} 58619947Sjhay 58724659Sjhaystatic int 58824659Sjhayipx_shutdown(so) 58924659Sjhay struct socket *so; 59024659Sjhay{ 59124659Sjhay socantsendmore(so); 59224659Sjhay return (0); 59324659Sjhay} 59424659Sjhay 59511819Sjulianint 59624659Sjhayipx_sockaddr(so, nam) 59711819Sjulian struct socket *so; 59828270Swollman struct sockaddr **nam; 59911819Sjulian{ 60011819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 60111819Sjulian 60228270Swollman ipx_setsockaddr(ipxp, nam); /* XXX what if alloc fails? */ 60324659Sjhay return (0); 60424659Sjhay} 60511819Sjulian 60624659Sjhaystatic int 60783366Sjulianripx_attach(so, proto, td) 60824659Sjhay struct socket *so; 60924659Sjhay int proto; 61083366Sjulian struct thread *td; 61124659Sjhay{ 61224659Sjhay int error = 0; 61324659Sjhay int s; 61424659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 61511819Sjulian 61693593Sjhb if (td != NULL && (error = suser(td)) != 0) 61725345Sjhay return (error); 61824659Sjhay s = splnet(); 61983366Sjulian error = ipx_pcballoc(so, &ipxrawpcb, td); 62024659Sjhay splx(s); 62124659Sjhay if (error) 62224659Sjhay return (error); 62324659Sjhay error = soreserve(so, ipxsendspace, ipxrecvspace); 62424659Sjhay if (error) 62524659Sjhay return (error); 62624659Sjhay ipxp = sotoipxpcb(so); 62724659Sjhay ipxp->ipxp_faddr.x_host = ipx_broadhost; 62824659Sjhay ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT; 62911819Sjulian return (error); 63011819Sjulian} 631