xref: /csrg-svn/sbin/XNSrouted/tables.c (revision 24313)
1*24313Ssklower #ifndef lint
2*24313Ssklower static char rcsid[] = "$Header$";
3*24313Ssklower #endif
4*24313Ssklower 
5*24313Ssklower /*
6*24313Ssklower  * Routing Table Management Daemon
7*24313Ssklower  */
8*24313Ssklower #include "defs.h"
9*24313Ssklower #include <sys/ioctl.h>
10*24313Ssklower #include <errno.h>
11*24313Ssklower 
12*24313Ssklower #ifndef DEBUG
13*24313Ssklower #define	DEBUG	0
14*24313Ssklower #endif
15*24313Ssklower 
16*24313Ssklower int	install = !DEBUG;		/* if 1 call kernel */
17*24313Ssklower static  int	s;			/* for routing table ioctl's */
18*24313Ssklower /*
19*24313Ssklower  * Lookup dst in the tables for an exact match.
20*24313Ssklower  */
21*24313Ssklower struct rt_entry *
22*24313Ssklower rtlookup(dst)
23*24313Ssklower 	struct sockaddr *dst;
24*24313Ssklower {
25*24313Ssklower 	register struct rt_entry *rt;
26*24313Ssklower 	register struct rthash *rh;
27*24313Ssklower 	register u_int hash;
28*24313Ssklower 	struct afhash h;
29*24313Ssklower 	int doinghost = 1;
30*24313Ssklower 
31*24313Ssklower 	if (dst->sa_family >= AF_MAX)
32*24313Ssklower 		return (0);
33*24313Ssklower 	(*afswitch[dst->sa_family].af_hash)(dst, &h);
34*24313Ssklower 	hash = h.afh_hosthash;
35*24313Ssklower 	rh = &hosthash[hash & ROUTEHASHMASK];
36*24313Ssklower again:
37*24313Ssklower 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
38*24313Ssklower 		if (rt->rt_hash != hash)
39*24313Ssklower 			continue;
40*24313Ssklower 		if (equal(&rt->rt_dst, dst))
41*24313Ssklower 			return (rt);
42*24313Ssklower 	}
43*24313Ssklower 	if (doinghost) {
44*24313Ssklower 		doinghost = 0;
45*24313Ssklower 		hash = h.afh_nethash;
46*24313Ssklower 		rh = &nethash[hash & ROUTEHASHMASK];
47*24313Ssklower 		goto again;
48*24313Ssklower 	}
49*24313Ssklower 	return (0);
50*24313Ssklower }
51*24313Ssklower 
52*24313Ssklower /*
53*24313Ssklower  * Find a route to dst as the kernel would.
54*24313Ssklower  */
55*24313Ssklower struct rt_entry *
56*24313Ssklower rtfind(dst)
57*24313Ssklower 	struct sockaddr *dst;
58*24313Ssklower {
59*24313Ssklower 	register struct rt_entry *rt;
60*24313Ssklower 	register struct rthash *rh;
61*24313Ssklower 	register u_int hash;
62*24313Ssklower 	struct afhash h;
63*24313Ssklower 	int af = dst->sa_family;
64*24313Ssklower 	int doinghost = 1, (*match)();
65*24313Ssklower 
66*24313Ssklower 	if (af >= AF_MAX)
67*24313Ssklower 		return (0);
68*24313Ssklower 	(*afswitch[af].af_hash)(dst, &h);
69*24313Ssklower 	hash = h.afh_hosthash;
70*24313Ssklower 	rh = &hosthash[hash & ROUTEHASHMASK];
71*24313Ssklower 
72*24313Ssklower again:
73*24313Ssklower 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
74*24313Ssklower 		if (rt->rt_hash != hash)
75*24313Ssklower 			continue;
76*24313Ssklower 		if (doinghost) {
77*24313Ssklower 			if (equal(&rt->rt_dst, dst))
78*24313Ssklower 				return (rt);
79*24313Ssklower 		} else {
80*24313Ssklower 			if (rt->rt_dst.sa_family == af &&
81*24313Ssklower 			    (*match)(&rt->rt_dst, dst))
82*24313Ssklower 				return (rt);
83*24313Ssklower 		}
84*24313Ssklower 	}
85*24313Ssklower 	if (doinghost) {
86*24313Ssklower 		doinghost = 0;
87*24313Ssklower 		hash = h.afh_nethash;
88*24313Ssklower 		rh = &nethash[hash & ROUTEHASHMASK];
89*24313Ssklower 		match = afswitch[af].af_netmatch;
90*24313Ssklower 		goto again;
91*24313Ssklower 	}
92*24313Ssklower 	return (0);
93*24313Ssklower }
94*24313Ssklower 
95*24313Ssklower rtadd(dst, gate, metric, state)
96*24313Ssklower 	struct sockaddr *dst, *gate;
97*24313Ssklower 	int metric, state;
98*24313Ssklower {
99*24313Ssklower 	struct afhash h;
100*24313Ssklower 	register struct rt_entry *rt;
101*24313Ssklower 	struct rthash *rh;
102*24313Ssklower 	int af = dst->sa_family, flags;
103*24313Ssklower 	u_int hash;
104*24313Ssklower 
105*24313Ssklower 	if (af >= AF_MAX)
106*24313Ssklower 		return;
107*24313Ssklower 	(*afswitch[af].af_hash)(dst, &h);
108*24313Ssklower 	flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
109*24313Ssklower 	if (flags & RTF_HOST) {
110*24313Ssklower 		hash = h.afh_hosthash;
111*24313Ssklower 		rh = &hosthash[hash & ROUTEHASHMASK];
112*24313Ssklower 	} else {
113*24313Ssklower 		hash = h.afh_nethash;
114*24313Ssklower 		rh = &nethash[hash & ROUTEHASHMASK];
115*24313Ssklower 	}
116*24313Ssklower 	rt = (struct rt_entry *)malloc(sizeof (*rt));
117*24313Ssklower 	if (rt == 0)
118*24313Ssklower 		return;
119*24313Ssklower 	rt->rt_hash = hash;
120*24313Ssklower 	rt->rt_dst = *dst;
121*24313Ssklower 	rt->rt_router = *gate;
122*24313Ssklower 	rt->rt_metric = metric;
123*24313Ssklower 	rt->rt_timer = 0;
124*24313Ssklower 	rt->rt_flags = RTF_UP | flags;
125*24313Ssklower 	rt->rt_state = state | RTS_CHANGED;
126*24313Ssklower 	rt->rt_ifp = if_ifwithnet(&rt->rt_router);
127*24313Ssklower 	if (metric)
128*24313Ssklower 		rt->rt_flags |= RTF_GATEWAY;
129*24313Ssklower 	insque(rt, rh);
130*24313Ssklower 	TRACE_ACTION(ADD, rt);
131*24313Ssklower 	/*
132*24313Ssklower 	 * If the ioctl fails because the gateway is unreachable
133*24313Ssklower 	 * from this host, discard the entry.  This should only
134*24313Ssklower 	 * occur because of an incorrect entry in /etc/gateways.
135*24313Ssklower 	 */
136*24313Ssklower 	if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
137*24313Ssklower 		perror("SIOCADDRT");
138*24313Ssklower 		if (errno == ENETUNREACH) {
139*24313Ssklower 			TRACE_ACTION(DELETE, rt);
140*24313Ssklower 			remque(rt);
141*24313Ssklower 			free((char *)rt);
142*24313Ssklower 		}
143*24313Ssklower 	}
144*24313Ssklower }
145*24313Ssklower 
146*24313Ssklower rtchange(rt, gate, metric)
147*24313Ssklower 	struct rt_entry *rt;
148*24313Ssklower 	struct sockaddr *gate;
149*24313Ssklower 	short metric;
150*24313Ssklower {
151*24313Ssklower 	int doioctl = 0, metricchanged = 0;
152*24313Ssklower 	struct rtentry oldroute;
153*24313Ssklower 
154*24313Ssklower 	if (!equal(&rt->rt_router, gate))
155*24313Ssklower 		doioctl++;
156*24313Ssklower 	if (metric != rt->rt_metric)
157*24313Ssklower 		metricchanged++;
158*24313Ssklower 	if (doioctl || metricchanged) {
159*24313Ssklower 		TRACE_ACTION(CHANGE FROM, rt);
160*24313Ssklower 		if (doioctl) {
161*24313Ssklower 			oldroute = rt->rt_rt;
162*24313Ssklower 			rt->rt_router = *gate;
163*24313Ssklower 		}
164*24313Ssklower 		rt->rt_metric = metric;
165*24313Ssklower 		rt->rt_state &= ~RTS_INTERFACE;
166*24313Ssklower 		if (metric)
167*24313Ssklower 			rt->rt_state |= RTF_GATEWAY;
168*24313Ssklower 		rt->rt_state |= RTS_CHANGED;
169*24313Ssklower 		TRACE_ACTION(CHANGE TO, rt);
170*24313Ssklower 	}
171*24313Ssklower 	if (doioctl && install) {
172*24313Ssklower 		if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
173*24313Ssklower 			perror("SIOCADDRT");
174*24313Ssklower 		if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
175*24313Ssklower 			perror("SIOCDELRT");
176*24313Ssklower 	}
177*24313Ssklower }
178*24313Ssklower 
179*24313Ssklower rtdelete(rt)
180*24313Ssklower 	struct rt_entry *rt;
181*24313Ssklower {
182*24313Ssklower 
183*24313Ssklower 	TRACE_ACTION(DELETE, rt);
184*24313Ssklower 	if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
185*24313Ssklower 		perror("SIOCDELRT");
186*24313Ssklower 	remque(rt);
187*24313Ssklower 	free((char *)rt);
188*24313Ssklower }
189*24313Ssklower 
190*24313Ssklower rtinit()
191*24313Ssklower {
192*24313Ssklower 	register struct rthash *rh;
193*24313Ssklower 
194*24313Ssklower 	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
195*24313Ssklower 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
196*24313Ssklower 	for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
197*24313Ssklower 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
198*24313Ssklower 
199*24313Ssklower 	if ((s = socket(AF_XNS, SOCK_RAW, IDPPROTO_RAW)) < 0) {
200*24313Ssklower 		perror("socket");
201*24313Ssklower 		exit(1);
202*24313Ssklower 	}
203*24313Ssklower }
204