changes to allow subnets to remain local, propogate net route
[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
4fad5a6e 8static char sccsid[] = "@(#)tables.c 5.3 (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);
4fad5a6e
MK
115 flags = (*afswitch[af].af_rtflags)(dst);
116 /*
117 * Subnet flag isn't visible to kernel, move to state. XXX
118 */
119 if (flags & RTF_SUBNET) {
120 state |= RTS_SUBNET;
121 flags &= ~RTF_SUBNET;
122 }
b9b7b06a
SL
123 if (flags & RTF_HOST) {
124 hash = h.afh_hosthash;
49139b80 125 rh = &hosthash[hash & ROUTEHASHMASK];
b9b7b06a
SL
126 } else {
127 hash = h.afh_nethash;
49139b80 128 rh = &nethash[hash & ROUTEHASHMASK];
b9b7b06a
SL
129 }
130 rt = (struct rt_entry *)malloc(sizeof (*rt));
131 if (rt == 0)
132 return;
133 rt->rt_hash = hash;
134 rt->rt_dst = *dst;
135 rt->rt_router = *gate;
136 rt->rt_metric = metric;
137 rt->rt_timer = 0;
138 rt->rt_flags = RTF_UP | flags;
139 rt->rt_state = state | RTS_CHANGED;
4fad5a6e
MK
140 rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
141 if (rt->rt_ifp == 0)
142 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
b9b7b06a
SL
143 if (metric)
144 rt->rt_flags |= RTF_GATEWAY;
145 insque(rt, rh);
146 TRACE_ACTION(ADD, rt);
a8d9e287
SL
147 /*
148 * If the ioctl fails because the gateway is unreachable
149 * from this host, discard the entry. This should only
150 * occur because of an incorrect entry in /etc/gateways.
151 */
4fad5a6e
MK
152 if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
153 ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
b9b7b06a 154 perror("SIOCADDRT");
a8d9e287
SL
155 if (errno == ENETUNREACH) {
156 TRACE_ACTION(DELETE, rt);
157 remque(rt);
158 free((char *)rt);
159 }
160 }
b9b7b06a
SL
161}
162
163rtchange(rt, gate, metric)
164 struct rt_entry *rt;
165 struct sockaddr *gate;
166 short metric;
167{
168 int doioctl = 0, metricchanged = 0;
169 struct rtentry oldroute;
170
4fad5a6e 171 if (!equal(&rt->rt_router, gate) && (rt->rt_state & RTS_INTERNAL) == 0)
b9b7b06a 172 doioctl++;
b7e4f8be 173 if (metric != rt->rt_metric)
b9b7b06a 174 metricchanged++;
b9b7b06a 175 if (doioctl || metricchanged) {
b7e4f8be
MK
176 TRACE_ACTION(CHANGE FROM, rt);
177 if (doioctl) {
178 oldroute = rt->rt_rt;
179 rt->rt_router = *gate;
4fad5a6e
MK
180 rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
181 if (rt->rt_ifp == 0)
182 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
b7e4f8be
MK
183 }
184 rt->rt_metric = metric;
69b7ef61
MK
185 if ((rt->rt_state & RTS_INTERFACE) && metric) {
186 rt->rt_state &= ~RTS_INTERFACE;
187 syslog(LOG_ERR,
78c998d3 188 "changing route from interface %s (timed out)",
69b7ef61
MK
189 rt->rt_ifp->int_name);
190 }
b7e4f8be 191 if (metric)
78c998d3
MK
192 rt->rt_flags |= RTF_GATEWAY;
193 else
194 rt->rt_flags &= ~RTF_GATEWAY;
b9b7b06a 195 rt->rt_state |= RTS_CHANGED;
b7e4f8be 196 TRACE_ACTION(CHANGE TO, rt);
b9b7b06a 197 }
b7e4f8be
MK
198 if (doioctl && install) {
199 if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
200 perror("SIOCADDRT");
201 if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
202 perror("SIOCDELRT");
b9b7b06a
SL
203 }
204}
205
206rtdelete(rt)
207 struct rt_entry *rt;
208{
a8d9e287 209
69b7ef61
MK
210 if (rt->rt_state & RTS_INTERFACE)
211 syslog(LOG_ERR, "deleting route to interface %s (timed out)",
212 rt->rt_ifp->int_name);
b9b7b06a 213 TRACE_ACTION(DELETE, rt);
4fad5a6e
MK
214 if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL) == 0) &&
215 ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
b9b7b06a
SL
216 perror("SIOCDELRT");
217 remque(rt);
218 free((char *)rt);
219}
220
ad34083f
MK
221/*
222 * If we have an interface to the wide, wide world,
223 * add an entry for an Internet default route (wildcard) to the internal
224 * tables and advertise it. This route is not added to the kernel routes,
225 * but this entry prevents us from listening to other people's defaults
226 * and installing them in the kernel here.
227 */
228rtdefault()
229{
ad34083f
MK
230 extern struct sockaddr inet_default;
231
4fad5a6e
MK
232 rtadd(&inet_default, &inet_default, 0,
233 RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
ad34083f
MK
234}
235
b9b7b06a
SL
236rtinit()
237{
238 register struct rthash *rh;
239
240 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
241 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
242 for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
243 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
244}