Remove advertising header from all userland binaries.
[dragonfly.git] / usr.sbin / IPXrouted / tables.c
1 /*
2  * Copyright (c) 1985, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Copyright (c) 1995 John Hay.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 4. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $FreeBSD: src/usr.sbin/IPXrouted/tables.c,v 1.7 1999/08/28 01:15:05 peter Exp $
32  *
33  * @(#)tables.c 8.1 (Berkeley) 6/5/93
34  */
35
36 /*
37  * Routing Table Management Daemon
38  */
39 #include "defs.h"
40 #include <sys/ioctl.h>
41 #include <errno.h>
42 #include <search.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45
46 #ifndef DEBUG
47 #define DEBUG   0
48 #endif
49
50 #define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));}
51
52 int     install = !DEBUG;               /* if 1 call kernel */
53 int     delete = 1;
54
55 struct  rthash nethash[ROUTEHASHSIZ];
56
57 /*
58  * Lookup dst in the tables for an exact match.
59  */
60 struct rt_entry *
61 rtlookup(struct sockaddr *dst)
62 {
63         struct rt_entry *rt;
64         struct rthash *rh;
65         u_int hash;
66         struct afhash h;
67
68         if (dst->sa_family >= AF_MAX)
69                 return (0);
70         (*afswitch[dst->sa_family].af_hash)(dst, &h);
71         hash = h.afh_nethash;
72         rh = &nethash[hash & ROUTEHASHMASK];
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 (equal(&rt->rt_dst, dst))
77                         return (rt);
78         }
79         return (0);
80 }
81
82 /*
83  * Find a route to dst as the kernel would.
84  */
85 struct rt_entry *
86 rtfind(struct sockaddr *dst)
87 {
88         struct rt_entry *rt;
89         struct rthash *rh;
90         u_int hash;
91         struct afhash h;
92         int af = dst->sa_family;
93         int (*match)() = NULL;
94
95         if (af >= AF_MAX)
96                 return (0);
97         (*afswitch[af].af_hash)(dst, &h);
98
99         hash = h.afh_nethash;
100         rh = &nethash[hash & ROUTEHASHMASK];
101         match = afswitch[af].af_netmatch;
102         for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
103                 if (rt->rt_hash != hash)
104                         continue;
105                 if (rt->rt_dst.sa_family == af &&
106                     (*match)(&rt->rt_dst, dst))
107                         return (rt);
108         }
109         return (0);
110 }
111
112 void
113 rtadd(struct sockaddr *dst, struct sockaddr *gate, short metric, short ticks,
114       int state)
115 {
116         struct afhash h;
117         struct rt_entry *rt;
118         struct rthash *rh;
119         int af = dst->sa_family, flags;
120         u_int hash;
121
122         FIXLEN(dst);
123         FIXLEN(gate);
124         if (af >= AF_MAX)
125                 return;
126         (*afswitch[af].af_hash)(dst, &h);
127         flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
128         hash = h.afh_nethash;
129         rh = &nethash[hash & ROUTEHASHMASK];
130         rt = (struct rt_entry *)malloc(sizeof (*rt));
131         if (rt == NULL)
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_ticks = ticks;
138         rt->rt_timer = 0;
139         rt->rt_flags = RTF_UP | flags;
140         rt->rt_state = state | RTS_CHANGED;
141         rt->rt_ifp = if_ifwithnet(&rt->rt_router);
142         rt->rt_clone = NULL;
143         if (metric)
144                 rt->rt_flags |= RTF_GATEWAY;
145         insque(rt, rh);
146         TRACE_ACTION("ADD", rt);
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          */
152         if (install && rtioctl(ADD, &rt->rt_rt) < 0) {
153                 if (errno != EEXIST)
154                         perror("SIOCADDRT");
155                 if (errno == ENETUNREACH) {
156                         TRACE_ACTION("DELETE", rt);
157                         remque(rt);
158                         free((char *)rt);
159                 }
160         }
161 }
162
163 void
164 rtadd_clone(struct rt_entry *ort, struct sockaddr *dst, struct sockaddr *gate,
165             short metric, short ticks, int state)
166 {
167         struct afhash h;
168         struct rt_entry *rt;
169         int af = dst->sa_family, flags;
170         u_int hash;
171
172         FIXLEN(dst);
173         FIXLEN(gate);
174         if (af >= AF_MAX)
175                 return;
176         (*afswitch[af].af_hash)(dst, &h);
177         flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
178         hash = h.afh_nethash;
179         rt = (struct rt_entry *)malloc(sizeof (*rt));
180         if (rt == NULL)
181                 return;
182         rt->rt_hash = hash;
183         rt->rt_dst = *dst;
184         rt->rt_router = *gate;
185         rt->rt_metric = metric;
186         rt->rt_ticks = ticks;
187         rt->rt_timer = 0;
188         rt->rt_flags = RTF_UP | flags;
189         rt->rt_state = state | RTS_CHANGED;
190         rt->rt_ifp = if_ifwithnet(&rt->rt_router);
191         rt->rt_clone = NULL;
192         rt->rt_forw = NULL;
193         rt->rt_back = NULL;
194         if (metric)
195                 rt->rt_flags |= RTF_GATEWAY;
196
197         while(ort->rt_clone != NULL)
198                 ort = ort->rt_clone;
199         ort->rt_clone = rt;
200         TRACE_ACTION("ADD_CLONE", rt);
201 }
202
203 void
204 rtchange(struct rt_entry *rt, struct sockaddr *gate, short metric, short ticks)
205 {
206         int doioctl = 0, metricchanged = 0;
207
208         FIXLEN(gate);
209         /*
210          * Handling of clones.
211          * When the route changed and it had clones, handle it special.
212          * 1. If the new route is cheaper than the clone(s), free the clones.
213          * 2. If the new route is the same cost, it may be one of the clones,
214          *    search for it and free it.
215          * 3. If the new route is more expensive than the clone(s), use the
216          *    values of the clone(s).
217          */
218         if (rt->rt_clone) {
219                 if ((ticks < rt->rt_clone->rt_ticks) ||
220                     ((ticks == rt->rt_clone->rt_ticks) &&
221                      (metric < rt->rt_clone->rt_metric))) {
222                         /*
223                          * Free all clones.
224                          */
225                         struct rt_entry *trt, *nrt;
226
227                         trt = rt->rt_clone;
228                         rt->rt_clone = NULL;
229                         while(trt) {
230                                 nrt = trt->rt_clone;
231                                 free((char *)trt);
232                                 trt = nrt;
233                         }
234                 } else if ((ticks == rt->rt_clone->rt_ticks) &&
235                      (metric == rt->rt_clone->rt_metric)) {
236                         struct rt_entry *prt, *trt;
237
238                         prt = rt;
239                         trt = rt->rt_clone;
240
241                         while(trt) {
242                                 if (equal(&trt->rt_router, gate)) {
243                                         prt->rt_clone = trt->rt_clone;
244                                         free(trt);
245                                         trt = prt->rt_clone;
246                                 } else {
247                                         prt = trt;
248                                         trt = trt->rt_clone;
249                                 }
250                         }
251                 } else {
252                         /*
253                          * Use the values of the first clone. 
254                          * Delete the corresponding clone.
255                          */
256                         struct rt_entry *trt;
257
258                         trt = rt->rt_clone;
259                         rt->rt_clone = rt->rt_clone->rt_clone;
260                         metric = trt->rt_metric;
261                         ticks = trt->rt_ticks;
262                         *gate = trt->rt_router;
263                         free((char *)trt);
264                 }
265         }
266
267         if (!equal(&rt->rt_router, gate))
268                 doioctl++;
269         if ((metric != rt->rt_metric) || (ticks != rt->rt_ticks))
270                 metricchanged++;
271         if (doioctl || metricchanged) {
272                 TRACE_ACTION("CHANGE FROM", rt);
273                 if (doioctl)
274                         rt->rt_router = *gate;
275                 rt->rt_metric = metric;
276                 rt->rt_ticks = ticks;
277                 if ((rt->rt_state & RTS_INTERFACE) && metric) {
278                         rt->rt_state &= ~RTS_INTERFACE;
279                         if(rt->rt_ifp) 
280                                 syslog(LOG_ERR,
281                                 "changing route from interface %s (timed out)",
282                                 rt->rt_ifp->int_name);
283                         else
284                                 syslog(LOG_ERR,
285                                 "changing route from interface ??? (timed out)");
286                 }
287                 if (metric)
288                         rt->rt_flags |= RTF_GATEWAY;
289                 else
290                         rt->rt_flags &= ~RTF_GATEWAY;
291                 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
292                 rt->rt_state |= RTS_CHANGED;
293                 TRACE_ACTION("CHANGE TO", rt);
294         }
295         if (doioctl && install) {
296                 if (delete == 0) {
297                         if (rtioctl(ADD, &rt->rt_rt) >= 0)
298                                 return;
299                 } else {
300                         if (rtioctl(CHANGE, &rt->rt_rt) >= 0)
301                                 return;
302                 }
303                 syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m",
304                    ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr),
305                    ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr));
306         }
307 }
308
309 void
310 rtdelete(struct rt_entry *rt)
311 {
312         struct sockaddr *sa = &(rt->rt_router);
313
314         FIXLEN(sa);
315         sa = &(rt->rt_dst);
316         FIXLEN(sa);
317         if (rt->rt_clone) {
318                 /*
319                  * If there is a clone we just do a rt_change to it.
320                  */
321                 struct rt_entry *trt = rt->rt_clone;
322                 rtchange(rt, &trt->rt_router, trt->rt_metric, trt->rt_ticks);
323                 return;
324         }
325         if (rt->rt_state & RTS_INTERFACE) {
326                 if (rt->rt_ifp)
327                         syslog(LOG_ERR, 
328                                 "deleting route to interface %s (timed out)",
329                                 rt->rt_ifp->int_name);
330                 else
331                         syslog(LOG_ERR, 
332                                 "deleting route to interface ??? (timed out)");
333         }
334         TRACE_ACTION("DELETE", rt);
335         if (install && rtioctl(DELETE, &rt->rt_rt) < 0)
336                 perror("rtioctl DELETE");
337         remque(rt);
338         free((char *)rt);
339 }
340
341 void
342 rtinit(void)
343 {
344         struct rthash *rh;
345
346         for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
347                 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
348 }
349 int seqno;
350
351 int
352 rtioctl(int action, struct rtuentry *ort)
353 {
354         struct {
355                 struct rt_msghdr w_rtm;
356                 struct sockaddr w_dst;
357                 struct sockaddr w_gate;
358                 struct sockaddr_ipx w_netmask;
359         } w;
360 #define rtm w.w_rtm
361
362         bzero((char *)&w, sizeof(w));
363         rtm.rtm_msglen = sizeof(w);
364         rtm.rtm_version = RTM_VERSION;
365         rtm.rtm_type = (action == ADD ? RTM_ADD :
366                                 (action == DELETE ? RTM_DELETE : RTM_CHANGE));
367         rtm.rtm_flags = ort->rtu_flags;
368         rtm.rtm_seq = ++seqno;
369         rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
370         bcopy((char *)&ort->rtu_dst, (char *)&w.w_dst, sizeof(w.w_dst));
371         bcopy((char *)&ort->rtu_router, (char *)&w.w_gate, sizeof(w.w_gate));
372         w.w_gate.sa_family = w.w_dst.sa_family = AF_IPX;
373         w.w_gate.sa_len = w.w_dst.sa_len = sizeof(w.w_dst);
374         if (rtm.rtm_flags & RTF_HOST) {
375                 rtm.rtm_msglen -= sizeof(w.w_netmask);
376         } else {
377                 rtm.rtm_addrs |= RTA_NETMASK;
378                 w.w_netmask = ipx_netmask;
379                 rtm.rtm_msglen -= sizeof(w.w_netmask) - ipx_netmask.sipx_len;
380         }
381         errno = 0;
382         return write(r, (char *)&w, rtm.rtm_msglen);
383 }