Add OLSR support for NIIT (IP 4to6 tunnel device)
[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 #define RT_NIIT 6
56
57 #if !LINUX_POLICY_ROUTING
58
59 static int delete_all_inet_gws(void);
60
61 #else /* !LINUX_POLICY_ROUTING */
62
63 #include <assert.h>
64 #include <linux/types.h>
65 #include <linux/rtnetlink.h>
66
67 extern struct rtnl_handle rth;
68
69 struct olsr_rtreq {
70   struct nlmsghdr n;
71   struct rtmsg r;
72   char buf[512];
73 };
74
75 #if LINUX_RTNETLINK_LISTEN
76 #include "ifnet.h"
77 #include "socket_parser.h"
78
79 int rtnetlink_register_socket(int rtnl_mgrp)
80 {
81   int sock = socket(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE);
82   struct sockaddr_nl addr;
83
84   if (sock<0) {
85     OLSR_PRINTF(1,"could not create rtnetlink socket! %d",sock);
86   }
87   else {
88     memset(&addr, 0, sizeof(addr));
89
90     addr.nl_family = AF_NETLINK;
91     addr.nl_pid = 0; //kernel will assign appropiate number instead of pid (which is already used by primaray rtnetlink socket to add/delete routes)
92     addr.nl_groups = rtnl_mgrp;
93     if (bind(sock,(struct sockaddr *)&addr,sizeof(addr))<0) {
94       OLSR_PRINTF(1,"could not bind socket! (%d %s)",errno,strerror(errno));
95     }
96     else {
97       add_olsr_socket(sock, &rtnetlink_read);
98     }
99     fcntl(sock, F_SETFL, O_NONBLOCK);
100   }
101   return sock;
102 }
103
104 static void netlink_process_link(struct nlmsghdr *h)
105 {
106   struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(h);
107   struct interface *iface;
108   struct olsr_if *tmp_if;
109
110   iface = if_ifwithindex(ifi->ifi_index);
111   if (iface == NULL) {
112     return;
113   }
114   
115   //all IFF flags: LOOPBACK,BROADCAST;POINTOPOINT;MULTICAST;NOARP;ALLMULTI;PROMISC;MASTER;SLAVE;DEBUG;DYNAMIC;AUTOMEDIA;PORTSEL;NOTRAILERS;UP;LOWER_UP;DORMANT
116   /* check if interface is up and running? (a not running interface keeps its routes, so better not react like on ifdown!!??) */
117   if (ifi->ifi_flags&IFF_UP) {
118     OLSR_PRINTF(3,"interface %s changed but is still up! ", iface->int_name);
119     return; //we are currently only interested in interfaces that are/go down
120   } else {
121     OLSR_PRINTF(1,"interface %s is down! ", iface->int_name);
122   }
123
124   //only for still configured interfaces (ifup has to be detected with regular interface polling)
125   for (tmp_if = olsr_cnf->interfaces; tmp_if != NULL; tmp_if = tmp_if->next) {
126     if (tmp_if->interf==iface) {
127       OLSR_PRINTF(1,"-> removing %s from olsr config! ", iface->int_name);
128       RemoveInterface(tmp_if,true);
129       break;
130     }
131   }
132 }
133
134
135 void rtnetlink_read(int sock)
136 {
137   int len, plen;
138   struct iovec iov;
139   struct sockaddr_nl nladdr;
140   struct msghdr msg = {
141     &nladdr,
142     sizeof(nladdr),
143     &iov,
144     1,
145     NULL,
146     0,
147     0
148   };
149
150   char buffer[4096];
151   struct nlmsghdr *nlh = (struct nlmsghdr *)(ARM_NOWARN_ALIGN) buffer;
152   int ret;
153
154   iov.iov_base = (void *) buffer;
155   iov.iov_len = sizeof(buffer);
156
157   while (true) { //read until ret<0;
158     ret=recvmsg(sock, &msg, 0);
159     if (ret<0) {
160       if (errno != EAGAIN) OLSR_PRINTF(1,"\nnetlink listen error %u - %s",errno,strerror(errno));
161       return;
162     }
163     /*check message*/
164     len = nlh->nlmsg_len;
165     plen = len - sizeof(nlh);
166     if (len > ret || plen < 0) {
167       OLSR_PRINTF(1,"Malformed netlink message: "
168              "len=%d left=%d plen=%d",
169               len, ret, plen);
170       return;
171     }
172     if ( (nlh->nlmsg_type == RTM_NEWLINK) || ( nlh->nlmsg_type == RTM_DELLINK) ) netlink_process_link(nlh);
173   }
174 }
175
176 #endif /*linux_rtnetlink_listen*/
177
178 static void
179 olsr_netlink_addreq(struct olsr_rtreq *req, int type, const void *data, int len)
180 {
181   struct rtattr *rta = (struct rtattr *)(ARM_NOWARN_ALIGN)(((char *)req) + NLMSG_ALIGN(req->n.nlmsg_len));
182   req->n.nlmsg_len = NLMSG_ALIGN(req->n.nlmsg_len) + RTA_LENGTH(len);
183   assert(req->n.nlmsg_len < sizeof(struct olsr_rtreq));
184   rta->rta_type = type;
185   rta->rta_len = RTA_LENGTH(len);
186   memcpy(RTA_DATA(rta), data, len);
187 }
188
189 /* returns
190  * -1 on unrecoverable error (calling function will have to handle it)
191  *  0 on unexpected but recoverable rtnetlink behaviour
192  *    but some of the implemented recovery methods only cure symptoms, 
193  *    not the cause, like unintelligent ordering of inserted routes.
194  *  1 on success */
195 static int
196 olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd, uint8_t flag)
197 {
198   int ret = 1; /* helper variable for rtnetlink_message processing */
199   int rt_ret = -2;  /* if no response from rtnetlink it must be considered as failed! */
200   struct olsr_rtreq req;
201   struct iovec iov;
202   struct sockaddr_nl nladdr;
203   struct msghdr msg = {
204     &nladdr,
205     sizeof(nladdr),
206     &iov,
207     1,
208     NULL,
209     0,
210     0
211   };
212
213   uint32_t metric = 0;
214   const struct rt_nexthop *nexthop = NULL;
215   if ( ( cmd != RTM_NEWRULE ) && ( cmd != RTM_DELRULE ) ) {
216     if (FIBM_FLAT == olsr_cnf->fib_metric) {
217       metric = RT_METRIC_DEFAULT;
218     }
219     else {
220       metric = (RTM_NEWROUTE == cmd) ? rt->rt_best->rtp_metric.hops : rt->rt_metric.hops;
221     }
222
223     if (( RTM_NEWROUTE == cmd ) ||
224         (( RTM_DELROUTE == cmd ) && ( RT_DELETE_SIMILAR_ROUTE == flag || RT_DELETE_SIMILAR_AUTO_ROUTE == flag ))) {
225       nexthop = &rt->rt_best->rtp_nexthop;
226     }
227     else {
228       nexthop = &rt->rt_nexthop;
229     }
230   }
231
232   memset(&req, 0, sizeof(req));
233
234   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
235   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
236   req.n.nlmsg_type = cmd;
237   
238   /*sanity check for niit ipv4 over ipv6 routes*/
239   if (family == AF_INET && flag == RT_NIIT) {
240     olsr_syslog(OLSR_LOG_ERR,"niit makes no sense with olsrd running on ipv4!");
241     return -1;
242   }
243
244   if (flag == RT_NIIT) {
245     req.r.rtm_family=AF_INET; /*we create an ipv4 niit route*/
246   }
247   else {
248     req.r.rtm_family = family;
249   }
250
251   req.r.rtm_table = rttable;
252
253   /* RTN_UNSPEC would be the wildcard, but blackhole broadcast or nat roules should usually not conflict */
254   /* -> olsr only adds deletes unicast routes */
255   req.r.rtm_type = RTN_UNICAST;
256
257   /* wildcard to delete routes of all protos if no simlar-delete correct proto will get set below */
258   req.r.rtm_protocol = RTPROT_UNSPEC;
259
260   /* as wildcard for deletion */
261   req.r.rtm_scope = RT_SCOPE_NOWHERE;
262
263   if ( ( cmd == RTM_NEWRULE ) || ( cmd == RTM_DELRULE ) ) {
264     /* add or delete a rule */
265     static uint32_t priority = 65535;
266
267     req.r.rtm_scope = RT_SCOPE_UNIVERSE;
268     olsr_netlink_addreq(&req, RTA_PRIORITY, &priority, sizeof(priority));
269   }
270   else {
271     req.r.rtm_dst_len = rt->rt_dst.prefix_len;
272
273     /* do not specify much as we wanna delete similar/conflicting routes */
274     if ( ( flag != RT_DELETE_SIMILAR_ROUTE ) && ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE )) {
275       /* 0 gets replaced by OS-specifc default (3)
276        * 1 is reserved so we take 0 instead (this really makes some sense)
277        * other numbers are used 1:1 */
278       req.r.rtm_protocol = ( (olsr_cnf->rtproto<1) ? RTPROT_BOOT : ( (olsr_cnf->rtproto==1) ? 0 : olsr_cnf->rtproto) );
279       req.r.rtm_scope = RT_SCOPE_LINK;
280
281       /*add interface*/
282       if (flag == RT_NIIT) {
283         olsr_netlink_addreq(&req, RTA_OIF, &olsr_cnf->niit_if_index, sizeof(&olsr_cnf->niit_if_index));
284       }
285       else {
286         olsr_netlink_addreq(&req, RTA_OIF, &nexthop->iif_index, sizeof(nexthop->iif_index));
287       }
288
289 #if SOURCE_IP_ROUTES
290       /**
291        * source ip here is based on now static olsr_cnf->main_addr in this olsr-0.5.6-r4,
292        * should be based on orignator-id in newer olsrds
293        **/
294       if (flag != RT_NIIT) {
295         if (AF_INET == family) {
296           olsr_netlink_addreq(&req, RTA_PREFSRC, &olsr_cnf->main_addr.v4.s_addr, sizeof(olsr_cnf->main_addr.v4.s_addr));
297         }
298         else {
299           olsr_netlink_addreq(&req, RTA_PREFSRC, &olsr_cnf->main_addr.v6.s6_addr, sizeof(olsr_cnf->main_addr.v6.s6_addr));
300         }
301       }
302 #endif
303     }
304
305     /* metric is specified always as we can only delete one route per iteration, and wanna hit the correct one first */
306     if (FIBM_APPROX != olsr_cnf->fib_metric || (RTM_NEWROUTE == cmd) ) {
307       olsr_netlink_addreq(&req, RTA_PRIORITY, &metric, sizeof(metric));
308     }
309
310     /* make sure that netmask = maxplen (32 or 128) as this is an autogenarated (host)route */
311     if (( flag == RT_AUTO_ADD_GATEWAY_ROUTE ) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) {
312       req.r.rtm_dst_len = olsr_cnf->maxplen;
313     }
314
315     /**
316      * for ipv4 or ipv6 we add gateway if one is specified,
317      * or leave gateway away if we want to delete similar routes aswell,
318      * or even use the gateway as target if we add a auto-generated route,
319      * or if delete-similar to make insertion of auto-generated route possible
320      **/
321     if (AF_INET == family) {
322       if ( ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE) && 
323            ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) && (rt->rt_dst.prefix.v4.s_addr != nexthop->gateway.v4.s_addr) ) {
324         olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v4, sizeof(nexthop->gateway.v4));
325         req.r.rtm_scope = RT_SCOPE_UNIVERSE;
326       }
327       olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
328                           &nexthop->gateway.v4 : &rt->rt_dst.prefix.v4, sizeof(rt->rt_dst.prefix.v4));
329     } else {
330       if (flag == RT_NIIT) {
331         union olsr_ip_addr ipv4_addr;
332         /* create an ipv4 route */
333         olsr_syslog(OLSR_LOG_ERR,"niit suport not fully implemented!!"); 
334
335         /* fix prefix length */
336         req.r.rtm_dst_len = rt->rt_dst.prefix_len - 96;
337         olsr_netlink_addreq(&req, RTA_DST, olsr_ipv6_to_ipv4(&rt->rt_dst.prefix, &ipv4_addr), sizeof(ipv4_addr.v4));
338       }
339       else {
340         if ( ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE ) && ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) 
341             && (0 != memcmp(&rt->rt_dst.prefix.v6, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6))) ) {
342           olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6));
343           req.r.rtm_scope = RT_SCOPE_UNIVERSE;
344         }
345         olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
346                             &nexthop->gateway.v6 : &rt->rt_dst.prefix.v6, sizeof(rt->rt_dst.prefix.v6));
347       }
348     }
349   }
350
351   iov.iov_base = &req.n;
352   iov.iov_len = req.n.nlmsg_len;
353   memset(&nladdr, 0, sizeof(nladdr));
354   nladdr.nl_family = AF_NETLINK;
355   if (0 <= (ret = sendmsg(olsr_cnf->rtnl_s, &msg, 0))) {
356     iov.iov_base = req.buf;
357     iov.iov_len = sizeof(req.buf);
358     if (0 < (ret = recvmsg(olsr_cnf->rtnl_s, &msg, 0))) {
359       struct nlmsghdr *h = (struct nlmsghdr *)(ARM_NOWARN_ALIGN)req.buf;
360       while (NLMSG_OK(h, (unsigned int)ret)) {
361         if (NLMSG_DONE == h->nlmsg_type) {
362           /* seems to reached never */
363           olsr_syslog(OLSR_LOG_INFO, "_received NLMSG_DONE");
364           break;
365         }
366         if (NLMSG_ERROR == h->nlmsg_type) {
367           if (NLMSG_LENGTH(sizeof(struct nlmsgerr) <= h->nlmsg_len)) {
368             struct ipaddr_str ibuf;
369             struct ipaddr_str gbuf;
370             struct nlmsgerr *l_err = (struct nlmsgerr *)NLMSG_DATA(h);
371             errno = -l_err->error;
372             if (0 != errno) {
373               const char *const err_msg = strerror(errno);
374               struct ipaddr_str buf;
375               rt_ret = -1;
376
377               /* syslog debug output for various situations */
378               if ( cmd == RTM_NEWRULE ) {
379                 olsr_syslog(OLSR_LOG_ERR,"Error '%s' (%d) on inserting empty policy rule aimed to activate RtTable %u!", err_msg, errno, rttable);
380               }
381               else if ( cmd == RTM_DELRULE ) {
382                 olsr_syslog(OLSR_LOG_ERR,"Error '%s' (%d) on deleting empty policy rule aimed to activate rtTable %u!", err_msg, errno, rttable);
383               }
384               else if ( flag == RT_NIIT ) {
385                 olsr_syslog(OLSR_LOG_ERR,"Error '%s' (%d) on manipulating niit route of %s!", err_msg, errno, olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix));
386               }
387               else if ( flag <= RT_RETRY_AFTER_DELETE_SIMILAR ) {
388                 if (rt->rt_dst.prefix.v4.s_addr!=nexthop->gateway.v4.s_addr) {
389                   olsr_syslog(OLSR_LOG_ERR, "error '%s' (%d) %s route to %s/%d via %s dev %s",
390                       err_msg, errno, (cmd == RTM_NEWROUTE) ? "add" : "del",
391                       olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix), req.r.rtm_dst_len,
392                       olsr_ip_to_string(&gbuf,&nexthop->gateway), if_ifwithindex_name(nexthop->iif_index));
393                 }
394                 else {
395                   olsr_syslog(OLSR_LOG_ERR, "error '%s' (%d) %s route to %s/%d dev %s",
396                       err_msg, errno, (cmd == RTM_NEWROUTE) ? "add" : "del",
397                       olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix), req.r.rtm_dst_len, if_ifwithindex_name(nexthop->iif_index));
398                 }
399               }
400               else if (flag == RT_AUTO_ADD_GATEWAY_ROUTE) {
401                 olsr_syslog(OLSR_LOG_ERR, ". error '%s' (%d) auto-add route to %s dev %s", err_msg, errno,
402                     olsr_ip_to_string(&ibuf,&nexthop->gateway), if_ifwithindex_name(nexthop->iif_index));
403               }
404               else if (flag == RT_DELETE_SIMILAR_ROUTE) {
405                 olsr_syslog(OLSR_LOG_ERR, ". error '%s' (%d) auto-delete route to %s dev %s", err_msg, errno,
406                     olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix), if_ifwithindex_name(nexthop->iif_index));
407               }
408               else if (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) {
409                 olsr_syslog(OLSR_LOG_ERR, ". . error '%s' (%d) auto-delete similar route to %s dev %s", err_msg, errno,
410                     olsr_ip_to_string(&ibuf,&nexthop->gateway), if_ifwithindex_name(nexthop->iif_index));
411               }
412               else {
413                 /* should never happen */
414                 olsr_syslog(OLSR_LOG_ERR, "# invalid internal route delete/add flag (%d) used!", flag);
415               }
416             }
417             else {
418               /* netlink acks requests with an errno=0 NLMSG_ERROR response! */
419               rt_ret = 1;
420             }
421
422             /* resolve "File exist" (17) propblems (on orig and autogen routes)*/       
423             if ((errno == 17) && (cmd == RTM_NEWROUTE) && ((flag == RT_ORIG_REQUEST) || (flag == RT_AUTO_ADD_GATEWAY_ROUTE))) {
424               /* a similar route going over another gateway may be present, which has to be deleted! */
425               olsr_syslog(OLSR_LOG_ERR, ". auto-deleting similar routes to resolve 'File exists' (17) while adding route!");
426               rt_ret = RT_DELETE_SIMILAR_ROUTE; /* processing will contiune after this loop */
427             }
428             /* report success on "No such process" (3) */
429             else if ((errno == 3) && (cmd == RTM_DELROUTE) && (flag == RT_ORIG_REQUEST)) {
430               /* another similar (but slightly different) route may be present at this point
431               * , if so this will get solved when adding new route to this destination */
432               olsr_syslog(OLSR_LOG_ERR, ". ignoring 'No such process' (3) while deleting route!");
433               rt_ret = 0;
434             }
435             /* insert route to gateway on the fly if "Network unreachable" (128) on 2.4 kernels
436              * or on 2.6 kernel No such process (3) or Network unreachable (101) is reported in rtnetlink response
437              * do this only with flat metric, as using metric values inherited from 
438              * a target behind the gateway is really strange, and could lead to multiple routes!
439              * anyways if invalid gateway ips may happen we are f*cked up!!
440              * but if not, these on the fly generated routes are no problem, and will only get used when needed */
441             else if ( ( (errno == 3) || (errno == 101) || (errno == 128) )
442                 && (flag == RT_ORIG_REQUEST) && (FIBM_FLAT == olsr_cnf->fib_metric)
443                      && (cmd == RTM_NEWROUTE) && (rt->rt_dst.prefix.v4.s_addr!=nexthop->gateway.v4.s_addr)) {
444               if (errno == 128)  {
445                 olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (128) while adding route!");
446               }
447               else if (errno == 101) {
448                 olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (101) while adding route!");
449               }
450               else {
451                 olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'No such process' (3) while adding route!");
452               }
453
454               /* processing will contiune after this loop */
455               rt_ret = RT_AUTO_ADD_GATEWAY_ROUTE;
456             }
457           }
458           /* report invalid message size */
459           else {
460             olsr_syslog(OLSR_LOG_INFO,"_received invalid netlink message size %lu != %u",
461                 (unsigned long int)sizeof(struct nlmsgerr), h->nlmsg_len);
462           }
463         }
464         /* log all other messages */
465         else {
466           olsr_syslog(OLSR_LOG_INFO,"_received %u Byte rtnetlink response of type %u with seqnr %u and flags %u from %u (%u)",
467               h->nlmsg_len, h->nlmsg_type, h->nlmsg_seq, h->nlmsg_flags, h->nlmsg_pid, NLMSG_ERROR);
468         }
469 /*
470  * The ARM compile complains about alignment. Copied
471  * from /usr/include/linux/netlink.h and adapted for ARM
472  */
473 #define MY_NLMSG_NEXT(nlh,len)   ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
474                                   (struct nlmsghdr*)(ARM_NOWARN_ALIGN)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
475         h = MY_NLMSG_NEXT(h, ret);
476       }
477     }
478   }
479   if ( rt_ret == RT_DELETE_SIMILAR_ROUTE ) {
480     /* delete all routes that may collide */
481
482     /* recursive call to delete simlar routes, using flag 2 to invoke deletion of similar, not only exact matches*/
483     rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_DELROUTE, 
484         flag == RT_AUTO_ADD_GATEWAY_ROUTE ? RT_DELETE_SIMILAR_AUTO_ROUTE : RT_DELETE_SIMILAR_ROUTE);
485
486     /* retry insert original route, if deleting similar succeeded, using flag=1 to prevent recursions */
487     if (rt_ret > 0) {
488       rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_RETRY_AFTER_DELETE_SIMILAR);
489     }
490     else {
491       olsr_syslog(OLSR_LOG_ERR, ". failed on auto-deleting similar route conflicting with above route!");
492     }
493
494     /* set appropriate return code for original request, while returning simple -1/1 if called recursive */
495     if (flag != RT_AUTO_ADD_GATEWAY_ROUTE) {
496       if (rt_ret > 0) {
497         /* successful recovery */
498         rt_ret = 0;
499       }
500       else {
501         /* unrecoverable error */
502         rt_ret = -1;
503       }
504     }
505   }
506   if ( rt_ret == RT_AUTO_ADD_GATEWAY_ROUTE ) {
507     /* autoadd route via gateway */
508
509     /* recursive call to invoke creation of a route to the gateway */
510     rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_AUTO_ADD_GATEWAY_ROUTE);
511
512     /* retry insert original route, if above succeeded without problems */
513     if (rt_ret > 0) {
514       rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_RETRY_AFTER_ADD_GATEWAY);
515     }
516     else {
517       olsr_syslog(OLSR_LOG_ERR, ". failed on inserting auto-generated route to gateway of above route!");
518     }
519
520     /* set appropriate return code for original request*/
521     if (rt_ret > 0) {
522       /* successful recovery */
523       rt_ret = 0;
524     }
525     else {
526       /* unrecoverable error */
527       rt_ret = -1;
528     }
529   }
530   /* send ipc update on success */
531   if ( ( cmd != RTM_NEWRULE ) && ( cmd != RTM_DELRULE )
532       && (flag == RT_ORIG_REQUEST) && (0 <= rt_ret && olsr_cnf->ipc_connections > 0) ) {
533     ipc_route_send_rtentry(&rt->rt_dst.prefix, &nexthop->gateway, metric,
534         RTM_NEWROUTE == cmd, if_ifwithindex_name(nexthop->iif_index));
535   }
536   if (rt_ret == -2) {
537     olsr_syslog(OLSR_LOG_ERR,"no rtnetlink response! (no system ressources left?, everything may happen now ...)");
538   }
539   return rt_ret;
540 }
541
542 /* external wrapper function for above patched multi purpose rtnetlink function */
543 int
544 olsr_netlink_rule(uint8_t family, uint8_t rttable, uint16_t cmd)
545 {
546   return olsr_netlink_route_int(NULL, family, rttable, cmd, RT_ORIG_REQUEST);
547 }
548
549 /* internal wrapper function for above patched function */
550 static int
551 olsr_netlink_route(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd)
552 {
553   /*create/delete niit route if we have an niit device*/
554   if ((olsr_cnf->niit_if_index!=0) && (family != AF_INET) && (olsr_is_niit_ip(&rt->rt_dst.prefix))) {
555     olsr_netlink_route_int(rt, family, rttable, cmd, RT_NIIT);
556   }
557
558   return olsr_netlink_route_int(rt, family, rttable, cmd, RT_ORIG_REQUEST);
559 }
560
561 #endif /* LINUX_POLICY_ROUTING */
562
563 /**
564  * Insert a route in the kernel routing table
565  *
566  * @param destination the route to add
567  *
568  * @return negative on error
569  */
570 int
571 olsr_ioctl_add_route(const struct rt_entry *rt)
572 {
573 #if !LINUX_POLICY_ROUTING
574   struct rtentry kernel_route;
575   union olsr_ip_addr mask;
576   int rslt;
577 #endif /* LINUX_POLICY_ROUTING */
578
579   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
580
581 #if !LINUX_POLICY_ROUTING
582   memset(&kernel_route, 0, sizeof(struct rtentry));
583
584   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
585   ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
586   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
587
588   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4;
589
590   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
591     return -1;
592   }
593   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4;
594
595   if (rt->rt_dst.prefix.v4.s_addr != rt->rt_best->rtp_nexthop.gateway.v4.s_addr) {
596     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr = rt->rt_best->rtp_nexthop.gateway.v4;
597   }
598
599   kernel_route.rt_flags = olsr_rt_flags(rt);
600   kernel_route.rt_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
601
602   /*
603    * Set interface
604    */
605   kernel_route.rt_dev = if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index);
606
607   /* delete existing default route before ? */
608   if ((olsr_cnf->del_gws) && (rt->rt_dst.prefix.v4.s_addr == INADDR_ANY) && (rt->rt_dst.prefix_len == INADDR_ANY)) {
609     delete_all_inet_gws();
610     olsr_cnf->del_gws = false;
611   }
612
613   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) {
614
615     /*
616      * Send IPC route update message
617      */
618     ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, rt->rt_best->rtp_metric.hops, 1,
619                            if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
620   }
621
622   return rslt;
623 #else /* !LINUX_POLICY_ROUTING */
624   if (0 == olsr_cnf->rttable_default && 0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable) {
625     /*
626      * Users start whining about not having internet with policy
627      * routing activated and no static default route in table 254.
628      * We maintain a fallback defroute in the default=253 table.
629      */
630     olsr_netlink_route(rt, AF_INET, 253, RTM_NEWROUTE);
631   }
632   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0) {
633     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable_default, RTM_NEWROUTE);
634   }
635   else {
636     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable, RTM_NEWROUTE);
637   }
638 #endif /* LINUX_POLICY_ROUTING */
639 }
640
641 /**
642  *Insert a route in the kernel routing table
643  *
644  *@param destination the route to add
645  *
646  *@return negative on error
647  */
648 int
649 olsr_ioctl_add_route6(const struct rt_entry *rt)
650 {
651 #if !LINUX_POLICY_ROUTING
652   struct in6_rtmsg kernel_route;
653   int rslt;
654
655   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
656
657   memset(&kernel_route, 0, sizeof(struct in6_rtmsg));
658
659   kernel_route.rtmsg_dst = rt->rt_dst.prefix.v6;
660   kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len;
661
662   kernel_route.rtmsg_gateway = rt->rt_best->rtp_nexthop.gateway.v6;
663
664   kernel_route.rtmsg_flags = olsr_rt_flags(rt);
665   kernel_route.rtmsg_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
666
667   /*
668    * set interface
669    */
670   kernel_route.rtmsg_ifindex = rt->rt_best->rtp_nexthop.iif_index;
671
672   /* XXX delete 0/0 route before ? */
673
674   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) {
675
676     /*
677      * Send IPC route update message
678      */
679     ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, rt->rt_best->rtp_metric.hops, 1,
680                            if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
681   }
682   return rslt;
683 #else /* !LINUX_POLICY_ROUTING */
684   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0) {
685     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable_default, RTM_NEWROUTE);
686   }
687   else {
688     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable, RTM_NEWROUTE);
689   }
690 #endif /* LINUX_POLICY_ROUTING */
691 }
692
693 /**
694  *Remove a route from the kernel
695  *
696  *@param destination the route to remove
697  *
698  *@return negative on error
699  */
700 int
701 olsr_ioctl_del_route(const struct rt_entry *rt)
702 {
703 #if !LINUX_POLICY_ROUTING
704   struct rtentry kernel_route;
705   union olsr_ip_addr mask;
706   int rslt;
707 #endif /* LINUX_POLICY_ROUTING */
708
709   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
710
711 #if !LINUX_POLICY_ROUTING
712   memset(&kernel_route, 0, sizeof(struct rtentry));
713
714   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
715   ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
716   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
717
718   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4;
719
720   if (rt->rt_dst.prefix.v4.s_addr != rt->rt_nexthop.gateway.v4.s_addr) {
721     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr = rt->rt_nexthop.gateway.v4;
722   }
723
724   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
725     return -1;
726   } else {
727     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4;
728   }
729
730   kernel_route.rt_flags = olsr_rt_flags(rt);
731   kernel_route.rt_metric = olsr_fib_metric(&rt->rt_metric.hops);
732
733   /*
734    * Set interface
735    */
736   kernel_route.rt_dev = NULL;
737
738   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route)) >= 0) {
739
740     /*
741      * Send IPC route update message
742      */
743     ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
744   }
745
746   return rslt;
747 #else /* !LINUX_POLICY_ROUTING */
748   if (0 == olsr_cnf->rttable_default && 0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable) {
749     /*
750      * Also remove the fallback default route
751      */
752     olsr_netlink_route(rt, AF_INET, 253, RTM_DELROUTE);
753   }
754   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0) {
755     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable_default, RTM_DELROUTE);
756   }
757   else {
758     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable, RTM_DELROUTE);
759   }
760 #endif /* LINUX_POLICY_ROUTING */
761 }
762
763 /**
764  *Remove a route from the kernel
765  *
766  *@param destination the route to remove
767  *
768  *@return negative on error
769  */
770 int
771 olsr_ioctl_del_route6(const struct rt_entry *rt)
772 {
773 #if !LINUX_POLICY_ROUTING
774   struct in6_rtmsg kernel_route;
775   int rslt;
776 #endif /* LINUX_POLICY_ROUTING */
777
778   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
779
780 #if !LINUX_POLICY_ROUTING
781   memset(&kernel_route, 0, sizeof(struct in6_rtmsg));
782
783   kernel_route.rtmsg_dst = rt->rt_dst.prefix.v6;
784   kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len;
785
786   kernel_route.rtmsg_gateway = rt->rt_best->rtp_nexthop.gateway.v6;
787
788   kernel_route.rtmsg_flags = olsr_rt_flags(rt);
789   kernel_route.rtmsg_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
790
791   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route) >= 0)) {
792
793     /*
794      * Send IPC route update message
795      */
796     ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
797   }
798
799   return rslt;
800 #else /* !LINUX_POLICY_ROUTING */
801   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0) {
802     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable_default, RTM_DELROUTE);
803   }
804   else {
805     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable, RTM_DELROUTE);
806   }
807 #endif /* LINUX_POLICY_ROUTING */
808 }
809
810 #if !LINUX_POLICY_ROUTING
811 static int
812 delete_all_inet_gws(void)
813 {
814   int s;
815   char buf[BUFSIZ], *cp, *cplim;
816   struct ifconf ifc;
817   struct ifreq *ifr;
818
819   OLSR_PRINTF(1, "Internet gateway detected...\nTrying to delete default gateways\n");
820
821   /* Get a socket */
822   if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
823     olsr_syslog(OLSR_LOG_ERR, "socket: %m");
824     return -1;
825   }
826
827   ifc.ifc_len = sizeof(buf);
828   ifc.ifc_buf = buf;
829   if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
830     olsr_syslog(OLSR_LOG_ERR, "ioctl (get interface configuration)");
831     close(s);
832     return -1;
833   }
834
835   ifr = ifc.ifc_req;
836   cplim = buf + ifc.ifc_len;    /*skip over if's with big ifr_addr's */
837   for (cp = buf; cp < cplim; cp += sizeof(ifr->ifr_name) + sizeof(ifr->ifr_addr)) {
838     struct rtentry kernel_route;
839     ifr = (struct ifreq *)cp;
840
841     if (strcmp(ifr->ifr_ifrn.ifrn_name, "lo") == 0) {
842       OLSR_PRINTF(1, "Skipping loopback...\n");
843       continue;
844     }
845
846     OLSR_PRINTF(1, "Trying 0.0.0.0/0 %s...", ifr->ifr_ifrn.ifrn_name);
847
848     memset(&kernel_route, 0, sizeof(struct rtentry));
849
850     ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr = 0;
851     ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
852     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = 0;
853     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
854
855     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr.s_addr = INADDR_ANY;
856     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
857
858     kernel_route.rt_flags = RTF_UP | RTF_GATEWAY;
859
860     kernel_route.rt_dev = ifr->ifr_ifrn.ifrn_name;
861
862     if ((ioctl(s, SIOCDELRT, &kernel_route)) < 0)
863       OLSR_PRINTF(1, "NO\n");
864     else
865       OLSR_PRINTF(1, "YES\n");
866   }
867   close(s);
868   return 0;
869 }
870 #endif /* LINUX_POLICY_ROUTING */
871
872 /*
873  * Local Variables:
874  * c-basic-offset: 2
875  * indent-tabs-mode: nil
876  * End:
877  */