tables.c revision 11820
11556Srgrimes/* 21556Srgrimes * Copyright (c) 1985, 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * Copyright (c) 1995 John Hay. All rights reserved. 61556Srgrimes * 71556Srgrimes * Redistribution and use in source and binary forms, with or without 81556Srgrimes * modification, are permitted provided that the following conditions 91556Srgrimes * are met: 101556Srgrimes * 1. Redistributions of source code must retain the above copyright 111556Srgrimes * notice, this list of conditions and the following disclaimer. 121556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 131556Srgrimes * notice, this list of conditions and the following disclaimer in the 141556Srgrimes * documentation and/or other materials provided with the distribution. 151556Srgrimes * 3. All advertising materials mentioning features or use of this software 161556Srgrimes * must display the following acknowledgement: 171556Srgrimes * This product includes software developed by the University of 181556Srgrimes * California, Berkeley and its contributors. 191556Srgrimes * 4. Neither the name of the University nor the names of its contributors 201556Srgrimes * may be used to endorse or promote products derived from this software 211556Srgrimes * without specific prior written permission. 221556Srgrimes * 231556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 241556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 251556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 261556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 271556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 281556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 291556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 301556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 311556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 321556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 331556Srgrimes * SUCH DAMAGE. 341556Srgrimes * 351556Srgrimes * $Id: tables.c,v 1.6 1995/10/11 18:57:31 jhay Exp $ 361556Srgrimes */ 371556Srgrimes 3836150Scharnier#ifndef lint 3936150Scharnierstatic char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 6/5/93"; 4036150Scharnier#endif /* not lint */ 4136150Scharnier 4250471Speter/* 431556Srgrimes * Routing Table Management Daemon 441556Srgrimes */ 4517987Speter#include "defs.h" 4617987Speter#include <sys/ioctl.h> 4717987Speter#include <errno.h> 481556Srgrimes#include <stdlib.h> 491556Srgrimes#include <unistd.h> 501556Srgrimes/* XXX I thought that this should work! #include <sys/systm.h> */ 511556Srgrimes#include <machine/cpufunc.h> 5217525Sache 5317525Sache#ifndef DEBUG 541556Srgrimes#define DEBUG 0 551556Srgrimes#endif 561556Srgrimes 571556Srgrimes#define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));} 581556Srgrimes 591556Srgrimesint install = !DEBUG; /* if 1 call kernel */ 601556Srgrimesint delete = 1; 611556Srgrimes/* 621556Srgrimes * Lookup dst in the tables for an exact match. 631556Srgrimes */ 641556Srgrimesstruct rt_entry * 651556Srgrimesrtlookup(dst) 661556Srgrimes struct sockaddr *dst; 6720425Ssteve{ 6817987Speter register struct rt_entry *rt; 6917987Speter register struct rthash *rh; 7017987Speter register u_int hash; 711556Srgrimes struct afhash h; 721556Srgrimes int doinghost = 1; 731556Srgrimes 741556Srgrimes if (dst->sa_family >= AF_MAX) 751556Srgrimes return (0); 761556Srgrimes (*afswitch[dst->sa_family].af_hash)(dst, &h); 771556Srgrimes hash = h.afh_hosthash; 781556Srgrimes rh = &hosthash[hash & ROUTEHASHMASK]; 791556Srgrimesagain: 8090111Simp for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 811556Srgrimes if (rt->rt_hash != hash) 821556Srgrimes continue; 831556Srgrimes if (equal(&rt->rt_dst, dst)) 841556Srgrimes return (rt); 851556Srgrimes } 861556Srgrimes if (doinghost) { 8717987Speter doinghost = 0; 881556Srgrimes hash = h.afh_nethash; 8917987Speter rh = &nethash[hash & ROUTEHASHMASK]; 901556Srgrimes goto again; 911556Srgrimes } 921556Srgrimes return (0); 931556Srgrimes} 941556Srgrimes 951556Srgrimes/* 961556Srgrimes * Find a route to dst as the kernel would. 971556Srgrimes */ 981556Srgrimesstruct rt_entry * 991556Srgrimesrtfind(dst) 10020425Ssteve struct sockaddr *dst; 1011556Srgrimes{ 1021556Srgrimes register struct rt_entry *rt; 1031556Srgrimes register struct rthash *rh; 10420425Ssteve register u_int hash; 10520425Ssteve struct afhash h; 1061556Srgrimes int af = dst->sa_family; 10717987Speter int doinghost = 1, (*match)() = 0; 10820425Ssteve 10920425Ssteve if (af >= AF_MAX) 11017987Speter return (0); 11120425Ssteve (*afswitch[af].af_hash)(dst, &h); 11220425Ssteve hash = h.afh_hosthash; 11320425Ssteve rh = &hosthash[hash & ROUTEHASHMASK]; 11420425Ssteve 11520425Ssteveagain: 11620425Ssteve for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 11720425Ssteve if (rt->rt_hash != hash) 11820425Ssteve continue; 1198855Srgrimes if (doinghost) { 1201556Srgrimes if (equal(&rt->rt_dst, dst)) 1211556Srgrimes return (rt); 12220425Ssteve } else { 12320425Ssteve if (rt->rt_dst.sa_family == af && 1241556Srgrimes (match != 0) && 12520425Ssteve (*match)(&rt->rt_dst, dst)) 12620425Ssteve return (rt); 1271556Srgrimes } 12820425Ssteve } 12920425Ssteve if (doinghost) { 13020425Ssteve doinghost = 0; 13120425Ssteve hash = h.afh_nethash; 1321556Srgrimes rh = &nethash[hash & ROUTEHASHMASK]; 1331556Srgrimes match = afswitch[af].af_netmatch; 1341556Srgrimes goto again; 1351556Srgrimes } 13690111Simp return (0); 13790111Simp} 13890111Simp 1391556Srgrimesvoid 1401556Srgrimesrtadd(dst, gate, metric, ticks, state) 1411556Srgrimes struct sockaddr *dst, *gate; 1421556Srgrimes short metric, ticks; 1431556Srgrimes int state; 1441556Srgrimes{ 1451556Srgrimes struct afhash h; 1461556Srgrimes register struct rt_entry *rt; 1471556Srgrimes struct rthash *rh; 1481556Srgrimes int af = dst->sa_family, flags; 1491556Srgrimes u_int hash; 1501556Srgrimes 1511556Srgrimes FIXLEN(dst); 1521556Srgrimes FIXLEN(gate); 1531556Srgrimes if (af >= AF_MAX) 1541556Srgrimes return; 1551556Srgrimes (*afswitch[af].af_hash)(dst, &h); 1561556Srgrimes flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 1571556Srgrimes if (flags & RTF_HOST) { 1581556Srgrimes hash = h.afh_hosthash; 1591556Srgrimes rh = &hosthash[hash & ROUTEHASHMASK]; 1601556Srgrimes } else { 1611556Srgrimes hash = h.afh_nethash; 1621556Srgrimes rh = &nethash[hash & ROUTEHASHMASK]; 1631556Srgrimes } 1641556Srgrimes rt = (struct rt_entry *)malloc(sizeof (*rt)); 1651556Srgrimes if (rt == 0) 16690111Simp return; 16790111Simp rt->rt_hash = hash; 1681556Srgrimes rt->rt_dst = *dst; 1691556Srgrimes rt->rt_router = *gate; 1701556Srgrimes rt->rt_metric = metric; 1711556Srgrimes rt->rt_ticks = ticks; 1721556Srgrimes rt->rt_timer = 0; 1731556Srgrimes rt->rt_flags = RTF_UP | flags; 1741556Srgrimes rt->rt_state = state | RTS_CHANGED; 1751556Srgrimes rt->rt_ifp = if_ifwithnet(&rt->rt_router); 1761556Srgrimes rt->rt_clone = NULL; 1771556Srgrimes if (metric) 1781556Srgrimes rt->rt_flags |= RTF_GATEWAY; 17920425Ssteve insque(rt, rh); 1801556Srgrimes TRACE_ACTION(ADD, rt); 1811556Srgrimes /* 1821556Srgrimes * If the ioctl fails because the gateway is unreachable 1831556Srgrimes * from this host, discard the entry. This should only 1841556Srgrimes * occur because of an incorrect entry in /etc/gateways. 1851556Srgrimes */ 1861556Srgrimes if (install && rtioctl(ADD, &rt->rt_rt) < 0) { 1871556Srgrimes if (errno != EEXIST) 1881556Srgrimes perror("SIOCADDRT"); 1891556Srgrimes if (errno == ENETUNREACH) { 1901556Srgrimes TRACE_ACTION(DELETE, rt); 1911556Srgrimes remque(rt); 1921556Srgrimes free((char *)rt); 1931556Srgrimes } 1941556Srgrimes } 19520425Ssteve} 19620425Ssteve 19720425Sstevevoid 19820425Sstevertadd_clone(ort, dst, gate, metric, ticks, state) 19990111Simp struct rt_entry *ort; 20020425Ssteve struct sockaddr *dst, *gate; 20120425Ssteve short metric, ticks; 20220425Ssteve int state; 20320425Ssteve{ 20420425Ssteve struct afhash h; 20520425Ssteve register struct rt_entry *rt; 20620425Ssteve struct rthash *rh; 20720425Ssteve int af = dst->sa_family, flags; 20820425Ssteve u_int hash; 20920425Ssteve 21020425Ssteve FIXLEN(dst); 21120425Ssteve FIXLEN(gate); 21220425Ssteve if (af >= AF_MAX) 21320425Ssteve return; 21420425Ssteve (*afswitch[af].af_hash)(dst, &h); 21520425Ssteve flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 21620425Ssteve if (flags & RTF_HOST) { 21720425Ssteve hash = h.afh_hosthash; 21820425Ssteve rh = &hosthash[hash & ROUTEHASHMASK]; 21920425Ssteve } else { 22045621Scracauer hash = h.afh_nethash; 2211556Srgrimes rh = &nethash[hash & ROUTEHASHMASK]; 2221556Srgrimes } 2231556Srgrimes rt = (struct rt_entry *)malloc(sizeof (*rt)); 2241556Srgrimes if (rt == 0) 22590111Simp return; 22617987Speter rt->rt_hash = hash; 2271556Srgrimes rt->rt_dst = *dst; 2281556Srgrimes rt->rt_router = *gate; 2291556Srgrimes rt->rt_metric = metric; 2301556Srgrimes rt->rt_ticks = ticks; 2311556Srgrimes rt->rt_timer = 0; 2321556Srgrimes rt->rt_flags = RTF_UP | flags; 2331556Srgrimes rt->rt_state = state | RTS_CHANGED; 2341556Srgrimes rt->rt_ifp = if_ifwithnet(&rt->rt_router); 23517525Sache rt->rt_clone = NULL; 2361556Srgrimes rt->rt_forw = NULL; 23717525Sache rt->rt_back = NULL; 2381556Srgrimes if (metric) 2391556Srgrimes rt->rt_flags |= RTF_GATEWAY; 2401556Srgrimes 2411556Srgrimes while(ort->rt_clone != NULL) 2421556Srgrimes ort = ort->rt_clone; 2431556Srgrimes ort->rt_clone = rt; 2441556Srgrimes TRACE_ACTION(ADD_CLONE, rt); 2451556Srgrimes} 2461556Srgrimes 2471556Srgrimesvoid 2481556Srgrimesrtchange(rt, gate, metric, ticks) 2491556Srgrimes struct rt_entry *rt; 2501556Srgrimes struct sockaddr *gate; 2511556Srgrimes short metric, ticks; 2521556Srgrimes{ 2531556Srgrimes int doioctl = 0, metricchanged = 0; 2541556Srgrimes struct rtuentry oldroute; 2551556Srgrimes 2561556Srgrimes FIXLEN(gate); 2571556Srgrimes /* 2581556Srgrimes * Handling of clones. 2591556Srgrimes * When the route changed and it had clones, handle it special. 2601556Srgrimes * 1. If the new route is cheaper than the clone(s), free the clones. 2611556Srgrimes * 2. If the new route is the same cost, it may be one of the clones, 2621556Srgrimes * search for it and free it. 2631556Srgrimes * 3. If the new route is more expensive than the clone(s), use the 2641556Srgrimes * values of the clone(s). 2651556Srgrimes */ 26617525Sache if (rt->rt_clone) { 26790111Simp if ((ticks < rt->rt_clone->rt_ticks) || 26890111Simp ((ticks == rt->rt_clone->rt_ticks) && 26917525Sache (metric < rt->rt_clone->rt_metric))) { 27017525Sache /* 27117525Sache * Free all clones. 27217525Sache */ 27317525Sache struct rt_entry *trt, *nrt; 2741556Srgrimes 27517525Sache trt = rt->rt_clone; 27617525Sache rt->rt_clone = NULL; 27717525Sache while(trt) { 27817525Sache nrt = trt->rt_clone; 27917525Sache free((char *)trt); 28017525Sache trt = nrt; 28117525Sache } 28217525Sache } else if ((ticks == rt->rt_clone->rt_ticks) && 28317525Sache (metric == rt->rt_clone->rt_metric)) { 28417525Sache struct rt_entry *prt, *trt; 28517525Sache 2861556Srgrimes prt = rt; 2871556Srgrimes trt = rt->rt_clone; 2881556Srgrimes 2891556Srgrimes while(trt) { 2901556Srgrimes if (equal(&trt->rt_router, gate)) { 2911556Srgrimes prt->rt_clone = trt->rt_clone; 2921556Srgrimes free(trt); 2931556Srgrimes trt = prt->rt_clone; 2941556Srgrimes } else { 29590111Simp prt = trt; 29617987Speter trt = trt->rt_clone; 2971556Srgrimes } 2981556Srgrimes } 29945263Scracauer } else { 30045263Scracauer /* 3011556Srgrimes * Use the values of the first clone. 3021556Srgrimes * Delete the corresponding clone. 3031556Srgrimes */ 3041556Srgrimes struct rt_entry *trt; 30520425Ssteve 3061556Srgrimes trt = rt->rt_clone; 3071556Srgrimes rt->rt_clone = rt->rt_clone->rt_clone; 3081556Srgrimes metric = trt->rt_metric; 30920425Ssteve ticks = trt->rt_ticks; 31020425Ssteve *gate = trt->rt_router; 31120425Ssteve free((char *)trt); 31220425Ssteve } 3131556Srgrimes } 3141556Srgrimes 31520425Ssteve if (!equal(&rt->rt_router, gate)) 31620425Ssteve doioctl++; 3171556Srgrimes if ((metric != rt->rt_metric) || (ticks != rt->rt_ticks)) 3181556Srgrimes metricchanged++; 31920425Ssteve if (doioctl || metricchanged) { 32020425Ssteve TRACE_ACTION(CHANGE FROM, rt); 32120425Ssteve if (doioctl) { 32220425Ssteve oldroute = rt->rt_rt; 32320425Ssteve rt->rt_router = *gate; 3241556Srgrimes } 3251556Srgrimes rt->rt_metric = metric; 32617525Sache rt->rt_ticks = ticks; 32717525Sache if ((rt->rt_state & RTS_INTERFACE) && metric) { 32817525Sache rt->rt_state &= ~RTS_INTERFACE; 32917525Sache if(rt->rt_ifp) 3301556Srgrimes syslog(LOG_ERR, 3311556Srgrimes "changing route from interface %s (timed out)", 3321556Srgrimes rt->rt_ifp->int_name); 3331556Srgrimes else 3341556Srgrimes syslog(LOG_ERR, 3351556Srgrimes "changing route from interface ??? (timed out)"); 3361556Srgrimes } 3371556Srgrimes if (metric) 3381556Srgrimes rt->rt_flags |= RTF_GATEWAY; 33920425Ssteve else 34017525Sache rt->rt_flags &= ~RTF_GATEWAY; 3411556Srgrimes rt->rt_state |= RTS_CHANGED; 34217525Sache TRACE_ACTION(CHANGE TO, rt); 34317525Sache } 34417525Sache if (doioctl && install) { 34517525Sache#ifndef RTM_ADD 34617525Sache if (rtioctl(ADD, &rt->rt_rt) < 0) 3471556Srgrimes syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m", 3481556Srgrimes xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr), 3491556Srgrimes xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr)); 3501556Srgrimes if (delete && rtioctl(DELETE, &oldroute) < 0) 3511556Srgrimes perror("rtioctl DELETE"); 3521556Srgrimes#else 3531556Srgrimes if (delete == 0) { 3541556Srgrimes if (rtioctl(ADD, &rt->rt_rt) >= 0) 3551556Srgrimes return; 35690111Simp } else { 35790111Simp if (rtioctl(CHANGE, &rt->rt_rt) >= 0) 3581556Srgrimes return; 3591556Srgrimes } 3601556Srgrimes syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m", 3611556Srgrimes ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr), 3621556Srgrimes ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr)); 3631556Srgrimes#endif 3641556Srgrimes } 3651556Srgrimes} 3661556Srgrimes 3671556Srgrimesvoid 3681556Srgrimesrtdelete(rt) 3691556Srgrimes struct rt_entry *rt; 3701556Srgrimes{ 3711556Srgrimes 3721556Srgrimes struct sockaddr *sa = &(rt->rt_router); 3731556Srgrimes FIXLEN(sa); 37490111Simp sa = &(rt->rt_dst); 37590111Simp FIXLEN(sa); 3761556Srgrimes if (rt->rt_clone) { 3771556Srgrimes /* 3781556Srgrimes * If there is a clone we just do a rt_change to it. 3791556Srgrimes */ 3801556Srgrimes struct rt_entry *trt = rt->rt_clone; 3811556Srgrimes rtchange(rt, &trt->rt_router, trt->rt_metric, trt->rt_ticks); 3821556Srgrimes return; 3831556Srgrimes } 3841556Srgrimes if (rt->rt_state & RTS_INTERFACE) { 3851556Srgrimes if (rt->rt_ifp) 3861556Srgrimes syslog(LOG_ERR, 3871556Srgrimes "deleting route to interface %s (timed out)", 3881556Srgrimes rt->rt_ifp->int_name); 3891556Srgrimes else 3901556Srgrimes syslog(LOG_ERR, 3911556Srgrimes "deleting route to interface ??? (timed out)"); 3921556Srgrimes } 3931556Srgrimes TRACE_ACTION(DELETE, rt); 3941556Srgrimes if (install && rtioctl(DELETE, &rt->rt_rt) < 0) 3951556Srgrimes perror("rtioctl DELETE"); 3961556Srgrimes remque(rt); 39790111Simp free((char *)rt); 39817987Speter} 3991556Srgrimes 4001556Srgrimesvoid 4011556Srgrimesrtinit(void) 4021556Srgrimes{ 4031556Srgrimes register struct rthash *rh; 4041556Srgrimes 4051556Srgrimes for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 4061556Srgrimes rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 4071556Srgrimes for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 40817987Speter rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 40917987Speter} 4101556Srgrimesint seqno; 4111556Srgrimes 4121556Srgrimesint 4131556Srgrimesrtioctl(action, ort) 4141556Srgrimes int action; 4151556Srgrimes struct rtuentry *ort; 4161556Srgrimes{ 4171556Srgrimes#ifndef RTM_ADD 4181556Srgrimes if (install == 0) 4191556Srgrimes return (errno = 0); 4201556Srgrimes 4211556Srgrimes ort->rtu_rtflags = ort->rtu_flags; 4221556Srgrimes 4231556Srgrimes switch (action) { 4241556Srgrimes 42590111Simp case ADD: 42690111Simp return (ioctl(s, SIOCADDRT, (char *)ort)); 4271556Srgrimes 4281556Srgrimes case DELETE: 4291556Srgrimes return (ioctl(s, SIOCDELRT, (char *)ort)); 4301556Srgrimes 4311556Srgrimes default: 4321556Srgrimes return (-1); 4331556Srgrimes } 4341556Srgrimes#else /* RTM_ADD */ 4351556Srgrimes struct { 4361556Srgrimes struct rt_msghdr w_rtm; 4371556Srgrimes struct sockaddr w_dst; 4381556Srgrimes struct sockaddr w_gate; 4391556Srgrimes struct sockaddr_ipx w_netmask; 4401556Srgrimes } w; 4411556Srgrimes#define rtm w.w_rtm 4421556Srgrimes 4431556Srgrimes bzero((char *)&w, sizeof(w)); 4441556Srgrimes rtm.rtm_msglen = sizeof(w); 4451556Srgrimes rtm.rtm_version = RTM_VERSION; 4461556Srgrimes rtm.rtm_type = (action == ADD ? RTM_ADD : 4471556Srgrimes (action == DELETE ? RTM_DELETE : RTM_CHANGE)); 4481556Srgrimes rtm.rtm_flags = ort->rtu_flags; 4491556Srgrimes rtm.rtm_seq = ++seqno; 4501556Srgrimes rtm.rtm_addrs = RTA_DST|RTA_GATEWAY; 4511556Srgrimes bcopy((char *)&ort->rtu_dst, (char *)&w.w_dst, sizeof(w.w_dst)); 4521556Srgrimes bcopy((char *)&ort->rtu_router, (char *)&w.w_gate, sizeof(w.w_gate)); 4531556Srgrimes w.w_gate.sa_family = w.w_dst.sa_family = AF_IPX; 4541556Srgrimes w.w_gate.sa_len = w.w_dst.sa_len = sizeof(w.w_dst); 4551556Srgrimes if (rtm.rtm_flags & RTF_HOST) { 4561556Srgrimes rtm.rtm_msglen -= sizeof(w.w_netmask); 4571556Srgrimes } else { 4581556Srgrimes rtm.rtm_addrs |= RTA_NETMASK; 4591556Srgrimes w.w_netmask = ipx_netmask; 4601556Srgrimes rtm.rtm_msglen -= sizeof(w.w_netmask) - ipx_netmask.sipx_len; 4611556Srgrimes } 4621556Srgrimes errno = 0; 4631556Srgrimes return write(r, (char *)&w, rtm.rtm_msglen); 46490111Simp#endif /* RTM_ADD */ 46590111Simp} 4661556Srgrimes 4671556Srgrimes