c4502cb61a81656bf1fc95d93b40aa69eec9406a
[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 <net/if.h>
65 #include <linux/rtnetlink.h>
66
67 struct olsr_rtreq {
68   struct nlmsghdr n;
69   struct rtmsg r;
70   char buf[512];
71 };
72
73 static void
74 olsr_netlink_addreq(struct olsr_rtreq *req, int type, const void *data, int len)
75 {
76   struct rtattr *rta = (struct rtattr *)(((char *)req) + NLMSG_ALIGN(req->n.nlmsg_len));
77   req->n.nlmsg_len = NLMSG_ALIGN(req->n.nlmsg_len) + RTA_LENGTH(len);
78   assert(req->n.nlmsg_len < sizeof(struct olsr_rtreq));
79   rta->rta_type = type;
80   rta->rta_len = RTA_LENGTH(len);
81   memcpy(RTA_DATA(rta), data, len);
82 }
83
84 /* returns
85  * -1 on unrecoverable error (calling function will handle it)
86  * 0 on unexpected but recoverable behaviour like (no such process, file existsm, network unreachable)
87  *   but the implemented recovery methods only cure the symptoms, not the cause, which still wansn`t found/fixed
88  *   but ignoring this errors and just logging them into syslog without any recover mechanisms may cause significatn ressource usage and missing routes in kernel
89  *   to ensure that this problems are fixed at proper place in future, recovery process logs warnings into syslog!
90  * 1 on success */
91 static int
92 olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd, uint8_t flag)
93 {
94   int ret = 1; //helper variable for rtnetlink_message processing
95   int rt_ret = -2;  //if no response from rtnetlink it must be considered as failed!!!
96   struct olsr_rtreq req;
97   struct iovec iov;
98   struct sockaddr_nl nladdr;
99   struct msghdr msg = {
100     &nladdr,
101     sizeof(nladdr),
102     &iov,
103     1,
104     NULL,
105     0,
106     0
107   };
108   uint32_t metric = ((cmd != RTM_NEWRULE) | (cmd != RTM_DELRULE)) ?
109     FIBM_FLAT != olsr_cnf->fib_metric ? 
110       ((RTM_NEWROUTE == cmd) ? rt->rt_best->rtp_metric.hops : rt->rt_metric.hops) 
111       : RT_METRIC_DEFAULT
112       : 0;
113   const struct rt_nexthop *nexthop = ((cmd != RTM_NEWRULE) | (cmd != RTM_DELRULE)) ? (RTM_NEWROUTE == cmd) ? &rt->rt_best->rtp_nexthop : &rt->rt_nexthop : NULL;
114
115   memset(&req, 0, sizeof(req));
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   req.r.rtm_type = RTN_UNICAST;//RTN_UNSPEC /*different rtm_type will not conflict, but of course if there a blackhole routes they will do what they do,..*/
122   req.r.rtm_protocol = RTPROT_UNSPEC;//wildcard to delete routes of all protos if no simlar-delete correct proto will get set below
123   req.r.rtm_scope = RT_SCOPE_NOWHERE;//as wildcard for deletion
124
125   if (( cmd != RTM_NEWRULE ) & ( cmd != RTM_DELRULE ) ) {
126     req.r.rtm_dst_len = rt->rt_dst.prefix_len;
127
128     /*do not specify much if we wanna delete similar routes*/
129     /*this currently works for different interfaces, src-ips metrics, gateways, protos*/
130     if ((flag != RT_DELETE_SIMILAR_ROUTE) & (flag != RT_DELETE_SIMILAR_AUTO_ROUTE)) {
131       req.r.rtm_protocol = RTPROT_BOOT;
132       req.r.rtm_scope = RT_SCOPE_LINK;
133       /*add interface*/
134       olsr_netlink_addreq(&req, RTA_OIF, &nexthop->iif_index, sizeof(nexthop->iif_index));
135     }
136
137     /*metric is specified always as we can only delete one route per iteration, and wanna hit the correct one first*/
138     if (FIBM_APPROX != olsr_cnf->fib_metric || (RTM_NEWROUTE == cmd) ) {
139       olsr_netlink_addreq(&req, RTA_PRIORITY, &metric, sizeof(metric));
140     }
141
142     //make sure that netmask = /32 as this is an autogenarated route
143     if (( flag == RT_AUTO_ADD_GATEWAY_ROUTE ) | (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) req.r.rtm_dst_len = 32;
144
145     /* for ipv4 or ipv6 we add gateway if one is specified, 
146     * or leave gateway away if we want to delete similar routes aswell, 
147     * 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)*/
148     if (AF_INET == family) {
149       if ( ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) & (flag != RT_DELETE_SIMILAR_ROUTE) & 
150            ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) & (rt->rt_dst.prefix.v4.s_addr != nexthop->gateway.v4.s_addr) ) {
151         olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v4, sizeof(nexthop->gateway.v4));
152         req.r.rtm_scope = RT_SCOPE_UNIVERSE;
153       }
154       olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) | (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
155                           &nexthop->gateway.v4 : &rt->rt_dst.prefix.v4, sizeof(rt->rt_dst.prefix.v4));
156     } else {
157       if ( ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) & (flag != RT_DELETE_SIMILAR_ROUTE ) & 
158            ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) & (0 != memcmp(&rt->rt_dst.prefix.v6, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6))) ) {
159         olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6));
160         req.r.rtm_scope = RT_SCOPE_UNIVERSE;
161       }
162       olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) | (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
163                         &nexthop->gateway.v6 : &rt->rt_dst.prefix.v6, sizeof(rt->rt_dst.prefix.v6));
164     }
165   } else {//add or delete a rule
166     static uint32_t priority = 65535;
167     req.r.rtm_scope = RT_SCOPE_UNIVERSE;
168     olsr_netlink_addreq(&req, RTA_PRIORITY, &priority, sizeof(priority));
169   }
170
171   iov.iov_base = &req.n;
172   iov.iov_len = req.n.nlmsg_len;
173   memset(&nladdr, 0, sizeof(nladdr));
174   nladdr.nl_family = AF_NETLINK;
175   if (0 <= (ret = sendmsg(olsr_cnf->rtnl_s, &msg, 0))) {
176     iov.iov_base = req.buf;
177     iov.iov_len = sizeof(req.buf);
178     if (0 < (ret = recvmsg(olsr_cnf->rtnl_s, &msg, 0))) {
179       struct nlmsghdr *h = (struct nlmsghdr *)req.buf;
180       while (NLMSG_OK(h, (unsigned int)ret)) {
181         if (NLMSG_DONE == h->nlmsg_type) {
182           //seems to reached never
183           olsr_syslog(OLSR_LOG_INFO, "_received NLMSG_DONE");
184           break;
185         }
186         if (NLMSG_ERROR == h->nlmsg_type) {
187           if (NLMSG_LENGTH(sizeof(struct nlmsgerr) <= h->nlmsg_len)) {
188             struct ipaddr_str ibuf;
189             struct ipaddr_str gbuf;
190             struct nlmsgerr *l_err = (struct nlmsgerr *)NLMSG_DATA(h);
191             errno = -l_err->error;
192             if (0 != errno) {
193               const char *const err_msg = strerror(errno);
194               struct ipaddr_str buf;
195               rt_ret = -1;
196               char ifbuf[IF_NAMESIZE];
197               /*debug output for original and retry attempts*/
198               if ( cmd == RTM_NEWRULE ) {
199                 olsr_syslog(OLSR_LOG_ERR,"Error '%s' (%d) on inserting empty policy rule aimed to activate RtTable %u!", err_msg, errno, rttable);
200               }
201               else if ( cmd == RTM_DELRULE ) {
202                 olsr_syslog(OLSR_LOG_ERR,"Error '%s' (%d) on deleting empty policy rule aimed to activate rtTable %u!", err_msg, errno, rttable);
203               }
204               else {
205                 if_indextoname(nexthop->iif_index, *ifbuf);
206                 if ( flag <= RT_RETRY_AFTER_DELETE_SIMILAR ) {
207                   if (rt->rt_dst.prefix.v4.s_addr!=nexthop->gateway.v4.s_addr)
208                     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",
209                                olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix),
210                                req.r.rtm_dst_len,
211                                olsr_ip_to_string(&gbuf,&nexthop->gateway), ifbuf); 
212                   else olsr_syslog(OLSR_LOG_ERR, "error '%s' (%d) %s route to %s/%d dev %s", err_msg, errno, (cmd == RTM_NEWROUTE) ? "add" : "del",
213                                   olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix),
214                                   req.r.rtm_dst_len, ifbuf);
215                 }
216                 //deug output for autogen routes
217                 else if (flag == RT_AUTO_ADD_GATEWAY_ROUTE) olsr_syslog(OLSR_LOG_ERR, ". error '%s' (%d) auto-add route to %s dev %d", err_msg, errno, 
218                                  olsr_ip_to_string(&ibuf,&nexthop->gateway), ifbuf);
219                 //debug output for auto-delete similar
220                 else if (flag == RT_DELETE_SIMILAR_ROUTE) olsr_syslog(OLSR_LOG_ERR, ". error '%s' (%d) auto-delete route to %s dev %s", err_msg, errno, 
221                                                olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix), ifbuf);
222                 //debug output for auto-delete similar
223                 else if (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) olsr_syslog(OLSR_LOG_ERR, ". . error '%s' (%d) auto-delete similar route to %s dev %s", err_msg, errno, 
224                                                                olsr_ip_to_string(&ibuf,&nexthop->gateway), ifbuf);
225                 //should never happen
226                 else {
227                   olsr_syslog(OLSR_LOG_ERR, "# invalid internal route delete/add flag (%d) used!", flag);
228                 }
229               }
230             }
231             else {
232               //netlink acks rquests with an errno=0 NLMSG_ERROR response!
233               //olsr_syslog(OLSR_LOG_INFO, "# RTNETLINK ACK!");
234               rt_ret = 1;
235             }
236
237             //olsr_syslog(OLSR_LOG_ERR
238             /* resolve "File exist" (17) propblems (on orig and autogen routes)*/       
239             if ((errno == 17) & ((flag == RT_ORIG_REQUEST) | (flag == RT_AUTO_ADD_GATEWAY_ROUTE)) & (cmd == RTM_NEWROUTE)) {
240               /*a simlar route going over another gateway may be present, which should be deleted*/
241               olsr_syslog(OLSR_LOG_ERR, ". auto-deleting similar routes to resolve 'File exists' (17) while adding route!");
242               rt_ret = RT_DELETE_SIMILAR_ROUTE;/*processing will contiune after this loop is finished as otherwise the rtnetlink is still blocked*/
243             }
244             /* report success on "No such process" (3) */
245             else if ((errno == 3) & (cmd == RTM_DELROUTE) & (flag == RT_ORIG_REQUEST)) {
246               /*another similar (but different) route may be present, but as we don not have a better route, nothing to think about*/
247               olsr_syslog(OLSR_LOG_ERR, ". ignoring 'No such process' (3) while deleting route!");
248               rt_ret = 0;
249             }
250             /* insert route to gateway on the fly if "Network unreachable" (128) on 2.4 kernels
251              * or on 2.6 kernel No such process (3) is reported in rtneltink response
252              * do this only with flat metric, as using metric values inherited from 
253              * a target behind the gateway is really strange, and could lead to multiple routes!
254              * anyways if invalid gateway ips may happen we are f*cked up!!
255              * but if not, these on the fly generated routes are no problem, and will only get used when needed*/
256             else if (((errno == 3)|(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)) {
257               if (errno == 128) olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (128) while adding route!");
258               else olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'No such process' (3) while adding route!");
259               rt_ret = RT_AUTO_ADD_GATEWAY_ROUTE;/*processing will contiune after this loop is finished as otherwise the rtnetlink is still blocked*/
260             }
261           }
262           // report invalid message size
263           else olsr_syslog(OLSR_LOG_INFO,"_received invalid netlink message size %u != %u",sizeof(struct nlmsgerr), h->nlmsg_len);
264           //break;
265         }
266         //log all other messages
267         else olsr_syslog(OLSR_LOG_INFO,"_received %u Byte rtnetlink response of type %u with seqnr %u and flags %u from %u (%u)",
268                          h->nlmsg_len, h->nlmsg_type, h->nlmsg_seq, h->nlmsg_flags, h->nlmsg_pid, NLMSG_ERROR);
269         h = NLMSG_NEXT(h, ret);
270       }
271     }
272   }
273   if ( rt_ret == RT_DELETE_SIMILAR_ROUTE ) {//delete all routes that may collide
274     /* recursive call to delete simlar routes, using flag 2 to invoke deletion of similar, not only exact matches*/
275     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);
276     /* retry insert original route, if deleting similar succeeded, using flag=1 to prevent recursions*/
277     if (rt_ret > 0) rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_RETRY_AFTER_DELETE_SIMILAR);
278     else olsr_syslog(OLSR_LOG_ERR, ". failed on auto-deleting similar route conflicting with above route!");
279
280     /* set appropriate return code for original request , while returning simple -1/1 if called from within an AUTO_ADD_ROUTE*/
281     if (flag != RT_AUTO_ADD_GATEWAY_ROUTE) {
282       if (rt_ret > 0) rt_ret = 0;//0 means successful recovery
283       else rt_ret = -1;//unrecoverable error
284     }
285   }
286   if ( rt_ret == RT_AUTO_ADD_GATEWAY_ROUTE ) {//autoadd route via gateway
287     /* recursive call with flag==2 to invoke gateway route*/
288     rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_AUTO_ADD_GATEWAY_ROUTE);
289     /* retry insert original route, if above succeeded (really) using flag 1 to prevent recursions*/
290     if (rt_ret > 0) rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_RETRY_AFTER_ADD_GATEWAY);
291     else olsr_syslog(OLSR_LOG_ERR, ". failed on inserting auto-generated route to gateway of above route!");
292
293     /* set appropriate return code for original request*/
294     if (rt_ret > 0) rt_ret = 0;//0 means successful recovery
295     else rt_ret = -1;//unrecoverable error
296   }
297   //send ipc update on success
298   if ( ( cmd != RTM_NEWRULE ) & ( cmd != RTM_DELRULE ) & (flag = RT_ORIG_REQUEST) & (0 <= rt_ret && olsr_cnf->ipc_connections > 0)) {
299     ipc_route_send_rtentry(&rt->rt_dst.prefix, &nexthop->gateway, metric, RTM_NEWROUTE == cmd,
300                              if_ifwithindex_name(nexthop->iif_index));
301   }
302   if (rt_ret == -2) olsr_syslog(OLSR_LOG_ERR,"no rtnetlink response was received! (no more system ressources?, everything may happen now ...)");
303   return rt_ret;
304 }
305
306 /*external wrapper function for above patched multi purpose rtnetlink function*/
307 int
308 olsr_netlink_rule(uint8_t family, uint8_t rttable, uint16_t cmd)
309 {
310   struct rt_entry rt;
311   return olsr_netlink_route_int(&rt, family, rttable, cmd, RT_ORIG_REQUEST);
312 }
313
314 /*internal wrapper function for above patched function*/
315 static int
316 olsr_netlink_route(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd)
317 {
318   return olsr_netlink_route_int(rt, family, rttable, cmd, RT_ORIG_REQUEST);
319 }
320
321 #endif /* LINUX_POLICY_ROUTING */
322
323 /**
324  * Insert a route in the kernel routing table
325  *
326  * @param destination the route to add
327  *
328  * @return negative on error
329  */
330 int
331 olsr_ioctl_add_route(const struct rt_entry *rt)
332 {
333 #if !LINUX_POLICY_ROUTING
334   struct rtentry kernel_route;
335   union olsr_ip_addr mask;
336   int rslt;
337 #endif /* LINUX_POLICY_ROUTING */
338
339   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
340
341 #if !LINUX_POLICY_ROUTING
342   memset(&kernel_route, 0, sizeof(struct rtentry));
343
344   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
345   ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
346   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
347
348   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4;
349
350   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
351     return -1;
352   }
353   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4;
354
355   if (rt->rt_dst.prefix.v4.s_addr != rt->rt_best->rtp_nexthop.gateway.v4.s_addr) {
356     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr = rt->rt_best->rtp_nexthop.gateway.v4;
357   }
358
359   kernel_route.rt_flags = olsr_rt_flags(rt);
360   kernel_route.rt_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
361
362   /*
363    * Set interface
364    */
365   kernel_route.rt_dev = if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index);
366
367   /* delete existing default route before ? */
368   if ((olsr_cnf->del_gws) && (rt->rt_dst.prefix.v4.s_addr == INADDR_ANY) && (rt->rt_dst.prefix_len == INADDR_ANY)) {
369     delete_all_inet_gws();
370     olsr_cnf->del_gws = false;
371   }
372
373   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) {
374
375     /*
376      * Send IPC route update message
377      */
378     ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, rt->rt_best->rtp_metric.hops, 1,
379                            if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
380   }
381
382   return rslt;
383 #else /* !LINUX_POLICY_ROUTING */
384   if (0 == olsr_cnf->rttable_default && 0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable) {
385     /*
386      * Users start whining about not having internet with policy
387      * routing activated and no static default route in table 254.
388      * We maintain a fallback defroute in the default=253 table.
389      */
390     olsr_netlink_route(rt, AF_INET, 253, RTM_NEWROUTE);
391   }
392   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0)
393     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable_default, RTM_NEWROUTE);
394   else
395     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable, RTM_NEWROUTE);
396 #endif /* LINUX_POLICY_ROUTING */
397 }
398
399 /**
400  *Insert a route in the kernel routing table
401  *
402  *@param destination the route to add
403  *
404  *@return negative on error
405  */
406 int
407 olsr_ioctl_add_route6(const struct rt_entry *rt)
408 {
409 #if !LINUX_POLICY_ROUTING
410   struct in6_rtmsg kernel_route;
411   int rslt;
412
413   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
414
415   memset(&kernel_route, 0, sizeof(struct in6_rtmsg));
416
417   kernel_route.rtmsg_dst = rt->rt_dst.prefix.v6;
418   kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len;
419
420   kernel_route.rtmsg_gateway = rt->rt_best->rtp_nexthop.gateway.v6;
421
422   kernel_route.rtmsg_flags = olsr_rt_flags(rt);
423   kernel_route.rtmsg_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
424
425   /*
426    * set interface
427    */
428   kernel_route.rtmsg_ifindex = rt->rt_best->rtp_nexthop.iif_index;
429
430   /* XXX delete 0/0 route before ? */
431
432   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) {
433
434     /*
435      * Send IPC route update message
436      */
437     ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, rt->rt_best->rtp_metric.hops, 1,
438                            if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
439   }
440
441   return rslt;
442 #else /* !LINUX_POLICY_ROUTING */
443   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0)
444     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable_default, RTM_NEWROUTE);
445   else
446     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable, RTM_NEWROUTE);
447 #endif /* LINUX_POLICY_ROUTING */
448 }
449
450 /**
451  *Remove a route from the kernel
452  *
453  *@param destination the route to remove
454  *
455  *@return negative on error
456  */
457 int
458 olsr_ioctl_del_route(const struct rt_entry *rt)
459 {
460 #if !LINUX_POLICY_ROUTING
461   struct rtentry kernel_route;
462   union olsr_ip_addr mask;
463   int rslt;
464 #endif /* LINUX_POLICY_ROUTING */
465
466   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
467
468 #if !LINUX_POLICY_ROUTING
469   memset(&kernel_route, 0, sizeof(struct rtentry));
470
471   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
472   ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
473   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
474
475   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4;
476
477   if (rt->rt_dst.prefix.v4.s_addr != rt->rt_nexthop.gateway.v4.s_addr) {
478     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr = rt->rt_nexthop.gateway.v4;
479   }
480
481   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
482     return -1;
483   } else {
484     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4;
485   }
486
487   kernel_route.rt_flags = olsr_rt_flags(rt);
488   kernel_route.rt_metric = olsr_fib_metric(&rt->rt_metric.hops);
489
490   /*
491    * Set interface
492    */
493   kernel_route.rt_dev = NULL;
494
495   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route)) >= 0) {
496
497     /*
498      * Send IPC route update message
499      */
500     ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
501   }
502
503   return rslt;
504 #else /* !LINUX_POLICY_ROUTING */
505   if (0 == olsr_cnf->rttable_default && 0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable) {
506     /*
507      * Also remove the fallback default route
508      */
509     olsr_netlink_route(rt, AF_INET, 253, RTM_DELROUTE);
510   }
511   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0)
512     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable_default, RTM_DELROUTE);
513   else
514     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable, RTM_DELROUTE);
515 #endif /* LINUX_POLICY_ROUTING */
516 }
517
518 /**
519  *Remove a route from the kernel
520  *
521  *@param destination the route to remove
522  *
523  *@return negative on error
524  */
525 int
526 olsr_ioctl_del_route6(const struct rt_entry *rt)
527 {
528 #if !LINUX_POLICY_ROUTING
529   struct in6_rtmsg kernel_route;
530   int rslt;
531 #endif /* LINUX_POLICY_ROUTING */
532
533   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
534
535 #if !LINUX_POLICY_ROUTING
536   memset(&kernel_route, 0, sizeof(struct in6_rtmsg));
537
538   kernel_route.rtmsg_dst = rt->rt_dst.prefix.v6;
539   kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len;
540
541   kernel_route.rtmsg_gateway = rt->rt_best->rtp_nexthop.gateway.v6;
542
543   kernel_route.rtmsg_flags = olsr_rt_flags(rt);
544   kernel_route.rtmsg_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
545
546   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route) >= 0)) {
547
548     /*
549      * Send IPC route update message
550      */
551     ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
552   }
553
554   return rslt;
555 #else /* !LINUX_POLICY_ROUTING */
556   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0)
557     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable_default, RTM_DELROUTE);
558   else
559     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable, RTM_DELROUTE);
560 #endif /* LINUX_POLICY_ROUTING */
561 }
562
563 #if !LINUX_POLICY_ROUTING
564 static int
565 delete_all_inet_gws(void)
566 {
567   int s;
568   char buf[BUFSIZ], *cp, *cplim;
569   struct ifconf ifc;
570   struct ifreq *ifr;
571
572   OLSR_PRINTF(1, "Internet gateway detected...\nTrying to delete default gateways\n");
573
574   /* Get a socket */
575   if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
576     olsr_syslog(OLSR_LOG_ERR, "socket: %m");
577     return -1;
578   }
579
580   ifc.ifc_len = sizeof(buf);
581   ifc.ifc_buf = buf;
582   if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
583     olsr_syslog(OLSR_LOG_ERR, "ioctl (get interface configuration)");
584     close(s);
585     return -1;
586   }
587
588   ifr = ifc.ifc_req;
589   cplim = buf + ifc.ifc_len;    /*skip over if's with big ifr_addr's */
590   for (cp = buf; cp < cplim; cp += sizeof(ifr->ifr_name) + sizeof(ifr->ifr_addr)) {
591     struct rtentry kernel_route;
592     ifr = (struct ifreq *)cp;
593
594     if (strcmp(ifr->ifr_ifrn.ifrn_name, "lo") == 0) {
595       OLSR_PRINTF(1, "Skipping loopback...\n");
596       continue;
597     }
598
599     OLSR_PRINTF(1, "Trying 0.0.0.0/0 %s...", ifr->ifr_ifrn.ifrn_name);
600
601     memset(&kernel_route, 0, sizeof(struct rtentry));
602
603     ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr = 0;
604     ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
605     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = 0;
606     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
607
608     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr.s_addr = INADDR_ANY;
609     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
610
611     kernel_route.rt_flags = RTF_UP | RTF_GATEWAY;
612
613     kernel_route.rt_dev = ifr->ifr_ifrn.ifrn_name;
614
615     if ((ioctl(s, SIOCDELRT, &kernel_route)) < 0)
616       OLSR_PRINTF(1, "NO\n");
617     else
618       OLSR_PRINTF(1, "YES\n");
619   }
620   close(s);
621   return 0;
622 }
623 #endif /* LINUX_POLICY_ROUTING */
624
625 /*
626  * Local Variables:
627  * c-basic-offset: 2
628  * indent-tabs-mode: nil
629  * End:
630  */