xref: /csrg-svn/sbin/XNSrouted/tables.c (revision 30350)
124323Ssklower /*
224323Ssklower  * Copyright (c) 1985 Regents of the University of California.
324323Ssklower  * All rights reserved.  The Berkeley software License Agreement
424323Ssklower  * specifies the terms and conditions for redistribution.
524323Ssklower  *
624323Ssklower  */
724323Ssklower 
824323Ssklower 
924313Ssklower #ifndef lint
10*30350Skarels static char sccsid[] = "@(#)tables.c	5.6 (Berkeley) 12/30/86";
1124323Ssklower #endif not lint
1224313Ssklower 
1324313Ssklower /*
1424313Ssklower  * Routing Table Management Daemon
1524313Ssklower  */
1624313Ssklower #include "defs.h"
1724313Ssklower #include <sys/ioctl.h>
1824313Ssklower #include <errno.h>
1924313Ssklower 
2024313Ssklower #ifndef DEBUG
2124313Ssklower #define	DEBUG	0
2224313Ssklower #endif
2324313Ssklower 
24*30350Skarels extern	char *xns_ntoa();
25*30350Skarels 
2624313Ssklower int	install = !DEBUG;		/* if 1 call kernel */
2724318Ssklower int	delete = 1;
2824313Ssklower /*
2924313Ssklower  * Lookup dst in the tables for an exact match.
3024313Ssklower  */
3124313Ssklower struct rt_entry *
3224313Ssklower rtlookup(dst)
3324313Ssklower 	struct sockaddr *dst;
3424313Ssklower {
3524313Ssklower 	register struct rt_entry *rt;
3624313Ssklower 	register struct rthash *rh;
3724313Ssklower 	register u_int hash;
3824313Ssklower 	struct afhash h;
3924313Ssklower 	int doinghost = 1;
4024313Ssklower 
4124313Ssklower 	if (dst->sa_family >= AF_MAX)
4224313Ssklower 		return (0);
4324313Ssklower 	(*afswitch[dst->sa_family].af_hash)(dst, &h);
4424313Ssklower 	hash = h.afh_hosthash;
4524313Ssklower 	rh = &hosthash[hash & ROUTEHASHMASK];
4624313Ssklower again:
4724313Ssklower 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
4824313Ssklower 		if (rt->rt_hash != hash)
4924313Ssklower 			continue;
5024313Ssklower 		if (equal(&rt->rt_dst, dst))
5124313Ssklower 			return (rt);
5224313Ssklower 	}
5324313Ssklower 	if (doinghost) {
5424313Ssklower 		doinghost = 0;
5524313Ssklower 		hash = h.afh_nethash;
5624313Ssklower 		rh = &nethash[hash & ROUTEHASHMASK];
5724313Ssklower 		goto again;
5824313Ssklower 	}
5924313Ssklower 	return (0);
6024313Ssklower }
6124313Ssklower 
6224313Ssklower /*
6324313Ssklower  * Find a route to dst as the kernel would.
6424313Ssklower  */
6524313Ssklower struct rt_entry *
6624313Ssklower rtfind(dst)
6724313Ssklower 	struct sockaddr *dst;
6824313Ssklower {
6924313Ssklower 	register struct rt_entry *rt;
7024313Ssklower 	register struct rthash *rh;
7124313Ssklower 	register u_int hash;
7224313Ssklower 	struct afhash h;
7324313Ssklower 	int af = dst->sa_family;
7424313Ssklower 	int doinghost = 1, (*match)();
7524313Ssklower 
7624313Ssklower 	if (af >= AF_MAX)
7724313Ssklower 		return (0);
7824313Ssklower 	(*afswitch[af].af_hash)(dst, &h);
7924313Ssklower 	hash = h.afh_hosthash;
8024313Ssklower 	rh = &hosthash[hash & ROUTEHASHMASK];
8124313Ssklower 
8224313Ssklower again:
8324313Ssklower 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
8424313Ssklower 		if (rt->rt_hash != hash)
8524313Ssklower 			continue;
8624313Ssklower 		if (doinghost) {
8724313Ssklower 			if (equal(&rt->rt_dst, dst))
8824313Ssklower 				return (rt);
8924323Ssklower 		} else {
9024323Ssklower 			if (rt->rt_dst.sa_family == af &&
9124323Ssklower 			    (*match)(&rt->rt_dst, dst))
9224323Ssklower 				return (rt);
9324313Ssklower 		}
9424313Ssklower 	}
9524313Ssklower 	if (doinghost) {
9624313Ssklower 		doinghost = 0;
9724313Ssklower 		hash = h.afh_nethash;
9824313Ssklower 		rh = &nethash[hash & ROUTEHASHMASK];
9924313Ssklower 		match = afswitch[af].af_netmatch;
10024313Ssklower 		goto again;
10124313Ssklower 	}
10224313Ssklower 	return (0);
10324313Ssklower }
10424313Ssklower 
10524313Ssklower rtadd(dst, gate, metric, state)
10624313Ssklower 	struct sockaddr *dst, *gate;
10724313Ssklower 	int metric, state;
10824313Ssklower {
10924313Ssklower 	struct afhash h;
11024313Ssklower 	register struct rt_entry *rt;
11124313Ssklower 	struct rthash *rh;
11224313Ssklower 	int af = dst->sa_family, flags;
11324313Ssklower 	u_int hash;
11424313Ssklower 
11524313Ssklower 	if (af >= AF_MAX)
11624313Ssklower 		return;
11724313Ssklower 	(*afswitch[af].af_hash)(dst, &h);
11824313Ssklower 	flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
11924313Ssklower 	if (flags & RTF_HOST) {
12024313Ssklower 		hash = h.afh_hosthash;
12124313Ssklower 		rh = &hosthash[hash & ROUTEHASHMASK];
12224313Ssklower 	} else {
12324313Ssklower 		hash = h.afh_nethash;
12424313Ssklower 		rh = &nethash[hash & ROUTEHASHMASK];
12524313Ssklower 	}
12624313Ssklower 	rt = (struct rt_entry *)malloc(sizeof (*rt));
12724313Ssklower 	if (rt == 0)
12824313Ssklower 		return;
12924313Ssklower 	rt->rt_hash = hash;
13024313Ssklower 	rt->rt_dst = *dst;
13124313Ssklower 	rt->rt_router = *gate;
13224313Ssklower 	rt->rt_metric = metric;
13324313Ssklower 	rt->rt_timer = 0;
13424313Ssklower 	rt->rt_flags = RTF_UP | flags;
13524313Ssklower 	rt->rt_state = state | RTS_CHANGED;
13624313Ssklower 	rt->rt_ifp = if_ifwithnet(&rt->rt_router);
13724313Ssklower 	if (metric)
13824313Ssklower 		rt->rt_flags |= RTF_GATEWAY;
13924313Ssklower 	insque(rt, rh);
14024313Ssklower 	TRACE_ACTION(ADD, rt);
14124313Ssklower 	/*
14224313Ssklower 	 * If the ioctl fails because the gateway is unreachable
14324313Ssklower 	 * from this host, discard the entry.  This should only
14424313Ssklower 	 * occur because of an incorrect entry in /etc/gateways.
14524313Ssklower 	 */
14624313Ssklower 	if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
147*30350Skarels 		if (errno != EEXIST)
148*30350Skarels 			perror("SIOCADDRT");
14924313Ssklower 		if (errno == ENETUNREACH) {
15024313Ssklower 			TRACE_ACTION(DELETE, rt);
15124313Ssklower 			remque(rt);
15224313Ssklower 			free((char *)rt);
15324313Ssklower 		}
15424313Ssklower 	}
15524313Ssklower }
15624313Ssklower 
15724313Ssklower rtchange(rt, gate, metric)
15824313Ssklower 	struct rt_entry *rt;
15924313Ssklower 	struct sockaddr *gate;
16024313Ssklower 	short metric;
16124313Ssklower {
16224313Ssklower 	int doioctl = 0, metricchanged = 0;
16324313Ssklower 	struct rtentry oldroute;
16424313Ssklower 
16524313Ssklower 	if (!equal(&rt->rt_router, gate))
16624313Ssklower 		doioctl++;
16724313Ssklower 	if (metric != rt->rt_metric)
16824313Ssklower 		metricchanged++;
16924313Ssklower 	if (doioctl || metricchanged) {
17024313Ssklower 		TRACE_ACTION(CHANGE FROM, rt);
17124313Ssklower 		if (doioctl) {
17224313Ssklower 			oldroute = rt->rt_rt;
17324313Ssklower 			rt->rt_router = *gate;
17424313Ssklower 		}
17524313Ssklower 		rt->rt_metric = metric;
17626171Ssklower 		if ((rt->rt_state & RTS_INTERFACE) && metric) {
17726171Ssklower 			rt->rt_state &= ~RTS_INTERFACE;
17826171Ssklower 			syslog(LOG_ERR,
17926171Ssklower 				"changing route from interface %s (timed out)",
18026171Ssklower 				rt->rt_ifp->int_name);
18126171Ssklower 		}
18224313Ssklower 		if (metric)
18326171Ssklower 			rt->rt_flags |= RTF_GATEWAY;
18426171Ssklower 		else
18526171Ssklower 			rt->rt_flags &= ~RTF_GATEWAY;
18624313Ssklower 		rt->rt_state |= RTS_CHANGED;
18724313Ssklower 		TRACE_ACTION(CHANGE TO, rt);
18824313Ssklower 	}
18924313Ssklower 	if (doioctl && install) {
19024313Ssklower 		if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
191*30350Skarels 		  syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m",
192*30350Skarels 		   xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr),
193*30350Skarels 		   xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr));
194*30350Skarels 		if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
195*30350Skarels 			perror("SIOCDELRT");
19624313Ssklower 	}
19724313Ssklower }
19824313Ssklower 
19924313Ssklower rtdelete(rt)
20024313Ssklower 	struct rt_entry *rt;
20124313Ssklower {
20224313Ssklower 
20326171Ssklower 	if (rt->rt_state & RTS_INTERFACE) {
20426171Ssklower 		syslog(LOG_ERR, "deleting route to interface %s (timed out)",
20526171Ssklower 			rt->rt_ifp->int_name);
20626171Ssklower 	}
20724313Ssklower 	TRACE_ACTION(DELETE, rt);
20826171Ssklower 	if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
20926171Ssklower 		perror("SIOCDELRT");
21024313Ssklower 	remque(rt);
21124313Ssklower 	free((char *)rt);
21224313Ssklower }
21324313Ssklower 
21424313Ssklower rtinit()
21524313Ssklower {
21624313Ssklower 	register struct rthash *rh;
21724313Ssklower 
21824313Ssklower 	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
21924313Ssklower 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
22024313Ssklower 	for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
22124313Ssklower 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
22224313Ssklower }
223