many cleanups; avoid interface timing out; put it back asap
[unix-history] / usr / src / sbin / routed / tables.c
CommitLineData
b9b7b06a 1#ifndef lint
b7e4f8be 2static char sccsid[] = "@(#)tables.c 4.6 (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>
11
12#ifndef DEBUG
13#define DEBUG 0
14#endif
15
16int install = !DEBUG; /* if 1 call kernel */
17
18/*
19 * Lookup dst in the tables for an exact match.
20 */
21struct rt_entry *
22rtlookup(dst)
23 struct sockaddr *dst;
24{
25 register struct rt_entry *rt;
26 register struct rthash *rh;
d5568f13 27 register u_int hash;
b9b7b06a
SL
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 % ROUTEHASHSIZ];
36again:
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 % ROUTEHASHSIZ];
47 goto again;
48 }
49 return (0);
50}
51
52/*
53 * Find a route to dst as the kernel would.
54 */
55struct rt_entry *
56rtfind(dst)
57 struct sockaddr *dst;
58{
59 register struct rt_entry *rt;
60 register struct rthash *rh;
d5568f13 61 register u_int hash;
b9b7b06a
SL
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 % ROUTEHASHSIZ];
71
72again:
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 % ROUTEHASHSIZ];
89 match = afswitch[af].af_netmatch;
90 goto again;
91 }
92 return (0);
93}
94
95rtadd(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;
d5568f13
MK
102 int af = dst->sa_family, flags;
103 u_int hash;
b9b7b06a
SL
104
105 if (af >= AF_MAX)
106 return;
107 (*afswitch[af].af_hash)(dst, &h);
d5568f13 108 flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
b9b7b06a
SL
109 if (flags & RTF_HOST) {
110 hash = h.afh_hosthash;
111 rh = &hosthash[hash % ROUTEHASHSIZ];
112 } else {
113 hash = h.afh_nethash;
114 rh = &nethash[hash % ROUTEHASHSIZ];
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);
a8d9e287
SL
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) {
b9b7b06a 137 perror("SIOCADDRT");
a8d9e287
SL
138 if (errno == ENETUNREACH) {
139 TRACE_ACTION(DELETE, rt);
140 remque(rt);
141 free((char *)rt);
142 }
143 }
b9b7b06a
SL
144}
145
146rtchange(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;
b7e4f8be
MK
153#define NDEBUG
154#ifdef NDEBUG
155 int turntraceoff = 0;
156#endif
b9b7b06a
SL
157
158 if (!equal(&rt->rt_router, gate))
159 doioctl++;
b7e4f8be 160 if (metric != rt->rt_metric)
b9b7b06a 161 metricchanged++;
b9b7b06a 162 if (doioctl || metricchanged) {
b7e4f8be
MK
163#ifdef NDEBUG
164 if (rt->rt_state & RTS_INTERFACE) {
165 if (!tracing) {
166 traceon("/usr/adm/routed.log");
167 turntraceoff = 1;
168 fprintf(ftrace, "**** Changing route from interface\n");
169 fprintf(ftrace, "rt_timer = %d\n", rt->rt_timer);
170 }
171 }
172#endif
173 TRACE_ACTION(CHANGE FROM, rt);
174 if (doioctl) {
175 oldroute = rt->rt_rt;
176 rt->rt_router = *gate;
177 }
178 rt->rt_metric = metric;
179 rt->rt_state &= ~RTS_INTERFACE;
180 if (metric)
181 rt->rt_state |= 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 190 }
b7e4f8be
MK
191#ifdef NDEBUG
192 if (turntraceoff)
193 traceoff();
194#endif
b9b7b06a
SL
195}
196
197rtdelete(rt)
198 struct rt_entry *rt;
199{
a8d9e287 200
b9b7b06a
SL
201 TRACE_ACTION(DELETE, rt);
202 if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
203 perror("SIOCDELRT");
204 remque(rt);
205 free((char *)rt);
206}
207
208rtinit()
209{
210 register struct rthash *rh;
211
212 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
213 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
214 for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
215 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
216}