process_routes: fix potential null pointer dereference warnings on gcc 7
[olsrd.git] / src / process_routes.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * (c) by the OLSR project
5  *
6  * See our Git repository to find out who worked on this file
7  * and thus is a copyright holder on it.
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * * Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * * Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in
19  *   the documentation and/or other materials provided with the
20  *   distribution.
21  * * Neither the name of olsr.org, olsrd nor the names of its
22  *   contributors may be used to endorse or promote products derived
23  *   from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Visit http://www.olsr.org for more information.
39  *
40  * If you find this software useful feel free to make a donation
41  * to the project. For more information see the website or contact
42  * the copyright holders.
43  *
44  */
45
46 #include "ipcalc.h"
47 #include "defs.h"
48 #include "olsr.h"
49 #include "log.h"
50 #include "kernel_routes.h"
51 #include "common/avl.h"
52 #include "net_olsr.h"
53 #include "tc_set.h"
54 #include "olsr_cookie.h"
55 #include "olsr_niit.h"
56
57 #ifdef _WIN32
58 char *StrError(unsigned int ErrNo);
59 #undef strerror
60 #define strerror(x) StrError(x)
61 #endif /* _WIN32 */
62
63 static struct list_node chg_kernel_list;
64
65 /**
66  *
67  * Calculate the kernel route flags.
68  * Called before enqueuing a change/delete operation
69  *
70  */
71 uint8_t
72 olsr_rt_flags(const struct rt_entry *rt, int add)
73 {
74   const struct rt_nexthop *nh;
75   uint8_t flags = RTF_UP;
76
77   /* destination is host */
78   if (rt->rt_dst.prefix_len == olsr_cnf->maxplen) {
79     flags |= RTF_HOST;
80   }
81
82   if (add) nh = olsr_get_nh(rt);
83   else nh = &rt->rt_nexthop;
84
85   if (!ipequal(&rt->rt_dst.prefix, &nh->gateway)) {
86     flags |= RTF_GATEWAY;
87   }
88
89   return flags;
90 }
91
92 export_route_function olsr_addroute_function;
93 export_route_function olsr_addroute6_function;
94 export_route_function olsr_delroute_function;
95 export_route_function olsr_delroute6_function;
96
97 void
98 olsr_init_export_route(void)
99 {
100   /* the add/chg/del kernel queues */
101   //list_head_init(&add_kernel_list);
102   list_head_init(&chg_kernel_list);
103
104   olsr_addroute_function = olsr_ioctl_add_route;
105   olsr_addroute6_function = olsr_ioctl_add_route6;
106   olsr_delroute_function = olsr_ioctl_del_route;
107   olsr_delroute6_function = olsr_ioctl_del_route6;
108 }
109
110 /**
111  * Delete all OLSR routes.
112  *
113  * This is extremely simple - Just increment the version of the
114  * tree and then olsr_update_rib_routes() will see all routes in the tree
115  * as outdated and olsr_update_kernel_routes() will finally flush it.
116  *
117  */
118 void
119 olsr_delete_all_kernel_routes(void)
120 {
121   OLSR_PRINTF(1, "Deleting all routes...\n");
122
123   olsr_bump_routingtree_version();
124   olsr_update_rib_routes();
125   olsr_update_kernel_routes();
126 }
127
128 /**
129  * Enqueue a route on a kernel add/chg/del queue.
130  */
131 static void
132 olsr_enqueue_rt(struct list_node *head_node, struct rt_entry *rt)
133 {
134   const struct rt_nexthop *nh;
135
136   /* if this node is already on some changelist we are done */
137   if (list_node_on_list(&rt->rt_change_node)) {
138     return;
139   }
140
141   /*
142    * For easier route dependency tracking we enqueue nexthop routes
143    * at the head of the queue and non-nexthop routes at the tail of the queue.
144    */
145   nh = olsr_get_nh(rt);
146
147   if (ipequal(&rt->rt_dst.prefix, &nh->gateway)) {
148     list_add_after(head_node, &rt->rt_change_node);
149   } else {
150     list_add_before(head_node, &rt->rt_change_node);
151   }
152 }
153
154 /**
155  * Process a route from the kernel deletion list.
156  *
157  *@return -1 on error, else 0
158  */
159 static int
160 olsr_delete_kernel_route(struct rt_entry *rt)
161 {
162   if (rt->rt_metric.hops > 1) {
163     /* multihop route */
164     if (ip_is_linklocal(&rt->rt_dst.prefix)) {
165       /* do not delete a route with a LL IP as a destination */
166       return 0;
167     }
168   }
169
170   if (!olsr_cnf->host_emul) {
171     int16_t error = olsr_cnf->ip_version == AF_INET ? olsr_delroute_function(rt) : olsr_delroute6_function(rt);
172
173     if (error != 0) {
174       const char *const err_msg = strerror(errno);
175       const char *const routestr = olsr_rt_to_string(rt);
176       OLSR_PRINTF(1, "KERN: ERROR deleting %s: %s\n", routestr, err_msg);
177
178       olsr_syslog(OLSR_LOG_ERR, "Delete route %s: %s", routestr, err_msg);
179       return -1;
180     }
181 #ifdef __linux__
182     /* call NIIT handler (always)*/
183     if (olsr_cnf->use_niit) {
184       olsr_niit_handle_route(rt, false);
185     }
186 #endif /* __linux__ */
187   }
188   return 0;
189 }
190
191 /**
192  * Process a route from the kernel addition list.
193  *
194  *@return nada
195  */
196 static void
197 olsr_add_kernel_route(struct rt_entry *rt)
198 {
199   if (!rt) return;
200
201   if (rt->rt_best->rtp_metric.hops > 1) {
202     /* multihop route */
203     if (ip_is_linklocal(&rt->rt_best->rtp_dst.prefix)) {
204       /* do not create a route with a LL IP as a destination */
205       return;
206     }
207   }
208   if (!olsr_cnf->host_emul) {
209     int16_t error = (olsr_cnf->ip_version == AF_INET) ? olsr_addroute_function(rt) : olsr_addroute6_function(rt);
210
211     if (error != 0) {
212       const char *const err_msg = strerror(errno);
213       const char *const routestr = olsr_rtp_to_string(rt->rt_best);
214       OLSR_PRINTF(1, "KERN: ERROR adding %s: %s\n", routestr, err_msg);
215
216       olsr_syslog(OLSR_LOG_ERR, "Add route %s: %s", routestr, err_msg);
217     } else {
218       /* route addition has suceeded */
219
220       /* save the nexthop and metric in the route entry */
221       rt->rt_nexthop = rt->rt_best->rtp_nexthop;
222       rt->rt_metric = rt->rt_best->rtp_metric;
223
224 #ifdef __linux__
225       /* call NIIT handler */
226       if (olsr_cnf->use_niit) {
227         olsr_niit_handle_route(rt, true);
228       }
229 #endif /* __linux__ */
230     }
231   }
232 }
233
234 /**
235  * process the kernel change list.
236  * the routes are already ordered such that nexthop routes
237  * are on the head of the queue.
238  * non-nexthop routes need to be changed first and therefore
239  * the queue needs to be traversed from tail to head.
240  */
241 static void
242 olsr_chg_kernel_routes(struct list_node *head_node)
243 {
244   struct rt_entry *rt;
245
246   if (list_is_empty(head_node)) {
247     return;
248   }
249
250   /*
251    * Traverse from the beginning to the end of the list,
252    * such that nexthop routes are added first.
253    */
254   while (!list_is_empty(head_node)) {
255     rt = changelist2rt(head_node->next);
256
257 #ifdef __linux__
258     /*
259     *   actively deleting routes is not necessary as we use (NLM_F_CREATE | NLM_F_REPLACE) with linux
260     *        (i.e. new routes simply overwrite the old ones in kernel)
261     *   BUT: We still have to actively delete routes if fib_metric != FLAT or we run on ipv6.
262     *        As NLM_F_REPLACE is not supported with IPv6, or simply of no use with varying route metrics.
263     *        We also actively delete routes if custom route functions are in place. (e.g. quagga plugin)
264     */
265     if (((olsr_cnf->ip_version != AF_INET ) || (olsr_cnf->fib_metric != FIBM_FLAT)
266          || (olsr_addroute_function != olsr_ioctl_add_route) || (olsr_addroute6_function != olsr_ioctl_add_route6)
267          || (olsr_delroute_function != olsr_ioctl_del_route) || (olsr_delroute6_function != olsr_ioctl_del_route6))
268         && (rt->rt_nexthop.iif_index > -1)) {
269       olsr_delete_kernel_route(rt);
270     }
271 #else /* __linux__ */
272     /*no rtnetlink we have to delete routes*/
273     if (rt && (rt->rt_nexthop.iif_index > -1)) olsr_delete_kernel_route(rt);
274 #endif /* __linux__ */
275
276     olsr_add_kernel_route(rt);
277
278     list_remove(&rt->rt_change_node);
279   }
280 }
281
282 /**
283  * Check the version number of all route paths hanging off a route entry.
284  * If a route does not match the current routing tree number, remove it
285  * from the global originator tree for that rt_entry.
286  * Reset the best route pointer.
287  */
288 static void
289 olsr_delete_outdated_routes(struct rt_entry *rt)
290 {
291   struct rt_path *rtp;
292   struct avl_node *rtp_tree_node, *next_rtp_tree_node;
293
294   for (rtp_tree_node = avl_walk_first(&rt->rt_path_tree); rtp_tree_node != NULL; rtp_tree_node = next_rtp_tree_node) {
295     /*
296      * pre-fetch the next node before loosing context.
297      */
298     next_rtp_tree_node = avl_walk_next(rtp_tree_node);
299
300     rtp = rtp_tree2rtp(rtp_tree_node);
301
302     /*
303      * check the version number which gets incremented on every SPF run.
304      * comparing for unequalness avoids handling version number wraps.
305      */
306     if (routingtree_version != rtp->rtp_version) {
307       /* remove from the originator tree */
308       avl_delete(&rt->rt_path_tree, rtp_tree_node);
309       rtp->rtp_rt = NULL;
310
311       if (rt->rt_best == rtp) {
312         rt->rt_best = NULL;
313       }
314     }
315   }
316 }
317
318 /**
319  * Walk all the routes, remove outdated routes and run
320  * best path selection on the remaining set.
321  * Finally compare the nexthop of the route head and the best
322  * path and enqueue an add/chg operation.
323  */
324 void
325 olsr_update_rib_routes(void)
326 {
327   struct rt_entry *rt;
328
329   OLSR_PRINTF(3, "Updating kernel routes...\n");
330
331   /* walk all routes in the RIB. */
332
333   OLSR_FOR_ALL_RT_ENTRIES(rt) {
334
335     /* eliminate first unused routes */
336     olsr_delete_outdated_routes(rt);
337
338     if (!rt->rt_path_tree.count) {
339
340       /* oops, all routes are gone - flush the route head */
341   
342       if (olsr_delete_kernel_route(rt) == 0) {
343         /*only remove if deletion was successful*/
344         avl_delete(&routingtree, &rt->rt_tree_node);
345         olsr_cookie_free(rt_mem_cookie, rt);
346       }
347
348       continue;
349     }
350
351     /* run best route election */
352     olsr_rt_best(rt);
353
354     /* nexthop or hopcount change ? */
355     if (olsr_nh_change(&rt->rt_best->rtp_nexthop, &rt->rt_nexthop)
356         || (FIBM_CORRECT == olsr_cnf->fib_metric && olsr_hopcount_change(&rt->rt_best->rtp_metric, &rt->rt_metric))) {
357
358         /* this is a route add or change. */
359         olsr_enqueue_rt(&chg_kernel_list, rt);
360     }
361   }
362   OLSR_FOR_ALL_RT_ENTRIES_END(rt);
363 }
364
365 void
366 olsr_delete_interface_routes(int if_index) {
367   struct rt_entry *rt;
368   bool triggerUpdate = false;
369
370   OLSR_FOR_ALL_RT_ENTRIES(rt) {
371     bool mightTrigger = false;
372     struct rt_path *rtp;
373     struct avl_node *rtp_tree_node, *next_rtp_tree_node;
374
375     /* run through all routing paths of route */
376     for (rtp_tree_node = avl_walk_first(&rt->rt_path_tree); rtp_tree_node != NULL; rtp_tree_node = next_rtp_tree_node) {
377       /*
378        * pre-fetch the next node before loosing context.
379        */
380       next_rtp_tree_node = avl_walk_next(rtp_tree_node);
381
382       rtp = rtp_tree2rtp(rtp_tree_node);
383
384       /* nexthop use lost interface ? */
385       if (rtp->rtp_nexthop.iif_index == if_index) {
386         /* remove from the originator tree */
387         avl_delete(&rt->rt_path_tree, rtp_tree_node);
388         rtp->rtp_rt = NULL;
389
390         if (rt->rt_best == rtp) {
391           rt->rt_best = NULL;
392           mightTrigger = true;
393         }
394       }
395     }
396
397     if (mightTrigger) {
398       if (!rt->rt_path_tree.count) {
399         /* oops, all routes are gone - flush the route head */
400         avl_delete(&routingtree, rt_tree_node);
401
402         /* do not dequeue route because they are already gone */
403       }
404       triggerUpdate = true;
405     }
406   } OLSR_FOR_ALL_RT_ENTRIES_END(rt)
407
408   /* trigger route update if necessary */
409   if (triggerUpdate) {
410     olsr_update_rib_routes();
411     olsr_update_kernel_routes();
412   }
413 }
414
415 /**
416  * Propagate the accumulated changes from the last rib update to the kernel.
417  */
418 void
419 olsr_update_kernel_routes(void)
420 {
421   /* route changes */
422   olsr_chg_kernel_routes(&chg_kernel_list);
423
424 #if defined DEBUG && DEBUG
425   olsr_print_routing_table(&routingtree);
426 #endif /* defined DEBUG && DEBUG */
427 }
428
429 void
430 olsr_force_kernelroutes_refresh(void) {
431   struct rt_entry *rt;
432
433   /* enqueue all existing routes for a rewrite */
434   OLSR_FOR_ALL_RT_ENTRIES(rt) {
435     olsr_enqueue_rt(&chg_kernel_list, rt);
436   } OLSR_FOR_ALL_RT_ENTRIES_END(rt)
437
438   /* trigger kernel route refresh */
439   olsr_chg_kernel_routes(&chg_kernel_list);
440 }
441
442 /*
443  * Local Variables:
444  * c-basic-offset: 2
445  * indent-tabs-mode: nil
446  * End:
447  */