7bec2949ce8b9609b771bcfa22a13620776ad6f8
[olsrd.git] / src / linux / kernel_routes.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
5  * Copyright (c) 2007, Sven-Ola for the policy routing stuff
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  *   notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer in
16  *   the documentation and/or other materials provided with the
17  *   distribution.
18  * * Neither the name of olsr.org, olsrd nor the names of its
19  *   contributors may be used to endorse or promote products derived
20  *   from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * Visit http://www.olsr.org for more information.
36  *
37  * If you find this software useful feel free to make a donation
38  * to the project. For more information see the website or contact
39  * the copyright holders.
40  *
41  */
42
43 #include "kernel_routes.h"
44 #include "ipc_frontend.h"
45 #include "log.h"
46
47 /*flags for recursive route corrections (specified here as they are currently only used in linux specific kernel_routes.c)*/
48
49 #define RT_ORIG_REQUEST 0
50 #define RT_RETRY_AFTER_ADD_GATEWAY 1
51 #define RT_RETRY_AFTER_DELETE_SIMILAR 2
52 #define RT_DELETE_SIMILAR_ROUTE 3
53 #define RT_AUTO_ADD_GATEWAY_ROUTE 4
54 #define RT_DELETE_SIMILAR_AUTO_ROUTE 5
55
56 #if !LINUX_POLICY_ROUTING
57
58 static int delete_all_inet_gws(void);
59
60 #else /* !LINUX_POLICY_ROUTING */
61
62 #include <assert.h>
63 #include <linux/types.h>
64 #include <linux/rtnetlink.h>
65
66 struct olsr_rtreq {
67   struct nlmsghdr n;
68   struct rtmsg r;
69   char buf[512];
70 };
71
72 static void
73 olsr_netlink_addreq(struct olsr_rtreq *req, int type, const void *data, int len)
74 {
75   struct rtattr *rta = (struct rtattr *)(((char *)req) + NLMSG_ALIGN(req->n.nlmsg_len));
76   req->n.nlmsg_len = NLMSG_ALIGN(req->n.nlmsg_len) + RTA_LENGTH(len);
77   assert(req->n.nlmsg_len < sizeof(struct olsr_rtreq));
78   rta->rta_type = type;
79   rta->rta_len = RTA_LENGTH(len);
80   memcpy(RTA_DATA(rta), data, len);
81 }
82
83 /* returns
84  * -1 on unrecoverable error (calling function will handle it)
85  * 0 on unexpected but recoverable behaviour like (no such process, file existsm, network unreachable)
86  *   but the implemented recovery methods only cure the symptoms, not the cause, which still wansn`t found/fixed
87  *   but ignoring this errors and just logging them into syslog without any recover mechanisms may cause significatn ressource usage and missing routes in kernel
88  *   to ensure that this problems are fixed at proper place in future, recovery process logs warnings into syslog!
89  * 1 on success */
90 static int
91 olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd, uint8_t flag)
92 {
93   int ret = 1; //helper variable for rtnetlink_message processing
94   int rt_ret = -2;  //if no response from rtnetlink it must be considered as failed!!!
95   struct olsr_rtreq req;
96   struct iovec iov;
97   struct sockaddr_nl nladdr;
98   struct msghdr msg = {
99     &nladdr,
100     sizeof(nladdr),
101     &iov,
102     1,
103     NULL,
104     0,
105     0
106   };
107   uint32_t metric =
108     FIBM_FLAT != olsr_cnf->fib_metric ? 
109       ((RTM_NEWROUTE == cmd) ? rt->rt_best->rtp_metric.hops : rt->rt_metric.hops) 
110       : RT_METRIC_DEFAULT;
111   const struct rt_nexthop *nexthop = (RTM_NEWROUTE == cmd) ? &rt->rt_best->rtp_nexthop : &rt->rt_nexthop;
112
113   memset(&req, 0, sizeof(req));
114   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
115   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
116   req.n.nlmsg_type = cmd;
117   req.r.rtm_family = family;
118   req.r.rtm_table = rttable;
119   req.r.rtm_dst_len = rt->rt_dst.prefix_len;
120   req.r.rtm_type = RTN_UNICAST; /*different rtm_type will not conflict, but of course if there a blackhole routes they will do what they do,..*/
121   req.r.rtm_protocol = RTPROT_UNSPEC;//wildcard to delete routes of all protos if no simlar-delete correct proto will get set below
122   req.r.rtm_scope = RT_SCOPE_NOWHERE;//as wildcard for deletion
123
124   /*do not specify much if we wanna delete similar routes*/
125   /*this currently works for different interfaces, src-ips metrics, gateways, protos*/
126   if ((flag != RT_DELETE_SIMILAR_ROUTE) & (flag != RT_DELETE_SIMILAR_AUTO_ROUTE)) {
127     req.r.rtm_protocol = RTPROT_BOOT;
128     req.r.rtm_scope = RT_SCOPE_LINK;
129
130     /*metric*/
131     if (FIBM_APPROX != olsr_cnf->fib_metric || (RTM_NEWROUTE == cmd) ) {
132       olsr_netlink_addreq(&req, RTA_PRIORITY, &metric, sizeof(metric));
133     }
134
135     /*interface*/
136     olsr_netlink_addreq(&req, RTA_OIF, &nexthop->iif_index, sizeof(nexthop->iif_index));
137   }
138
139   //make sure that netmask = /32 as this is an autogenarated route
140   if (( flag == RT_AUTO_ADD_GATEWAY_ROUTE ) | (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) req.r.rtm_dst_len = 32;
141
142   /* for ipv4 or ipv6 we add gateway if one is specified, 
143   * or leave gateway away if we want to delete similar routes aswell, 
144   * or even use the gateway as target if we add a autogenrated route (or do an delete_sim to make insertion of autogen route possible)*/
145   if (AF_INET == family) {
146     if ( ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) & (flag != RT_DELETE_SIMILAR_ROUTE) & 
147          ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) & (rt->rt_dst.prefix.v4.s_addr != nexthop->gateway.v4.s_addr) ) {
148       olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v4, sizeof(nexthop->gateway.v4));
149       req.r.rtm_scope = RT_SCOPE_UNIVERSE;
150     }
151     olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) | (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
152                                       &nexthop->gateway.v4 : &rt->rt_dst.prefix.v4, sizeof(rt->rt_dst.prefix.v4));
153   } else {
154     if ( ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) & (flag != RT_DELETE_SIMILAR_ROUTE ) & 
155          ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) & (0 != memcmp(&rt->rt_dst.prefix.v6, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6))) ) {
156       olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6));
157       req.r.rtm_scope = RT_SCOPE_UNIVERSE;
158     }
159     olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) | (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
160                                       &nexthop->gateway.v6 : &rt->rt_dst.prefix.v6, sizeof(rt->rt_dst.prefix.v6));
161   }
162
163   iov.iov_base = &req.n;
164   iov.iov_len = req.n.nlmsg_len;
165   memset(&nladdr, 0, sizeof(nladdr));
166   nladdr.nl_family = AF_NETLINK;
167   if (0 <= (ret = sendmsg(olsr_cnf->rtnl_s, &msg, 0))) {
168     iov.iov_base = req.buf;
169     iov.iov_len = sizeof(req.buf);
170     if (0 < (ret = recvmsg(olsr_cnf->rtnl_s, &msg, 0))) {
171       struct nlmsghdr *h = (struct nlmsghdr *)req.buf;
172       while (NLMSG_OK(h, (unsigned int)ret)) {
173         if (NLMSG_DONE == h->nlmsg_type) {
174           //seems to reached never
175           olsr_syslog(OLSR_LOG_INFO, "_received NLMSG_DONE");
176           break;
177         }
178         if (NLMSG_ERROR == h->nlmsg_type) {
179           if (NLMSG_LENGTH(sizeof(struct nlmsgerr) <= h->nlmsg_len)) {
180             struct ipaddr_str ibuf;
181             struct ipaddr_str gbuf;
182             struct nlmsgerr *l_err = (struct nlmsgerr *)NLMSG_DATA(h);
183             errno = -l_err->error;
184             if (0 != errno) {
185               const char *const err_msg = strerror(errno);
186               struct ipaddr_str buf;
187               rt_ret = -1;
188               /*debug output for original and retry attempts*/
189               if ( flag <= RT_RETRY_AFTER_DELETE_SIMILAR ) {
190                 if (rt->rt_dst.prefix.v4.s_addr!=nexthop->gateway.v4.s_addr)
191                   olsr_syslog(OLSR_LOG_ERR, "error %d %s %s route to %s/%d via %s dev %d", errno, err_msg, (cmd == RTM_NEWROUTE) ? "add" : "del",
192                              olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix),
193                              req.r.rtm_dst_len,
194                              olsr_ip_to_string(&gbuf,&nexthop->gateway), nexthop->iif_index); 
195                 else olsr_syslog(OLSR_LOG_ERR, "error %d %s %s route to %s/%d dev %d", errno, err_msg, (cmd == RTM_NEWROUTE) ? "add" : "del",
196                                 olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix),
197                                 req.r.rtm_dst_len, nexthop->iif_index);
198               }
199               //deug output for autogen routes
200               else if (flag == RT_AUTO_ADD_GATEWAY_ROUTE) olsr_syslog(OLSR_LOG_ERR, ". error %d %s auto-add route to %s dev %d", errno, err_msg,
201                                olsr_ip_to_string(&ibuf,&nexthop->gateway), nexthop->iif_index);
202               //debug output for auto-delete similar
203               else if (flag == RT_DELETE_SIMILAR_ROUTE) olsr_syslog(OLSR_LOG_ERR, ". error %d %s auto-delete route to %s", errno, err_msg,
204                                              olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix));
205               //debug output for auto-delete similar
206               else if (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) olsr_syslog(OLSR_LOG_ERR, ". . error %d %s auto-del-similar route to %s", errno, err_msg,
207                                                              olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix));
208               //should never happen
209               else {
210                 olsr_syslog(OLSR_LOG_ERR, "# invalid internal route delete/add flag (%d) used!", flag);
211               }
212             }
213             else {
214               //netlink acks rquests with an errno=0 NLMSG_ERROR response!
215               //olsr_syslog(OLSR_LOG_INFO, "# RTNETLINK ACK!");
216               rt_ret = 1;
217             }
218
219             //olsr_syslog(OLSR_LOG_ERR
220             /* resolve "File exist" (17) propblems (on orig and autogen routes)*/       
221             if ((errno == 17) & ((flag == RT_ORIG_REQUEST) | (flag == RT_AUTO_ADD_GATEWAY_ROUTE)) & (cmd == RTM_NEWROUTE)) {
222               /*a simlar route going over another gateway may be present, which should be deleted*/
223               olsr_syslog(OLSR_LOG_ERR, ". auto-deleting similar routes to resolve '17 - File exists' while adding route!");
224               rt_ret = RT_DELETE_SIMILAR_ROUTE;/*processing will contiune after this loop is finished as otherwise the rtnetlink is still blocked*/
225             }
226             /* report success on "No such process" (3) */
227             else if ((errno == 3) & (cmd == RTM_DELROUTE) & (flag == RT_ORIG_REQUEST)) {
228               /*another similar (but different) route may be present, but as we don not have a better route, nothing to think about*/
229               olsr_syslog(OLSR_LOG_ERR, ". ignoring '3 - No such process' while deleting route!");
230               rt_ret = 0;
231             }
232             /* insert route to gateway on the fly if "Network unreachable" (128) 
233              * is issued by rtnetlink when adding route via gateway!
234              * do this only with flat metric, as using metric values inherited from 
235              * a target behind the gateway is really strange, and could lead to multiple routes!
236              * anyways if invalid gateways ips may happen we are f*cked up!!
237              * but if not, these on the fly generated routes are no problem*/
238             else if ((errno == 128) & (flag == RT_ORIG_REQUEST) & (FIBM_FLAT == olsr_cnf->fib_metric) & (cmd == RTM_NEWROUTE) & (rt->rt_dst.prefix.v4.s_addr!=nexthop->gateway.v4.s_addr)) {
239               olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle '128 - Network unreachable' while adding route!");
240               rt_ret = RT_AUTO_ADD_GATEWAY_ROUTE;/*processing will contiune after this loop is finished as otherwise the rtnetlink is still blocked*/
241             }
242           }
243           // report invalid message size
244           else olsr_syslog(OLSR_LOG_INFO,"_received invalid netlink message size %u != %u",sizeof(struct nlmsgerr), h->nlmsg_len);
245           //break;
246         }
247         //log all other messages
248         else olsr_syslog(OLSR_LOG_INFO,"_received %u Byte rtnetlink response of type %u with seqnr %u and flags %u from %u (%u)",
249                          h->nlmsg_len, h->nlmsg_type, h->nlmsg_seq, h->nlmsg_flags, h->nlmsg_pid, NLMSG_ERROR);
250         h = NLMSG_NEXT(h, ret);
251       }
252     }
253   }
254   if ( rt_ret == RT_DELETE_SIMILAR_ROUTE ) {//delete all routes that may collide
255     /* recursive call to delete simlar routes, using flag 2 to invoke deletion of similar, not only exact matches*/
256     rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_DELROUTE, flag == RT_AUTO_ADD_GATEWAY_ROUTE ? RT_DELETE_SIMILAR_AUTO_ROUTE : RT_DELETE_SIMILAR_ROUTE);
257     /* retry insert original route, if deleting similar succeeded, using flag=1 to prevent recursions*/
258     if (rt_ret > 0) rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_RETRY_AFTER_DELETE_SIMILAR);
259     else olsr_syslog(OLSR_LOG_ERR, ". failed on auto-deleting similar route conflicting with above route!");
260
261     /* set appropriate return code for original request , while returning simple -1/1 if called from within an AUTO_ADD_ROUTE*/
262     if (flag != RT_AUTO_ADD_GATEWAY_ROUTE) {
263       if (rt_ret > 0) rt_ret = 0;//0 means successful recovery
264       else rt_ret = -1;//unrecoverable error
265     }
266   }
267   if ( rt_ret == RT_AUTO_ADD_GATEWAY_ROUTE ) {//autoadd route via gateway
268     /* recursive call with flag==2 to invoke gateway route*/
269     rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_AUTO_ADD_GATEWAY_ROUTE);
270     /* retry insert original route, if above succeeded (really) using flag 1 to prevent recursions*/
271     if (rt_ret > 0) rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_RETRY_AFTER_ADD_GATEWAY);
272     else olsr_syslog(OLSR_LOG_ERR, ". failed on inserting auto-generated route to gateway of above route!");
273
274     /* set appropriate return code for original request*/
275     if (rt_ret > 0) rt_ret = 0;//0 means successful recovery
276     else rt_ret = -1;//unrecoverable error
277   }
278   //send ipc update on success
279   if ((flag = RT_ORIG_REQUEST) & (0 <= rt_ret && olsr_cnf->ipc_connections > 0)) {
280     ipc_route_send_rtentry(&rt->rt_dst.prefix, &nexthop->gateway, metric, RTM_NEWROUTE == cmd,
281                              if_ifwithindex_name(nexthop->iif_index));
282   }
283   if ((rt_ret < 0 ) & (flag == RT_ORIG_REQUEST)) olsr_syslog(OLSR_LOG_INFO,"_returning %i", rt_ret);
284   if (rt_ret == -2) olsr_syslog(OLSR_LOG_ERR,"no rtnetlink response was received! (everything may happen now ...)");
285   return rt_ret;
286 }
287
288 /*external wrapper function for above patched function*/
289 static int
290 olsr_netlink_route(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd)
291 {
292   return olsr_netlink_route_int(rt, family, rttable, cmd, RT_ORIG_REQUEST);
293 }
294
295 #endif /* LINUX_POLICY_ROUTING */
296
297 /**
298  * Insert a route in the kernel routing table
299  *
300  * @param destination the route to add
301  *
302  * @return negative on error
303  */
304 int
305 olsr_ioctl_add_route(const struct rt_entry *rt)
306 {
307 #if !LINUX_POLICY_ROUTING
308   struct rtentry kernel_route;
309   union olsr_ip_addr mask;
310   int rslt;
311 #endif /* LINUX_POLICY_ROUTING */
312
313   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
314
315 #if !LINUX_POLICY_ROUTING
316   memset(&kernel_route, 0, sizeof(struct rtentry));
317
318   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
319   ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
320   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
321
322   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4;
323
324   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
325     return -1;
326   }
327   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4;
328
329   if (rt->rt_dst.prefix.v4.s_addr != rt->rt_best->rtp_nexthop.gateway.v4.s_addr) {
330     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr = rt->rt_best->rtp_nexthop.gateway.v4;
331   }
332
333   kernel_route.rt_flags = olsr_rt_flags(rt);
334   kernel_route.rt_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
335
336   /*
337    * Set interface
338    */
339   kernel_route.rt_dev = if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index);
340
341   /* delete existing default route before ? */
342   if ((olsr_cnf->del_gws) && (rt->rt_dst.prefix.v4.s_addr == INADDR_ANY) && (rt->rt_dst.prefix_len == INADDR_ANY)) {
343     delete_all_inet_gws();
344     olsr_cnf->del_gws = false;
345   }
346
347   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) {
348
349     /*
350      * Send IPC route update message
351      */
352     ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, rt->rt_best->rtp_metric.hops, 1,
353                            if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
354   }
355
356   return rslt;
357 #else /* !LINUX_POLICY_ROUTING */
358   if (0 == olsr_cnf->rttable_default && 0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable) {
359     /*
360      * Users start whining about not having internet with policy
361      * routing activated and no static default route in table 254.
362      * We maintain a fallback defroute in the default=253 table.
363      */
364     olsr_netlink_route(rt, AF_INET, 253, RTM_NEWROUTE);
365   }
366   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0)
367     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable_default, RTM_NEWROUTE);
368   else
369     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable, RTM_NEWROUTE);
370 #endif /* LINUX_POLICY_ROUTING */
371 }
372
373 /**
374  *Insert a route in the kernel routing table
375  *
376  *@param destination the route to add
377  *
378  *@return negative on error
379  */
380 int
381 olsr_ioctl_add_route6(const struct rt_entry *rt)
382 {
383 #if !LINUX_POLICY_ROUTING
384   struct in6_rtmsg kernel_route;
385   int rslt;
386
387   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
388
389   memset(&kernel_route, 0, sizeof(struct in6_rtmsg));
390
391   kernel_route.rtmsg_dst = rt->rt_dst.prefix.v6;
392   kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len;
393
394   kernel_route.rtmsg_gateway = rt->rt_best->rtp_nexthop.gateway.v6;
395
396   kernel_route.rtmsg_flags = olsr_rt_flags(rt);
397   kernel_route.rtmsg_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
398
399   /*
400    * set interface
401    */
402   kernel_route.rtmsg_ifindex = rt->rt_best->rtp_nexthop.iif_index;
403
404   /* XXX delete 0/0 route before ? */
405
406   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) {
407
408     /*
409      * Send IPC route update message
410      */
411     ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, rt->rt_best->rtp_metric.hops, 1,
412                            if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
413   }
414
415   return rslt;
416 #else /* !LINUX_POLICY_ROUTING */
417   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0)
418     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable_default, RTM_NEWROUTE);
419   else
420     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable, RTM_NEWROUTE);
421 #endif /* LINUX_POLICY_ROUTING */
422 }
423
424 /**
425  *Remove a route from the kernel
426  *
427  *@param destination the route to remove
428  *
429  *@return negative on error
430  */
431 int
432 olsr_ioctl_del_route(const struct rt_entry *rt)
433 {
434 #if !LINUX_POLICY_ROUTING
435   struct rtentry kernel_route;
436   union olsr_ip_addr mask;
437   int rslt;
438 #endif /* LINUX_POLICY_ROUTING */
439
440   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
441
442 #if !LINUX_POLICY_ROUTING
443   memset(&kernel_route, 0, sizeof(struct rtentry));
444
445   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
446   ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
447   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
448
449   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4;
450
451   if (rt->rt_dst.prefix.v4.s_addr != rt->rt_nexthop.gateway.v4.s_addr) {
452     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr = rt->rt_nexthop.gateway.v4;
453   }
454
455   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
456     return -1;
457   } else {
458     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4;
459   }
460
461   kernel_route.rt_flags = olsr_rt_flags(rt);
462   kernel_route.rt_metric = olsr_fib_metric(&rt->rt_metric.hops);
463
464   /*
465    * Set interface
466    */
467   kernel_route.rt_dev = NULL;
468
469   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route)) >= 0) {
470
471     /*
472      * Send IPC route update message
473      */
474     ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
475   }
476
477   return rslt;
478 #else /* !LINUX_POLICY_ROUTING */
479   if (0 == olsr_cnf->rttable_default && 0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable) {
480     /*
481      * Also remove the fallback default route
482      */
483     olsr_netlink_route(rt, AF_INET, 253, RTM_DELROUTE);
484   }
485   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0)
486     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable_default, RTM_DELROUTE);
487   else
488     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable, RTM_DELROUTE);
489 #endif /* LINUX_POLICY_ROUTING */
490 }
491
492 /**
493  *Remove a route from the kernel
494  *
495  *@param destination the route to remove
496  *
497  *@return negative on error
498  */
499 int
500 olsr_ioctl_del_route6(const struct rt_entry *rt)
501 {
502 #if !LINUX_POLICY_ROUTING
503   struct in6_rtmsg kernel_route;
504   int rslt;
505 #endif /* LINUX_POLICY_ROUTING */
506
507   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
508
509 #if !LINUX_POLICY_ROUTING
510   memset(&kernel_route, 0, sizeof(struct in6_rtmsg));
511
512   kernel_route.rtmsg_dst = rt->rt_dst.prefix.v6;
513   kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len;
514
515   kernel_route.rtmsg_gateway = rt->rt_best->rtp_nexthop.gateway.v6;
516
517   kernel_route.rtmsg_flags = olsr_rt_flags(rt);
518   kernel_route.rtmsg_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
519
520   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route) >= 0)) {
521
522     /*
523      * Send IPC route update message
524      */
525     ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
526   }
527
528   return rslt;
529 #else /* !LINUX_POLICY_ROUTING */
530   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0)
531     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable_default, RTM_DELROUTE);
532   else
533     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable, RTM_DELROUTE);
534 #endif /* LINUX_POLICY_ROUTING */
535 }
536
537 #if !LINUX_POLICY_ROUTING
538 static int
539 delete_all_inet_gws(void)
540 {
541   int s;
542   char buf[BUFSIZ], *cp, *cplim;
543   struct ifconf ifc;
544   struct ifreq *ifr;
545
546   OLSR_PRINTF(1, "Internet gateway detected...\nTrying to delete default gateways\n");
547
548   /* Get a socket */
549   if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
550     olsr_syslog(OLSR_LOG_ERR, "socket: %m");
551     return -1;
552   }
553
554   ifc.ifc_len = sizeof(buf);
555   ifc.ifc_buf = buf;
556   if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
557     olsr_syslog(OLSR_LOG_ERR, "ioctl (get interface configuration)");
558     close(s);
559     return -1;
560   }
561
562   ifr = ifc.ifc_req;
563   cplim = buf + ifc.ifc_len;    /*skip over if's with big ifr_addr's */
564   for (cp = buf; cp < cplim; cp += sizeof(ifr->ifr_name) + sizeof(ifr->ifr_addr)) {
565     struct rtentry kernel_route;
566     ifr = (struct ifreq *)cp;
567
568     if (strcmp(ifr->ifr_ifrn.ifrn_name, "lo") == 0) {
569       OLSR_PRINTF(1, "Skipping loopback...\n");
570       continue;
571     }
572
573     OLSR_PRINTF(1, "Trying 0.0.0.0/0 %s...", ifr->ifr_ifrn.ifrn_name);
574
575     memset(&kernel_route, 0, sizeof(struct rtentry));
576
577     ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr = 0;
578     ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
579     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = 0;
580     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
581
582     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr.s_addr = INADDR_ANY;
583     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
584
585     kernel_route.rt_flags = RTF_UP | RTF_GATEWAY;
586
587     kernel_route.rt_dev = ifr->ifr_ifrn.ifrn_name;
588
589     if ((ioctl(s, SIOCDELRT, &kernel_route)) < 0)
590       OLSR_PRINTF(1, "NO\n");
591     else
592       OLSR_PRINTF(1, "YES\n");
593   }
594   close(s);
595   return 0;
596 }
597 #endif /* LINUX_POLICY_ROUTING */
598
599 /*
600  * Local Variables:
601  * c-basic-offset: 2
602  * indent-tabs-mode: nil
603  * End:
604  */