xref: /csrg-svn/sbin/routed/tables.c (revision 16128)
19020Ssam #ifndef lint
2*16128Skarels static char sccsid[] = "@(#)tables.c	4.5 (Berkeley) 03/07/84";
39020Ssam #endif
49020Ssam 
59020Ssam /*
69020Ssam  * Routing Table Management Daemon
79020Ssam  */
810245Ssam #include "defs.h"
99020Ssam #include <sys/ioctl.h>
109020Ssam #include <errno.h>
119020Ssam 
129020Ssam #ifndef DEBUG
139020Ssam #define	DEBUG	0
149020Ssam #endif
159020Ssam 
169020Ssam int	install = !DEBUG;		/* if 1 call kernel */
179020Ssam 
189020Ssam /*
199020Ssam  * Lookup dst in the tables for an exact match.
209020Ssam  */
219020Ssam struct rt_entry *
229020Ssam rtlookup(dst)
239020Ssam 	struct sockaddr *dst;
249020Ssam {
259020Ssam 	register struct rt_entry *rt;
269020Ssam 	register struct rthash *rh;
27*16128Skarels 	register u_int hash;
289020Ssam 	struct afhash h;
299020Ssam 	int doinghost = 1;
309020Ssam 
319020Ssam 	if (dst->sa_family >= AF_MAX)
329020Ssam 		return (0);
339020Ssam 	(*afswitch[dst->sa_family].af_hash)(dst, &h);
349020Ssam 	hash = h.afh_hosthash;
359020Ssam 	rh = &hosthash[hash % ROUTEHASHSIZ];
369020Ssam again:
379020Ssam 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
389020Ssam 		if (rt->rt_hash != hash)
399020Ssam 			continue;
409020Ssam 		if (equal(&rt->rt_dst, dst))
419020Ssam 			return (rt);
429020Ssam 	}
439020Ssam 	if (doinghost) {
449020Ssam 		doinghost = 0;
459020Ssam 		hash = h.afh_nethash;
469020Ssam 		rh = &nethash[hash % ROUTEHASHSIZ];
479020Ssam 		goto again;
489020Ssam 	}
499020Ssam 	return (0);
509020Ssam }
519020Ssam 
529020Ssam /*
539020Ssam  * Find a route to dst as the kernel would.
549020Ssam  */
559020Ssam struct rt_entry *
569020Ssam rtfind(dst)
579020Ssam 	struct sockaddr *dst;
589020Ssam {
599020Ssam 	register struct rt_entry *rt;
609020Ssam 	register struct rthash *rh;
61*16128Skarels 	register u_int hash;
629020Ssam 	struct afhash h;
639020Ssam 	int af = dst->sa_family;
649020Ssam 	int doinghost = 1, (*match)();
659020Ssam 
669020Ssam 	if (af >= AF_MAX)
679020Ssam 		return (0);
689020Ssam 	(*afswitch[af].af_hash)(dst, &h);
699020Ssam 	hash = h.afh_hosthash;
709020Ssam 	rh = &hosthash[hash % ROUTEHASHSIZ];
719020Ssam 
729020Ssam again:
739020Ssam 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
749020Ssam 		if (rt->rt_hash != hash)
759020Ssam 			continue;
769020Ssam 		if (doinghost) {
779020Ssam 			if (equal(&rt->rt_dst, dst))
789020Ssam 				return (rt);
799020Ssam 		} else {
809020Ssam 			if (rt->rt_dst.sa_family == af &&
819020Ssam 			    (*match)(&rt->rt_dst, dst))
829020Ssam 				return (rt);
839020Ssam 		}
849020Ssam 	}
859020Ssam 	if (doinghost) {
869020Ssam 		doinghost = 0;
879020Ssam 		hash = h.afh_nethash;
889020Ssam 		rh = &nethash[hash % ROUTEHASHSIZ];
899020Ssam 		match = afswitch[af].af_netmatch;
909020Ssam 		goto again;
919020Ssam 	}
929020Ssam 	return (0);
939020Ssam }
949020Ssam 
959020Ssam rtadd(dst, gate, metric, state)
969020Ssam 	struct sockaddr *dst, *gate;
979020Ssam 	int metric, state;
989020Ssam {
999020Ssam 	struct afhash h;
1009020Ssam 	register struct rt_entry *rt;
1019020Ssam 	struct rthash *rh;
102*16128Skarels 	int af = dst->sa_family, flags;
103*16128Skarels 	u_int hash;
1049020Ssam 
1059020Ssam 	if (af >= AF_MAX)
1069020Ssam 		return;
1079020Ssam 	(*afswitch[af].af_hash)(dst, &h);
108*16128Skarels 	flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
1099020Ssam 	if (flags & RTF_HOST) {
1109020Ssam 		hash = h.afh_hosthash;
1119020Ssam 		rh = &hosthash[hash % ROUTEHASHSIZ];
1129020Ssam 	} else {
1139020Ssam 		hash = h.afh_nethash;
1149020Ssam 		rh = &nethash[hash % ROUTEHASHSIZ];
1159020Ssam 	}
1169020Ssam 	rt = (struct rt_entry *)malloc(sizeof (*rt));
1179020Ssam 	if (rt == 0)
1189020Ssam 		return;
1199020Ssam 	rt->rt_hash = hash;
1209020Ssam 	rt->rt_dst = *dst;
1219020Ssam 	rt->rt_router = *gate;
1229020Ssam 	rt->rt_metric = metric;
1239020Ssam 	rt->rt_timer = 0;
1249020Ssam 	rt->rt_flags = RTF_UP | flags;
1259020Ssam 	rt->rt_state = state | RTS_CHANGED;
1269020Ssam 	rt->rt_ifp = if_ifwithnet(&rt->rt_router);
1279020Ssam 	if (metric)
1289020Ssam 		rt->rt_flags |= RTF_GATEWAY;
1299020Ssam 	insque(rt, rh);
1309020Ssam 	TRACE_ACTION(ADD, rt);
13115098Ssam 	/*
13215098Ssam 	 * If the ioctl fails because the gateway is unreachable
13315098Ssam 	 * from this host, discard the entry.  This should only
13415098Ssam 	 * occur because of an incorrect entry in /etc/gateways.
13515098Ssam 	 */
13615098Ssam 	if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
1379020Ssam 		perror("SIOCADDRT");
13815098Ssam 		if (errno == ENETUNREACH) {
13915098Ssam 			TRACE_ACTION(DELETE, rt);
14015098Ssam 			remque(rt);
14115098Ssam 			free((char *)rt);
14215098Ssam 		}
14315098Ssam 	}
1449020Ssam }
1459020Ssam 
1469020Ssam rtchange(rt, gate, metric)
1479020Ssam 	struct rt_entry *rt;
1489020Ssam 	struct sockaddr *gate;
1499020Ssam 	short metric;
1509020Ssam {
1519020Ssam 	int doioctl = 0, metricchanged = 0;
1529020Ssam 	struct rtentry oldroute;
1539020Ssam 
1549020Ssam 	if (!equal(&rt->rt_router, gate))
1559020Ssam 		doioctl++;
1569020Ssam 	if (metric != rt->rt_metric) {
1579020Ssam 		metricchanged++;
1589020Ssam 		rt->rt_metric = metric;
1599020Ssam 	}
1609020Ssam 	if (doioctl || metricchanged) {
1619020Ssam 		TRACE_ACTION(CHANGE, rt);
1629020Ssam 		rt->rt_state |= RTS_CHANGED;
1639020Ssam 	}
1649020Ssam 	if (doioctl) {
1659020Ssam 		oldroute = rt->rt_rt;
1669020Ssam 		rt->rt_router = *gate;
1679020Ssam 		if (install) {
1689020Ssam 			if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
1699020Ssam 				perror("SIOCADDRT");
1709020Ssam 			if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
1719020Ssam 				perror("SIOCDELRT");
1729020Ssam 		}
1739020Ssam 	}
1749020Ssam }
1759020Ssam 
1769020Ssam rtdelete(rt)
1779020Ssam 	struct rt_entry *rt;
1789020Ssam {
17915098Ssam 
1809020Ssam 	TRACE_ACTION(DELETE, rt);
1819020Ssam 	if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
1829020Ssam 		perror("SIOCDELRT");
1839020Ssam 	remque(rt);
1849020Ssam 	free((char *)rt);
1859020Ssam }
1869020Ssam 
1879020Ssam rtinit()
1889020Ssam {
1899020Ssam 	register struct rthash *rh;
1909020Ssam 
1919020Ssam 	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
1929020Ssam 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
1939020Ssam 	for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
1949020Ssam 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
1959020Ssam }
196