Commit | Line | Data |
---|---|---|
b9b7b06a | 1 | #ifndef lint |
b7e4f8be | 2 | static 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 | ||
16 | int install = !DEBUG; /* if 1 call kernel */ | |
17 | ||
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; | |
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]; | |
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 % ROUTEHASHSIZ]; | |
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; | |
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 | ||
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 % ROUTEHASHSIZ]; | |
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; | |
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 | ||
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; | |
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 | ||
197 | rtdelete(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 | ||
208 | rtinit() | |
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 | } |