ipx_usrreq.c revision 33181
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 3512057Sjulian * 3633181Seivind * $Id: ipx_usrreq.c,v 1.18 1997/12/15 20:31:15 eivind Exp $ 3711819Sjulian */ 3811819Sjulian 3931742Seivind#include "opt_ipx.h" 4031742Seivind 4111819Sjulian#include <sys/param.h> 4211819Sjulian#include <sys/systm.h> 4319947Sjhay#include <sys/kernel.h> 4411819Sjulian#include <sys/mbuf.h> 4525345Sjhay#include <sys/proc.h> 4611819Sjulian#include <sys/protosw.h> 4711819Sjulian#include <sys/socket.h> 4811819Sjulian#include <sys/socketvar.h> 4919947Sjhay#include <sys/sysctl.h> 5011819Sjulian 5111819Sjulian#include <net/if.h> 5211819Sjulian#include <net/route.h> 5311819Sjulian 5411947Sjulian#include <netinet/in.h> 5511947Sjulian 5611819Sjulian#include <netipx/ipx.h> 5711819Sjulian#include <netipx/ipx_pcb.h> 5811819Sjulian#include <netipx/ipx_if.h> 5911819Sjulian#include <netipx/ipx_var.h> 6011947Sjulian#include <netipx/ipx_ip.h> 6111819Sjulian 6211819Sjulian/* 6311819Sjulian * IPX protocol implementation. 6411819Sjulian */ 6511819Sjulian 6633181Seivindstatic int ipxsendspace = IPXSNDQ; 6719947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 6819947Sjhay &ipxsendspace, 0, ""); 6933181Seivindstatic int ipxrecvspace = IPXRCVQ; 7019947SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 7119947Sjhay &ipxrecvspace, 0, ""); 7219947Sjhay 7324659Sjhaystatic int ipx_usr_abort(struct socket *so); 7425345Sjhaystatic int ipx_attach(struct socket *so, int proto, struct proc *p); 7528270Swollmanstatic int ipx_bind(struct socket *so, struct sockaddr *nam, struct proc *p); 7628270Swollmanstatic int ipx_connect(struct socket *so, struct sockaddr *nam, 7728270Swollman struct proc *p); 7824659Sjhaystatic int ipx_detach(struct socket *so); 7924659Sjhaystatic int ipx_disconnect(struct socket *so); 8024659Sjhaystatic int ipx_send(struct socket *so, int flags, struct mbuf *m, 8128270Swollman struct sockaddr *addr, struct mbuf *control, 8228270Swollman struct proc *p); 8324659Sjhaystatic int ipx_shutdown(struct socket *so); 8425345Sjhaystatic int ripx_attach(struct socket *so, int proto, struct proc *p); 8525652Sjhaystatic int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 8624659Sjhay 8725652Sjhaystruct pr_usrreqs ipx_usrreqs = { 8824659Sjhay ipx_usr_abort, pru_accept_notsupp, ipx_attach, ipx_bind, 8924659Sjhay ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach, 9024659Sjhay ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp, 9124659Sjhay pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown, 9229366Speter ipx_sockaddr, sosend, soreceive, sopoll 9324659Sjhay}; 9424659Sjhay 9525652Sjhaystruct pr_usrreqs ripx_usrreqs = { 9624659Sjhay ipx_usr_abort, pru_accept_notsupp, ripx_attach, ipx_bind, 9724659Sjhay ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach, 9824659Sjhay ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp, 9924659Sjhay pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown, 10029366Speter ipx_sockaddr, sosend, soreceive, sopoll 10124659Sjhay}; 10224659Sjhay 10311819Sjulian/* 10411819Sjulian * This may also be called for raw listeners. 10511819Sjulian */ 10611819Sjulianvoid 10711819Sjulianipx_input(m, ipxp) 10811819Sjulian struct mbuf *m; 10911819Sjulian register struct ipxpcb *ipxp; 11011819Sjulian{ 11111819Sjulian register struct ipx *ipx = mtod(m, struct ipx *); 11211819Sjulian struct ifnet *ifp = m->m_pkthdr.rcvif; 11315245Sjhay struct sockaddr_ipx ipx_ipx; 11411819Sjulian 11525652Sjhay if (ipxp == NULL) 11611819Sjulian panic("No ipxpcb"); 11711819Sjulian /* 11811819Sjulian * Construct sockaddr format source address. 11911819Sjulian * Stuff source address and datagram in user buffer. 12011819Sjulian */ 12115245Sjhay ipx_ipx.sipx_len = sizeof(ipx_ipx); 12215245Sjhay ipx_ipx.sipx_family = AF_IPX; 12311819Sjulian ipx_ipx.sipx_addr = ipx->ipx_sna; 12415245Sjhay ipx_ipx.sipx_zero[0] = '\0'; 12515245Sjhay ipx_ipx.sipx_zero[1] = '\0'; 12625652Sjhay if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { 12711819Sjulian register struct ifaddr *ifa; 12811819Sjulian 12925652Sjhay for (ifa = ifp->if_addrhead.tqh_first; ifa != NULL; 13020407Swollman ifa = ifa->ifa_link.tqe_next) { 13111819Sjulian if (ifa->ifa_addr->sa_family == AF_IPX) { 13211819Sjulian ipx_ipx.sipx_addr.x_net = 13311819Sjulian IA_SIPX(ifa)->sipx_addr.x_net; 13411819Sjulian break; 13511819Sjulian } 13611819Sjulian } 13711819Sjulian } 13811819Sjulian ipxp->ipxp_rpt = ipx->ipx_pt; 13925652Sjhay if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) { 14025652Sjhay m->m_len -= sizeof(struct ipx); 14125652Sjhay m->m_pkthdr.len -= sizeof(struct ipx); 14225652Sjhay m->m_data += sizeof(struct ipx); 14311819Sjulian } 14411819Sjulian if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx, 14525652Sjhay m, (struct mbuf *)NULL) == 0) 14611819Sjulian goto bad; 14711819Sjulian sorwakeup(ipxp->ipxp_socket); 14811819Sjulian return; 14911819Sjulianbad: 15011819Sjulian m_freem(m); 15111819Sjulian} 15211819Sjulian 15311819Sjulianvoid 15411819Sjulianipx_abort(ipxp) 15511819Sjulian struct ipxpcb *ipxp; 15611819Sjulian{ 15711819Sjulian struct socket *so = ipxp->ipxp_socket; 15811819Sjulian 15911819Sjulian ipx_pcbdisconnect(ipxp); 16011819Sjulian soisdisconnected(so); 16111819Sjulian} 16225652Sjhay 16311819Sjulian/* 16411819Sjulian * Drop connection, reporting 16511819Sjulian * the specified error. 16611819Sjulian */ 16711819Sjulianvoid 16811819Sjulianipx_drop(ipxp, errno) 16911819Sjulian register struct ipxpcb *ipxp; 17011819Sjulian int errno; 17111819Sjulian{ 17211819Sjulian struct socket *so = ipxp->ipxp_socket; 17311819Sjulian 17411819Sjulian /* 17525652Sjhay * someday, in the IPX world 17611819Sjulian * we will generate error protocol packets 17711819Sjulian * announcing that the socket has gone away. 17825652Sjhay * 17925652Sjhay * XXX Probably never. IPX does not have error packets. 18011819Sjulian */ 18111819Sjulian /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 18211819Sjulian tp->t_state = TCPS_CLOSED; 18325652Sjhay tcp_output(tp); 18411819Sjulian }*/ 18511819Sjulian so->so_error = errno; 18611819Sjulian ipx_pcbdisconnect(ipxp); 18711819Sjulian soisdisconnected(so); 18811819Sjulian} 18911819Sjulian 19025652Sjhaystatic int 19111819Sjulianipx_output(ipxp, m0) 19211819Sjulian struct ipxpcb *ipxp; 19311819Sjulian struct mbuf *m0; 19411819Sjulian{ 19511819Sjulian register struct mbuf *m; 19611819Sjulian register struct ipx *ipx; 19711819Sjulian register struct socket *so; 19811819Sjulian register int len = 0; 19911819Sjulian register struct route *ro; 20011819Sjulian struct mbuf *mprev = NULL; 20111819Sjulian 20211819Sjulian /* 20311819Sjulian * Calculate data length. 20411819Sjulian */ 20525652Sjhay for (m = m0; m != NULL; m = m->m_next) { 20611819Sjulian mprev = m; 20711819Sjulian len += m->m_len; 20811819Sjulian } 20911819Sjulian /* 21011819Sjulian * Make sure packet is actually of even length. 21111819Sjulian */ 21211819Sjulian 21311819Sjulian if (len & 1) { 21411819Sjulian m = mprev; 21511819Sjulian if ((m->m_flags & M_EXT) == 0 && 21611819Sjulian (m->m_len + m->m_data < &m->m_dat[MLEN])) { 21711819Sjulian m->m_len++; 21811819Sjulian } else { 21911819Sjulian struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 22011819Sjulian 22125652Sjhay if (m1 == NULL) { 22211819Sjulian m_freem(m0); 22311819Sjulian return (ENOBUFS); 22411819Sjulian } 22511819Sjulian m1->m_len = 1; 22611819Sjulian * mtod(m1, char *) = 0; 22711819Sjulian m->m_next = m1; 22811819Sjulian } 22911819Sjulian m0->m_pkthdr.len++; 23011819Sjulian } 23111819Sjulian 23211819Sjulian /* 23311819Sjulian * Fill in mbuf with extended IPX header 23411819Sjulian * and addresses and length put into network format. 23511819Sjulian */ 23611819Sjulian m = m0; 23711819Sjulian if (ipxp->ipxp_flags & IPXP_RAWOUT) { 23811819Sjulian ipx = mtod(m, struct ipx *); 23911819Sjulian } else { 24025652Sjhay M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT); 24125652Sjhay if (m == NULL) 24211819Sjulian return (ENOBUFS); 24311819Sjulian ipx = mtod(m, struct ipx *); 24411819Sjulian ipx->ipx_tc = 0; 24511819Sjulian ipx->ipx_pt = ipxp->ipxp_dpt; 24611819Sjulian ipx->ipx_sna = ipxp->ipxp_laddr; 24711819Sjulian ipx->ipx_dna = ipxp->ipxp_faddr; 24825652Sjhay len += sizeof(struct ipx); 24911819Sjulian } 25011819Sjulian 25111819Sjulian ipx->ipx_len = htons((u_short)len); 25211819Sjulian 25311819Sjulian if (ipxcksum) { 25411819Sjulian ipx->ipx_sum = 0; 25511819Sjulian len = ((len - 1) | 1) + 1; 25611819Sjulian ipx->ipx_sum = ipx_cksum(m, len); 25711819Sjulian } else 25811819Sjulian ipx->ipx_sum = 0xffff; 25911819Sjulian 26011819Sjulian /* 26111819Sjulian * Output datagram. 26211819Sjulian */ 26311819Sjulian so = ipxp->ipxp_socket; 26411819Sjulian if (so->so_options & SO_DONTROUTE) 26525652Sjhay return (ipx_outputfl(m, (struct route *)NULL, 26611819Sjulian (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 26711819Sjulian /* 26811819Sjulian * Use cached route for previous datagram if 26911819Sjulian * possible. If the previous net was the same 27011819Sjulian * and the interface was a broadcast medium, or 27111819Sjulian * if the previous destination was identical, 27211819Sjulian * then we are ok. 27311819Sjulian * 27411819Sjulian * NB: We don't handle broadcasts because that 27511819Sjulian * would require 3 subroutine calls. 27611819Sjulian */ 27711819Sjulian ro = &ipxp->ipxp_route; 27811819Sjulian#ifdef ancient_history 27911819Sjulian /* 28011819Sjulian * I think that this will all be handled in ipx_pcbconnect! 28111819Sjulian */ 28225652Sjhay if (ro->ro_rt != NULL) { 28311819Sjulian if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 28411819Sjulian /* 28511819Sjulian * This assumes we have no GH type routes 28611819Sjulian */ 28711819Sjulian if (ro->ro_rt->rt_flags & RTF_HOST) { 28811819Sjulian if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 28911819Sjulian goto re_route; 29011819Sjulian 29111819Sjulian } 29211819Sjulian if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 29311819Sjulian register struct ipx_addr *dst = 29411819Sjulian &satoipx_addr(ro->ro_dst); 29511819Sjulian dst->x_host = ipx->ipx_dna.x_host; 29611819Sjulian } 29711819Sjulian /* 29811819Sjulian * Otherwise, we go through the same gateway 29911819Sjulian * and dst is already set up. 30011819Sjulian */ 30111819Sjulian } else { 30211819Sjulian re_route: 30311819Sjulian RTFREE(ro->ro_rt); 30425652Sjhay ro->ro_rt = NULL; 30511819Sjulian } 30611819Sjulian } 30711819Sjulian ipxp->ipxp_lastdst = ipx->ipx_dna; 30811819Sjulian#endif /* ancient_history */ 30911819Sjulian return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 31011819Sjulian} 31119947Sjhay 31211819Sjulianint 31325345Sjhayipx_ctloutput(req, so, level, name, value, p) 31411819Sjulian int req, level; 31511819Sjulian struct socket *so; 31611819Sjulian int name; 31711819Sjulian struct mbuf **value; 31825345Sjhay struct proc *p; 31911819Sjulian{ 32011819Sjulian register struct mbuf *m; 32111819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 32211819Sjulian int mask, error = 0; 32311819Sjulian 32411819Sjulian if (ipxp == NULL) 32511819Sjulian return (EINVAL); 32611819Sjulian 32711819Sjulian switch (req) { 32811819Sjulian 32911819Sjulian case PRCO_GETOPT: 33025652Sjhay if (value == NULL) 33111819Sjulian return (EINVAL); 33211819Sjulian m = m_get(M_DONTWAIT, MT_DATA); 33325652Sjhay if (m == NULL) 33411819Sjulian return (ENOBUFS); 33511819Sjulian switch (name) { 33611819Sjulian 33711819Sjulian case SO_ALL_PACKETS: 33811819Sjulian mask = IPXP_ALL_PACKETS; 33911819Sjulian goto get_flags; 34011819Sjulian 34111819Sjulian case SO_HEADERS_ON_INPUT: 34211819Sjulian mask = IPXP_RAWIN; 34311819Sjulian goto get_flags; 34411819Sjulian 34511819Sjulian case SO_HEADERS_ON_OUTPUT: 34611819Sjulian mask = IPXP_RAWOUT; 34711819Sjulian get_flags: 34811819Sjulian m->m_len = sizeof(short); 34911819Sjulian *mtod(m, short *) = ipxp->ipxp_flags & mask; 35011819Sjulian break; 35111819Sjulian 35211819Sjulian case SO_DEFAULT_HEADERS: 35311819Sjulian m->m_len = sizeof(struct ipx); 35411819Sjulian { 35511819Sjulian register struct ipx *ipx = mtod(m, struct ipx *); 35611819Sjulian ipx->ipx_len = 0; 35711819Sjulian ipx->ipx_sum = 0; 35811819Sjulian ipx->ipx_tc = 0; 35911819Sjulian ipx->ipx_pt = ipxp->ipxp_dpt; 36011819Sjulian ipx->ipx_dna = ipxp->ipxp_faddr; 36111819Sjulian ipx->ipx_sna = ipxp->ipxp_laddr; 36211819Sjulian } 36311819Sjulian break; 36411819Sjulian 36511819Sjulian case SO_SEQNO: 36611819Sjulian m->m_len = sizeof(long); 36711819Sjulian *mtod(m, long *) = ipx_pexseq++; 36811819Sjulian break; 36911819Sjulian 37011819Sjulian default: 37111819Sjulian error = EINVAL; 37211819Sjulian } 37311819Sjulian *value = m; 37411819Sjulian break; 37511819Sjulian 37611819Sjulian case PRCO_SETOPT: 37711819Sjulian switch (name) { 37811819Sjulian int *ok; 37911819Sjulian 38011819Sjulian case SO_ALL_PACKETS: 38111819Sjulian mask = IPXP_ALL_PACKETS; 38211819Sjulian goto set_head; 38311819Sjulian 38411819Sjulian case SO_HEADERS_ON_INPUT: 38511819Sjulian mask = IPXP_RAWIN; 38611819Sjulian goto set_head; 38711819Sjulian 38811819Sjulian case SO_HEADERS_ON_OUTPUT: 38911819Sjulian mask = IPXP_RAWOUT; 39011819Sjulian set_head: 39111819Sjulian if (value && *value) { 39211819Sjulian ok = mtod(*value, int *); 39311819Sjulian if (*ok) 39411819Sjulian ipxp->ipxp_flags |= mask; 39511819Sjulian else 39611819Sjulian ipxp->ipxp_flags &= ~mask; 39711819Sjulian } else error = EINVAL; 39811819Sjulian break; 39911819Sjulian 40011819Sjulian case SO_DEFAULT_HEADERS: 40111819Sjulian { 40211819Sjulian register struct ipx *ipx 40311819Sjulian = mtod(*value, struct ipx *); 40411819Sjulian ipxp->ipxp_dpt = ipx->ipx_pt; 40511819Sjulian } 40611819Sjulian break; 40711819Sjulian#ifdef IPXIP 40811819Sjulian case SO_IPXIP_ROUTE: 40925345Sjhay error = ipxip_route(so, *value, p); 41011819Sjulian break; 41111819Sjulian#endif /* IPXIP */ 41231742Seivind#ifdef IPTUNNEL 41331742Seivind#if 0 41431742Seivind case SO_IPXTUNNEL_ROUTE: 41525345Sjhay error = ipxtun_route(so, *value, p); 41611819Sjulian break; 41711819Sjulian#endif 41831742Seivind#endif 41911819Sjulian default: 42011819Sjulian error = EINVAL; 42111819Sjulian } 42211819Sjulian if (value && *value) 42311819Sjulian m_freem(*value); 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); 43924659Sjhay sofree(so); 44024659Sjhay soisdisconnected(so); 44124659Sjhay return (0); 44224659Sjhay} 44311819Sjulian 44424659Sjhaystatic int 44525345Sjhayipx_attach(so, proto, p) 44624659Sjhay struct socket *so; 44724659Sjhay int proto; 44825345Sjhay struct proc *p; 44924659Sjhay{ 45024659Sjhay int error; 45124659Sjhay int s; 45224659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 45324659Sjhay 45424659Sjhay if (ipxp != NULL) 45524659Sjhay return (EINVAL); 45624659Sjhay s = splnet(); 45725345Sjhay error = ipx_pcballoc(so, &ipxpcb, p); 45824659Sjhay splx(s); 45924659Sjhay if (error == 0) 46019947Sjhay error = soreserve(so, ipxsendspace, ipxrecvspace); 46124659Sjhay return (error); 46224659Sjhay} 46311819Sjulian 46424659Sjhaystatic int 46525345Sjhayipx_bind(so, nam, p) 46624659Sjhay struct socket *so; 46728270Swollman struct sockaddr *nam; 46825345Sjhay struct proc *p; 46924659Sjhay{ 47024659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 47111819Sjulian 47225345Sjhay return (ipx_pcbbind(ipxp, nam, p)); 47324659Sjhay} 47411819Sjulian 47524659Sjhaystatic int 47625345Sjhayipx_connect(so, nam, p) 47724659Sjhay struct socket *so; 47828270Swollman struct sockaddr *nam; 47925345Sjhay struct proc *p; 48024659Sjhay{ 48124659Sjhay int error; 48224659Sjhay int s; 48324659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 48411819Sjulian 48524659Sjhay if (!ipx_nullhost(ipxp->ipxp_faddr)) 48624659Sjhay return (EISCONN); 48724659Sjhay s = splnet(); 48825345Sjhay error = ipx_pcbconnect(ipxp, nam, p); 48924659Sjhay splx(s); 49024659Sjhay if (error == 0) 49124659Sjhay soisconnected(so); 49224659Sjhay return (error); 49324659Sjhay} 49411819Sjulian 49524659Sjhaystatic int 49624659Sjhayipx_detach(so) 49724659Sjhay struct socket *so; 49824659Sjhay{ 49924659Sjhay int s; 50024659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 50111819Sjulian 50224659Sjhay if (ipxp == NULL) 50324659Sjhay return (ENOTCONN); 50424659Sjhay s = splnet(); 50524659Sjhay ipx_pcbdetach(ipxp); 50624659Sjhay splx(s); 50724659Sjhay return (0); 50824659Sjhay} 50911819Sjulian 51024659Sjhaystatic int 51124659Sjhayipx_disconnect(so) 51224659Sjhay struct socket *so; 51324659Sjhay{ 51424659Sjhay int s; 51524659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 51611819Sjulian 51724659Sjhay if (ipx_nullhost(ipxp->ipxp_faddr)) 51824659Sjhay return (ENOTCONN); 51924659Sjhay s = splnet(); 52024659Sjhay ipx_pcbdisconnect(ipxp); 52124659Sjhay splx(s); 52224659Sjhay soisdisconnected(so); 52324659Sjhay return (0); 52424659Sjhay} 52511819Sjulian 52624659Sjhayint 52724659Sjhayipx_peeraddr(so, nam) 52824659Sjhay struct socket *so; 52928270Swollman struct sockaddr **nam; 53024659Sjhay{ 53124659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 53211819Sjulian 53328270Swollman ipx_setpeeraddr(ipxp, nam); /* XXX what if alloc fails? */ 53424659Sjhay return (0); 53524659Sjhay} 53624659Sjhay 53724659Sjhaystatic int 53825345Sjhayipx_send(so, flags, m, nam, control, p) 53924659Sjhay struct socket *so; 54024659Sjhay int flags; 54124659Sjhay struct mbuf *m; 54228270Swollman struct sockaddr *nam; 54324659Sjhay struct mbuf *control; 54425345Sjhay struct proc *p; 54524659Sjhay{ 54624659Sjhay int error; 54724659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 54824659Sjhay struct ipx_addr laddr; 54924659Sjhay int s = 0; 55024659Sjhay 55125652Sjhay if (nam != NULL) { 55224659Sjhay laddr = ipxp->ipxp_laddr; 55324659Sjhay if (!ipx_nullhost(ipxp->ipxp_faddr)) { 55424659Sjhay error = EISCONN; 55524659Sjhay goto send_release; 55611819Sjulian } 55724659Sjhay /* 55824659Sjhay * Must block input while temporarily connected. 55924659Sjhay */ 56024659Sjhay s = splnet(); 56125345Sjhay error = ipx_pcbconnect(ipxp, nam, p); 56224659Sjhay if (error) { 56311819Sjulian splx(s); 56424659Sjhay goto send_release; 56511819Sjulian } 56624659Sjhay } else { 56724659Sjhay if (ipx_nullhost(ipxp->ipxp_faddr)) { 56824659Sjhay error = ENOTCONN; 56924659Sjhay goto send_release; 57024659Sjhay } 57111819Sjulian } 57224659Sjhay error = ipx_output(ipxp, m); 57324659Sjhay m = NULL; 57425652Sjhay if (nam != NULL) { 57524659Sjhay ipx_pcbdisconnect(ipxp); 57624659Sjhay splx(s); 57724659Sjhay ipxp->ipxp_laddr.x_host = laddr.x_host; 57824659Sjhay ipxp->ipxp_laddr.x_port = laddr.x_port; 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 60725345Sjhayripx_attach(so, proto, p) 60824659Sjhay struct socket *so; 60924659Sjhay int proto; 61025345Sjhay struct proc *p; 61124659Sjhay{ 61224659Sjhay int error = 0; 61324659Sjhay int s; 61424659Sjhay struct ipxpcb *ipxp = sotoipxpcb(so); 61511819Sjulian 61625652Sjhay if (p != NULL && (error = suser(p->p_ucred, &p->p_acflag)) != 0) 61725345Sjhay return (error); 61824659Sjhay s = splnet(); 61925345Sjhay error = ipx_pcballoc(so, &ipxrawpcb, p); 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