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