manual page first distributed with 4.2BSD
[unix-history] / usr / src / sbin / routed / tables.c
CommitLineData
b9b7b06a 1#ifndef lint
78c998d3 2static char sccsid[] = "@(#)tables.c 4.11 (Berkeley) %G%";
b9b7b06a
SL
3#endif
4
5/*
6 * Routing Table Management Daemon
7 */
7fe7fe74 8#include "defs.h"
b9b7b06a
SL
9#include <sys/ioctl.h>
10#include <errno.h>
69b7ef61 11#include <syslog.h>
b9b7b06a
SL
12
13#ifndef DEBUG
14#define DEBUG 0
15#endif
16
17int install = !DEBUG; /* if 1 call kernel */
18
19/*
20 * Lookup dst in the tables for an exact match.
21 */
22struct rt_entry *
23rtlookup(dst)
24 struct sockaddr *dst;
25{
26 register struct rt_entry *rt;
27 register struct rthash *rh;
d5568f13 28 register u_int hash;
b9b7b06a
SL
29 struct afhash h;
30 int doinghost = 1;
31
32 if (dst->sa_family >= AF_MAX)
33 return (0);
34 (*afswitch[dst->sa_family].af_hash)(dst, &h);
35 hash = h.afh_hosthash;
49139b80 36 rh = &hosthash[hash & ROUTEHASHMASK];
b9b7b06a
SL
37again:
38 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
39 if (rt->rt_hash != hash)
40 continue;
41 if (equal(&rt->rt_dst, dst))
42 return (rt);
43 }
44 if (doinghost) {
45 doinghost = 0;
46 hash = h.afh_nethash;
49139b80 47 rh = &nethash[hash & ROUTEHASHMASK];
b9b7b06a
SL
48 goto again;
49 }
50 return (0);
51}
52
53/*
54 * Find a route to dst as the kernel would.
55 */
56struct rt_entry *
57rtfind(dst)
58 struct sockaddr *dst;
59{
60 register struct rt_entry *rt;
61 register struct rthash *rh;
d5568f13 62 register u_int hash;
b9b7b06a
SL
63 struct afhash h;
64 int af = dst->sa_family;
65 int doinghost = 1, (*match)();
66
67 if (af >= AF_MAX)
68 return (0);
69 (*afswitch[af].af_hash)(dst, &h);
70 hash = h.afh_hosthash;
49139b80 71 rh = &hosthash[hash & ROUTEHASHMASK];
b9b7b06a
SL
72
73again:
74 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
75 if (rt->rt_hash != hash)
76 continue;
77 if (doinghost) {
78 if (equal(&rt->rt_dst, dst))
79 return (rt);
80 } else {
81 if (rt->rt_dst.sa_family == af &&
82 (*match)(&rt->rt_dst, dst))
83 return (rt);
84 }
85 }
86 if (doinghost) {
87 doinghost = 0;
88 hash = h.afh_nethash;
49139b80 89 rh = &nethash[hash & ROUTEHASHMASK];
b9b7b06a
SL
90 match = afswitch[af].af_netmatch;
91 goto again;
92 }
93 return (0);
94}
95
96rtadd(dst, gate, metric, state)
97 struct sockaddr *dst, *gate;
98 int metric, state;
99{
100 struct afhash h;
101 register struct rt_entry *rt;
102 struct rthash *rh;
d5568f13
MK
103 int af = dst->sa_family, flags;
104 u_int hash;
b9b7b06a
SL
105
106 if (af >= AF_MAX)
107 return;
108 (*afswitch[af].af_hash)(dst, &h);
d5568f13 109 flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
b9b7b06a
SL
110 if (flags & RTF_HOST) {
111 hash = h.afh_hosthash;
49139b80 112 rh = &hosthash[hash & ROUTEHASHMASK];
b9b7b06a
SL
113 } else {
114 hash = h.afh_nethash;
49139b80 115 rh = &nethash[hash & ROUTEHASHMASK];
b9b7b06a
SL
116 }
117 rt = (struct rt_entry *)malloc(sizeof (*rt));
118 if (rt == 0)
119 return;
120 rt->rt_hash = hash;
121 rt->rt_dst = *dst;
122 rt->rt_router = *gate;
123 rt->rt_metric = metric;
124 rt->rt_timer = 0;
125 rt->rt_flags = RTF_UP | flags;
126 rt->rt_state = state | RTS_CHANGED;
127 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
128 if (metric)
129 rt->rt_flags |= RTF_GATEWAY;
130 insque(rt, rh);
131 TRACE_ACTION(ADD, rt);
a8d9e287
SL
132 /*
133 * If the ioctl fails because the gateway is unreachable
134 * from this host, discard the entry. This should only
135 * occur because of an incorrect entry in /etc/gateways.
136 */
137 if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
b9b7b06a 138 perror("SIOCADDRT");
a8d9e287
SL
139 if (errno == ENETUNREACH) {
140 TRACE_ACTION(DELETE, rt);
141 remque(rt);
142 free((char *)rt);
143 }
144 }
b9b7b06a
SL
145}
146
147rtchange(rt, gate, metric)
148 struct rt_entry *rt;
149 struct sockaddr *gate;
150 short metric;
151{
152 int doioctl = 0, metricchanged = 0;
153 struct rtentry oldroute;
154
155 if (!equal(&rt->rt_router, gate))
156 doioctl++;
b7e4f8be 157 if (metric != rt->rt_metric)
b9b7b06a 158 metricchanged++;
b9b7b06a 159 if (doioctl || metricchanged) {
b7e4f8be
MK
160 TRACE_ACTION(CHANGE FROM, rt);
161 if (doioctl) {
162 oldroute = rt->rt_rt;
163 rt->rt_router = *gate;
164 }
165 rt->rt_metric = metric;
69b7ef61
MK
166 if ((rt->rt_state & RTS_INTERFACE) && metric) {
167 rt->rt_state &= ~RTS_INTERFACE;
168 syslog(LOG_ERR,
78c998d3 169 "changing route from interface %s (timed out)",
69b7ef61
MK
170 rt->rt_ifp->int_name);
171 }
b7e4f8be 172 if (metric)
78c998d3
MK
173 rt->rt_flags |= RTF_GATEWAY;
174 else
175 rt->rt_flags &= ~RTF_GATEWAY;
b9b7b06a 176 rt->rt_state |= RTS_CHANGED;
b7e4f8be 177 TRACE_ACTION(CHANGE TO, rt);
b9b7b06a 178 }
b7e4f8be
MK
179 if (doioctl && install) {
180 if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
181 perror("SIOCADDRT");
182 if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
183 perror("SIOCDELRT");
b9b7b06a
SL
184 }
185}
186
187rtdelete(rt)
188 struct rt_entry *rt;
189{
a8d9e287 190
69b7ef61
MK
191 if (rt->rt_state & RTS_INTERFACE)
192 syslog(LOG_ERR, "deleting route to interface %s (timed out)",
193 rt->rt_ifp->int_name);
b9b7b06a
SL
194 TRACE_ACTION(DELETE, rt);
195 if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
196 perror("SIOCDELRT");
197 remque(rt);
198 free((char *)rt);
199}
200
ad34083f
MK
201/*
202 * If we have an interface to the wide, wide world,
203 * add an entry for an Internet default route (wildcard) to the internal
204 * tables and advertise it. This route is not added to the kernel routes,
205 * but this entry prevents us from listening to other people's defaults
206 * and installing them in the kernel here.
207 */
208rtdefault()
209{
210 struct afhash h;
211 register struct rt_entry *rt;
212 struct rthash *rh;
213 extern struct sockaddr inet_default;
214
215 rt = (struct rt_entry *)malloc(sizeof (*rt));
216 if (rt == 0)
217 return;
ad34083f
MK
218 rt->rt_dst = inet_default;
219 rt->rt_router = rt->rt_dst;
220 (*afswitch[AF_INET].af_hash)(&rt->rt_dst, &h);
49139b80 221 rh = &nethash[h.afh_nethash & ROUTEHASHMASK];
8aa8bd6a 222 rt->rt_hash = h.afh_nethash;
ad34083f
MK
223 rt->rt_metric = 0;
224 rt->rt_timer = 0;
225 rt->rt_flags = RTF_UP | RTF_GATEWAY;
226 rt->rt_state = RTS_CHANGED | RTS_PASSIVE;
227 rt->rt_ifp = 0;
228 insque(rt, rh);
229 TRACE_ACTION(ADD, rt);
230}
231
b9b7b06a
SL
232rtinit()
233{
234 register struct rthash *rh;
235
236 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
237 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
238 for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
239 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
240}