tables.c revision 189369
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 189369 2009-03-04 18:36:48Z ed $ 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 * 67189369Sedrtlookup(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 * 92189369Sedrtfind(struct sockaddr *dst) 9311820Sjulian{ 9411820Sjulian register struct rt_entry *rt; 9511820Sjulian register struct rthash *rh; 9611820Sjulian register u_int hash; 9711820Sjulian struct afhash h; 9811820Sjulian int af = dst->sa_family; 9927244Sjhay int (*match)() = 0; 10011820Sjulian 10111820Sjulian if (af >= AF_MAX) 10211820Sjulian return (0); 10311820Sjulian (*afswitch[af].af_hash)(dst, &h); 10411820Sjulian 10527244Sjhay hash = h.afh_nethash; 10627244Sjhay rh = &nethash[hash & ROUTEHASHMASK]; 10727244Sjhay match = afswitch[af].af_netmatch; 10811820Sjulian for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 10911820Sjulian if (rt->rt_hash != hash) 11011820Sjulian continue; 11127244Sjhay if (rt->rt_dst.sa_family == af && 11227244Sjhay (*match)(&rt->rt_dst, dst)) 11327244Sjhay return (rt); 11411820Sjulian } 11511820Sjulian return (0); 11611820Sjulian} 11711820Sjulian 11811820Sjulianvoid 119189369Sedrtadd(struct sockaddr *dst, struct sockaddr *gate, short metric, 120189369Sed short ticks, int state) 12111820Sjulian{ 12211820Sjulian struct afhash h; 12311820Sjulian register struct rt_entry *rt; 12411820Sjulian struct rthash *rh; 12511820Sjulian int af = dst->sa_family, flags; 12611820Sjulian u_int hash; 12711820Sjulian 12811820Sjulian FIXLEN(dst); 12911820Sjulian FIXLEN(gate); 13011820Sjulian if (af >= AF_MAX) 13111820Sjulian return; 13211820Sjulian (*afswitch[af].af_hash)(dst, &h); 13311820Sjulian flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 13427244Sjhay hash = h.afh_nethash; 13527244Sjhay rh = &nethash[hash & ROUTEHASHMASK]; 13611820Sjulian rt = (struct rt_entry *)malloc(sizeof (*rt)); 13711820Sjulian if (rt == 0) 13811820Sjulian return; 13911820Sjulian rt->rt_hash = hash; 14011820Sjulian rt->rt_dst = *dst; 14111820Sjulian rt->rt_router = *gate; 14211820Sjulian rt->rt_metric = metric; 14311820Sjulian rt->rt_ticks = ticks; 14411820Sjulian rt->rt_timer = 0; 14511820Sjulian rt->rt_flags = RTF_UP | flags; 14611820Sjulian rt->rt_state = state | RTS_CHANGED; 14711820Sjulian rt->rt_ifp = if_ifwithnet(&rt->rt_router); 14811820Sjulian rt->rt_clone = NULL; 14911820Sjulian if (metric) 15011820Sjulian rt->rt_flags |= RTF_GATEWAY; 15111820Sjulian insque(rt, rh); 15227244Sjhay TRACE_ACTION("ADD", rt); 15311820Sjulian /* 15411820Sjulian * If the ioctl fails because the gateway is unreachable 15511820Sjulian * from this host, discard the entry. This should only 15611820Sjulian * occur because of an incorrect entry in /etc/gateways. 15711820Sjulian */ 15811820Sjulian if (install && rtioctl(ADD, &rt->rt_rt) < 0) { 15911820Sjulian if (errno != EEXIST) 16011820Sjulian perror("SIOCADDRT"); 16111820Sjulian if (errno == ENETUNREACH) { 16227244Sjhay TRACE_ACTION("DELETE", rt); 16311820Sjulian remque(rt); 16411820Sjulian free((char *)rt); 16511820Sjulian } 16611820Sjulian } 16711820Sjulian} 16811820Sjulian 16911820Sjulianvoid 170189369Sedrtadd_clone(struct rt_entry *ort, struct sockaddr *dst, 171189369Sed struct sockaddr *gate, short metric, short ticks, int state) 17211820Sjulian{ 17311820Sjulian struct afhash h; 17411820Sjulian register struct rt_entry *rt; 17511820Sjulian struct rthash *rh; 17611820Sjulian int af = dst->sa_family, flags; 17711820Sjulian u_int hash; 17811820Sjulian 17911820Sjulian FIXLEN(dst); 18011820Sjulian FIXLEN(gate); 18111820Sjulian if (af >= AF_MAX) 18211820Sjulian return; 18311820Sjulian (*afswitch[af].af_hash)(dst, &h); 18411820Sjulian flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 18527244Sjhay hash = h.afh_nethash; 18627244Sjhay rh = &nethash[hash & ROUTEHASHMASK]; 18711820Sjulian rt = (struct rt_entry *)malloc(sizeof (*rt)); 18811820Sjulian if (rt == 0) 18911820Sjulian return; 19011820Sjulian rt->rt_hash = hash; 19111820Sjulian rt->rt_dst = *dst; 19211820Sjulian rt->rt_router = *gate; 19311820Sjulian rt->rt_metric = metric; 19411820Sjulian rt->rt_ticks = ticks; 19511820Sjulian rt->rt_timer = 0; 19611820Sjulian rt->rt_flags = RTF_UP | flags; 19711820Sjulian rt->rt_state = state | RTS_CHANGED; 19811820Sjulian rt->rt_ifp = if_ifwithnet(&rt->rt_router); 19911820Sjulian rt->rt_clone = NULL; 20011820Sjulian rt->rt_forw = NULL; 20111820Sjulian rt->rt_back = NULL; 20211820Sjulian if (metric) 20311820Sjulian rt->rt_flags |= RTF_GATEWAY; 20411820Sjulian 20511820Sjulian while(ort->rt_clone != NULL) 20611820Sjulian ort = ort->rt_clone; 20711820Sjulian ort->rt_clone = rt; 20827244Sjhay TRACE_ACTION("ADD_CLONE", rt); 20911820Sjulian} 21011820Sjulian 21111820Sjulianvoid 212189369Sedrtchange(struct rt_entry *rt, struct sockaddr *gate, short metric, 213189369Sed short ticks) 21411820Sjulian{ 21511820Sjulian int doioctl = 0, metricchanged = 0; 21611820Sjulian struct rtuentry oldroute; 21711820Sjulian 21811820Sjulian FIXLEN(gate); 21911820Sjulian /* 22011820Sjulian * Handling of clones. 22111820Sjulian * When the route changed and it had clones, handle it special. 22211820Sjulian * 1. If the new route is cheaper than the clone(s), free the clones. 22311820Sjulian * 2. If the new route is the same cost, it may be one of the clones, 22411820Sjulian * search for it and free it. 22511820Sjulian * 3. If the new route is more expensive than the clone(s), use the 22611820Sjulian * values of the clone(s). 22711820Sjulian */ 22811820Sjulian if (rt->rt_clone) { 22911820Sjulian if ((ticks < rt->rt_clone->rt_ticks) || 23011820Sjulian ((ticks == rt->rt_clone->rt_ticks) && 23111820Sjulian (metric < rt->rt_clone->rt_metric))) { 23211820Sjulian /* 23311820Sjulian * Free all clones. 23411820Sjulian */ 23511820Sjulian struct rt_entry *trt, *nrt; 23611820Sjulian 23711820Sjulian trt = rt->rt_clone; 23811820Sjulian rt->rt_clone = NULL; 23911820Sjulian while(trt) { 24011820Sjulian nrt = trt->rt_clone; 24111820Sjulian free((char *)trt); 24211820Sjulian trt = nrt; 24311820Sjulian } 24411820Sjulian } else if ((ticks == rt->rt_clone->rt_ticks) && 24511820Sjulian (metric == rt->rt_clone->rt_metric)) { 24611820Sjulian struct rt_entry *prt, *trt; 24711820Sjulian 24811820Sjulian prt = rt; 24911820Sjulian trt = rt->rt_clone; 25011820Sjulian 25111820Sjulian while(trt) { 25211820Sjulian if (equal(&trt->rt_router, gate)) { 25311820Sjulian prt->rt_clone = trt->rt_clone; 25411820Sjulian free(trt); 25511820Sjulian trt = prt->rt_clone; 25611820Sjulian } else { 25711820Sjulian prt = trt; 25811820Sjulian trt = trt->rt_clone; 25911820Sjulian } 26011820Sjulian } 26111820Sjulian } else { 26211820Sjulian /* 26311820Sjulian * Use the values of the first clone. 26411820Sjulian * Delete the corresponding clone. 26511820Sjulian */ 26611820Sjulian struct rt_entry *trt; 26711820Sjulian 26811820Sjulian trt = rt->rt_clone; 26911820Sjulian rt->rt_clone = rt->rt_clone->rt_clone; 27011820Sjulian metric = trt->rt_metric; 27111820Sjulian ticks = trt->rt_ticks; 27211820Sjulian *gate = trt->rt_router; 27311820Sjulian free((char *)trt); 27411820Sjulian } 27511820Sjulian } 27611820Sjulian 27711820Sjulian if (!equal(&rt->rt_router, gate)) 27811820Sjulian doioctl++; 27911820Sjulian if ((metric != rt->rt_metric) || (ticks != rt->rt_ticks)) 28011820Sjulian metricchanged++; 28111820Sjulian if (doioctl || metricchanged) { 28227244Sjhay TRACE_ACTION("CHANGE FROM", rt); 28311820Sjulian if (doioctl) { 28411820Sjulian oldroute = rt->rt_rt; 28511820Sjulian rt->rt_router = *gate; 28611820Sjulian } 28711820Sjulian rt->rt_metric = metric; 28811820Sjulian rt->rt_ticks = ticks; 28911820Sjulian if ((rt->rt_state & RTS_INTERFACE) && metric) { 29011820Sjulian rt->rt_state &= ~RTS_INTERFACE; 29111820Sjulian if(rt->rt_ifp) 29211820Sjulian syslog(LOG_ERR, 29311820Sjulian "changing route from interface %s (timed out)", 29411820Sjulian rt->rt_ifp->int_name); 29511820Sjulian else 29611820Sjulian syslog(LOG_ERR, 29711820Sjulian "changing route from interface ??? (timed out)"); 29811820Sjulian } 29911820Sjulian if (metric) 30011820Sjulian rt->rt_flags |= RTF_GATEWAY; 30111820Sjulian else 30211820Sjulian rt->rt_flags &= ~RTF_GATEWAY; 30327244Sjhay rt->rt_ifp = if_ifwithnet(&rt->rt_router); 30411820Sjulian rt->rt_state |= RTS_CHANGED; 30527244Sjhay TRACE_ACTION("CHANGE TO", rt); 30611820Sjulian } 30711820Sjulian if (doioctl && install) { 30811820Sjulian#ifndef RTM_ADD 30911820Sjulian if (rtioctl(ADD, &rt->rt_rt) < 0) 31011820Sjulian syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m", 31127244Sjhay ipx_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr), 31227244Sjhay ipx_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr)); 31311820Sjulian if (delete && rtioctl(DELETE, &oldroute) < 0) 31411820Sjulian perror("rtioctl DELETE"); 31511820Sjulian#else 31611820Sjulian if (delete == 0) { 31711820Sjulian if (rtioctl(ADD, &rt->rt_rt) >= 0) 31811820Sjulian return; 31911820Sjulian } else { 32011820Sjulian if (rtioctl(CHANGE, &rt->rt_rt) >= 0) 32111820Sjulian return; 32211820Sjulian } 32311820Sjulian syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m", 32411820Sjulian ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr), 32511820Sjulian ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr)); 32611820Sjulian#endif 32711820Sjulian } 32811820Sjulian} 32911820Sjulian 33011820Sjulianvoid 331189369Sedrtdelete(struct rt_entry *rt) 33211820Sjulian{ 33311820Sjulian 33411820Sjulian struct sockaddr *sa = &(rt->rt_router); 33511820Sjulian FIXLEN(sa); 33611820Sjulian sa = &(rt->rt_dst); 33711820Sjulian FIXLEN(sa); 33811820Sjulian if (rt->rt_clone) { 33911820Sjulian /* 34011820Sjulian * If there is a clone we just do a rt_change to it. 34111820Sjulian */ 34211820Sjulian struct rt_entry *trt = rt->rt_clone; 34311820Sjulian rtchange(rt, &trt->rt_router, trt->rt_metric, trt->rt_ticks); 34411820Sjulian return; 34511820Sjulian } 34611820Sjulian if (rt->rt_state & RTS_INTERFACE) { 34711820Sjulian if (rt->rt_ifp) 34811820Sjulian syslog(LOG_ERR, 34911820Sjulian "deleting route to interface %s (timed out)", 35011820Sjulian rt->rt_ifp->int_name); 35111820Sjulian else 35211820Sjulian syslog(LOG_ERR, 35311820Sjulian "deleting route to interface ??? (timed out)"); 35411820Sjulian } 35527244Sjhay TRACE_ACTION("DELETE", rt); 35611820Sjulian if (install && rtioctl(DELETE, &rt->rt_rt) < 0) 35711820Sjulian perror("rtioctl DELETE"); 35811820Sjulian remque(rt); 35911820Sjulian free((char *)rt); 36011820Sjulian} 36111820Sjulian 36211820Sjulianvoid 36311820Sjulianrtinit(void) 36411820Sjulian{ 36511820Sjulian register struct rthash *rh; 36611820Sjulian 36711820Sjulian for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 36811820Sjulian rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 36911820Sjulian} 37011820Sjulianint seqno; 37111820Sjulian 37211820Sjulianint 373189369Sedrtioctl(int action, struct rtuentry *ort) 37411820Sjulian{ 37511820Sjulian#ifndef RTM_ADD 37611820Sjulian if (install == 0) 37711820Sjulian return (errno = 0); 37811820Sjulian 37911820Sjulian ort->rtu_rtflags = ort->rtu_flags; 38011820Sjulian 38111820Sjulian switch (action) { 38211820Sjulian 38311820Sjulian case ADD: 38411820Sjulian return (ioctl(s, SIOCADDRT, (char *)ort)); 38511820Sjulian 38611820Sjulian case DELETE: 38711820Sjulian return (ioctl(s, SIOCDELRT, (char *)ort)); 38811820Sjulian 38911820Sjulian default: 39011820Sjulian return (-1); 39111820Sjulian } 39211820Sjulian#else /* RTM_ADD */ 39311820Sjulian struct { 39411820Sjulian struct rt_msghdr w_rtm; 39511820Sjulian struct sockaddr w_dst; 39611820Sjulian struct sockaddr w_gate; 39711820Sjulian struct sockaddr_ipx w_netmask; 39811820Sjulian } w; 39911820Sjulian#define rtm w.w_rtm 40011820Sjulian 40111820Sjulian bzero((char *)&w, sizeof(w)); 40211820Sjulian rtm.rtm_msglen = sizeof(w); 40311820Sjulian rtm.rtm_version = RTM_VERSION; 40411820Sjulian rtm.rtm_type = (action == ADD ? RTM_ADD : 40511820Sjulian (action == DELETE ? RTM_DELETE : RTM_CHANGE)); 40611820Sjulian rtm.rtm_flags = ort->rtu_flags; 40711820Sjulian rtm.rtm_seq = ++seqno; 40811820Sjulian rtm.rtm_addrs = RTA_DST|RTA_GATEWAY; 40911820Sjulian bcopy((char *)&ort->rtu_dst, (char *)&w.w_dst, sizeof(w.w_dst)); 41011820Sjulian bcopy((char *)&ort->rtu_router, (char *)&w.w_gate, sizeof(w.w_gate)); 41111820Sjulian w.w_gate.sa_family = w.w_dst.sa_family = AF_IPX; 41211820Sjulian w.w_gate.sa_len = w.w_dst.sa_len = sizeof(w.w_dst); 41311820Sjulian if (rtm.rtm_flags & RTF_HOST) { 41411820Sjulian rtm.rtm_msglen -= sizeof(w.w_netmask); 41511820Sjulian } else { 41611820Sjulian rtm.rtm_addrs |= RTA_NETMASK; 41711820Sjulian w.w_netmask = ipx_netmask; 41811820Sjulian rtm.rtm_msglen -= sizeof(w.w_netmask) - ipx_netmask.sipx_len; 41911820Sjulian } 42011820Sjulian errno = 0; 42111820Sjulian return write(r, (char *)&w, rtm.rtm_msglen); 42211820Sjulian#endif /* RTM_ADD */ 42311820Sjulian} 424