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