Revert last change, mixed up ipv4 and ipv6 length
[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 *)(ARM_NOWARN_ALIGN)(((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
107   uint32_t metric = 0;
108   const struct rt_nexthop *nexthop = NULL;
109   if ( ( cmd != RTM_NEWRULE ) && ( cmd != RTM_DELRULE ) ) {
110     if (FIBM_FLAT == olsr_cnf->fib_metric) {
111       metric = RT_METRIC_DEFAULT;
112     }
113     else {
114       metric = (RTM_NEWROUTE == cmd) ? rt->rt_best->rtp_metric.hops : rt->rt_metric.hops;
115     }
116
117     if (( RTM_NEWROUTE == cmd ) ||
118         (( RTM_DELROUTE == cmd ) && ( RT_DELETE_SIMILAR_ROUTE == flag || RT_DELETE_SIMILAR_AUTO_ROUTE == flag ))) {
119       nexthop = &rt->rt_best->rtp_nexthop;
120     }
121     else {
122       nexthop = &rt->rt_nexthop;
123     }
124   }
125
126   memset(&req, 0, sizeof(req));
127
128   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
129   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
130   req.n.nlmsg_type = cmd;
131   req.r.rtm_family = family;
132   req.r.rtm_table = rttable;
133
134   /* RTN_UNSPEC would be the wildcard, but blackhole broadcast or nat roules should usually not conflict */
135   /* -> olsr only adds deletes unicast routes */
136   req.r.rtm_type = RTN_UNICAST;
137
138   /* wildcard to delete routes of all protos if no simlar-delete correct proto will get set below */
139   req.r.rtm_protocol = RTPROT_UNSPEC;
140
141   /* as wildcard for deletion */
142   req.r.rtm_scope = RT_SCOPE_NOWHERE;
143
144   if ( ( cmd != RTM_NEWRULE ) && ( cmd != RTM_DELRULE ) ) {
145     req.r.rtm_dst_len = rt->rt_dst.prefix_len;
146
147     /* do not specify much as we wanna delete similar/conflicting routes */
148     if ( ( flag != RT_DELETE_SIMILAR_ROUTE ) && ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE )) {
149       /* 0 gets replaced by OS-specifc default (3)
150        * 1 is reserved so we take 0 instead (this really makes some sense)
151        * other numbers are used 1:1 */
152       req.r.rtm_protocol = ( (olsr_cnf->rtproto<1) ? RTPROT_BOOT : ( (olsr_cnf->rtproto==1) ? 0 : olsr_cnf->rtproto) );
153       req.r.rtm_scope = RT_SCOPE_LINK;
154
155       /*add interface*/
156       olsr_netlink_addreq(&req, RTA_OIF, &nexthop->iif_index, sizeof(nexthop->iif_index));
157
158 #if SOURCE_IP_ROUTES
159       /* 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 */
160       if (AF_INET == family) {
161         olsr_netlink_addreq(&req, RTA_PREFSRC, &olsr_cnf->main_addr.v4.s_addr, sizeof(olsr_cnf->main_addr.v4.s_addr));
162       }
163       else {
164         olsr_netlink_addreq(&req, RTA_PREFSRC, &olsr_cnf->main_addr.v6.s6_addr, sizeof(olsr_cnf->main_addr.v6.s6_addr));
165       }
166 #endif
167     }
168
169     /* metric is specified always as we can only delete one route per iteration, and wanna hit the correct one first */
170     if (FIBM_APPROX != olsr_cnf->fib_metric || (RTM_NEWROUTE == cmd) ) {
171       olsr_netlink_addreq(&req, RTA_PRIORITY, &metric, sizeof(metric));
172     }
173
174     /* make sure that netmask = /32 as this is an autogenarated route */
175     if (( flag == RT_AUTO_ADD_GATEWAY_ROUTE ) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) {
176       req.r.rtm_dst_len = 32;
177     }
178
179     /* for ipv4 or ipv6 we add gateway if one is specified, 
180     * or leave gateway away if we want to delete similar routes aswell, 
181     * or even use the gateway as target if we add a auto-generated route, 
182     * or if delete-similar to make insertion of auto-generated route possible */
183     if (AF_INET == family) {
184       if ( ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE) && 
185            ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) && (rt->rt_dst.prefix.v4.s_addr != nexthop->gateway.v4.s_addr) ) {
186         olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v4, sizeof(nexthop->gateway.v4));
187         req.r.rtm_scope = RT_SCOPE_UNIVERSE;
188       }
189       olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
190                           &nexthop->gateway.v4 : &rt->rt_dst.prefix.v4, sizeof(rt->rt_dst.prefix.v4));
191     } else {
192       if ( ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE ) && ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) 
193           && (0 != memcmp(&rt->rt_dst.prefix.v6, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6))) ) {
194         olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6));
195         req.r.rtm_scope = RT_SCOPE_UNIVERSE;
196       }
197       olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
198                           &nexthop->gateway.v6 : &rt->rt_dst.prefix.v6, sizeof(rt->rt_dst.prefix.v6));
199     }
200   } else {
201     /* add or delete a rule */
202     static uint32_t priority = 65535;
203
204     req.r.rtm_scope = RT_SCOPE_UNIVERSE;
205     olsr_netlink_addreq(&req, RTA_PRIORITY, &priority, sizeof(priority));
206   }
207
208   iov.iov_base = &req.n;
209   iov.iov_len = req.n.nlmsg_len;
210   memset(&nladdr, 0, sizeof(nladdr));
211   nladdr.nl_family = AF_NETLINK;
212   if (0 <= (ret = sendmsg(olsr_cnf->rtnl_s, &msg, 0))) {
213     iov.iov_base = req.buf;
214     iov.iov_len = sizeof(req.buf);
215     if (0 < (ret = recvmsg(olsr_cnf->rtnl_s, &msg, 0))) {
216       struct nlmsghdr *h = (struct nlmsghdr *)(ARM_NOWARN_ALIGN)req.buf;
217       while (NLMSG_OK(h, (unsigned int)ret)) {
218         if (NLMSG_DONE == h->nlmsg_type) {
219           /* seems to reached never */
220           olsr_syslog(OLSR_LOG_INFO, "_received NLMSG_DONE");
221           break;
222         }
223         if (NLMSG_ERROR == h->nlmsg_type) {
224           if (NLMSG_LENGTH(sizeof(struct nlmsgerr) <= h->nlmsg_len)) {
225             struct ipaddr_str ibuf;
226             struct ipaddr_str gbuf;
227             struct nlmsgerr *l_err = (struct nlmsgerr *)NLMSG_DATA(h);
228             errno = -l_err->error;
229             if (0 != errno) {
230               const char *const err_msg = strerror(errno);
231               struct ipaddr_str buf;
232               rt_ret = -1;
233
234               /* syslog debug output for various situations */
235               if ( cmd == RTM_NEWRULE ) {
236                 olsr_syslog(OLSR_LOG_ERR,"Error '%s' (%d) on inserting empty policy rule aimed to activate RtTable %u!", err_msg, errno, rttable);
237               }
238               else if ( cmd == RTM_DELRULE ) {
239                 olsr_syslog(OLSR_LOG_ERR,"Error '%s' (%d) on deleting empty policy rule aimed to activate rtTable %u!", err_msg, errno, rttable);
240               }
241               else if ( flag <= RT_RETRY_AFTER_DELETE_SIMILAR ) {
242                 if (rt->rt_dst.prefix.v4.s_addr!=nexthop->gateway.v4.s_addr) {
243                   olsr_syslog(OLSR_LOG_ERR, "error '%s' (%d) %s route to %s/%d via %s dev %s",
244                       err_msg, errno, (cmd == RTM_NEWROUTE) ? "add" : "del",
245                       olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix), req.r.rtm_dst_len,
246                       olsr_ip_to_string(&gbuf,&nexthop->gateway), if_ifwithindex_name(nexthop->iif_index));
247                 }
248                 else {
249                   olsr_syslog(OLSR_LOG_ERR, "error '%s' (%d) %s route to %s/%d dev %s",
250                       err_msg, errno, (cmd == RTM_NEWROUTE) ? "add" : "del",
251                       olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix), req.r.rtm_dst_len, if_ifwithindex_name(nexthop->iif_index));
252                 }
253               }
254               else if (flag == RT_AUTO_ADD_GATEWAY_ROUTE) {
255                 olsr_syslog(OLSR_LOG_ERR, ". error '%s' (%d) auto-add route to %s dev %s", err_msg, errno,
256                     olsr_ip_to_string(&ibuf,&nexthop->gateway), if_ifwithindex_name(nexthop->iif_index));
257               }
258               else if (flag == RT_DELETE_SIMILAR_ROUTE) {
259                 olsr_syslog(OLSR_LOG_ERR, ". error '%s' (%d) auto-delete route to %s dev %s", err_msg, errno,
260                     olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix), if_ifwithindex_name(nexthop->iif_index));
261               }
262               else if (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) {
263                 olsr_syslog(OLSR_LOG_ERR, ". . error '%s' (%d) auto-delete similar route to %s dev %s", err_msg, errno,
264                     olsr_ip_to_string(&ibuf,&nexthop->gateway), if_ifwithindex_name(nexthop->iif_index));
265               }
266               else {
267                 /* should never happen */
268                 olsr_syslog(OLSR_LOG_ERR, "# invalid internal route delete/add flag (%d) used!", flag);
269               }
270             }
271             else {
272               /* netlink acks requests with an errno=0 NLMSG_ERROR response! */
273               rt_ret = 1;
274             }
275
276             /* resolve "File exist" (17) propblems (on orig and autogen routes)*/       
277             if ((errno == 17) && (cmd == RTM_NEWROUTE) && ((flag == RT_ORIG_REQUEST) || (flag == RT_AUTO_ADD_GATEWAY_ROUTE))) {
278               /* a similar route going over another gateway may be present, which has to be deleted! */
279               olsr_syslog(OLSR_LOG_ERR, ". auto-deleting similar routes to resolve 'File exists' (17) while adding route!");
280               rt_ret = RT_DELETE_SIMILAR_ROUTE; /* processing will contiune after this loop */
281             }
282             /* report success on "No such process" (3) */
283             else if ((errno == 3) && (cmd == RTM_DELROUTE) && (flag == RT_ORIG_REQUEST)) {
284               /* another similar (but slightly different) route may be present at this point
285               * , if so this will get solved when adding new route to this destination */
286               olsr_syslog(OLSR_LOG_ERR, ". ignoring 'No such process' (3) while deleting route!");
287               rt_ret = 0;
288             }
289             /* insert route to gateway on the fly if "Network unreachable" (128) on 2.4 kernels
290              * or on 2.6 kernel No such process (3) or Network unreachable (101) is reported in rtnetlink response
291              * do this only with flat metric, as using metric values inherited from 
292              * a target behind the gateway is really strange, and could lead to multiple routes!
293              * anyways if invalid gateway ips may happen we are f*cked up!!
294              * but if not, these on the fly generated routes are no problem, and will only get used when needed */
295             else if ( ( (errno == 3) || (errno == 101) || (errno == 128) )
296                 && (flag == RT_ORIG_REQUEST) && (FIBM_FLAT == olsr_cnf->fib_metric)
297                      && (cmd == RTM_NEWROUTE) && (rt->rt_dst.prefix.v4.s_addr!=nexthop->gateway.v4.s_addr)) {
298               if (errno == 128)  {
299                 olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (128) while adding route!");
300               }
301               else if (errno == 101) {
302                 olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (101) while adding route!");
303               }
304               else {
305                 olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'No such process' (3) while adding route!");
306               }
307
308               /* processing will contiune after this loop */
309               rt_ret = RT_AUTO_ADD_GATEWAY_ROUTE;
310             }
311           }
312           /* report invalid message size */
313           else {
314             olsr_syslog(OLSR_LOG_INFO,"_received invalid netlink message size %lu != %u",
315                 (unsigned long int)sizeof(struct nlmsgerr), h->nlmsg_len);
316           }
317         }
318         /* log all other messages */
319         else {
320           olsr_syslog(OLSR_LOG_INFO,"_received %u Byte rtnetlink response of type %u with seqnr %u and flags %u from %u (%u)",
321               h->nlmsg_len, h->nlmsg_type, h->nlmsg_seq, h->nlmsg_flags, h->nlmsg_pid, NLMSG_ERROR);
322         }
323 /*
324  * The ARM compile complains about alignment. Copied
325  * from /usr/include/linux/netlink.h and adapted for ARM
326  */
327 #define MY_NLMSG_NEXT(nlh,len)   ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
328                                   (struct nlmsghdr*)(ARM_NOWARN_ALIGN)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
329         h = MY_NLMSG_NEXT(h, ret);
330       }
331     }
332   }
333   if ( rt_ret == RT_DELETE_SIMILAR_ROUTE ) {
334     /* delete all routes that may collide */
335
336     /* recursive call to delete simlar routes, using flag 2 to invoke deletion of similar, not only exact matches*/
337     rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_DELROUTE, 
338         flag == RT_AUTO_ADD_GATEWAY_ROUTE ? RT_DELETE_SIMILAR_AUTO_ROUTE : RT_DELETE_SIMILAR_ROUTE);
339
340     /* retry insert original route, if deleting similar succeeded, using flag=1 to prevent recursions */
341     if (rt_ret > 0) {
342       rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_RETRY_AFTER_DELETE_SIMILAR);
343     }
344     else {
345       olsr_syslog(OLSR_LOG_ERR, ". failed on auto-deleting similar route conflicting with above route!");
346     }
347
348     /* set appropriate return code for original request, while returning simple -1/1 if called recursive */
349     if (flag != RT_AUTO_ADD_GATEWAY_ROUTE) {
350       if (rt_ret > 0) {
351         /* successful recovery */
352         rt_ret = 0;
353       }
354       else {
355         /* unrecoverable error */
356         rt_ret = -1;
357       }
358     }
359   }
360   if ( rt_ret == RT_AUTO_ADD_GATEWAY_ROUTE ) {
361     /* autoadd route via gateway */
362
363     /* recursive call to invoke creation of a route to the gateway */
364     rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_AUTO_ADD_GATEWAY_ROUTE);
365
366     /* retry insert original route, if above succeeded without problems */
367     if (rt_ret > 0) {
368       rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_RETRY_AFTER_ADD_GATEWAY);
369     }
370     else {
371       olsr_syslog(OLSR_LOG_ERR, ". failed on inserting auto-generated route to gateway of above route!");
372     }
373
374     /* set appropriate return code for original request*/
375     if (rt_ret > 0) {
376       /* successful recovery */
377       rt_ret = 0;
378     }
379     else {
380       /* unrecoverable error */
381       rt_ret = -1;
382     }
383   }
384   /* send ipc update on success */
385   if ( ( cmd != RTM_NEWRULE ) && ( cmd != RTM_DELRULE )
386       && (flag = RT_ORIG_REQUEST) && (0 <= rt_ret && olsr_cnf->ipc_connections > 0) ) {
387     ipc_route_send_rtentry(&rt->rt_dst.prefix, &nexthop->gateway, metric,
388         RTM_NEWROUTE == cmd, if_ifwithindex_name(nexthop->iif_index));
389   }
390   if (rt_ret == -2) {
391     olsr_syslog(OLSR_LOG_ERR,"no rtnetlink response! (no system ressources left?, everything may happen now ...)");
392   }
393   return rt_ret;
394 }
395
396 /* external wrapper function for above patched multi purpose rtnetlink function */
397 int
398 olsr_netlink_rule(uint8_t family, uint8_t rttable, uint16_t cmd)
399 {
400   return olsr_netlink_route_int(NULL, family, rttable, cmd, RT_ORIG_REQUEST);
401 }
402
403 /* internal wrapper function for above patched function */
404 static int
405 olsr_netlink_route(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd)
406 {
407   return olsr_netlink_route_int(rt, family, rttable, cmd, RT_ORIG_REQUEST);
408 }
409
410 #endif /* LINUX_POLICY_ROUTING */
411
412 /**
413  * Insert a route in the kernel routing table
414  *
415  * @param destination the route to add
416  *
417  * @return negative on error
418  */
419 int
420 olsr_ioctl_add_route(const struct rt_entry *rt)
421 {
422 #if !LINUX_POLICY_ROUTING
423   struct rtentry kernel_route;
424   union olsr_ip_addr mask;
425   int rslt;
426 #endif /* LINUX_POLICY_ROUTING */
427
428   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
429
430 #if !LINUX_POLICY_ROUTING
431   memset(&kernel_route, 0, sizeof(struct rtentry));
432
433   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
434   ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
435   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
436
437   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4;
438
439   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
440     return -1;
441   }
442   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4;
443
444   if (rt->rt_dst.prefix.v4.s_addr != rt->rt_best->rtp_nexthop.gateway.v4.s_addr) {
445     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr = rt->rt_best->rtp_nexthop.gateway.v4;
446   }
447
448   kernel_route.rt_flags = olsr_rt_flags(rt);
449   kernel_route.rt_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
450
451   /*
452    * Set interface
453    */
454   kernel_route.rt_dev = if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index);
455
456   /* delete existing default route before ? */
457   if ((olsr_cnf->del_gws) && (rt->rt_dst.prefix.v4.s_addr == INADDR_ANY) && (rt->rt_dst.prefix_len == INADDR_ANY)) {
458     delete_all_inet_gws();
459     olsr_cnf->del_gws = false;
460   }
461
462   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) {
463
464     /*
465      * Send IPC route update message
466      */
467     ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, rt->rt_best->rtp_metric.hops, 1,
468                            if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
469   }
470
471   return rslt;
472 #else /* !LINUX_POLICY_ROUTING */
473   if (0 == olsr_cnf->rttable_default && 0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable) {
474     /*
475      * Users start whining about not having internet with policy
476      * routing activated and no static default route in table 254.
477      * We maintain a fallback defroute in the default=253 table.
478      */
479     olsr_netlink_route(rt, AF_INET, 253, RTM_NEWROUTE);
480   }
481   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0) {
482     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable_default, RTM_NEWROUTE);
483   }
484   else {
485     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable, RTM_NEWROUTE);
486   }
487 #endif /* LINUX_POLICY_ROUTING */
488 }
489
490 /**
491  *Insert a route in the kernel routing table
492  *
493  *@param destination the route to add
494  *
495  *@return negative on error
496  */
497 int
498 olsr_ioctl_add_route6(const struct rt_entry *rt)
499 {
500 #if !LINUX_POLICY_ROUTING
501   struct in6_rtmsg kernel_route;
502   int rslt;
503
504   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
505
506   memset(&kernel_route, 0, sizeof(struct in6_rtmsg));
507
508   kernel_route.rtmsg_dst = rt->rt_dst.prefix.v6;
509   kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len;
510
511   kernel_route.rtmsg_gateway = rt->rt_best->rtp_nexthop.gateway.v6;
512
513   kernel_route.rtmsg_flags = olsr_rt_flags(rt);
514   kernel_route.rtmsg_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
515
516   /*
517    * set interface
518    */
519   kernel_route.rtmsg_ifindex = rt->rt_best->rtp_nexthop.iif_index;
520
521   /* XXX delete 0/0 route before ? */
522
523   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) {
524
525     /*
526      * Send IPC route update message
527      */
528     ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, rt->rt_best->rtp_metric.hops, 1,
529                            if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
530   }
531   return rslt;
532 #else /* !LINUX_POLICY_ROUTING */
533   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0) {
534     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable_default, RTM_NEWROUTE);
535   }
536   else {
537     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable, RTM_NEWROUTE);
538   }
539 #endif /* LINUX_POLICY_ROUTING */
540 }
541
542 /**
543  *Remove a route from the kernel
544  *
545  *@param destination the route to remove
546  *
547  *@return negative on error
548  */
549 int
550 olsr_ioctl_del_route(const struct rt_entry *rt)
551 {
552 #if !LINUX_POLICY_ROUTING
553   struct rtentry kernel_route;
554   union olsr_ip_addr mask;
555   int rslt;
556 #endif /* LINUX_POLICY_ROUTING */
557
558   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
559
560 #if !LINUX_POLICY_ROUTING
561   memset(&kernel_route, 0, sizeof(struct rtentry));
562
563   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
564   ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
565   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
566
567   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4;
568
569   if (rt->rt_dst.prefix.v4.s_addr != rt->rt_nexthop.gateway.v4.s_addr) {
570     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr = rt->rt_nexthop.gateway.v4;
571   }
572
573   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
574     return -1;
575   } else {
576     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4;
577   }
578
579   kernel_route.rt_flags = olsr_rt_flags(rt);
580   kernel_route.rt_metric = olsr_fib_metric(&rt->rt_metric.hops);
581
582   /*
583    * Set interface
584    */
585   kernel_route.rt_dev = NULL;
586
587   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route)) >= 0) {
588
589     /*
590      * Send IPC route update message
591      */
592     ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
593   }
594
595   return rslt;
596 #else /* !LINUX_POLICY_ROUTING */
597   if (0 == olsr_cnf->rttable_default && 0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable) {
598     /*
599      * Also remove the fallback default route
600      */
601     olsr_netlink_route(rt, AF_INET, 253, RTM_DELROUTE);
602   }
603   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0) {
604     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable_default, RTM_DELROUTE);
605   }
606   else {
607     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable, RTM_DELROUTE);
608   }
609 #endif /* LINUX_POLICY_ROUTING */
610 }
611
612 /**
613  *Remove a route from the kernel
614  *
615  *@param destination the route to remove
616  *
617  *@return negative on error
618  */
619 int
620 olsr_ioctl_del_route6(const struct rt_entry *rt)
621 {
622 #if !LINUX_POLICY_ROUTING
623   struct in6_rtmsg kernel_route;
624   int rslt;
625 #endif /* LINUX_POLICY_ROUTING */
626
627   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
628
629 #if !LINUX_POLICY_ROUTING
630   memset(&kernel_route, 0, sizeof(struct in6_rtmsg));
631
632   kernel_route.rtmsg_dst = rt->rt_dst.prefix.v6;
633   kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len;
634
635   kernel_route.rtmsg_gateway = rt->rt_best->rtp_nexthop.gateway.v6;
636
637   kernel_route.rtmsg_flags = olsr_rt_flags(rt);
638   kernel_route.rtmsg_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
639
640   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route) >= 0)) {
641
642     /*
643      * Send IPC route update message
644      */
645     ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
646   }
647
648   return rslt;
649 #else /* !LINUX_POLICY_ROUTING */
650   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0) {
651     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable_default, RTM_DELROUTE);
652   }
653   else {
654     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable, RTM_DELROUTE);
655   }
656 #endif /* LINUX_POLICY_ROUTING */
657 }
658
659 #if !LINUX_POLICY_ROUTING
660 static int
661 delete_all_inet_gws(void)
662 {
663   int s;
664   char buf[BUFSIZ], *cp, *cplim;
665   struct ifconf ifc;
666   struct ifreq *ifr;
667
668   OLSR_PRINTF(1, "Internet gateway detected...\nTrying to delete default gateways\n");
669
670   /* Get a socket */
671   if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
672     olsr_syslog(OLSR_LOG_ERR, "socket: %m");
673     return -1;
674   }
675
676   ifc.ifc_len = sizeof(buf);
677   ifc.ifc_buf = buf;
678   if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
679     olsr_syslog(OLSR_LOG_ERR, "ioctl (get interface configuration)");
680     close(s);
681     return -1;
682   }
683
684   ifr = ifc.ifc_req;
685   cplim = buf + ifc.ifc_len;    /*skip over if's with big ifr_addr's */
686   for (cp = buf; cp < cplim; cp += sizeof(ifr->ifr_name) + sizeof(ifr->ifr_addr)) {
687     struct rtentry kernel_route;
688     ifr = (struct ifreq *)cp;
689
690     if (strcmp(ifr->ifr_ifrn.ifrn_name, "lo") == 0) {
691       OLSR_PRINTF(1, "Skipping loopback...\n");
692       continue;
693     }
694
695     OLSR_PRINTF(1, "Trying 0.0.0.0/0 %s...", ifr->ifr_ifrn.ifrn_name);
696
697     memset(&kernel_route, 0, sizeof(struct rtentry));
698
699     ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr = 0;
700     ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
701     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = 0;
702     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
703
704     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr.s_addr = INADDR_ANY;
705     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
706
707     kernel_route.rt_flags = RTF_UP | RTF_GATEWAY;
708
709     kernel_route.rt_dev = ifr->ifr_ifrn.ifrn_name;
710
711     if ((ioctl(s, SIOCDELRT, &kernel_route)) < 0)
712       OLSR_PRINTF(1, "NO\n");
713     else
714       OLSR_PRINTF(1, "YES\n");
715   }
716   close(s);
717   return 0;
718 }
719 #endif /* LINUX_POLICY_ROUTING */
720
721 /*
722  * Local Variables:
723  * c-basic-offset: 2
724  * indent-tabs-mode: nil
725  * End:
726  */