xref: /csrg-svn/sbin/routed/tables.c (revision 15098)
19020Ssam #ifndef lint
2*15098Ssam static char sccsid[] = "@(#)tables.c	4.4 (Berkeley) 09/25/83";
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;
279020Ssam 	register 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;
619020Ssam 	register 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;
1029020Ssam 	int af = dst->sa_family, flags, hash;
1039020Ssam 
1049020Ssam 	if (af >= AF_MAX)
1059020Ssam 		return;
1069020Ssam 	(*afswitch[af].af_hash)(dst, &h);
1079020Ssam 	flags = (*afswitch[af].af_checkhost)(dst) ? RTF_HOST : 0;
1089020Ssam 	if (flags & RTF_HOST) {
1099020Ssam 		hash = h.afh_hosthash;
1109020Ssam 		rh = &hosthash[hash % ROUTEHASHSIZ];
1119020Ssam 	} else {
1129020Ssam 		hash = h.afh_nethash;
1139020Ssam 		rh = &nethash[hash % ROUTEHASHSIZ];
1149020Ssam 	}
1159020Ssam 	rt = (struct rt_entry *)malloc(sizeof (*rt));
1169020Ssam 	if (rt == 0)
1179020Ssam 		return;
1189020Ssam 	rt->rt_hash = hash;
1199020Ssam 	rt->rt_dst = *dst;
1209020Ssam 	rt->rt_router = *gate;
1219020Ssam 	rt->rt_metric = metric;
1229020Ssam 	rt->rt_timer = 0;
1239020Ssam 	rt->rt_flags = RTF_UP | flags;
1249020Ssam 	rt->rt_state = state | RTS_CHANGED;
1259020Ssam 	rt->rt_ifp = if_ifwithnet(&rt->rt_router);
1269020Ssam 	if (metric)
1279020Ssam 		rt->rt_flags |= RTF_GATEWAY;
1289020Ssam 	insque(rt, rh);
1299020Ssam 	TRACE_ACTION(ADD, rt);
130*15098Ssam 	/*
131*15098Ssam 	 * If the ioctl fails because the gateway is unreachable
132*15098Ssam 	 * from this host, discard the entry.  This should only
133*15098Ssam 	 * occur because of an incorrect entry in /etc/gateways.
134*15098Ssam 	 */
135*15098Ssam 	if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
1369020Ssam 		perror("SIOCADDRT");
137*15098Ssam 		if (errno == ENETUNREACH) {
138*15098Ssam 			TRACE_ACTION(DELETE, rt);
139*15098Ssam 			remque(rt);
140*15098Ssam 			free((char *)rt);
141*15098Ssam 		}
142*15098Ssam 	}
1439020Ssam }
1449020Ssam 
1459020Ssam rtchange(rt, gate, metric)
1469020Ssam 	struct rt_entry *rt;
1479020Ssam 	struct sockaddr *gate;
1489020Ssam 	short metric;
1499020Ssam {
1509020Ssam 	int doioctl = 0, metricchanged = 0;
1519020Ssam 	struct rtentry oldroute;
1529020Ssam 
1539020Ssam 	if (!equal(&rt->rt_router, gate))
1549020Ssam 		doioctl++;
1559020Ssam 	if (metric != rt->rt_metric) {
1569020Ssam 		metricchanged++;
1579020Ssam 		rt->rt_metric = metric;
1589020Ssam 	}
1599020Ssam 	if (doioctl || metricchanged) {
1609020Ssam 		TRACE_ACTION(CHANGE, rt);
1619020Ssam 		rt->rt_state |= RTS_CHANGED;
1629020Ssam 	}
1639020Ssam 	if (doioctl) {
1649020Ssam 		oldroute = rt->rt_rt;
1659020Ssam 		rt->rt_router = *gate;
1669020Ssam 		if (install) {
1679020Ssam 			if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
1689020Ssam 				perror("SIOCADDRT");
1699020Ssam 			if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
1709020Ssam 				perror("SIOCDELRT");
1719020Ssam 		}
1729020Ssam 	}
1739020Ssam }
1749020Ssam 
1759020Ssam rtdelete(rt)
1769020Ssam 	struct rt_entry *rt;
1779020Ssam {
178*15098Ssam 
1799020Ssam 	TRACE_ACTION(DELETE, rt);
1809020Ssam 	if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
1819020Ssam 		perror("SIOCDELRT");
1829020Ssam 	remque(rt);
1839020Ssam 	free((char *)rt);
1849020Ssam }
1859020Ssam 
1869020Ssam rtinit()
1879020Ssam {
1889020Ssam 	register struct rthash *rh;
1899020Ssam 
1909020Ssam 	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
1919020Ssam 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
1929020Ssam 	for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
1939020Ssam 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
1949020Ssam }
195