tables.c revision 15248
111820Sjulian/* 211820Sjulian * Copyright (c) 1985, 1993 311820Sjulian * The Regents of the University of California. All rights reserved. 411820Sjulian * 511820Sjulian * Copyright (c) 1995 John Hay. All rights reserved. 611820Sjulian * 711820Sjulian * Redistribution and use in source and binary forms, with or without 811820Sjulian * modification, are permitted provided that the following conditions 911820Sjulian * are met: 1011820Sjulian * 1. Redistributions of source code must retain the above copyright 1111820Sjulian * notice, this list of conditions and the following disclaimer. 1211820Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1311820Sjulian * notice, this list of conditions and the following disclaimer in the 1411820Sjulian * documentation and/or other materials provided with the distribution. 1511820Sjulian * 3. All advertising materials mentioning features or use of this software 1611820Sjulian * must display the following acknowledgement: 1711820Sjulian * This product includes software developed by the University of 1811820Sjulian * California, Berkeley and its contributors. 1911820Sjulian * 4. Neither the name of the University nor the names of its contributors 2011820Sjulian * may be used to endorse or promote products derived from this software 2111820Sjulian * without specific prior written permission. 2211820Sjulian * 2311820Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2411820Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2511820Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2611820Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2711820Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2811820Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2911820Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3011820Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3111820Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3211820Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3311820Sjulian * SUCH DAMAGE. 3411820Sjulian * 3515248Sjhay * $Id: tables.c,v 1.1 1995/10/26 21:28:27 julian Exp $ 3611820Sjulian */ 3711820Sjulian 3811820Sjulian#ifndef lint 3911820Sjulianstatic char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 6/5/93"; 4011820Sjulian#endif /* not lint */ 4111820Sjulian 4211820Sjulian/* 4311820Sjulian * Routing Table Management Daemon 4411820Sjulian */ 4511820Sjulian#include "defs.h" 4611820Sjulian#include <sys/ioctl.h> 4711820Sjulian#include <errno.h> 4811820Sjulian#include <stdlib.h> 4911820Sjulian#include <unistd.h> 5011820Sjulian/* XXX I thought that this should work! #include <sys/systm.h> */ 5111820Sjulian#include <machine/cpufunc.h> 5211820Sjulian 5311820Sjulian#ifndef DEBUG 5411820Sjulian#define DEBUG 0 5511820Sjulian#endif 5611820Sjulian 5711820Sjulian#define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));} 5811820Sjulian 5911820Sjulianint install = !DEBUG; /* if 1 call kernel */ 6011820Sjulianint delete = 1; 6115248Sjhay 6215248Sjhaystruct rthash nethash[ROUTEHASHSIZ]; 6315248Sjhaystruct rthash hosthash[ROUTEHASHSIZ]; 6415248Sjhay 6511820Sjulian/* 6611820Sjulian * Lookup dst in the tables for an exact match. 6711820Sjulian */ 6811820Sjulianstruct rt_entry * 6911820Sjulianrtlookup(dst) 7011820Sjulian struct sockaddr *dst; 7111820Sjulian{ 7211820Sjulian register struct rt_entry *rt; 7311820Sjulian register struct rthash *rh; 7411820Sjulian register u_int hash; 7511820Sjulian struct afhash h; 7611820Sjulian int doinghost = 1; 7711820Sjulian 7811820Sjulian if (dst->sa_family >= AF_MAX) 7911820Sjulian return (0); 8011820Sjulian (*afswitch[dst->sa_family].af_hash)(dst, &h); 8111820Sjulian hash = h.afh_hosthash; 8211820Sjulian rh = &hosthash[hash & ROUTEHASHMASK]; 8311820Sjulianagain: 8411820Sjulian for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 8511820Sjulian if (rt->rt_hash != hash) 8611820Sjulian continue; 8711820Sjulian if (equal(&rt->rt_dst, dst)) 8811820Sjulian return (rt); 8911820Sjulian } 9011820Sjulian if (doinghost) { 9111820Sjulian doinghost = 0; 9211820Sjulian hash = h.afh_nethash; 9311820Sjulian rh = &nethash[hash & ROUTEHASHMASK]; 9411820Sjulian goto again; 9511820Sjulian } 9611820Sjulian return (0); 9711820Sjulian} 9811820Sjulian 9911820Sjulian/* 10011820Sjulian * Find a route to dst as the kernel would. 10111820Sjulian */ 10211820Sjulianstruct rt_entry * 10311820Sjulianrtfind(dst) 10411820Sjulian struct sockaddr *dst; 10511820Sjulian{ 10611820Sjulian register struct rt_entry *rt; 10711820Sjulian register struct rthash *rh; 10811820Sjulian register u_int hash; 10911820Sjulian struct afhash h; 11011820Sjulian int af = dst->sa_family; 11111820Sjulian int doinghost = 1, (*match)() = 0; 11211820Sjulian 11311820Sjulian if (af >= AF_MAX) 11411820Sjulian return (0); 11511820Sjulian (*afswitch[af].af_hash)(dst, &h); 11611820Sjulian hash = h.afh_hosthash; 11711820Sjulian rh = &hosthash[hash & ROUTEHASHMASK]; 11811820Sjulian 11911820Sjulianagain: 12011820Sjulian for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 12111820Sjulian if (rt->rt_hash != hash) 12211820Sjulian continue; 12311820Sjulian if (doinghost) { 12411820Sjulian if (equal(&rt->rt_dst, dst)) 12511820Sjulian return (rt); 12611820Sjulian } else { 12711820Sjulian if (rt->rt_dst.sa_family == af && 12811820Sjulian (match != 0) && 12911820Sjulian (*match)(&rt->rt_dst, dst)) 13011820Sjulian return (rt); 13111820Sjulian } 13211820Sjulian } 13311820Sjulian if (doinghost) { 13411820Sjulian doinghost = 0; 13511820Sjulian hash = h.afh_nethash; 13611820Sjulian rh = &nethash[hash & ROUTEHASHMASK]; 13711820Sjulian match = afswitch[af].af_netmatch; 13811820Sjulian goto again; 13911820Sjulian } 14011820Sjulian return (0); 14111820Sjulian} 14211820Sjulian 14311820Sjulianvoid 14411820Sjulianrtadd(dst, gate, metric, ticks, state) 14511820Sjulian struct sockaddr *dst, *gate; 14611820Sjulian short metric, ticks; 14711820Sjulian int state; 14811820Sjulian{ 14911820Sjulian struct afhash h; 15011820Sjulian register struct rt_entry *rt; 15111820Sjulian struct rthash *rh; 15211820Sjulian int af = dst->sa_family, flags; 15311820Sjulian u_int hash; 15411820Sjulian 15511820Sjulian FIXLEN(dst); 15611820Sjulian FIXLEN(gate); 15711820Sjulian if (af >= AF_MAX) 15811820Sjulian return; 15911820Sjulian (*afswitch[af].af_hash)(dst, &h); 16011820Sjulian flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 16111820Sjulian if (flags & RTF_HOST) { 16211820Sjulian hash = h.afh_hosthash; 16311820Sjulian rh = &hosthash[hash & ROUTEHASHMASK]; 16411820Sjulian } else { 16511820Sjulian hash = h.afh_nethash; 16611820Sjulian rh = &nethash[hash & ROUTEHASHMASK]; 16711820Sjulian } 16811820Sjulian rt = (struct rt_entry *)malloc(sizeof (*rt)); 16911820Sjulian if (rt == 0) 17011820Sjulian return; 17111820Sjulian rt->rt_hash = hash; 17211820Sjulian rt->rt_dst = *dst; 17311820Sjulian rt->rt_router = *gate; 17411820Sjulian rt->rt_metric = metric; 17511820Sjulian rt->rt_ticks = ticks; 17611820Sjulian rt->rt_timer = 0; 17711820Sjulian rt->rt_flags = RTF_UP | flags; 17811820Sjulian rt->rt_state = state | RTS_CHANGED; 17911820Sjulian rt->rt_ifp = if_ifwithnet(&rt->rt_router); 18011820Sjulian rt->rt_clone = NULL; 18111820Sjulian if (metric) 18211820Sjulian rt->rt_flags |= RTF_GATEWAY; 18311820Sjulian insque(rt, rh); 18411820Sjulian TRACE_ACTION(ADD, rt); 18511820Sjulian /* 18611820Sjulian * If the ioctl fails because the gateway is unreachable 18711820Sjulian * from this host, discard the entry. This should only 18811820Sjulian * occur because of an incorrect entry in /etc/gateways. 18911820Sjulian */ 19011820Sjulian if (install && rtioctl(ADD, &rt->rt_rt) < 0) { 19111820Sjulian if (errno != EEXIST) 19211820Sjulian perror("SIOCADDRT"); 19311820Sjulian if (errno == ENETUNREACH) { 19411820Sjulian TRACE_ACTION(DELETE, rt); 19511820Sjulian remque(rt); 19611820Sjulian free((char *)rt); 19711820Sjulian } 19811820Sjulian } 19911820Sjulian} 20011820Sjulian 20111820Sjulianvoid 20211820Sjulianrtadd_clone(ort, dst, gate, metric, ticks, state) 20311820Sjulian struct rt_entry *ort; 20411820Sjulian struct sockaddr *dst, *gate; 20511820Sjulian short metric, ticks; 20611820Sjulian int state; 20711820Sjulian{ 20811820Sjulian struct afhash h; 20911820Sjulian register struct rt_entry *rt; 21011820Sjulian struct rthash *rh; 21111820Sjulian int af = dst->sa_family, flags; 21211820Sjulian u_int hash; 21311820Sjulian 21411820Sjulian FIXLEN(dst); 21511820Sjulian FIXLEN(gate); 21611820Sjulian if (af >= AF_MAX) 21711820Sjulian return; 21811820Sjulian (*afswitch[af].af_hash)(dst, &h); 21911820Sjulian flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 22011820Sjulian if (flags & RTF_HOST) { 22111820Sjulian hash = h.afh_hosthash; 22211820Sjulian rh = &hosthash[hash & ROUTEHASHMASK]; 22311820Sjulian } else { 22411820Sjulian hash = h.afh_nethash; 22511820Sjulian rh = &nethash[hash & ROUTEHASHMASK]; 22611820Sjulian } 22711820Sjulian rt = (struct rt_entry *)malloc(sizeof (*rt)); 22811820Sjulian if (rt == 0) 22911820Sjulian return; 23011820Sjulian rt->rt_hash = hash; 23111820Sjulian rt->rt_dst = *dst; 23211820Sjulian rt->rt_router = *gate; 23311820Sjulian rt->rt_metric = metric; 23411820Sjulian rt->rt_ticks = ticks; 23511820Sjulian rt->rt_timer = 0; 23611820Sjulian rt->rt_flags = RTF_UP | flags; 23711820Sjulian rt->rt_state = state | RTS_CHANGED; 23811820Sjulian rt->rt_ifp = if_ifwithnet(&rt->rt_router); 23911820Sjulian rt->rt_clone = NULL; 24011820Sjulian rt->rt_forw = NULL; 24111820Sjulian rt->rt_back = NULL; 24211820Sjulian if (metric) 24311820Sjulian rt->rt_flags |= RTF_GATEWAY; 24411820Sjulian 24511820Sjulian while(ort->rt_clone != NULL) 24611820Sjulian ort = ort->rt_clone; 24711820Sjulian ort->rt_clone = rt; 24811820Sjulian TRACE_ACTION(ADD_CLONE, rt); 24911820Sjulian} 25011820Sjulian 25111820Sjulianvoid 25211820Sjulianrtchange(rt, gate, metric, ticks) 25311820Sjulian struct rt_entry *rt; 25411820Sjulian struct sockaddr *gate; 25511820Sjulian short metric, ticks; 25611820Sjulian{ 25711820Sjulian int doioctl = 0, metricchanged = 0; 25811820Sjulian struct rtuentry oldroute; 25911820Sjulian 26011820Sjulian FIXLEN(gate); 26111820Sjulian /* 26211820Sjulian * Handling of clones. 26311820Sjulian * When the route changed and it had clones, handle it special. 26411820Sjulian * 1. If the new route is cheaper than the clone(s), free the clones. 26511820Sjulian * 2. If the new route is the same cost, it may be one of the clones, 26611820Sjulian * search for it and free it. 26711820Sjulian * 3. If the new route is more expensive than the clone(s), use the 26811820Sjulian * values of the clone(s). 26911820Sjulian */ 27011820Sjulian if (rt->rt_clone) { 27111820Sjulian if ((ticks < rt->rt_clone->rt_ticks) || 27211820Sjulian ((ticks == rt->rt_clone->rt_ticks) && 27311820Sjulian (metric < rt->rt_clone->rt_metric))) { 27411820Sjulian /* 27511820Sjulian * Free all clones. 27611820Sjulian */ 27711820Sjulian struct rt_entry *trt, *nrt; 27811820Sjulian 27911820Sjulian trt = rt->rt_clone; 28011820Sjulian rt->rt_clone = NULL; 28111820Sjulian while(trt) { 28211820Sjulian nrt = trt->rt_clone; 28311820Sjulian free((char *)trt); 28411820Sjulian trt = nrt; 28511820Sjulian } 28611820Sjulian } else if ((ticks == rt->rt_clone->rt_ticks) && 28711820Sjulian (metric == rt->rt_clone->rt_metric)) { 28811820Sjulian struct rt_entry *prt, *trt; 28911820Sjulian 29011820Sjulian prt = rt; 29111820Sjulian trt = rt->rt_clone; 29211820Sjulian 29311820Sjulian while(trt) { 29411820Sjulian if (equal(&trt->rt_router, gate)) { 29511820Sjulian prt->rt_clone = trt->rt_clone; 29611820Sjulian free(trt); 29711820Sjulian trt = prt->rt_clone; 29811820Sjulian } else { 29911820Sjulian prt = trt; 30011820Sjulian trt = trt->rt_clone; 30111820Sjulian } 30211820Sjulian } 30311820Sjulian } else { 30411820Sjulian /* 30511820Sjulian * Use the values of the first clone. 30611820Sjulian * Delete the corresponding clone. 30711820Sjulian */ 30811820Sjulian struct rt_entry *trt; 30911820Sjulian 31011820Sjulian trt = rt->rt_clone; 31111820Sjulian rt->rt_clone = rt->rt_clone->rt_clone; 31211820Sjulian metric = trt->rt_metric; 31311820Sjulian ticks = trt->rt_ticks; 31411820Sjulian *gate = trt->rt_router; 31511820Sjulian free((char *)trt); 31611820Sjulian } 31711820Sjulian } 31811820Sjulian 31911820Sjulian if (!equal(&rt->rt_router, gate)) 32011820Sjulian doioctl++; 32111820Sjulian if ((metric != rt->rt_metric) || (ticks != rt->rt_ticks)) 32211820Sjulian metricchanged++; 32311820Sjulian if (doioctl || metricchanged) { 32411820Sjulian TRACE_ACTION(CHANGE FROM, rt); 32511820Sjulian if (doioctl) { 32611820Sjulian oldroute = rt->rt_rt; 32711820Sjulian rt->rt_router = *gate; 32811820Sjulian } 32911820Sjulian rt->rt_metric = metric; 33011820Sjulian rt->rt_ticks = ticks; 33111820Sjulian if ((rt->rt_state & RTS_INTERFACE) && metric) { 33211820Sjulian rt->rt_state &= ~RTS_INTERFACE; 33311820Sjulian if(rt->rt_ifp) 33411820Sjulian syslog(LOG_ERR, 33511820Sjulian "changing route from interface %s (timed out)", 33611820Sjulian rt->rt_ifp->int_name); 33711820Sjulian else 33811820Sjulian syslog(LOG_ERR, 33911820Sjulian "changing route from interface ??? (timed out)"); 34011820Sjulian } 34111820Sjulian if (metric) 34211820Sjulian rt->rt_flags |= RTF_GATEWAY; 34311820Sjulian else 34411820Sjulian rt->rt_flags &= ~RTF_GATEWAY; 34511820Sjulian rt->rt_state |= RTS_CHANGED; 34611820Sjulian TRACE_ACTION(CHANGE TO, rt); 34711820Sjulian } 34811820Sjulian if (doioctl && install) { 34911820Sjulian#ifndef RTM_ADD 35011820Sjulian if (rtioctl(ADD, &rt->rt_rt) < 0) 35111820Sjulian syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m", 35211820Sjulian xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr), 35311820Sjulian xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr)); 35411820Sjulian if (delete && rtioctl(DELETE, &oldroute) < 0) 35511820Sjulian perror("rtioctl DELETE"); 35611820Sjulian#else 35711820Sjulian if (delete == 0) { 35811820Sjulian if (rtioctl(ADD, &rt->rt_rt) >= 0) 35911820Sjulian return; 36011820Sjulian } else { 36111820Sjulian if (rtioctl(CHANGE, &rt->rt_rt) >= 0) 36211820Sjulian return; 36311820Sjulian } 36411820Sjulian syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m", 36511820Sjulian ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr), 36611820Sjulian ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr)); 36711820Sjulian#endif 36811820Sjulian } 36911820Sjulian} 37011820Sjulian 37111820Sjulianvoid 37211820Sjulianrtdelete(rt) 37311820Sjulian struct rt_entry *rt; 37411820Sjulian{ 37511820Sjulian 37611820Sjulian struct sockaddr *sa = &(rt->rt_router); 37711820Sjulian FIXLEN(sa); 37811820Sjulian sa = &(rt->rt_dst); 37911820Sjulian FIXLEN(sa); 38011820Sjulian if (rt->rt_clone) { 38111820Sjulian /* 38211820Sjulian * If there is a clone we just do a rt_change to it. 38311820Sjulian */ 38411820Sjulian struct rt_entry *trt = rt->rt_clone; 38511820Sjulian rtchange(rt, &trt->rt_router, trt->rt_metric, trt->rt_ticks); 38611820Sjulian return; 38711820Sjulian } 38811820Sjulian if (rt->rt_state & RTS_INTERFACE) { 38911820Sjulian if (rt->rt_ifp) 39011820Sjulian syslog(LOG_ERR, 39111820Sjulian "deleting route to interface %s (timed out)", 39211820Sjulian rt->rt_ifp->int_name); 39311820Sjulian else 39411820Sjulian syslog(LOG_ERR, 39511820Sjulian "deleting route to interface ??? (timed out)"); 39611820Sjulian } 39711820Sjulian TRACE_ACTION(DELETE, rt); 39811820Sjulian if (install && rtioctl(DELETE, &rt->rt_rt) < 0) 39911820Sjulian perror("rtioctl DELETE"); 40011820Sjulian remque(rt); 40111820Sjulian free((char *)rt); 40211820Sjulian} 40311820Sjulian 40411820Sjulianvoid 40511820Sjulianrtinit(void) 40611820Sjulian{ 40711820Sjulian register struct rthash *rh; 40811820Sjulian 40911820Sjulian for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 41011820Sjulian rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 41111820Sjulian for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 41211820Sjulian rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 41311820Sjulian} 41411820Sjulianint seqno; 41511820Sjulian 41611820Sjulianint 41711820Sjulianrtioctl(action, ort) 41811820Sjulian int action; 41911820Sjulian struct rtuentry *ort; 42011820Sjulian{ 42111820Sjulian#ifndef RTM_ADD 42211820Sjulian if (install == 0) 42311820Sjulian return (errno = 0); 42411820Sjulian 42511820Sjulian ort->rtu_rtflags = ort->rtu_flags; 42611820Sjulian 42711820Sjulian switch (action) { 42811820Sjulian 42911820Sjulian case ADD: 43011820Sjulian return (ioctl(s, SIOCADDRT, (char *)ort)); 43111820Sjulian 43211820Sjulian case DELETE: 43311820Sjulian return (ioctl(s, SIOCDELRT, (char *)ort)); 43411820Sjulian 43511820Sjulian default: 43611820Sjulian return (-1); 43711820Sjulian } 43811820Sjulian#else /* RTM_ADD */ 43911820Sjulian struct { 44011820Sjulian struct rt_msghdr w_rtm; 44111820Sjulian struct sockaddr w_dst; 44211820Sjulian struct sockaddr w_gate; 44311820Sjulian struct sockaddr_ipx w_netmask; 44411820Sjulian } w; 44511820Sjulian#define rtm w.w_rtm 44611820Sjulian 44711820Sjulian bzero((char *)&w, sizeof(w)); 44811820Sjulian rtm.rtm_msglen = sizeof(w); 44911820Sjulian rtm.rtm_version = RTM_VERSION; 45011820Sjulian rtm.rtm_type = (action == ADD ? RTM_ADD : 45111820Sjulian (action == DELETE ? RTM_DELETE : RTM_CHANGE)); 45211820Sjulian rtm.rtm_flags = ort->rtu_flags; 45311820Sjulian rtm.rtm_seq = ++seqno; 45411820Sjulian rtm.rtm_addrs = RTA_DST|RTA_GATEWAY; 45511820Sjulian bcopy((char *)&ort->rtu_dst, (char *)&w.w_dst, sizeof(w.w_dst)); 45611820Sjulian bcopy((char *)&ort->rtu_router, (char *)&w.w_gate, sizeof(w.w_gate)); 45711820Sjulian w.w_gate.sa_family = w.w_dst.sa_family = AF_IPX; 45811820Sjulian w.w_gate.sa_len = w.w_dst.sa_len = sizeof(w.w_dst); 45911820Sjulian if (rtm.rtm_flags & RTF_HOST) { 46011820Sjulian rtm.rtm_msglen -= sizeof(w.w_netmask); 46111820Sjulian } else { 46211820Sjulian rtm.rtm_addrs |= RTA_NETMASK; 46311820Sjulian w.w_netmask = ipx_netmask; 46411820Sjulian rtm.rtm_msglen -= sizeof(w.w_netmask) - ipx_netmask.sipx_len; 46511820Sjulian } 46611820Sjulian errno = 0; 46711820Sjulian return write(r, (char *)&w, rtm.rtm_msglen); 46811820Sjulian#endif /* RTM_ADD */ 46911820Sjulian} 47011820Sjulian 471