xref: /csrg-svn/sbin/XNSrouted/tables.c (revision 24318)
124313Ssklower #ifndef lint
224313Ssklower static char rcsid[] = "$Header$";
324313Ssklower #endif
424313Ssklower 
524313Ssklower /*
624313Ssklower  * Routing Table Management Daemon
724313Ssklower  */
824313Ssklower #include "defs.h"
924313Ssklower #include <sys/ioctl.h>
1024313Ssklower #include <errno.h>
1124313Ssklower 
1224313Ssklower #ifndef DEBUG
1324313Ssklower #define	DEBUG	0
1424313Ssklower #endif
1524313Ssklower 
1624313Ssklower int	install = !DEBUG;		/* if 1 call kernel */
17*24318Ssklower int	delete = 1;
1824313Ssklower /*
1924313Ssklower  * Lookup dst in the tables for an exact match.
2024313Ssklower  */
2124313Ssklower struct rt_entry *
2224313Ssklower rtlookup(dst)
2324313Ssklower 	struct sockaddr *dst;
2424313Ssklower {
2524313Ssklower 	register struct rt_entry *rt;
2624313Ssklower 	register struct rthash *rh;
2724313Ssklower 	register u_int hash;
2824313Ssklower 	struct afhash h;
2924313Ssklower 	int doinghost = 1;
3024313Ssklower 
3124313Ssklower 	if (dst->sa_family >= AF_MAX)
3224313Ssklower 		return (0);
3324313Ssklower 	(*afswitch[dst->sa_family].af_hash)(dst, &h);
3424313Ssklower 	hash = h.afh_hosthash;
3524313Ssklower 	rh = &hosthash[hash & ROUTEHASHMASK];
3624313Ssklower again:
3724313Ssklower 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
3824313Ssklower 		if (rt->rt_hash != hash)
3924313Ssklower 			continue;
4024313Ssklower 		if (equal(&rt->rt_dst, dst))
4124313Ssklower 			return (rt);
4224313Ssklower 	}
4324313Ssklower 	if (doinghost) {
4424313Ssklower 		doinghost = 0;
4524313Ssklower 		hash = h.afh_nethash;
4624313Ssklower 		rh = &nethash[hash & ROUTEHASHMASK];
4724313Ssklower 		goto again;
4824313Ssklower 	}
4924313Ssklower 	return (0);
5024313Ssklower }
5124313Ssklower 
5224313Ssklower /*
5324313Ssklower  * Find a route to dst as the kernel would.
5424313Ssklower  */
5524313Ssklower struct rt_entry *
5624313Ssklower rtfind(dst)
5724313Ssklower 	struct sockaddr *dst;
5824313Ssklower {
5924313Ssklower 	register struct rt_entry *rt;
6024313Ssklower 	register struct rthash *rh;
6124313Ssklower 	register u_int hash;
6224313Ssklower 	struct afhash h;
6324313Ssklower 	int af = dst->sa_family;
6424313Ssklower 	int doinghost = 1, (*match)();
6524313Ssklower 
6624313Ssklower 	if (af >= AF_MAX)
6724313Ssklower 		return (0);
6824313Ssklower 	(*afswitch[af].af_hash)(dst, &h);
6924313Ssklower 	hash = h.afh_hosthash;
7024313Ssklower 	rh = &hosthash[hash & ROUTEHASHMASK];
7124313Ssklower 
7224313Ssklower again:
7324313Ssklower 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
7424313Ssklower 		if (rt->rt_hash != hash)
7524313Ssklower 			continue;
7624313Ssklower 		if (doinghost) {
7724313Ssklower 			if (equal(&rt->rt_dst, dst))
7824313Ssklower 				return (rt);
7924313Ssklower 		}
80*24318Ssklower 		if (rt->rt_dst.sa_family == af &&
81*24318Ssklower 		    (*match)(&rt->rt_dst, dst))
82*24318Ssklower 			return (rt);
8324313Ssklower 	}
8424313Ssklower 	if (doinghost) {
8524313Ssklower 		doinghost = 0;
8624313Ssklower 		hash = h.afh_nethash;
8724313Ssklower 		rh = &nethash[hash & ROUTEHASHMASK];
8824313Ssklower 		match = afswitch[af].af_netmatch;
8924313Ssklower 		goto again;
9024313Ssklower 	}
9124313Ssklower 	return (0);
9224313Ssklower }
9324313Ssklower 
9424313Ssklower rtadd(dst, gate, metric, state)
9524313Ssklower 	struct sockaddr *dst, *gate;
9624313Ssklower 	int metric, state;
9724313Ssklower {
9824313Ssklower 	struct afhash h;
9924313Ssklower 	register struct rt_entry *rt;
10024313Ssklower 	struct rthash *rh;
10124313Ssklower 	int af = dst->sa_family, flags;
10224313Ssklower 	u_int hash;
10324313Ssklower 
10424313Ssklower 	if (af >= AF_MAX)
10524313Ssklower 		return;
10624313Ssklower 	(*afswitch[af].af_hash)(dst, &h);
10724313Ssklower 	flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
10824313Ssklower 	if (flags & RTF_HOST) {
10924313Ssklower 		hash = h.afh_hosthash;
11024313Ssklower 		rh = &hosthash[hash & ROUTEHASHMASK];
11124313Ssklower 	} else {
11224313Ssklower 		hash = h.afh_nethash;
11324313Ssklower 		rh = &nethash[hash & ROUTEHASHMASK];
11424313Ssklower 	}
11524313Ssklower 	rt = (struct rt_entry *)malloc(sizeof (*rt));
11624313Ssklower 	if (rt == 0)
11724313Ssklower 		return;
11824313Ssklower 	rt->rt_hash = hash;
11924313Ssklower 	rt->rt_dst = *dst;
12024313Ssklower 	rt->rt_router = *gate;
12124313Ssklower 	rt->rt_metric = metric;
12224313Ssklower 	rt->rt_timer = 0;
12324313Ssklower 	rt->rt_flags = RTF_UP | flags;
12424313Ssklower 	rt->rt_state = state | RTS_CHANGED;
12524313Ssklower 	rt->rt_ifp = if_ifwithnet(&rt->rt_router);
12624313Ssklower 	if (metric)
12724313Ssklower 		rt->rt_flags |= RTF_GATEWAY;
12824313Ssklower 	insque(rt, rh);
12924313Ssklower 	TRACE_ACTION(ADD, rt);
13024313Ssklower 	/*
13124313Ssklower 	 * If the ioctl fails because the gateway is unreachable
13224313Ssklower 	 * from this host, discard the entry.  This should only
13324313Ssklower 	 * occur because of an incorrect entry in /etc/gateways.
13424313Ssklower 	 */
13524313Ssklower 	if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
13624313Ssklower 		perror("SIOCADDRT");
13724313Ssklower 		if (errno == ENETUNREACH) {
13824313Ssklower 			TRACE_ACTION(DELETE, rt);
13924313Ssklower 			remque(rt);
14024313Ssklower 			free((char *)rt);
14124313Ssklower 		}
14224313Ssklower 	}
14324313Ssklower }
14424313Ssklower 
14524313Ssklower rtchange(rt, gate, metric)
14624313Ssklower 	struct rt_entry *rt;
14724313Ssklower 	struct sockaddr *gate;
14824313Ssklower 	short metric;
14924313Ssklower {
15024313Ssklower 	int doioctl = 0, metricchanged = 0;
15124313Ssklower 	struct rtentry oldroute;
15224313Ssklower 
15324313Ssklower 	if (!equal(&rt->rt_router, gate))
15424313Ssklower 		doioctl++;
15524313Ssklower 	if (metric != rt->rt_metric)
15624313Ssklower 		metricchanged++;
15724313Ssklower 	if (doioctl || metricchanged) {
15824313Ssklower 		TRACE_ACTION(CHANGE FROM, rt);
15924313Ssklower 		if (doioctl) {
16024313Ssklower 			oldroute = rt->rt_rt;
16124313Ssklower 			rt->rt_router = *gate;
16224313Ssklower 		}
16324313Ssklower 		rt->rt_metric = metric;
16424313Ssklower 		rt->rt_state &= ~RTS_INTERFACE;
16524313Ssklower 		if (metric)
16624313Ssklower 			rt->rt_state |= RTF_GATEWAY;
16724313Ssklower 		rt->rt_state |= RTS_CHANGED;
16824313Ssklower 		TRACE_ACTION(CHANGE TO, rt);
16924313Ssklower 	}
17024313Ssklower 	if (doioctl && install) {
17124313Ssklower 		if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
17224313Ssklower 			perror("SIOCADDRT");
173*24318Ssklower 		if (delete)
17424313Ssklower 		if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
17524313Ssklower 			perror("SIOCDELRT");
17624313Ssklower 	}
17724313Ssklower }
17824313Ssklower 
17924313Ssklower rtdelete(rt)
18024313Ssklower 	struct rt_entry *rt;
18124313Ssklower {
18224313Ssklower 
18324313Ssklower 	TRACE_ACTION(DELETE, rt);
184*24318Ssklower 	if (install && delete && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
18524313Ssklower 		perror("SIOCDELRT");
18624313Ssklower 	remque(rt);
18724313Ssklower 	free((char *)rt);
18824313Ssklower }
18924313Ssklower 
19024313Ssklower rtinit()
19124313Ssklower {
19224313Ssklower 	register struct rthash *rh;
19324313Ssklower 
19424313Ssklower 	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
19524313Ssklower 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
19624313Ssklower 	for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
19724313Ssklower 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
19824313Ssklower }
199