xref: /csrg-svn/sbin/XNSrouted/tables.c (revision 38688)
124323Ssklower /*
235593Sbostic  * Copyright (c) 1985 The Regents of the University of California.
335593Sbostic  * All rights reserved.
424323Ssklower  *
535593Sbostic  * Redistribution and use in source and binary forms are permitted
635593Sbostic  * provided that the above copyright notice and this paragraph are
735593Sbostic  * duplicated in all such forms and that any documentation,
835593Sbostic  * advertising materials, and other materials related to such
935593Sbostic  * distribution and use acknowledge that the software was developed
1035593Sbostic  * by the University of California, Berkeley.  The name of the
1135593Sbostic  * University may not be used to endorse or promote products derived
1235593Sbostic  * from this software without specific prior written permission.
1335593Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1435593Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1535593Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1624323Ssklower  */
1724323Ssklower 
1824313Ssklower #ifndef lint
19*38688Skarels static char sccsid[] = "@(#)tables.c	5.8 (Berkeley) 08/21/89";
2035593Sbostic #endif /* not lint */
2124313Ssklower 
2224313Ssklower /*
2324313Ssklower  * Routing Table Management Daemon
2424313Ssklower  */
2524313Ssklower #include "defs.h"
2624313Ssklower #include <sys/ioctl.h>
2724313Ssklower #include <errno.h>
2824313Ssklower 
2924313Ssklower #ifndef DEBUG
3024313Ssklower #define	DEBUG	0
3124313Ssklower #endif
3224313Ssklower 
3330350Skarels extern	char *xns_ntoa();
34*38688Skarels #define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));}
3530350Skarels 
3624313Ssklower int	install = !DEBUG;		/* if 1 call kernel */
3724318Ssklower int	delete = 1;
3824313Ssklower /*
3924313Ssklower  * Lookup dst in the tables for an exact match.
4024313Ssklower  */
4124313Ssklower struct rt_entry *
4224313Ssklower rtlookup(dst)
4324313Ssklower 	struct sockaddr *dst;
4424313Ssklower {
4524313Ssklower 	register struct rt_entry *rt;
4624313Ssklower 	register struct rthash *rh;
4724313Ssklower 	register u_int hash;
4824313Ssklower 	struct afhash h;
4924313Ssklower 	int doinghost = 1;
5024313Ssklower 
5124313Ssklower 	if (dst->sa_family >= AF_MAX)
5224313Ssklower 		return (0);
5324313Ssklower 	(*afswitch[dst->sa_family].af_hash)(dst, &h);
5424313Ssklower 	hash = h.afh_hosthash;
5524313Ssklower 	rh = &hosthash[hash & ROUTEHASHMASK];
5624313Ssklower again:
5724313Ssklower 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
5824313Ssklower 		if (rt->rt_hash != hash)
5924313Ssklower 			continue;
6024313Ssklower 		if (equal(&rt->rt_dst, dst))
6124313Ssklower 			return (rt);
6224313Ssklower 	}
6324313Ssklower 	if (doinghost) {
6424313Ssklower 		doinghost = 0;
6524313Ssklower 		hash = h.afh_nethash;
6624313Ssklower 		rh = &nethash[hash & ROUTEHASHMASK];
6724313Ssklower 		goto again;
6824313Ssklower 	}
6924313Ssklower 	return (0);
7024313Ssklower }
7124313Ssklower 
7224313Ssklower /*
7324313Ssklower  * Find a route to dst as the kernel would.
7424313Ssklower  */
7524313Ssklower struct rt_entry *
7624313Ssklower rtfind(dst)
7724313Ssklower 	struct sockaddr *dst;
7824313Ssklower {
7924313Ssklower 	register struct rt_entry *rt;
8024313Ssklower 	register struct rthash *rh;
8124313Ssklower 	register u_int hash;
8224313Ssklower 	struct afhash h;
8324313Ssklower 	int af = dst->sa_family;
8424313Ssklower 	int doinghost = 1, (*match)();
8524313Ssklower 
8624313Ssklower 	if (af >= AF_MAX)
8724313Ssklower 		return (0);
8824313Ssklower 	(*afswitch[af].af_hash)(dst, &h);
8924313Ssklower 	hash = h.afh_hosthash;
9024313Ssklower 	rh = &hosthash[hash & ROUTEHASHMASK];
9124313Ssklower 
9224313Ssklower again:
9324313Ssklower 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
9424313Ssklower 		if (rt->rt_hash != hash)
9524313Ssklower 			continue;
9624313Ssklower 		if (doinghost) {
9724313Ssklower 			if (equal(&rt->rt_dst, dst))
9824313Ssklower 				return (rt);
9924323Ssklower 		} else {
10024323Ssklower 			if (rt->rt_dst.sa_family == af &&
10124323Ssklower 			    (*match)(&rt->rt_dst, dst))
10224323Ssklower 				return (rt);
10324313Ssklower 		}
10424313Ssklower 	}
10524313Ssklower 	if (doinghost) {
10624313Ssklower 		doinghost = 0;
10724313Ssklower 		hash = h.afh_nethash;
10824313Ssklower 		rh = &nethash[hash & ROUTEHASHMASK];
10924313Ssklower 		match = afswitch[af].af_netmatch;
11024313Ssklower 		goto again;
11124313Ssklower 	}
11224313Ssklower 	return (0);
11324313Ssklower }
11424313Ssklower 
11524313Ssklower rtadd(dst, gate, metric, state)
11624313Ssklower 	struct sockaddr *dst, *gate;
11724313Ssklower 	int metric, state;
11824313Ssklower {
11924313Ssklower 	struct afhash h;
12024313Ssklower 	register struct rt_entry *rt;
12124313Ssklower 	struct rthash *rh;
12224313Ssklower 	int af = dst->sa_family, flags;
12324313Ssklower 	u_int hash;
12424313Ssklower 
125*38688Skarels 	FIXLEN(dst);
126*38688Skarels 	FIXLEN(gate);
12724313Ssklower 	if (af >= AF_MAX)
12824313Ssklower 		return;
12924313Ssklower 	(*afswitch[af].af_hash)(dst, &h);
13024313Ssklower 	flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
13124313Ssklower 	if (flags & RTF_HOST) {
13224313Ssklower 		hash = h.afh_hosthash;
13324313Ssklower 		rh = &hosthash[hash & ROUTEHASHMASK];
13424313Ssklower 	} else {
13524313Ssklower 		hash = h.afh_nethash;
13624313Ssklower 		rh = &nethash[hash & ROUTEHASHMASK];
13724313Ssklower 	}
13824313Ssklower 	rt = (struct rt_entry *)malloc(sizeof (*rt));
13924313Ssklower 	if (rt == 0)
14024313Ssklower 		return;
14124313Ssklower 	rt->rt_hash = hash;
14224313Ssklower 	rt->rt_dst = *dst;
14324313Ssklower 	rt->rt_router = *gate;
14424313Ssklower 	rt->rt_metric = metric;
14524313Ssklower 	rt->rt_timer = 0;
14624313Ssklower 	rt->rt_flags = RTF_UP | flags;
14724313Ssklower 	rt->rt_state = state | RTS_CHANGED;
14824313Ssklower 	rt->rt_ifp = if_ifwithnet(&rt->rt_router);
14924313Ssklower 	if (metric)
15024313Ssklower 		rt->rt_flags |= RTF_GATEWAY;
15124313Ssklower 	insque(rt, rh);
15224313Ssklower 	TRACE_ACTION(ADD, rt);
15324313Ssklower 	/*
15424313Ssklower 	 * If the ioctl fails because the gateway is unreachable
15524313Ssklower 	 * from this host, discard the entry.  This should only
15624313Ssklower 	 * occur because of an incorrect entry in /etc/gateways.
15724313Ssklower 	 */
15824313Ssklower 	if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
15930350Skarels 		if (errno != EEXIST)
16030350Skarels 			perror("SIOCADDRT");
16124313Ssklower 		if (errno == ENETUNREACH) {
16224313Ssklower 			TRACE_ACTION(DELETE, rt);
16324313Ssklower 			remque(rt);
16424313Ssklower 			free((char *)rt);
16524313Ssklower 		}
16624313Ssklower 	}
16724313Ssklower }
16824313Ssklower 
16924313Ssklower rtchange(rt, gate, metric)
17024313Ssklower 	struct rt_entry *rt;
17124313Ssklower 	struct sockaddr *gate;
17224313Ssklower 	short metric;
17324313Ssklower {
17424313Ssklower 	int doioctl = 0, metricchanged = 0;
17524313Ssklower 	struct rtentry oldroute;
17624313Ssklower 
177*38688Skarels 	FIXLEN(gate);
17824313Ssklower 	if (!equal(&rt->rt_router, gate))
17924313Ssklower 		doioctl++;
18024313Ssklower 	if (metric != rt->rt_metric)
18124313Ssklower 		metricchanged++;
18224313Ssklower 	if (doioctl || metricchanged) {
18324313Ssklower 		TRACE_ACTION(CHANGE FROM, rt);
18424313Ssklower 		if (doioctl) {
18524313Ssklower 			oldroute = rt->rt_rt;
18624313Ssklower 			rt->rt_router = *gate;
18724313Ssklower 		}
18824313Ssklower 		rt->rt_metric = metric;
18926171Ssklower 		if ((rt->rt_state & RTS_INTERFACE) && metric) {
19026171Ssklower 			rt->rt_state &= ~RTS_INTERFACE;
19126171Ssklower 			syslog(LOG_ERR,
19226171Ssklower 				"changing route from interface %s (timed out)",
19326171Ssklower 				rt->rt_ifp->int_name);
19426171Ssklower 		}
19524313Ssklower 		if (metric)
19626171Ssklower 			rt->rt_flags |= RTF_GATEWAY;
19726171Ssklower 		else
19826171Ssklower 			rt->rt_flags &= ~RTF_GATEWAY;
19924313Ssklower 		rt->rt_state |= RTS_CHANGED;
20024313Ssklower 		TRACE_ACTION(CHANGE TO, rt);
20124313Ssklower 	}
20224313Ssklower 	if (doioctl && install) {
203*38688Skarels #ifndef RTM_ADD
20424313Ssklower 		if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
20530350Skarels 		  syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m",
20630350Skarels 		   xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr),
20730350Skarels 		   xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr));
20830350Skarels 		if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
20930350Skarels 			perror("SIOCDELRT");
210*38688Skarels #else
211*38688Skarels 		if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
212*38688Skarels 			perror("SIOCDELRT");
213*38688Skarels 		if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
214*38688Skarels 		  syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m",
215*38688Skarels 		   xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr),
216*38688Skarels 		   xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr));
217*38688Skarels #endif
21824313Ssklower 	}
21924313Ssklower }
22024313Ssklower 
22124313Ssklower rtdelete(rt)
22224313Ssklower 	struct rt_entry *rt;
22324313Ssklower {
22424313Ssklower 
225*38688Skarels 	struct sockaddr *sa = &(rt->rt_rt.rt_gateway);
226*38688Skarels 	FIXLEN(sa);
227*38688Skarels #undef rt_dst
228*38688Skarels 	sa = &(rt->rt_rt.rt_dst);
229*38688Skarels 	FIXLEN(sa);
23026171Ssklower 	if (rt->rt_state & RTS_INTERFACE) {
23126171Ssklower 		syslog(LOG_ERR, "deleting route to interface %s (timed out)",
23226171Ssklower 			rt->rt_ifp->int_name);
23326171Ssklower 	}
23424313Ssklower 	TRACE_ACTION(DELETE, rt);
23526171Ssklower 	if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
23626171Ssklower 		perror("SIOCDELRT");
23724313Ssklower 	remque(rt);
23824313Ssklower 	free((char *)rt);
23924313Ssklower }
24024313Ssklower 
24124313Ssklower rtinit()
24224313Ssklower {
24324313Ssklower 	register struct rthash *rh;
24424313Ssklower 
24524313Ssklower 	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
24624313Ssklower 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
24724313Ssklower 	for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
24824313Ssklower 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
24924313Ssklower }
250