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