ipx_pcb.c revision 25345
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_pcb.c 3512057Sjulian * 3625345Sjhay * $Id: ipx_pcb.c,v 1.7 1997/02/22 09:41:56 peter Exp $ 3711819Sjulian */ 3811819Sjulian 3911819Sjulian#include <sys/param.h> 4014546Sdg#include <sys/queue.h> 4111819Sjulian#include <sys/systm.h> 4211819Sjulian#include <sys/mbuf.h> 4325345Sjhay#include <sys/proc.h> 4425345Sjhay#include <sys/protosw.h> 4511819Sjulian#include <sys/errno.h> 4611819Sjulian#include <sys/socket.h> 4711819Sjulian#include <sys/socketvar.h> 4811819Sjulian 4911819Sjulian#include <net/if.h> 5011819Sjulian#include <net/route.h> 5111819Sjulian 5211819Sjulian#include <netipx/ipx.h> 5311819Sjulian#include <netipx/ipx_if.h> 5411819Sjulian#include <netipx/ipx_pcb.h> 5511819Sjulian 5611819Sjulianstruct ipx_addr zeroipx_addr; 5711819Sjulian 5811819Sjulianint 5925345Sjhayipx_pcballoc(so, head, p) 6011819Sjulian struct socket *so; 6111819Sjulian struct ipxpcb *head; 6225345Sjhay struct proc *p; 6311819Sjulian{ 6411819Sjulian struct mbuf *m; 6511819Sjulian register struct ipxpcb *ipxp; 6611819Sjulian 6711819Sjulian m = m_getclr(M_DONTWAIT, MT_PCB); 6811819Sjulian if (m == NULL) 6911819Sjulian return (ENOBUFS); 7011819Sjulian ipxp = mtod(m, struct ipxpcb *); 7111819Sjulian ipxp->ipxp_socket = so; 7211819Sjulian insque(ipxp, head); 7311819Sjulian so->so_pcb = (caddr_t)ipxp; 7411819Sjulian return (0); 7511819Sjulian} 7611819Sjulian 7711819Sjulianint 7825345Sjhayipx_pcbbind(ipxp, nam, p) 7911819Sjulian register struct ipxpcb *ipxp; 8011819Sjulian struct mbuf *nam; 8125345Sjhay struct proc *p; 8211819Sjulian{ 8311819Sjulian register struct sockaddr_ipx *sipx; 8411819Sjulian u_short lport = 0; 8511819Sjulian 8611819Sjulian if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr)) 8711819Sjulian return (EINVAL); 8811819Sjulian if (nam == 0) 8911819Sjulian goto noname; 9011819Sjulian sipx = mtod(nam, struct sockaddr_ipx *); 9111819Sjulian if (nam->m_len != sizeof (*sipx)) 9211819Sjulian return (EINVAL); 9311819Sjulian if (!ipx_nullhost(sipx->sipx_addr)) { 9411819Sjulian int tport = sipx->sipx_port; 9511819Sjulian 9611819Sjulian sipx->sipx_port = 0; /* yech... */ 9711819Sjulian if (ifa_ifwithaddr((struct sockaddr *)sipx) == 0) 9811819Sjulian return (EADDRNOTAVAIL); 9911819Sjulian sipx->sipx_port = tport; 10011819Sjulian } 10111819Sjulian lport = sipx->sipx_port; 10211819Sjulian if (lport) { 10311819Sjulian u_short aport = ntohs(lport); 10425345Sjhay int error; 10511819Sjulian 10611819Sjulian if (aport < IPXPORT_MAX && 10725345Sjhay p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) 10825345Sjhay return (error); 10911819Sjulian if (ipx_pcblookup(&zeroipx_addr, lport, 0)) 11011819Sjulian return (EADDRINUSE); 11111819Sjulian } 11211819Sjulian ipxp->ipxp_laddr = sipx->sipx_addr; 11311819Sjuliannoname: 11411819Sjulian if (lport == 0) 11511819Sjulian do { 11611819Sjulian if (ipxpcb.ipxp_lport++ < IPXPORT_MAX) 11711819Sjulian ipxpcb.ipxp_lport = IPXPORT_MAX; 11811819Sjulian lport = htons(ipxpcb.ipxp_lport); 11911819Sjulian } while (ipx_pcblookup(&zeroipx_addr, lport, 0)); 12011819Sjulian ipxp->ipxp_lport = lport; 12111819Sjulian return (0); 12211819Sjulian} 12311819Sjulian 12411819Sjulian/* 12511819Sjulian * Connect from a socket to a specified address. 12611819Sjulian * Both address and port must be specified in argument sipx. 12711819Sjulian * If don't have a local address for this socket yet, 12811819Sjulian * then pick one. 12911819Sjulian */ 13011819Sjulianint 13125345Sjhayipx_pcbconnect(ipxp, nam, p) 13211819Sjulian struct ipxpcb *ipxp; 13311819Sjulian struct mbuf *nam; 13425345Sjhay struct proc *p; 13511819Sjulian{ 13611819Sjulian struct ipx_ifaddr *ia; 13711819Sjulian register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *); 13811819Sjulian register struct ipx_addr *dst; 13911819Sjulian register struct route *ro; 14011819Sjulian struct ifnet *ifp; 14111819Sjulian 14211819Sjulian if (nam->m_len != sizeof (*sipx)) 14311819Sjulian return (EINVAL); 14411819Sjulian if (sipx->sipx_family != AF_IPX) 14511819Sjulian return (EAFNOSUPPORT); 14611819Sjulian if (sipx->sipx_port==0 || ipx_nullhost(sipx->sipx_addr)) 14711819Sjulian return (EADDRNOTAVAIL); 14811819Sjulian /* 14911819Sjulian * If we haven't bound which network number to use as ours, 15011819Sjulian * we will use the number of the outgoing interface. 15111819Sjulian * This depends on having done a routing lookup, which 15211819Sjulian * we will probably have to do anyway, so we might 15311819Sjulian * as well do it now. On the other hand if we are 15411819Sjulian * sending to multiple destinations we may have already 15511819Sjulian * done the lookup, so see if we can use the route 15611819Sjulian * from before. In any case, we only 15711819Sjulian * chose a port number once, even if sending to multiple 15811819Sjulian * destinations. 15911819Sjulian */ 16011819Sjulian ro = &ipxp->ipxp_route; 16111819Sjulian dst = &satoipx_addr(ro->ro_dst); 16211819Sjulian if (ipxp->ipxp_socket->so_options & SO_DONTROUTE) 16311819Sjulian goto flush; 16411819Sjulian if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) 16511819Sjulian goto flush; 16611819Sjulian if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) { 16711819Sjulian if (ro->ro_rt && ! (ro->ro_rt->rt_flags & RTF_HOST)) { 16811819Sjulian /* can patch route to avoid rtalloc */ 16911819Sjulian *dst = sipx->sipx_addr; 17011819Sjulian } else { 17111819Sjulian flush: 17211819Sjulian if (ro->ro_rt) 17311819Sjulian RTFREE(ro->ro_rt); 17411819Sjulian ro->ro_rt = (struct rtentry *)0; 17511819Sjulian ipxp->ipxp_laddr.x_net = ipx_zeronet; 17611819Sjulian } 17711819Sjulian }/* else cached route is ok; do nothing */ 17811819Sjulian ipxp->ipxp_lastdst = sipx->sipx_addr; 17911819Sjulian if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 18011819Sjulian (ro->ro_rt == (struct rtentry *)0 || 18111819Sjulian ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 18211819Sjulian /* No route yet, so try to acquire one */ 18311819Sjulian ro->ro_dst.sa_family = AF_IPX; 18411819Sjulian ro->ro_dst.sa_len = sizeof(ro->ro_dst); 18511819Sjulian *dst = sipx->sipx_addr; 18611819Sjulian dst->x_port = 0; 18711819Sjulian rtalloc(ro); 18811819Sjulian } 18911819Sjulian if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) { 19011819Sjulian /* 19111819Sjulian * If route is known or can be allocated now, 19211819Sjulian * our src addr is taken from the i/f, else punt. 19311819Sjulian */ 19411819Sjulian 19511819Sjulian ia = (struct ipx_ifaddr *)0; 19611819Sjulian /* 19711819Sjulian * If we found a route, use the address 19811819Sjulian * corresponding to the outgoing interface 19911819Sjulian */ 20011819Sjulian if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) 20111819Sjulian for (ia = ipx_ifaddr; ia; ia = ia->ia_next) 20211819Sjulian if (ia->ia_ifp == ifp) 20311819Sjulian break; 20411819Sjulian if (ia == 0) { 20511819Sjulian u_short fport = sipx->sipx_addr.x_port; 20611819Sjulian sipx->sipx_addr.x_port = 0; 20711819Sjulian ia = (struct ipx_ifaddr *) 20811819Sjulian ifa_ifwithdstaddr((struct sockaddr *)sipx); 20911819Sjulian sipx->sipx_addr.x_port = fport; 21011819Sjulian if (ia == 0) 21111819Sjulian ia = ipx_iaonnetof(&sipx->sipx_addr); 21211819Sjulian if (ia == 0) 21311819Sjulian ia = ipx_ifaddr; 21411819Sjulian if (ia == 0) 21511819Sjulian return (EADDRNOTAVAIL); 21611819Sjulian } 21711819Sjulian ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net; 21811819Sjulian } 21911819Sjulian if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0)) 22011819Sjulian return (EADDRINUSE); 22111819Sjulian if (ipx_nullhost(ipxp->ipxp_laddr)) { 22211819Sjulian if (ipxp->ipxp_lport == 0) 22325345Sjhay (void) ipx_pcbbind(ipxp, (struct mbuf *)0, p); 22411819Sjulian ipxp->ipxp_laddr.x_host = ipx_thishost; 22511819Sjulian } 22611819Sjulian ipxp->ipxp_faddr = sipx->sipx_addr; 22711819Sjulian /* Includes ipxp->ipxp_fport = sipx->sipx_port; */ 22811819Sjulian return (0); 22911819Sjulian} 23011819Sjulian 23111819Sjulianvoid 23211819Sjulianipx_pcbdisconnect(ipxp) 23311819Sjulian struct ipxpcb *ipxp; 23411819Sjulian{ 23511819Sjulian 23611819Sjulian ipxp->ipxp_faddr = zeroipx_addr; 23711819Sjulian if (ipxp->ipxp_socket->so_state & SS_NOFDREF) 23811819Sjulian ipx_pcbdetach(ipxp); 23911819Sjulian} 24011819Sjulian 24111819Sjulianvoid 24211819Sjulianipx_pcbdetach(ipxp) 24311819Sjulian struct ipxpcb *ipxp; 24411819Sjulian{ 24511819Sjulian struct socket *so = ipxp->ipxp_socket; 24611819Sjulian 24711819Sjulian so->so_pcb = 0; 24811819Sjulian sofree(so); 24911819Sjulian if (ipxp->ipxp_route.ro_rt) 25011819Sjulian rtfree(ipxp->ipxp_route.ro_rt); 25111819Sjulian remque(ipxp); 25211819Sjulian (void) m_free(dtom(ipxp)); 25311819Sjulian} 25411819Sjulian 25511819Sjulianvoid 25611819Sjulianipx_setsockaddr(ipxp, nam) 25711819Sjulian register struct ipxpcb *ipxp; 25811819Sjulian struct mbuf *nam; 25911819Sjulian{ 26011819Sjulian register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *); 26111819Sjulian 26211819Sjulian nam->m_len = sizeof (*sipx); 26311819Sjulian sipx = mtod(nam, struct sockaddr_ipx *); 26411819Sjulian bzero((caddr_t)sipx, sizeof (*sipx)); 26511819Sjulian sipx->sipx_len = sizeof(*sipx); 26611819Sjulian sipx->sipx_family = AF_IPX; 26711819Sjulian sipx->sipx_addr = ipxp->ipxp_laddr; 26811819Sjulian} 26911819Sjulian 27011819Sjulianvoid 27111819Sjulianipx_setpeeraddr(ipxp, nam) 27211819Sjulian register struct ipxpcb *ipxp; 27311819Sjulian struct mbuf *nam; 27411819Sjulian{ 27511819Sjulian register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *); 27611819Sjulian 27711819Sjulian nam->m_len = sizeof (*sipx); 27811819Sjulian sipx = mtod(nam, struct sockaddr_ipx *); 27911819Sjulian bzero((caddr_t)sipx, sizeof (*sipx)); 28011819Sjulian sipx->sipx_len = sizeof(*sipx); 28111819Sjulian sipx->sipx_family = AF_IPX; 28211819Sjulian sipx->sipx_addr = ipxp->ipxp_faddr; 28311819Sjulian} 28411819Sjulian 28511819Sjulian/* 28611819Sjulian * Pass some notification to all connections of a protocol 28711819Sjulian * associated with address dst. Call the 28811819Sjulian * protocol specific routine to handle each connection. 28911819Sjulian * Also pass an extra paramter via the ipxpcb. (which may in fact 29011819Sjulian * be a parameter list!) 29111819Sjulian */ 29211819Sjulianvoid 29311819Sjulianipx_pcbnotify(dst, errno, notify, param) 29411819Sjulian register struct ipx_addr *dst; 29511991Sjulian int errno; 29611991Sjulian void (*notify)(struct ipxpcb *); 29711819Sjulian long param; 29811819Sjulian{ 29911819Sjulian register struct ipxpcb *ipxp, *oinp; 30011819Sjulian int s = splimp(); 30111819Sjulian 30211819Sjulian for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb);) { 30311819Sjulian if (!ipx_hosteq(*dst,ipxp->ipxp_faddr)) { 30411819Sjulian next: 30511819Sjulian ipxp = ipxp->ipxp_next; 30611819Sjulian continue; 30711819Sjulian } 30811819Sjulian if (ipxp->ipxp_socket == 0) 30911819Sjulian goto next; 31011819Sjulian if (errno) 31111819Sjulian ipxp->ipxp_socket->so_error = errno; 31211819Sjulian oinp = ipxp; 31311819Sjulian ipxp = ipxp->ipxp_next; 31411819Sjulian oinp->ipxp_notify_param = param; 31511819Sjulian (*notify)(oinp); 31611819Sjulian } 31711819Sjulian splx(s); 31811819Sjulian} 31911819Sjulian 32011819Sjulian#ifdef notdef 32111819Sjulian/* 32211819Sjulian * After a routing change, flush old routing 32311819Sjulian * and allocate a (hopefully) better one. 32411819Sjulian */ 32511819Sjulianipx_rtchange(ipxp) 32611819Sjulian struct ipxpcb *ipxp; 32711819Sjulian{ 32811819Sjulian if (ipxp->ipxp_route.ro_rt) { 32911819Sjulian rtfree(ipxp->ipxp_route.ro_rt); 33011819Sjulian ipxp->ipxp_route.ro_rt = 0; 33111819Sjulian /* 33211819Sjulian * A new route can be allocated the next time 33311819Sjulian * output is attempted. 33411819Sjulian */ 33511819Sjulian } 33611819Sjulian /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */ 33711819Sjulian} 33811819Sjulian#endif 33911819Sjulian 34011819Sjulianstruct ipxpcb * 34111819Sjulianipx_pcblookup(faddr, lport, wildp) 34211819Sjulian struct ipx_addr *faddr; 34311819Sjulian u_short lport; 34411819Sjulian int wildp; 34511819Sjulian{ 34611819Sjulian register struct ipxpcb *ipxp, *match = 0; 34711819Sjulian int matchwild = 3, wildcard; 34811819Sjulian u_short fport; 34911819Sjulian 35011819Sjulian fport = faddr->x_port; 35111819Sjulian for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb); ipxp = ipxp->ipxp_next) { 35211819Sjulian if (ipxp->ipxp_lport != lport) 35311819Sjulian continue; 35411819Sjulian wildcard = 0; 35511819Sjulian if (ipx_nullhost(ipxp->ipxp_faddr)) { 35611819Sjulian if (!ipx_nullhost(*faddr)) 35711819Sjulian wildcard++; 35811819Sjulian } else { 35911819Sjulian if (ipx_nullhost(*faddr)) 36011819Sjulian wildcard++; 36111819Sjulian else { 36211819Sjulian if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr)) 36311819Sjulian continue; 36411819Sjulian if (ipxp->ipxp_fport != fport) { 36511819Sjulian if (ipxp->ipxp_fport != 0) 36611819Sjulian continue; 36711819Sjulian else 36811819Sjulian wildcard++; 36911819Sjulian } 37011819Sjulian } 37111819Sjulian } 37211819Sjulian if (wildcard && wildp==0) 37311819Sjulian continue; 37411819Sjulian if (wildcard < matchwild) { 37511819Sjulian match = ipxp; 37611819Sjulian matchwild = wildcard; 37711819Sjulian if (wildcard == 0) 37811819Sjulian break; 37911819Sjulian } 38011819Sjulian } 38111819Sjulian return (match); 38211819Sjulian} 383