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