tables.c revision 27244
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 * 3527244Sjhay * $Id: tables.c,v 1.5 1997/07/01 00:33:42 bde 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 5111820Sjulian#ifndef DEBUG 5211820Sjulian#define DEBUG 0 5311820Sjulian#endif 5411820Sjulian 5511820Sjulian#define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));} 5611820Sjulian 5711820Sjulianint install = !DEBUG; /* if 1 call kernel */ 5811820Sjulianint delete = 1; 5915248Sjhay 6015248Sjhaystruct rthash nethash[ROUTEHASHSIZ]; 6115248Sjhay 6211820Sjulian/* 6311820Sjulian * Lookup dst in the tables for an exact match. 6411820Sjulian */ 6511820Sjulianstruct rt_entry * 6611820Sjulianrtlookup(dst) 6711820Sjulian struct sockaddr *dst; 6811820Sjulian{ 6911820Sjulian register struct rt_entry *rt; 7011820Sjulian register struct rthash *rh; 7111820Sjulian register u_int hash; 7211820Sjulian struct afhash h; 7311820Sjulian 7411820Sjulian if (dst->sa_family >= AF_MAX) 7511820Sjulian return (0); 7611820Sjulian (*afswitch[dst->sa_family].af_hash)(dst, &h); 7727244Sjhay hash = h.afh_nethash; 7827244Sjhay rh = &nethash[hash & ROUTEHASHMASK]; 7911820Sjulian for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 8011820Sjulian if (rt->rt_hash != hash) 8111820Sjulian continue; 8211820Sjulian if (equal(&rt->rt_dst, dst)) 8311820Sjulian return (rt); 8411820Sjulian } 8511820Sjulian return (0); 8611820Sjulian} 8711820Sjulian 8811820Sjulian/* 8911820Sjulian * Find a route to dst as the kernel would. 9011820Sjulian */ 9111820Sjulianstruct rt_entry * 9211820Sjulianrtfind(dst) 9311820Sjulian struct sockaddr *dst; 9411820Sjulian{ 9511820Sjulian register struct rt_entry *rt; 9611820Sjulian register struct rthash *rh; 9711820Sjulian register u_int hash; 9811820Sjulian struct afhash h; 9911820Sjulian int af = dst->sa_family; 10027244Sjhay int (*match)() = 0; 10111820Sjulian 10211820Sjulian if (af >= AF_MAX) 10311820Sjulian return (0); 10411820Sjulian (*afswitch[af].af_hash)(dst, &h); 10511820Sjulian 10627244Sjhay hash = h.afh_nethash; 10727244Sjhay rh = &nethash[hash & ROUTEHASHMASK]; 10827244Sjhay match = afswitch[af].af_netmatch; 10911820Sjulian for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 11011820Sjulian if (rt->rt_hash != hash) 11111820Sjulian continue; 11227244Sjhay if (rt->rt_dst.sa_family == af && 11327244Sjhay (*match)(&rt->rt_dst, dst)) 11427244Sjhay return (rt); 11511820Sjulian } 11611820Sjulian return (0); 11711820Sjulian} 11811820Sjulian 11911820Sjulianvoid 12011820Sjulianrtadd(dst, gate, metric, ticks, state) 12111820Sjulian struct sockaddr *dst, *gate; 12211820Sjulian short metric, ticks; 12311820Sjulian int state; 12411820Sjulian{ 12511820Sjulian struct afhash h; 12611820Sjulian register struct rt_entry *rt; 12711820Sjulian struct rthash *rh; 12811820Sjulian int af = dst->sa_family, flags; 12911820Sjulian u_int hash; 13011820Sjulian 13111820Sjulian FIXLEN(dst); 13211820Sjulian FIXLEN(gate); 13311820Sjulian if (af >= AF_MAX) 13411820Sjulian return; 13511820Sjulian (*afswitch[af].af_hash)(dst, &h); 13611820Sjulian flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 13727244Sjhay hash = h.afh_nethash; 13827244Sjhay rh = &nethash[hash & ROUTEHASHMASK]; 13911820Sjulian rt = (struct rt_entry *)malloc(sizeof (*rt)); 14011820Sjulian if (rt == 0) 14111820Sjulian return; 14211820Sjulian rt->rt_hash = hash; 14311820Sjulian rt->rt_dst = *dst; 14411820Sjulian rt->rt_router = *gate; 14511820Sjulian rt->rt_metric = metric; 14611820Sjulian rt->rt_ticks = ticks; 14711820Sjulian rt->rt_timer = 0; 14811820Sjulian rt->rt_flags = RTF_UP | flags; 14911820Sjulian rt->rt_state = state | RTS_CHANGED; 15011820Sjulian rt->rt_ifp = if_ifwithnet(&rt->rt_router); 15111820Sjulian rt->rt_clone = NULL; 15211820Sjulian if (metric) 15311820Sjulian rt->rt_flags |= RTF_GATEWAY; 15411820Sjulian insque(rt, rh); 15527244Sjhay TRACE_ACTION("ADD", rt); 15611820Sjulian /* 15711820Sjulian * If the ioctl fails because the gateway is unreachable 15811820Sjulian * from this host, discard the entry. This should only 15911820Sjulian * occur because of an incorrect entry in /etc/gateways. 16011820Sjulian */ 16111820Sjulian if (install && rtioctl(ADD, &rt->rt_rt) < 0) { 16211820Sjulian if (errno != EEXIST) 16311820Sjulian perror("SIOCADDRT"); 16411820Sjulian if (errno == ENETUNREACH) { 16527244Sjhay TRACE_ACTION("DELETE", rt); 16611820Sjulian remque(rt); 16711820Sjulian free((char *)rt); 16811820Sjulian } 16911820Sjulian } 17011820Sjulian} 17111820Sjulian 17211820Sjulianvoid 17311820Sjulianrtadd_clone(ort, dst, gate, metric, ticks, state) 17411820Sjulian struct rt_entry *ort; 17511820Sjulian struct sockaddr *dst, *gate; 17611820Sjulian short metric, ticks; 17711820Sjulian int state; 17811820Sjulian{ 17911820Sjulian struct afhash h; 18011820Sjulian register struct rt_entry *rt; 18111820Sjulian struct rthash *rh; 18211820Sjulian int af = dst->sa_family, flags; 18311820Sjulian u_int hash; 18411820Sjulian 18511820Sjulian FIXLEN(dst); 18611820Sjulian FIXLEN(gate); 18711820Sjulian if (af >= AF_MAX) 18811820Sjulian return; 18911820Sjulian (*afswitch[af].af_hash)(dst, &h); 19011820Sjulian flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 19127244Sjhay hash = h.afh_nethash; 19227244Sjhay rh = &nethash[hash & ROUTEHASHMASK]; 19311820Sjulian rt = (struct rt_entry *)malloc(sizeof (*rt)); 19411820Sjulian if (rt == 0) 19511820Sjulian return; 19611820Sjulian rt->rt_hash = hash; 19711820Sjulian rt->rt_dst = *dst; 19811820Sjulian rt->rt_router = *gate; 19911820Sjulian rt->rt_metric = metric; 20011820Sjulian rt->rt_ticks = ticks; 20111820Sjulian rt->rt_timer = 0; 20211820Sjulian rt->rt_flags = RTF_UP | flags; 20311820Sjulian rt->rt_state = state | RTS_CHANGED; 20411820Sjulian rt->rt_ifp = if_ifwithnet(&rt->rt_router); 20511820Sjulian rt->rt_clone = NULL; 20611820Sjulian rt->rt_forw = NULL; 20711820Sjulian rt->rt_back = NULL; 20811820Sjulian if (metric) 20911820Sjulian rt->rt_flags |= RTF_GATEWAY; 21011820Sjulian 21111820Sjulian while(ort->rt_clone != NULL) 21211820Sjulian ort = ort->rt_clone; 21311820Sjulian ort->rt_clone = rt; 21427244Sjhay TRACE_ACTION("ADD_CLONE", rt); 21511820Sjulian} 21611820Sjulian 21711820Sjulianvoid 21811820Sjulianrtchange(rt, gate, metric, ticks) 21911820Sjulian struct rt_entry *rt; 22011820Sjulian struct sockaddr *gate; 22111820Sjulian short metric, ticks; 22211820Sjulian{ 22311820Sjulian int doioctl = 0, metricchanged = 0; 22411820Sjulian struct rtuentry oldroute; 22511820Sjulian 22611820Sjulian FIXLEN(gate); 22711820Sjulian /* 22811820Sjulian * Handling of clones. 22911820Sjulian * When the route changed and it had clones, handle it special. 23011820Sjulian * 1. If the new route is cheaper than the clone(s), free the clones. 23111820Sjulian * 2. If the new route is the same cost, it may be one of the clones, 23211820Sjulian * search for it and free it. 23311820Sjulian * 3. If the new route is more expensive than the clone(s), use the 23411820Sjulian * values of the clone(s). 23511820Sjulian */ 23611820Sjulian if (rt->rt_clone) { 23711820Sjulian if ((ticks < rt->rt_clone->rt_ticks) || 23811820Sjulian ((ticks == rt->rt_clone->rt_ticks) && 23911820Sjulian (metric < rt->rt_clone->rt_metric))) { 24011820Sjulian /* 24111820Sjulian * Free all clones. 24211820Sjulian */ 24311820Sjulian struct rt_entry *trt, *nrt; 24411820Sjulian 24511820Sjulian trt = rt->rt_clone; 24611820Sjulian rt->rt_clone = NULL; 24711820Sjulian while(trt) { 24811820Sjulian nrt = trt->rt_clone; 24911820Sjulian free((char *)trt); 25011820Sjulian trt = nrt; 25111820Sjulian } 25211820Sjulian } else if ((ticks == rt->rt_clone->rt_ticks) && 25311820Sjulian (metric == rt->rt_clone->rt_metric)) { 25411820Sjulian struct rt_entry *prt, *trt; 25511820Sjulian 25611820Sjulian prt = rt; 25711820Sjulian trt = rt->rt_clone; 25811820Sjulian 25911820Sjulian while(trt) { 26011820Sjulian if (equal(&trt->rt_router, gate)) { 26111820Sjulian prt->rt_clone = trt->rt_clone; 26211820Sjulian free(trt); 26311820Sjulian trt = prt->rt_clone; 26411820Sjulian } else { 26511820Sjulian prt = trt; 26611820Sjulian trt = trt->rt_clone; 26711820Sjulian } 26811820Sjulian } 26911820Sjulian } else { 27011820Sjulian /* 27111820Sjulian * Use the values of the first clone. 27211820Sjulian * Delete the corresponding clone. 27311820Sjulian */ 27411820Sjulian struct rt_entry *trt; 27511820Sjulian 27611820Sjulian trt = rt->rt_clone; 27711820Sjulian rt->rt_clone = rt->rt_clone->rt_clone; 27811820Sjulian metric = trt->rt_metric; 27911820Sjulian ticks = trt->rt_ticks; 28011820Sjulian *gate = trt->rt_router; 28111820Sjulian free((char *)trt); 28211820Sjulian } 28311820Sjulian } 28411820Sjulian 28511820Sjulian if (!equal(&rt->rt_router, gate)) 28611820Sjulian doioctl++; 28711820Sjulian if ((metric != rt->rt_metric) || (ticks != rt->rt_ticks)) 28811820Sjulian metricchanged++; 28911820Sjulian if (doioctl || metricchanged) { 29027244Sjhay TRACE_ACTION("CHANGE FROM", rt); 29111820Sjulian if (doioctl) { 29211820Sjulian oldroute = rt->rt_rt; 29311820Sjulian rt->rt_router = *gate; 29411820Sjulian } 29511820Sjulian rt->rt_metric = metric; 29611820Sjulian rt->rt_ticks = ticks; 29711820Sjulian if ((rt->rt_state & RTS_INTERFACE) && metric) { 29811820Sjulian rt->rt_state &= ~RTS_INTERFACE; 29911820Sjulian if(rt->rt_ifp) 30011820Sjulian syslog(LOG_ERR, 30111820Sjulian "changing route from interface %s (timed out)", 30211820Sjulian rt->rt_ifp->int_name); 30311820Sjulian else 30411820Sjulian syslog(LOG_ERR, 30511820Sjulian "changing route from interface ??? (timed out)"); 30611820Sjulian } 30711820Sjulian if (metric) 30811820Sjulian rt->rt_flags |= RTF_GATEWAY; 30911820Sjulian else 31011820Sjulian rt->rt_flags &= ~RTF_GATEWAY; 31127244Sjhay rt->rt_ifp = if_ifwithnet(&rt->rt_router); 31211820Sjulian rt->rt_state |= RTS_CHANGED; 31327244Sjhay TRACE_ACTION("CHANGE TO", rt); 31411820Sjulian } 31511820Sjulian if (doioctl && install) { 31611820Sjulian#ifndef RTM_ADD 31711820Sjulian if (rtioctl(ADD, &rt->rt_rt) < 0) 31811820Sjulian syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m", 31927244Sjhay ipx_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr), 32027244Sjhay ipx_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr)); 32111820Sjulian if (delete && rtioctl(DELETE, &oldroute) < 0) 32211820Sjulian perror("rtioctl DELETE"); 32311820Sjulian#else 32411820Sjulian if (delete == 0) { 32511820Sjulian if (rtioctl(ADD, &rt->rt_rt) >= 0) 32611820Sjulian return; 32711820Sjulian } else { 32811820Sjulian if (rtioctl(CHANGE, &rt->rt_rt) >= 0) 32911820Sjulian return; 33011820Sjulian } 33111820Sjulian syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m", 33211820Sjulian ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr), 33311820Sjulian ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr)); 33411820Sjulian#endif 33511820Sjulian } 33611820Sjulian} 33711820Sjulian 33811820Sjulianvoid 33911820Sjulianrtdelete(rt) 34011820Sjulian struct rt_entry *rt; 34111820Sjulian{ 34211820Sjulian 34311820Sjulian struct sockaddr *sa = &(rt->rt_router); 34411820Sjulian FIXLEN(sa); 34511820Sjulian sa = &(rt->rt_dst); 34611820Sjulian FIXLEN(sa); 34711820Sjulian if (rt->rt_clone) { 34811820Sjulian /* 34911820Sjulian * If there is a clone we just do a rt_change to it. 35011820Sjulian */ 35111820Sjulian struct rt_entry *trt = rt->rt_clone; 35211820Sjulian rtchange(rt, &trt->rt_router, trt->rt_metric, trt->rt_ticks); 35311820Sjulian return; 35411820Sjulian } 35511820Sjulian if (rt->rt_state & RTS_INTERFACE) { 35611820Sjulian if (rt->rt_ifp) 35711820Sjulian syslog(LOG_ERR, 35811820Sjulian "deleting route to interface %s (timed out)", 35911820Sjulian rt->rt_ifp->int_name); 36011820Sjulian else 36111820Sjulian syslog(LOG_ERR, 36211820Sjulian "deleting route to interface ??? (timed out)"); 36311820Sjulian } 36427244Sjhay TRACE_ACTION("DELETE", rt); 36511820Sjulian if (install && rtioctl(DELETE, &rt->rt_rt) < 0) 36611820Sjulian perror("rtioctl DELETE"); 36711820Sjulian remque(rt); 36811820Sjulian free((char *)rt); 36911820Sjulian} 37011820Sjulian 37111820Sjulianvoid 37211820Sjulianrtinit(void) 37311820Sjulian{ 37411820Sjulian register struct rthash *rh; 37511820Sjulian 37611820Sjulian for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 37711820Sjulian rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 37811820Sjulian} 37911820Sjulianint seqno; 38011820Sjulian 38111820Sjulianint 38211820Sjulianrtioctl(action, ort) 38311820Sjulian int action; 38411820Sjulian struct rtuentry *ort; 38511820Sjulian{ 38611820Sjulian#ifndef RTM_ADD 38711820Sjulian if (install == 0) 38811820Sjulian return (errno = 0); 38911820Sjulian 39011820Sjulian ort->rtu_rtflags = ort->rtu_flags; 39111820Sjulian 39211820Sjulian switch (action) { 39311820Sjulian 39411820Sjulian case ADD: 39511820Sjulian return (ioctl(s, SIOCADDRT, (char *)ort)); 39611820Sjulian 39711820Sjulian case DELETE: 39811820Sjulian return (ioctl(s, SIOCDELRT, (char *)ort)); 39911820Sjulian 40011820Sjulian default: 40111820Sjulian return (-1); 40211820Sjulian } 40311820Sjulian#else /* RTM_ADD */ 40411820Sjulian struct { 40511820Sjulian struct rt_msghdr w_rtm; 40611820Sjulian struct sockaddr w_dst; 40711820Sjulian struct sockaddr w_gate; 40811820Sjulian struct sockaddr_ipx w_netmask; 40911820Sjulian } w; 41011820Sjulian#define rtm w.w_rtm 41111820Sjulian 41211820Sjulian bzero((char *)&w, sizeof(w)); 41311820Sjulian rtm.rtm_msglen = sizeof(w); 41411820Sjulian rtm.rtm_version = RTM_VERSION; 41511820Sjulian rtm.rtm_type = (action == ADD ? RTM_ADD : 41611820Sjulian (action == DELETE ? RTM_DELETE : RTM_CHANGE)); 41711820Sjulian rtm.rtm_flags = ort->rtu_flags; 41811820Sjulian rtm.rtm_seq = ++seqno; 41911820Sjulian rtm.rtm_addrs = RTA_DST|RTA_GATEWAY; 42011820Sjulian bcopy((char *)&ort->rtu_dst, (char *)&w.w_dst, sizeof(w.w_dst)); 42111820Sjulian bcopy((char *)&ort->rtu_router, (char *)&w.w_gate, sizeof(w.w_gate)); 42211820Sjulian w.w_gate.sa_family = w.w_dst.sa_family = AF_IPX; 42311820Sjulian w.w_gate.sa_len = w.w_dst.sa_len = sizeof(w.w_dst); 42411820Sjulian if (rtm.rtm_flags & RTF_HOST) { 42511820Sjulian rtm.rtm_msglen -= sizeof(w.w_netmask); 42611820Sjulian } else { 42711820Sjulian rtm.rtm_addrs |= RTA_NETMASK; 42811820Sjulian w.w_netmask = ipx_netmask; 42911820Sjulian rtm.rtm_msglen -= sizeof(w.w_netmask) - ipx_netmask.sipx_len; 43011820Sjulian } 43111820Sjulian errno = 0; 43211820Sjulian return write(r, (char *)&w, rtm.rtm_msglen); 43311820Sjulian#endif /* RTM_ADD */ 43411820Sjulian} 435