ipx_usrreq.c revision 139444
111819Sjulian/* 2139444Srwatson * Copyright (c) 2004, Robert N. M. Watson 311819Sjulian * Copyright (c) 1995, Mike Mitchell 411819Sjulian * Copyright (c) 1984, 1985, 1986, 1987, 1993 511819Sjulian * The Regents of the University of California. 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. 1511819Sjulian * 3. All advertising materials mentioning features or use of this software 1611819Sjulian * must display the following acknowledgement: 1711819Sjulian * This product includes software developed by the University of 1811819Sjulian * California, Berkeley and its contributors. 1911819Sjulian * 4. Neither the name of the University nor the names of its contributors 2011819Sjulian * may be used to endorse or promote products derived from this software 2111819Sjulian * without specific prior written permission. 2211819Sjulian * 2311819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2411819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2511819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2611819Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2711819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2811819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2911819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3011819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3111819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3211819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3311819Sjulian * SUCH DAMAGE. 3411819Sjulian * 3512057Sjulian * @(#)ipx_usrreq.c 3611819Sjulian */ 3711819Sjulian 38116189Sobrien#include <sys/cdefs.h> 39116189Sobrien__FBSDID("$FreeBSD: head/sys/netipx/ipx_usrreq.c 139444 2004-12-30 17:49:40Z rwatson $"); 40116189Sobrien 4131742Seivind#include "opt_ipx.h" 4231742Seivind 4311819Sjulian#include <sys/param.h> 4419947Sjhay#include <sys/kernel.h> 4595759Stanimura#include <sys/lock.h> 4611819Sjulian#include <sys/mbuf.h> 4711819Sjulian#include <sys/protosw.h> 4895759Stanimura#include <sys/signalvar.h> 4911819Sjulian#include <sys/socket.h> 5011819Sjulian#include <sys/socketvar.h> 5195759Stanimura#include <sys/sx.h> 5219947Sjhay#include <sys/sysctl.h> 5395759Stanimura#include <sys/systm.h> 5411819Sjulian 5511819Sjulian#include <net/if.h> 5611819Sjulian#include <net/route.h> 5711819Sjulian 5811947Sjulian#include <netinet/in.h> 5911947Sjulian 6011819Sjulian#include <netipx/ipx.h> 6195759Stanimura#include <netipx/ipx_if.h> 6295759Stanimura#include <netipx/ipx_ip.h> 6311819Sjulian#include <netipx/ipx_pcb.h> 6411819Sjulian#include <netipx/ipx_var.h> 6511819Sjulian 6611819Sjulian/* 6711819Sjulian * IPX protocol implementation. 6811819Sjulian */ 6911819Sjulian 7033181Seivindstatic int ipxsendspace = IPXSNDQ; 7119947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 7219947Sjhay &ipxsendspace, 0, ""); 7333181Seivindstatic int ipxrecvspace = IPXRCVQ; 7419947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 7519947Sjhay &ipxrecvspace, 0, ""); 7619947Sjhay 7724659Sjhaystatic int ipx_usr_abort(struct socket *so); 7883366Sjulianstatic int ipx_attach(struct socket *so, int proto, struct thread *td); 7983366Sjulianstatic int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 8028270Swollmanstatic int ipx_connect(struct socket *so, struct sockaddr *nam, 8183366Sjulian struct thread *td); 8224659Sjhaystatic int ipx_detach(struct socket *so); 8324659Sjhaystatic int ipx_disconnect(struct socket *so); 8424659Sjhaystatic int ipx_send(struct socket *so, int flags, struct mbuf *m, 8528270Swollman struct sockaddr *addr, struct mbuf *control, 8683366Sjulian struct thread *td); 8724659Sjhaystatic int ipx_shutdown(struct socket *so); 8883366Sjulianstatic int ripx_attach(struct socket *so, int proto, struct thread *td); 8925652Sjhaystatic int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 9024659Sjhay 9125652Sjhaystruct pr_usrreqs ipx_usrreqs = { 92137386Sphk .pru_abort = ipx_usr_abort, 93137386Sphk .pru_attach = ipx_attach, 94137386Sphk .pru_bind = ipx_bind, 95137386Sphk .pru_connect = ipx_connect, 96137386Sphk .pru_control = ipx_control, 97137386Sphk .pru_detach = ipx_detach, 98137386Sphk .pru_disconnect = ipx_disconnect, 99137386Sphk .pru_peeraddr = ipx_peeraddr, 100137386Sphk .pru_send = ipx_send, 101137386Sphk .pru_shutdown = ipx_shutdown, 102137386Sphk .pru_sockaddr = ipx_sockaddr, 10324659Sjhay}; 10424659Sjhay 10525652Sjhaystruct pr_usrreqs ripx_usrreqs = { 106137386Sphk .pru_abort = ipx_usr_abort, 107137386Sphk .pru_attach = ripx_attach, 108137386Sphk .pru_bind = ipx_bind, 109137386Sphk .pru_connect = ipx_connect, 110137386Sphk .pru_control = ipx_control, 111137386Sphk .pru_detach = ipx_detach, 112137386Sphk .pru_disconnect = ipx_disconnect, 113137386Sphk .pru_peeraddr = ipx_peeraddr, 114137386Sphk .pru_send = ipx_send, 115137386Sphk .pru_shutdown = ipx_shutdown, 116137386Sphk .pru_sockaddr = ipx_sockaddr, 11724659Sjhay}; 11824659Sjhay 11911819Sjulian/* 12011819Sjulian * This may also be called for raw listeners. 12111819Sjulian */ 12211819Sjulianvoid 12311819Sjulianipx_input(m, ipxp) 12411819Sjulian struct mbuf *m; 12511819Sjulian register struct ipxpcb *ipxp; 12611819Sjulian{ 12711819Sjulian register struct ipx *ipx = mtod(m, struct ipx *); 12811819Sjulian struct ifnet *ifp = m->m_pkthdr.rcvif; 12915245Sjhay struct sockaddr_ipx ipx_ipx; 13011819Sjulian 13125652Sjhay if (ipxp == NULL) 13211819Sjulian panic("No ipxpcb"); 13311819Sjulian /* 13411819Sjulian * Construct sockaddr format source address. 13511819Sjulian * Stuff source address and datagram in user buffer. 13611819Sjulian */ 13715245Sjhay ipx_ipx.sipx_len = sizeof(ipx_ipx); 13815245Sjhay ipx_ipx.sipx_family = AF_IPX; 13911819Sjulian ipx_ipx.sipx_addr = ipx->ipx_sna; 14015245Sjhay ipx_ipx.sipx_zero[0] = '\0'; 14115245Sjhay ipx_ipx.sipx_zero[1] = '\0'; 14225652Sjhay if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { 14311819Sjulian register struct ifaddr *ifa; 14411819Sjulian 14571999Sphk for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; 14671999Sphk ifa = TAILQ_NEXT(ifa, ifa_link)) { 14711819Sjulian if (ifa->ifa_addr->sa_family == AF_IPX) { 14811819Sjulian ipx_ipx.sipx_addr.x_net = 14911819Sjulian IA_SIPX(ifa)->sipx_addr.x_net; 15011819Sjulian break; 15111819Sjulian } 15211819Sjulian } 15311819Sjulian } 15411819Sjulian ipxp->ipxp_rpt = ipx->ipx_pt; 15525652Sjhay if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) { 15625652Sjhay m->m_len -= sizeof(struct ipx); 15725652Sjhay m->m_pkthdr.len -= sizeof(struct ipx); 15825652Sjhay m->m_data += sizeof(struct ipx); 15911819Sjulian } 16011819Sjulian if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx, 16125652Sjhay m, (struct mbuf *)NULL) == 0) 16211819Sjulian goto bad; 16311819Sjulian sorwakeup(ipxp->ipxp_socket); 16411819Sjulian return; 16511819Sjulianbad: 16611819Sjulian m_freem(m); 16711819Sjulian} 16811819Sjulian 16911819Sjulianvoid 17011819Sjulianipx_abort(ipxp) 17111819Sjulian struct ipxpcb *ipxp; 17211819Sjulian{ 17311819Sjulian struct socket *so = ipxp->ipxp_socket; 17411819Sjulian 17511819Sjulian ipx_pcbdisconnect(ipxp); 17611819Sjulian soisdisconnected(so); 17711819Sjulian} 17825652Sjhay 17911819Sjulian/* 18011819Sjulian * Drop connection, reporting 18111819Sjulian * the specified error. 18211819Sjulian */ 18311819Sjulianvoid 18411819Sjulianipx_drop(ipxp, errno) 18511819Sjulian register struct ipxpcb *ipxp; 18611819Sjulian int errno; 18711819Sjulian{ 18811819Sjulian struct socket *so = ipxp->ipxp_socket; 18911819Sjulian 19011819Sjulian /* 19125652Sjhay * someday, in the IPX world 19211819Sjulian * we will generate error protocol packets 19311819Sjulian * announcing that the socket has gone away. 19425652Sjhay * 19525652Sjhay * XXX Probably never. IPX does not have error packets. 19611819Sjulian */ 19711819Sjulian /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 19811819Sjulian tp->t_state = TCPS_CLOSED; 19925652Sjhay tcp_output(tp); 20011819Sjulian }*/ 20111819Sjulian so->so_error = errno; 20211819Sjulian ipx_pcbdisconnect(ipxp); 20311819Sjulian soisdisconnected(so); 20411819Sjulian} 20511819Sjulian 20625652Sjhaystatic int 20711819Sjulianipx_output(ipxp, m0) 20811819Sjulian struct ipxpcb *ipxp; 20911819Sjulian struct mbuf *m0; 21011819Sjulian{ 21111819Sjulian register struct ipx *ipx; 21211819Sjulian register struct socket *so; 21311819Sjulian register int len = 0; 21411819Sjulian register struct route *ro; 21554799Sgreen struct mbuf *m; 21611819Sjulian struct mbuf *mprev = NULL; 21711819Sjulian 21811819Sjulian /* 21911819Sjulian * Calculate data length. 22011819Sjulian */ 22125652Sjhay for (m = m0; m != NULL; m = m->m_next) { 22211819Sjulian mprev = m; 22311819Sjulian len += m->m_len; 22411819Sjulian } 22511819Sjulian /* 22611819Sjulian * Make sure packet is actually of even length. 22711819Sjulian */ 22811819Sjulian 22911819Sjulian if (len & 1) { 23011819Sjulian m = mprev; 23111819Sjulian if ((m->m_flags & M_EXT) == 0 && 23211819Sjulian (m->m_len + m->m_data < &m->m_dat[MLEN])) { 23350519Sjhay mtod(m, char*)[m->m_len++] = 0; 23411819Sjulian } else { 235111119Simp struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 23611819Sjulian 23725652Sjhay if (m1 == NULL) { 23811819Sjulian m_freem(m0); 23911819Sjulian return (ENOBUFS); 24011819Sjulian } 24111819Sjulian m1->m_len = 1; 24211819Sjulian * mtod(m1, char *) = 0; 24311819Sjulian m->m_next = m1; 24411819Sjulian } 24511819Sjulian m0->m_pkthdr.len++; 24611819Sjulian } 24711819Sjulian 24811819Sjulian /* 24911819Sjulian * Fill in mbuf with extended IPX header 25011819Sjulian * and addresses and length put into network format. 25111819Sjulian */ 25211819Sjulian m = m0; 25311819Sjulian if (ipxp->ipxp_flags & IPXP_RAWOUT) { 25411819Sjulian ipx = mtod(m, struct ipx *); 25511819Sjulian } else { 256111119Simp M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT); 25725652Sjhay if (m == NULL) 25811819Sjulian return (ENOBUFS); 25911819Sjulian ipx = mtod(m, struct ipx *); 26011819Sjulian ipx->ipx_tc = 0; 26111819Sjulian ipx->ipx_pt = ipxp->ipxp_dpt; 26211819Sjulian ipx->ipx_sna = ipxp->ipxp_laddr; 26311819Sjulian ipx->ipx_dna = ipxp->ipxp_faddr; 26425652Sjhay len += sizeof(struct ipx); 26511819Sjulian } 26611819Sjulian 26711819Sjulian ipx->ipx_len = htons((u_short)len); 26811819Sjulian 26950519Sjhay if (ipxp->ipxp_flags & IPXP_CHECKSUM) { 27011819Sjulian ipx->ipx_sum = ipx_cksum(m, len); 27111819Sjulian } else 27211819Sjulian ipx->ipx_sum = 0xffff; 27311819Sjulian 27411819Sjulian /* 27511819Sjulian * Output datagram. 27611819Sjulian */ 27711819Sjulian so = ipxp->ipxp_socket; 27897658Stanimura if (so->so_options & SO_DONTROUTE) 27925652Sjhay return (ipx_outputfl(m, (struct route *)NULL, 28097658Stanimura (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 28111819Sjulian /* 28211819Sjulian * Use cached route for previous datagram if 28311819Sjulian * possible. If the previous net was the same 28411819Sjulian * and the interface was a broadcast medium, or 28511819Sjulian * if the previous destination was identical, 28611819Sjulian * then we are ok. 28711819Sjulian * 28811819Sjulian * NB: We don't handle broadcasts because that 28911819Sjulian * would require 3 subroutine calls. 29011819Sjulian */ 29111819Sjulian ro = &ipxp->ipxp_route; 29211819Sjulian#ifdef ancient_history 29311819Sjulian /* 29411819Sjulian * I think that this will all be handled in ipx_pcbconnect! 29511819Sjulian */ 29625652Sjhay if (ro->ro_rt != NULL) { 29711819Sjulian if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 29811819Sjulian /* 29911819Sjulian * This assumes we have no GH type routes 30011819Sjulian */ 30111819Sjulian if (ro->ro_rt->rt_flags & RTF_HOST) { 30211819Sjulian if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 30311819Sjulian goto re_route; 30411819Sjulian 30511819Sjulian } 30611819Sjulian if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 30711819Sjulian register struct ipx_addr *dst = 30811819Sjulian &satoipx_addr(ro->ro_dst); 30911819Sjulian dst->x_host = ipx->ipx_dna.x_host; 31011819Sjulian } 31111819Sjulian /* 31211819Sjulian * Otherwise, we go through the same gateway 31311819Sjulian * and dst is already set up. 31411819Sjulian */ 31511819Sjulian } else { 31611819Sjulian re_route: 31711819Sjulian RTFREE(ro->ro_rt); 31825652Sjhay ro->ro_rt = NULL; 31911819Sjulian } 32011819Sjulian } 32111819Sjulian ipxp->ipxp_lastdst = ipx->ipx_dna; 32211819Sjulian#endif /* ancient_history */ 32397658Stanimura return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 32411819Sjulian} 32519947Sjhay 32611819Sjulianint 32738482Swollmanipx_ctloutput(so, sopt) 32811819Sjulian struct socket *so; 32938482Swollman struct sockopt *sopt; 33011819Sjulian{ 33111819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 33238482Swollman int mask, error, optval; 33338482Swollman short soptval; 33438482Swollman struct ipx ioptval; 33511819Sjulian 33638482Swollman error = 0; 33711819Sjulian if (ipxp == NULL) 33811819Sjulian return (EINVAL); 33911819Sjulian 34038482Swollman switch (sopt->sopt_dir) { 34138482Swollman case SOPT_GET: 34238482Swollman switch (sopt->sopt_name) { 34311819Sjulian case SO_ALL_PACKETS: 34411819Sjulian mask = IPXP_ALL_PACKETS; 34511819Sjulian goto get_flags; 34611819Sjulian 34711819Sjulian case SO_HEADERS_ON_INPUT: 34811819Sjulian mask = IPXP_RAWIN; 34911819Sjulian goto get_flags; 35050519Sjhay 35150519Sjhay case SO_IPX_CHECKSUM: 35250519Sjhay mask = IPXP_CHECKSUM; 35350519Sjhay goto get_flags; 35411819Sjulian 35511819Sjulian case SO_HEADERS_ON_OUTPUT: 35611819Sjulian mask = IPXP_RAWOUT; 35711819Sjulian get_flags: 35838482Swollman soptval = ipxp->ipxp_flags & mask; 35938482Swollman error = sooptcopyout(sopt, &soptval, sizeof soptval); 36011819Sjulian break; 36111819Sjulian 36211819Sjulian case SO_DEFAULT_HEADERS: 36338482Swollman ioptval.ipx_len = 0; 36438482Swollman ioptval.ipx_sum = 0; 36538482Swollman ioptval.ipx_tc = 0; 36638482Swollman ioptval.ipx_pt = ipxp->ipxp_dpt; 36738482Swollman ioptval.ipx_dna = ipxp->ipxp_faddr; 36838482Swollman ioptval.ipx_sna = ipxp->ipxp_laddr; 36938482Swollman error = sooptcopyout(sopt, &soptval, sizeof soptval); 37011819Sjulian break; 37111819Sjulian 37211819Sjulian case SO_SEQNO: 37338482Swollman error = sooptcopyout(sopt, &ipx_pexseq, 37438482Swollman sizeof ipx_pexseq); 37538482Swollman ipx_pexseq++; 37611819Sjulian break; 37711819Sjulian 37811819Sjulian default: 37911819Sjulian error = EINVAL; 38011819Sjulian } 38111819Sjulian break; 38211819Sjulian 38338482Swollman case SOPT_SET: 38438482Swollman switch (sopt->sopt_name) { 38511819Sjulian case SO_ALL_PACKETS: 38611819Sjulian mask = IPXP_ALL_PACKETS; 38711819Sjulian goto set_head; 38811819Sjulian 38911819Sjulian case SO_HEADERS_ON_INPUT: 39011819Sjulian mask = IPXP_RAWIN; 39111819Sjulian goto set_head; 39211819Sjulian 39350519Sjhay case SO_IPX_CHECKSUM: 39450519Sjhay mask = IPXP_CHECKSUM; 39550519Sjhay 39611819Sjulian case SO_HEADERS_ON_OUTPUT: 39711819Sjulian mask = IPXP_RAWOUT; 39811819Sjulian set_head: 39938482Swollman error = sooptcopyin(sopt, &optval, sizeof optval, 40038482Swollman sizeof optval); 40138482Swollman if (error) 40238482Swollman break; 40338482Swollman if (optval) 40438482Swollman ipxp->ipxp_flags |= mask; 40538482Swollman else 40638482Swollman ipxp->ipxp_flags &= ~mask; 40711819Sjulian break; 40811819Sjulian 40911819Sjulian case SO_DEFAULT_HEADERS: 41038482Swollman error = sooptcopyin(sopt, &ioptval, sizeof ioptval, 41138482Swollman sizeof ioptval); 41238482Swollman if (error) 41338482Swollman break; 41438482Swollman ipxp->ipxp_dpt = ioptval.ipx_pt; 41511819Sjulian break; 41611819Sjulian#ifdef IPXIP 41711819Sjulian case SO_IPXIP_ROUTE: 41838482Swollman error = ipxip_route(so, sopt); 41911819Sjulian break; 42011819Sjulian#endif /* IPXIP */ 42111819Sjulian default: 42211819Sjulian error = EINVAL; 42311819Sjulian } 42411819Sjulian break; 42511819Sjulian } 42611819Sjulian return (error); 42711819Sjulian} 42811819Sjulian 42924659Sjhaystatic int 43024659Sjhayipx_usr_abort(so) 43111819Sjulian struct socket *so; 43211819Sjulian{ 43324659Sjhay int s; 43411819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 43511819Sjulian 43624659Sjhay s = splnet(); 43724659Sjhay ipx_pcbdetach(ipxp); 43824659Sjhay splx(s); 439130387Srwatson soisdisconnected(so); 440136682Srwatson ACCEPT_LOCK(); 441130387Srwatson SOCK_LOCK(so); 44286487Sdillon sotryfree(so); 44324659Sjhay return (0); 44424659Sjhay} 44511819Sjulian 44624659Sjhaystatic int 44783366Sjulianipx_attach(so, proto, td) 44824659Sjhay struct socket *so; 44924659Sjhay int proto; 45083366Sjulian struct thread *td; 45124659Sjhay{ 45224659Sjhay int error; 45324659Sjhay int s; 45424659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 45524659Sjhay 45624659Sjhay if (ipxp != NULL) 45724659Sjhay return (EINVAL); 45824659Sjhay s = splnet(); 459139444Srwatson error = ipx_pcballoc(so, &ipxpcb_list, td); 46024659Sjhay splx(s); 46124659Sjhay if (error == 0) 46219947Sjhay error = soreserve(so, ipxsendspace, ipxrecvspace); 46324659Sjhay return (error); 46424659Sjhay} 46511819Sjulian 46624659Sjhaystatic int 46783366Sjulianipx_bind(so, nam, td) 46824659Sjhay struct socket *so; 46928270Swollman struct sockaddr *nam; 47083366Sjulian struct thread *td; 47124659Sjhay{ 47224659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 47311819Sjulian 47483366Sjulian return (ipx_pcbbind(ipxp, nam, td)); 47524659Sjhay} 47611819Sjulian 47724659Sjhaystatic int 47883366Sjulianipx_connect(so, nam, td) 47924659Sjhay struct socket *so; 48028270Swollman struct sockaddr *nam; 48183366Sjulian struct thread *td; 48224659Sjhay{ 48324659Sjhay int error; 48424659Sjhay int s; 48524659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 48611819Sjulian 48724659Sjhay if (!ipx_nullhost(ipxp->ipxp_faddr)) 48824659Sjhay return (EISCONN); 48924659Sjhay s = splnet(); 49083366Sjulian error = ipx_pcbconnect(ipxp, nam, td); 49124659Sjhay splx(s); 49297658Stanimura if (error == 0) 49324659Sjhay soisconnected(so); 49424659Sjhay return (error); 49524659Sjhay} 49611819Sjulian 49724659Sjhaystatic int 49824659Sjhayipx_detach(so) 49924659Sjhay struct socket *so; 50024659Sjhay{ 50124659Sjhay int s; 50224659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 50311819Sjulian 50424659Sjhay if (ipxp == NULL) 50524659Sjhay return (ENOTCONN); 50624659Sjhay s = splnet(); 50724659Sjhay ipx_pcbdetach(ipxp); 50824659Sjhay splx(s); 50924659Sjhay return (0); 51024659Sjhay} 51111819Sjulian 51224659Sjhaystatic int 51324659Sjhayipx_disconnect(so) 51424659Sjhay struct socket *so; 51524659Sjhay{ 51624659Sjhay int s; 51724659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 51811819Sjulian 51924659Sjhay if (ipx_nullhost(ipxp->ipxp_faddr)) 52024659Sjhay return (ENOTCONN); 52124659Sjhay s = splnet(); 52224659Sjhay ipx_pcbdisconnect(ipxp); 52324659Sjhay splx(s); 52424659Sjhay soisdisconnected(so); 52524659Sjhay return (0); 52624659Sjhay} 52711819Sjulian 52824659Sjhayint 52924659Sjhayipx_peeraddr(so, nam) 53024659Sjhay struct socket *so; 53128270Swollman struct sockaddr **nam; 53224659Sjhay{ 53324659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 53411819Sjulian 53528270Swollman ipx_setpeeraddr(ipxp, nam); /* XXX what if alloc fails? */ 53624659Sjhay return (0); 53724659Sjhay} 53824659Sjhay 53924659Sjhaystatic int 54083366Sjulianipx_send(so, flags, m, nam, control, td) 54124659Sjhay struct socket *so; 54224659Sjhay int flags; 54324659Sjhay struct mbuf *m; 54428270Swollman struct sockaddr *nam; 54524659Sjhay struct mbuf *control; 54683366Sjulian struct thread *td; 54724659Sjhay{ 54824659Sjhay int error; 54924659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 55024659Sjhay struct ipx_addr laddr; 55124659Sjhay int s = 0; 55224659Sjhay 55325652Sjhay if (nam != NULL) { 55424659Sjhay laddr = ipxp->ipxp_laddr; 55524659Sjhay if (!ipx_nullhost(ipxp->ipxp_faddr)) { 55624659Sjhay error = EISCONN; 55724659Sjhay goto send_release; 55811819Sjulian } 55924659Sjhay /* 56024659Sjhay * Must block input while temporarily connected. 56124659Sjhay */ 56224659Sjhay s = splnet(); 56383366Sjulian error = ipx_pcbconnect(ipxp, nam, td); 56424659Sjhay if (error) { 56511819Sjulian splx(s); 56624659Sjhay goto send_release; 56711819Sjulian } 56824659Sjhay } else { 56924659Sjhay if (ipx_nullhost(ipxp->ipxp_faddr)) { 57024659Sjhay error = ENOTCONN; 57124659Sjhay goto send_release; 57224659Sjhay } 57311819Sjulian } 57424659Sjhay error = ipx_output(ipxp, m); 57524659Sjhay m = NULL; 57625652Sjhay if (nam != NULL) { 57724659Sjhay ipx_pcbdisconnect(ipxp); 57824659Sjhay splx(s); 57943712Sjhay ipxp->ipxp_laddr = laddr; 58024659Sjhay } 58111819Sjulian 58224659Sjhaysend_release: 58311819Sjulian if (m != NULL) 58411819Sjulian m_freem(m); 58511819Sjulian return (error); 58611819Sjulian} 58719947Sjhay 58824659Sjhaystatic int 58924659Sjhayipx_shutdown(so) 59024659Sjhay struct socket *so; 59124659Sjhay{ 59224659Sjhay socantsendmore(so); 59324659Sjhay return (0); 59424659Sjhay} 59524659Sjhay 59611819Sjulianint 59724659Sjhayipx_sockaddr(so, nam) 59811819Sjulian struct socket *so; 59928270Swollman struct sockaddr **nam; 60011819Sjulian{ 60111819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 60211819Sjulian 60328270Swollman ipx_setsockaddr(ipxp, nam); /* XXX what if alloc fails? */ 60424659Sjhay return (0); 60524659Sjhay} 60611819Sjulian 60724659Sjhaystatic int 60883366Sjulianripx_attach(so, proto, td) 60924659Sjhay struct socket *so; 61024659Sjhay int proto; 61183366Sjulian struct thread *td; 61224659Sjhay{ 61324659Sjhay int error = 0; 61424659Sjhay int s; 61524659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 61611819Sjulian 61793593Sjhb if (td != NULL && (error = suser(td)) != 0) 61825345Sjhay return (error); 61924659Sjhay s = splnet(); 620139444Srwatson error = ipx_pcballoc(so, &ipxrawpcb_list, td); 62124659Sjhay splx(s); 62224659Sjhay if (error) 62324659Sjhay return (error); 62424659Sjhay error = soreserve(so, ipxsendspace, ipxrecvspace); 62524659Sjhay if (error) 62624659Sjhay return (error); 62724659Sjhay ipxp = sotoipxpcb(so); 62824659Sjhay ipxp->ipxp_faddr.x_host = ipx_broadhost; 62924659Sjhay ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT; 63011819Sjulian return (error); 63111819Sjulian} 632