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