Let interface monitor take interface down and up
[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 #include "net_os.h"
46
47 /* values for control flag to handle recursive route corrections 
48  *  currently only requires in linux specific kernel_routes.c */
49
50 #define RT_ORIG_REQUEST 0
51 #define RT_RETRY_AFTER_ADD_GATEWAY 1
52 #define RT_RETRY_AFTER_DELETE_SIMILAR 2
53 #define RT_DELETE_SIMILAR_ROUTE 3
54 #define RT_AUTO_ADD_GATEWAY_ROUTE 4
55 #define RT_DELETE_SIMILAR_AUTO_ROUTE 5
56 #define RT_NIIT 6
57 #define RT_SMARTGW 7
58
59 #if !LINUX_POLICY_ROUTING
60
61 static int delete_all_inet_gws(void);
62
63 #else /* !LINUX_POLICY_ROUTING */
64
65 #include <assert.h>
66 #include <linux/types.h>
67 #include <linux/rtnetlink.h>
68
69 //ipip includes
70 #include <netinet/in.h>
71 #include <sys/ioctl.h>
72 #include <net/if.h>
73 #include <linux/ip.h>
74 #include <linux/if_tunnel.h>
75
76 //ifup includes
77 #include <sys/socket.h>
78 #include <sys/ioctl.h>
79 #include <sys/types.h>
80 #include <net/if.h>
81
82 extern struct rtnl_handle rth;
83
84 struct olsr_rtreq {
85   struct nlmsghdr n;
86   struct rtmsg r;
87   char buf[512];
88 };
89
90 #if LINUX_RTNETLINK_LISTEN
91 #include "ifnet.h"
92 #include "socket_parser.h"
93
94 int rtnetlink_register_socket(int rtnl_mgrp)
95 {
96   int sock = socket(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE);
97   struct sockaddr_nl addr;
98
99   if (sock<0) {
100     OLSR_PRINTF(1,"could not create rtnetlink socket! %s (%d)", strerror(errno), errno);
101     return -1;
102   }
103
104   memset(&addr, 0, sizeof(addr));
105   addr.nl_family = AF_NETLINK;
106   addr.nl_pid = 0; //kernel will assign appropiate number instead of pid (which is already used by primaray rtnetlink socket to add/delete routes)
107   addr.nl_groups = rtnl_mgrp;
108
109   if (bind(sock,(struct sockaddr *)&addr,sizeof(addr))<0) {
110     OLSR_PRINTF(1,"could not bind rtnetlink socket! %s (%d)",strerror(errno), errno);
111     return -1;
112   }
113
114   add_olsr_socket(sock, &rtnetlink_read);
115   return sock;
116 }
117
118 static void netlink_process_link(struct nlmsghdr *h)
119 {
120   struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(h);
121   struct interface *iface;
122
123   /*monitor tunl0 and olsrtunl*/
124   if (olsr_cnf->smart_gw_active) {
125     if (ifi->ifi_index==olsr_cnf->ipip_if_index) {
126       printf("olsrtunl state change:\n");
127       if (ifi->ifi_flags&IFF_UP)
128       {
129         printf("is up now\n");
130         olsr_cnf->ipip_if_up=true;
131       }
132       else if (olsr_cnf->ipip_if_up) {
133         /*we try to delete the interface completely (only if it is down, and was up before)*/
134         olsr_del_tunl();
135         //!!?? shall we mark the default route dirty?
136         /*we mark it unexisting -> we will create the tunnel again (if gateway changes)*/
137         olsr_cnf->ipip_if_index = olsr_cnf->ipip_if_up = false;
138       }
139       else printf("interface is down, but was never up -> ignoring!\n");
140       return;
141     }
142     if (ifi->ifi_index==olsr_cnf->ipip_base_if.if_index) {
143       if (ifi->ifi_flags&IFF_UP) {
144         /*we try to take it up again (if its only down it might workout)*/
145         printf("tunl0 is down, we try to take it up again\n");
146         if (olsr_if_set_state("tunl0",true)) return; //!!?? todo: test if we can really know that its up now
147         /*we disable -> this should stop us announcing being a smart gateway, 
148         * and can not use tunnels as its unlikely to be able to crete them without tunl0*/
149         olsr_cnf->smart_gw_active=false;
150         /*recovery is not easy as potentially the ipip module is not loaded any more*/
151         /*but it could just mean the tunl0 is down, and the gatewaytunnel would work*/
152         return;
153       }
154     }
155   }
156
157   iface = if_ifwithindex(ifi->ifi_index);
158   if (iface == NULL && (ifi->ifi_flags & IFF_UP) != 0) {
159     char namebuffer[IF_NAMESIZE];
160     struct olsr_if *oif;
161
162     if (if_indextoname(ifi->ifi_index, namebuffer)) {
163       if ((oif = olsrif_ifwithname(namebuffer)) != NULL) {
164         chk_if_up(oif, 3);
165       }
166     }
167   }
168   else if (iface != NULL && (ifi->ifi_flags & IFF_UP) == 0) {
169     olsr_remove_interface(iface->olsr_if);
170   }
171 }
172
173 void rtnetlink_read(int sock)
174 {
175   int len, plen;
176   struct iovec iov;
177   struct sockaddr_nl nladdr;
178   struct msghdr msg = {
179     &nladdr,
180     sizeof(nladdr),
181     &iov,
182     1,
183     NULL,
184     0,
185     0
186   };
187
188   char buffer[4096];
189   struct nlmsghdr *nlh = (struct nlmsghdr *)(ARM_NOWARN_ALIGN) buffer;
190   int ret;
191
192   iov.iov_base = (void *) buffer;
193   iov.iov_len = sizeof(buffer);
194
195   while (true) { //read until ret<0;
196     ret=recvmsg(sock, &msg, MSG_DONTWAIT);
197     if (ret<0) {
198       if (errno != EAGAIN) OLSR_PRINTF(1,"netlink listen error %u - %s\n",errno,strerror(errno));
199       return;
200     }
201     /*check message*/
202     len = nlh->nlmsg_len;
203     plen = len - sizeof(nlh);
204     if (len > ret || plen < 0) {
205       OLSR_PRINTF(1,"Malformed netlink message: "
206              "len=%d left=%d plen=%d\n",
207               len, ret, plen);
208       return;
209     }
210     if ( (nlh->nlmsg_type == RTM_NEWLINK) || ( nlh->nlmsg_type == RTM_DELLINK) ) netlink_process_link(nlh);
211   }
212 }
213
214 //!!?? listen on our own tunlx interfaces aswell
215
216 #endif /*linux_rtnetlink_listen*/
217
218 /*create or change a ipip tunnel ipv4 only*/
219 static int set_tunl(int cmd, unsigned long int ipv4)
220 {
221   struct ifreq ifr;
222   int fd;
223   int err;
224   struct ip_tunnel_parm p;
225
226   p.iph.version = 4;
227   p.iph.ihl = 5;
228   p.iph.protocol=IPPROTO_IPIP; //IPPROTO_IPV6
229   p.iph.saddr=0x00000000;
230   p.iph.daddr=ipv4;
231
232   strncpy(p.name, olsr_cnf->ipip_name, IFNAMSIZ);
233 printf("set tunl to name: %s\n",p.name);
234
235   //specify existing interface name
236   if (cmd==SIOCADDTUNNEL) strncpy(ifr.ifr_name, TUNL_BASE, IFNAMSIZ);
237   else strncpy(ifr.ifr_name, olsr_cnf->ipip_name, IFNAMSIZ);
238
239 printf("set tunl %s\n",ifr.ifr_name);
240
241   ifr.ifr_ifru.ifru_data = (void *) &p;
242   fd = socket(AF_INET, SOCK_DGRAM, 0);//warning hardcoded AF_INET
243   err = ioctl(fd, cmd, &ifr);
244 printf("set tunl result %i\n",err);
245   if (err) perror("ioctl");
246   close(fd);
247   return err;
248 }
249
250 int olsr_del_tunl(void)
251 {
252   printf("-----\ndelete olsrtunle!\n");
253   return set_tunl(SIOCDELTUNNEL,0x00000000);//!!??test if this deletes tunnel
254 }
255
256 static void
257 olsr_netlink_addreq(struct nlmsghdr *n, size_t reqSize __attribute__ ((unused)), int type, const void *data, int len)
258 {
259   struct rtattr *rta = (struct rtattr *)(ARM_NOWARN_ALIGN)(((char *)n) + NLMSG_ALIGN(n->nlmsg_len));
260   n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_LENGTH(len);
261   //produces strange compile error
262   //assert(n->nlmsg_len < reqSize);
263   rta->rta_type = type;
264   rta->rta_len = RTA_LENGTH(len);
265   memcpy(RTA_DATA(rta), data, len);
266 }
267
268 /*
269  * The ARM compile complains about alignment. Copied
270  * from /usr/include/linux/netlink.h and adapted for ARM
271  */
272 #define MY_NLMSG_NEXT(nlh,len)   ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
273           (struct nlmsghdr*)(ARM_NOWARN_ALIGN)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
274
275 /*rt_entry and nexthop and family and table must only be specified with an flag != RT_NONE  && != RT_LO_IP*/
276 static int
277 olsr_netlink_send(struct nlmsghdr *nl_hdr)
278 {
279   char rcvbuf[1024];
280   struct iovec iov;
281   struct sockaddr_nl nladdr;
282   struct msghdr msg;
283   struct nlmsghdr *h;
284   struct nlmsgerr *l_err;
285   int ret;
286
287   memset(&nladdr, 0, sizeof(nladdr));
288   memset(&msg, 0, sizeof(msg));
289
290   nladdr.nl_family = AF_NETLINK;
291
292   msg.msg_name = &nladdr;
293   msg.msg_namelen = sizeof(nladdr);
294   msg.msg_iov = &iov;
295   msg.msg_iovlen = 1;
296
297   iov.iov_base = nl_hdr;
298   iov.iov_len = nl_hdr->nlmsg_len;
299   ret = sendmsg(olsr_cnf->rtnl_s, &msg, 0);
300   if (ret <= 0) {
301     olsr_syslog(OLSR_LOG_ERR, "Cannot send data to netlink socket (%d: %s)", errno, strerror(errno));
302     return -1;
303   }
304
305   iov.iov_base = rcvbuf;
306   iov.iov_len = sizeof(rcvbuf);
307   ret = recvmsg(olsr_cnf->rtnl_s, &msg, 0);
308   if (ret <= 0) {
309     olsr_syslog(OLSR_LOG_ERR, "Error while reading answer to netlink message (%d: %s)", errno, strerror(errno));
310     return -1;
311   }
312
313   h = (struct nlmsghdr *)(ARM_NOWARN_ALIGN)rcvbuf;
314   if (!NLMSG_OK(h, (unsigned int)ret)) {
315     olsr_syslog(OLSR_LOG_ERR, "Received netlink message was malformed (ret=%d, %u)", ret, h->nlmsg_len);
316     return -1;
317   }
318
319   if (h->nlmsg_type != NLMSG_ERROR) {
320     olsr_syslog(OLSR_LOG_INFO,
321         "Received unknown netlink response: %u bytes, type %u (not %u) with seqnr %u and flags %u from %u",
322         h->nlmsg_len, h->nlmsg_type, NLMSG_ERROR, h->nlmsg_seq, h->nlmsg_flags, h->nlmsg_pid);
323     return -1;
324   }
325   if (NLMSG_LENGTH(sizeof(struct nlmsgerr)) > h->nlmsg_len) {
326     olsr_syslog(OLSR_LOG_INFO,"Received invalid netlink message size %lu != %u",
327         (unsigned long int)sizeof(struct nlmsgerr), h->nlmsg_len);
328     return -1;
329   }
330
331   l_err = (struct nlmsgerr *)NLMSG_DATA(h);
332
333   if (l_err->error) {
334     olsr_syslog(OLSR_LOG_INFO,"Received netlink error code %s (%d)", strerror(-l_err->error), l_err->error);
335   }
336   return -l_err->error;
337 }
338
339 int olsr_netlink_rule(int family, int rttable, uint32_t priority, const char *if_name, bool set) {
340   struct olsr_rtreq req;
341   int err;
342
343   memset(&req, 0, sizeof(req));
344
345   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
346   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
347
348   req.n.nlmsg_type = set ? RTM_NEWRULE : RTM_DELRULE;
349   req.r.rtm_family = family;
350   req.r.rtm_table = rttable;
351
352   /* RTN_UNSPEC would be the wildcard, but blackhole broadcast or nat roules should usually not conflict */
353   /* -> olsr only adds deletes unicast routes */
354   req.r.rtm_type = RTN_UNICAST;
355
356   /* wildcard to delete routes of all protos if no simlar-delete correct proto will get set below */
357   req.r.rtm_protocol = RTPROT_UNSPEC;
358
359   req.r.rtm_scope = RT_SCOPE_UNIVERSE;
360
361   olsr_netlink_addreq(&req.n, sizeof(req), RTA_PRIORITY, &priority, sizeof(priority));
362
363   if (if_name != NULL) {
364     /*add interface name to rule*/
365     olsr_netlink_addreq(&req.n, sizeof(req), RTA_IIF, if_name, strlen(if_name)+1);
366   }
367
368   err = olsr_netlink_send(&req.n);
369   if (err) {
370     olsr_syslog(OLSR_LOG_ERR,"Error on %s empty policy rule aimed to activate RtTable %u!",
371         set ? "inserting" : "deleting", rttable);
372   }
373
374   return err;
375 }
376
377 int olsr_new_netlink_route(int family, int rttable, int if_index, int metric, int protocol,
378     const union olsr_ip_addr *src, const union olsr_ip_addr *gw, const struct olsr_ip_prefix *dst,
379     bool set, bool del_similar);
380
381 int olsr_new_netlink_route(int family, int rttable, int if_index, int metric, int protocol,
382     const union olsr_ip_addr *src, const union olsr_ip_addr *gw, const struct olsr_ip_prefix *dst,
383     bool set, bool del_similar) {
384
385   struct olsr_rtreq req;
386   int family_size;
387   int err;
388
389   if (0) {
390     struct ipaddr_str buf1, buf2;
391
392     olsr_syslog(OLSR_LOG_INFO, "new_netlink_route: family=%d,rttable=%d,if_index=%d,metric=%d,protocol=%d,src=%s,gw=%s,dst=%s,set=%s,del_similar=%s",
393         family, rttable, if_index, metric, protocol, src == NULL ? "" : olsr_ip_to_string(&buf1, src),
394         gw == NULL ? "" : olsr_ip_to_string(&buf2, gw), olsr_ip_prefix_to_string(dst),
395         set ? "true" : "false", del_similar ? "true" : "false");
396   }
397   family_size = family == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr);
398
399   memset(&req, 0, sizeof(req));
400
401   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
402   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
403   if (set) {
404     req.n.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
405   }
406
407   req.n.nlmsg_type = set ? RTM_NEWROUTE : RTM_DELROUTE;
408   req.r.rtm_family = family;
409   req.r.rtm_table = rttable;
410
411   /* RTN_UNSPEC would be the wildcard, but blackhole broadcast or nat roules should usually not conflict */
412   /* -> olsr only adds deletes unicast routes */
413   req.r.rtm_type = RTN_UNICAST;
414
415   req.r.rtm_dst_len = dst->prefix_len;
416
417   if (set) {
418     /* add protocol for setting a route */
419     req.r.rtm_protocol = protocol;
420   }
421
422   /* calculate scope of operation */
423   if (!set && del_similar) {
424     /* as wildcard for fuzzy deletion */
425     req.r.rtm_scope = RT_SCOPE_NOWHERE;
426   }
427   else if (gw) {
428     /* for multihop routes */
429     req.r.rtm_scope = RT_SCOPE_UNIVERSE;
430   }
431   else {
432     /* for link neighbor routes */
433     req.r.rtm_scope = RT_SCOPE_LINK;
434   }
435
436   if (set || !del_similar) {
437     /* add interface*/
438     olsr_netlink_addreq(&req.n, sizeof(req), RTA_OIF, &if_index, sizeof(if_index));
439   }
440
441   if (set && src != NULL) {
442     /* add src-ip */
443     olsr_netlink_addreq(&req.n, sizeof(req), RTA_PREFSRC, src, family_size);
444   }
445
446   if (metric != -1) {
447     /* add metric */
448     olsr_netlink_addreq(&req.n, sizeof(req), RTA_PRIORITY, &metric, sizeof(metric));
449   }
450
451   if (gw) {
452     /* add gateway */
453     olsr_netlink_addreq(&req.n, sizeof(req), RTA_GATEWAY, gw, family_size);
454   }
455
456   /* add destination */
457   olsr_netlink_addreq(&req.n, sizeof(req), RTA_DST, &dst->prefix, family_size);
458
459   err = olsr_netlink_send(&req.n);
460   if (err) {
461     if (gw) {
462       struct ipaddr_str buf;
463       olsr_syslog(OLSR_LOG_ERR, ". error: %s route to %s via %s dev %s",
464           set ? "add" : "del",
465           olsr_ip_prefix_to_string(dst), olsr_ip_to_string(&buf, gw), if_ifwithindex_name(if_index));
466     }
467     else {
468       olsr_syslog(OLSR_LOG_ERR, ". error: %s route to %s dev %s",
469           set ? "add" : "del",
470           olsr_ip_prefix_to_string(dst), if_ifwithindex_name(if_index));
471     }
472   }
473
474   return err;
475 }
476
477 int olsr_netlink_static_niit_routes(const struct olsr_ip_prefix *route, bool set) {
478   int err;
479   if (!is_prefix_niit_ipv6(route)) {
480     return 0;
481   }
482
483   /* TODO: in welche Table kommen die NIIT-Routen ? ne eigene ? */
484   err = olsr_new_netlink_route(AF_INET6, olsr_cnf->rttable, olsr_cnf->niit6to4_if_index,
485       RT_METRIC_DEFAULT, RTPROT_BOOT, NULL, NULL, route, set, false);
486   if (err) {
487     olsr_syslog(OLSR_LOG_ERR, ". error while %s static niit route to %s",
488         set ? "setting" : "removing", olsr_ip_prefix_to_string(route));
489   }
490   return err;
491 }
492
493 static void olsr_netlink_process_niit(const struct rt_entry *rt, bool set) {
494   struct olsr_ip_prefix dst_v4;
495   if (!olsr_cnf->use_niit || !is_prefix_niit_ipv6(&rt->rt_dst)) {
496     return;
497   }
498
499   prefix_mappedv4_to_v4(&dst_v4, &rt->rt_dst);
500
501   /* TODO: in welche Table kommen die NIIT-Routen ? ne eigene ? */
502   if (olsr_new_netlink_route(AF_INET, olsr_cnf->rttable, olsr_cnf->niit4to6_if_index,
503       RT_METRIC_DEFAULT, RTPROT_BOOT, NULL, NULL, &dst_v4, set, false)) {
504     olsr_syslog(OLSR_LOG_ERR, ". error while %s niit route to %s",
505         set ? "setting" : "removing", olsr_ip_prefix_to_string(&dst_v4));
506   }
507 }
508
509 static bool olsr_netlink_process_smartgw(const struct rt_entry *rt, bool set) {
510   if (!olsr_cnf->smart_gw_active || !is_prefix_inetgw(&rt->rt_dst)) {
511     return false;
512   }
513
514   /* TODO maybe block internet gateway route */
515   return set && false;
516 }
517
518 int olsr_netlink_process_rt_entry(const struct rt_entry *rt, bool set);
519
520 int olsr_netlink_process_rt_entry(const struct rt_entry *rt, bool set) {
521   int metric, protocol, table;
522   const struct rt_nexthop *nexthop;
523   union olsr_ip_addr *src;
524   bool hostRoute;
525   int err;
526
527   /* handle NIIT special case */
528   olsr_netlink_process_niit(rt, set);
529
530   /* handle smart gateway case */
531   if (olsr_netlink_process_smartgw(rt, set)) {
532     /* skip inetgw routes if smartgw is active */
533     return 0;
534   }
535
536   /* calculate metric */
537   if (FIBM_FLAT == olsr_cnf->fib_metric) {
538     metric = RT_METRIC_DEFAULT;
539   }
540   else {
541     metric = set ? rt->rt_best->rtp_metric.hops : rt->rt_metric.hops;
542   }
543
544   /* get protocol
545    * 0 gets replaced by OS-specifc default (3)
546    * 1 is reserved so we take 0 instead (this really makes some sense)
547    * other numbers are used directly without change */
548   protocol = olsr_cnf->rtproto;
549   if (protocol <= 1) {
550     protocol = protocol < 1 ? RTPROT_BOOT : 0;
551   }
552
553   /* get table */
554   table = is_prefix_inetgw(&rt->rt_dst)
555       ? olsr_cnf->rttable_default : olsr_cnf->rttable;
556
557   /* get next hop */
558   if (rt->rt_best && set) {
559     nexthop = &rt->rt_best->rtp_nexthop;
560   }
561   else {
562     nexthop = &rt->rt_nexthop;
563   }
564
565   /* detect 1-hop hostroute */
566   hostRoute = rt->rt_dst.prefix_len == olsr_cnf->ipsize * 8
567       && ipequal(&nexthop->gateway, &rt->rt_dst.prefix);
568
569   if (0) {
570     struct ipaddr_str buf1, buf2;
571     olsr_syslog(OLSR_LOG_INFO, "hostroute (%s) = %d == %d && %s == %s",
572         hostRoute ? "true" : "false",
573         rt->rt_dst.prefix_len, (int)(olsr_cnf->ipsize * 8),
574         olsr_ip_to_string(&buf1, &nexthop->gateway),
575         olsr_ip_to_string(&buf2, &rt->rt_dst.prefix));
576   }
577
578   /* get src ip */
579   src = NULL;
580
581   /* create route */
582   err = olsr_new_netlink_route(olsr_cnf->ip_version, table, nexthop->iif_index, metric, protocol,
583       src, hostRoute ? NULL : &nexthop->gateway, &rt->rt_dst, set, false);
584
585   /* resolve "File exist" (17) propblems (on orig and autogen routes)*/
586   if (set && err == 17) {
587     /* a similar route going over another gateway may be present, which has to be deleted! */
588     olsr_syslog(OLSR_LOG_ERR, ". auto-deleting similar routes to resolve 'File exists' (17) while adding route!");
589
590     /* erase similar rule */
591     err = olsr_new_netlink_route(olsr_cnf->ip_version, table, 0, 0, -1, NULL, NULL, &rt->rt_dst, false, true);
592
593     if (!err) {
594       /* create this rule a second time if delete worked*/
595       err = olsr_new_netlink_route(olsr_cnf->ip_version, table, nexthop->iif_index, metric, protocol,
596           src, hostRoute ? NULL : &nexthop->gateway, &rt->rt_dst, set, false);
597     }
598     olsr_syslog(OLSR_LOG_ERR, ". %s (%d)", err == 0 ? "successful" : "failed", err);
599   }
600
601   /* report success on "No such process" (3) */
602   else if (!set && err == 3) {
603     /* another similar (but slightly different) route may be present at this point,
604      * if so this will get solved when adding new route to this destination */
605     olsr_syslog(OLSR_LOG_ERR, ". ignoring 'No such process' (3) while deleting route!");
606     err = 0;
607   }
608   /* insert route to gateway on the fly if "Network unreachable" (128) on 2.4 kernels
609    * or on 2.6 kernel No such process (3) or Network unreachable (101) is reported in rtnetlink response
610    * do this only with flat metric, as using metric values inherited from
611    * a target behind the gateway is really strange, and could lead to multiple routes!
612    * anyways if invalid gateway ips may happen we are f*cked up!!
613    * but if not, these on the fly generated routes are no problem, and will only get used when needed */
614   else if (!hostRoute && olsr_cnf->fib_metric == FIBM_FLAT
615       && (err == 128 || err == 101 || err == 3)) {
616     struct olsr_ip_prefix hostPrefix;
617
618     if (err == 128)  {
619       olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (128) while adding route!");
620     }
621     else if (err == 101) {
622       olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (101) while adding route!");
623     }
624     else {
625       olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'No such process' (3) while adding route!");
626     }
627
628     /* create hostroute */
629     hostPrefix.prefix = nexthop->gateway;
630     hostPrefix.prefix_len = olsr_cnf->ipsize * 8;
631
632     err = olsr_new_netlink_route(olsr_cnf->ip_version, olsr_cnf->rttable, nexthop->iif_index,
633         metric, protocol, src, NULL, &hostPrefix, true, false);
634     if (err == 0) {
635       /* create this rule a second time if hostrule generation was successful */
636       err = olsr_new_netlink_route(olsr_cnf->ip_version, table, nexthop->iif_index, metric, protocol,
637           src, hostRoute ? NULL : &nexthop->gateway, &rt->rt_dst, set, false);
638     }
639     olsr_syslog(OLSR_LOG_ERR, ". %s (%d)", err == 0 ? "successful" : "failed", err);
640   }
641
642   return err;
643 }
644
645 #if 0
646 /* returns
647  * -1 on unrecoverable error (calling function will have to handle it)
648  *  0 on unexpected but recoverable rtnetlink behaviour
649  *    but some of the implemented recovery methods only cure symptoms, 
650  *    not the cause, like unintelligent ordering of inserted routes.
651  *  1 on success */
652 static int
653 olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd, uint32_t flag)
654 {
655   int ret = 1; /* helper variable for rtnetlink_message processing */
656   int rt_ret = -2;  /* if no response from rtnetlink it must be considered as failed! */
657   struct olsr_rtreq req;
658   struct iovec iov;
659   struct sockaddr_nl nladdr;
660   struct msghdr msg = {
661     &nladdr,
662     sizeof(nladdr),
663     &iov,
664     1,
665     NULL,
666     0,
667     0
668   };
669
670   uint32_t metric = 0;
671   const struct rt_nexthop *nexthop = NULL;
672   if ( ( cmd != RTM_NEWRULE ) && ( cmd != RTM_DELRULE ) ) {
673     if (FIBM_FLAT == olsr_cnf->fib_metric) {
674       metric = RT_METRIC_DEFAULT;
675     }
676     else {
677       metric = (RTM_NEWROUTE == cmd) ? rt->rt_best->rtp_metric.hops : rt->rt_metric.hops;
678     }
679
680     if (( RTM_NEWROUTE == cmd ) ||
681         (( RTM_DELROUTE == cmd ) && ( RT_DELETE_SIMILAR_ROUTE == flag || RT_DELETE_SIMILAR_AUTO_ROUTE == flag ))) {
682       nexthop = &rt->rt_best->rtp_nexthop;
683     }
684     else {
685       nexthop = &rt->rt_nexthop;
686     }
687   }
688
689   memset(&req, 0, sizeof(req));
690
691   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
692   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
693   req.n.nlmsg_type = cmd;
694   
695   /*sanity check for niit ipv4 over ipv6 routes*/
696   if (family == AF_INET && flag == RT_NIIT) {
697     olsr_syslog(OLSR_LOG_ERR,"niit makes no sense with olsrd running on ipv4!");
698     return -1;
699   }
700
701   if (flag == RT_NIIT) {
702     req.r.rtm_family=AF_INET; /*we create an ipv4 niit route*/
703   }
704   else {
705     req.r.rtm_family = family;
706   }
707
708   req.r.rtm_table = rttable;
709
710   /* RTN_UNSPEC would be the wildcard, but blackhole broadcast or nat roules should usually not conflict */
711   /* -> olsr only adds deletes unicast routes */
712   req.r.rtm_type = RTN_UNICAST;
713
714   /* wildcard to delete routes of all protos if no simlar-delete correct proto will get set below */
715   req.r.rtm_protocol = RTPROT_UNSPEC;
716
717   /* as wildcard for deletion */
718   req.r.rtm_scope = RT_SCOPE_NOWHERE;
719
720   if ( ( cmd == RTM_NEWRULE ) || ( cmd == RTM_DELRULE ) ) {
721     /* add or delete a rule */
722     req.r.rtm_scope = RT_SCOPE_UNIVERSE;
723     olsr_netlink_addreq(&req, RTA_PRIORITY, &flag, sizeof(flag));
724     if (rt!=NULL) {
725       /*add interface name to rule*/
726       olsr_netlink_addreq(&req, RTA_IIF, rt, strlen((const char*) rt)+1);
727       //printf("\nrule to interface %s!",(const char*) rt);
728     } 
729   }
730   else {
731     req.r.rtm_dst_len = rt->rt_dst.prefix_len;
732
733     /* do not specify much as we wanna delete similar/conflicting routes */
734     if ( ( flag != RT_DELETE_SIMILAR_ROUTE ) && ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE )) {
735       /* 0 gets replaced by OS-specifc default (3)
736        * 1 is reserved so we take 0 instead (this really makes some sense)
737        * other numbers are used 1:1 */
738       req.r.rtm_protocol = ( (olsr_cnf->rtproto<1) ? RTPROT_BOOT : ( (olsr_cnf->rtproto==1) ? 0 : olsr_cnf->rtproto) );
739       req.r.rtm_scope = RT_SCOPE_LINK;
740
741       /*add interface*/
742       if ((olsr_cnf->smart_gw_active) && family != AF_INET)
743       {
744         printf("smart gateway not available for ipv6 currently\n");
745         return -1;
746       }
747       else if(flag == RT_SMARTGW)
748       //else if ((olsr_cnf->smart_gateway_active) && (rt->rt_dst.prefix_len == 0) && (&olsr_cnf->ipip_if_index))
749       {
750         //add interface (without nexthop if possible (if not use &rt->rt_best->rtp_originator))
751         olsr_netlink_addreq(&req, RTA_OIF, &olsr_cnf->ipip_if_index, sizeof(&olsr_cnf->ipip_if_index));
752       }
753       else if (flag == RT_NIIT) {
754         olsr_netlink_addreq(&req, RTA_OIF, &olsr_cnf->niit4to6_if_index, sizeof(&olsr_cnf->niit4to6_if_index));
755       }
756       else {
757         olsr_netlink_addreq(&req, RTA_OIF, &nexthop->iif_index, sizeof(nexthop->iif_index));
758       }
759
760 #if SOURCE_IP_ROUTES
761       /**
762        * source ip here is based on now static olsr_cnf->main_addr in this olsr-0.5.6-r4,
763        * should be based on orignator-id in newer olsrds
764        **/
765       if (flag != RT_NIIT) {
766         if (AF_INET == family) {
767           olsr_netlink_addreq(&req, RTA_PREFSRC, &olsr_cnf->main_addr.v4.s_addr, sizeof(olsr_cnf->main_addr.v4.s_addr));
768         }
769         else {
770           olsr_netlink_addreq(&req, RTA_PREFSRC, &olsr_cnf->main_addr.v6.s6_addr, sizeof(olsr_cnf->main_addr.v6.s6_addr));
771         }
772       }
773 #endif
774     }
775
776     /* metric is specified always as we can only delete one route per iteration, and wanna hit the correct one first */
777     if (FIBM_APPROX != olsr_cnf->fib_metric || (RTM_NEWROUTE == cmd) ) {
778       olsr_netlink_addreq(&req, RTA_PRIORITY, &metric, sizeof(metric));
779     }
780
781     /* make sure that netmask = maxplen (32 or 128) as this is an autogenarated (host)route */
782     if (( flag == RT_AUTO_ADD_GATEWAY_ROUTE ) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) {
783       req.r.rtm_dst_len = olsr_cnf->maxplen;
784     }
785
786     /**
787      * for ipv4 or ipv6 we add gateway if one is specified,
788      * or leave gateway away if we want to delete similar routes aswell,
789      * or even use the gateway as target if we add a auto-generated route,
790      * or if delete-similar to make insertion of auto-generated route possible
791      **/
792     if (AF_INET == family) {
793       if ( ( flag != RT_SMARTGW )
794            && ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE) && 
795            ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) && (rt->rt_dst.prefix.v4.s_addr != nexthop->gateway.v4.s_addr) ) {
796         olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v4, sizeof(nexthop->gateway.v4));
797         req.r.rtm_scope = RT_SCOPE_UNIVERSE;
798       }
799       olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
800                           &nexthop->gateway.v4 : &rt->rt_dst.prefix.v4, sizeof(rt->rt_dst.prefix.v4));
801     } else {
802       if (flag == RT_NIIT) {
803         union olsr_ip_addr ipv4_addr;
804         /* create an ipv4 route */
805         olsr_syslog(OLSR_LOG_ERR,"niit suport not fully implemented!!\n");
806
807         /* fix prefix length */
808         req.r.rtm_dst_len = rt->rt_dst.prefix_len - 96;
809         olsr_netlink_addreq(&req, RTA_DST, olsr_ipv6_to_ipv4(&rt->rt_dst.prefix, &ipv4_addr), sizeof(ipv4_addr.v4));
810       }
811       else {
812         if ( ( flag != RT_SMARTGW ) 
813             && ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE ) && ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) 
814             && (0 != memcmp(&rt->rt_dst.prefix.v6, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6))) ) {
815           olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6));
816           req.r.rtm_scope = RT_SCOPE_UNIVERSE;
817         }
818         olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
819                             &nexthop->gateway.v6 : &rt->rt_dst.prefix.v6, sizeof(rt->rt_dst.prefix.v6));
820       }
821     }
822   }
823
824   iov.iov_base = &req.n;
825   iov.iov_len = req.n.nlmsg_len;
826   memset(&nladdr, 0, sizeof(nladdr));
827   nladdr.nl_family = AF_NETLINK;
828   if (0 <= (ret = sendmsg(olsr_cnf->rtnl_s, &msg, 0))) {
829     iov.iov_base = req.buf;
830     iov.iov_len = sizeof(req.buf);
831     if (0 < (ret = recvmsg(olsr_cnf->rtnl_s, &msg, 0))) {
832       struct nlmsghdr *h = (struct nlmsghdr *)(ARM_NOWARN_ALIGN)req.buf;
833       while (NLMSG_OK(h, (unsigned int)ret)) {
834         if (NLMSG_DONE == h->nlmsg_type) {
835           /* seems to reached never */
836           olsr_syslog(OLSR_LOG_INFO, "_received NLMSG_DONE");
837           break;
838         }
839         if (NLMSG_ERROR == h->nlmsg_type) {
840           if (NLMSG_LENGTH(sizeof(struct nlmsgerr) <= h->nlmsg_len)) {
841             struct ipaddr_str ibuf;
842             struct ipaddr_str gbuf;
843             struct nlmsgerr *l_err = (struct nlmsgerr *)NLMSG_DATA(h);
844             errno = -l_err->error;
845             if (0 != errno) {
846               const char *const err_msg = strerror(errno);
847               struct ipaddr_str buf;
848               rt_ret = -1;
849
850               /* syslog debug output for various situations */
851               if ( cmd == RTM_NEWRULE ) {
852                 olsr_syslog(OLSR_LOG_ERR,"Error '%s' (%d) on inserting empty policy rule aimed to activate RtTable %u!", err_msg, errno, rttable);
853               }
854               else if ( cmd == RTM_DELRULE ) {
855                 olsr_syslog(OLSR_LOG_ERR,"Error '%s' (%d) on deleting empty policy rule aimed to activate rtTable %u!", err_msg, errno, rttable);
856               }
857               else if ( flag == RT_NIIT ) {
858                 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));
859               }
860               else if ( flag <= RT_RETRY_AFTER_DELETE_SIMILAR ) {
861                 if (rt->rt_dst.prefix.v4.s_addr!=nexthop->gateway.v4.s_addr) {
862                   olsr_syslog(OLSR_LOG_ERR, "error '%s' (%d) %s route to %s/%d via %s dev %s",
863                       err_msg, errno, (cmd == RTM_NEWROUTE) ? "add" : "del",
864                       olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix), req.r.rtm_dst_len,
865                       olsr_ip_to_string(&gbuf,&nexthop->gateway), if_ifwithindex_name(nexthop->iif_index));
866                 }
867                 else {
868                   olsr_syslog(OLSR_LOG_ERR, "error '%s' (%d) %s route to %s/%d dev %s",
869                       err_msg, errno, (cmd == RTM_NEWROUTE) ? "add" : "del",
870                       olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix), req.r.rtm_dst_len, if_ifwithindex_name(nexthop->iif_index));
871                 }
872               }
873               else if (flag == RT_AUTO_ADD_GATEWAY_ROUTE) {
874                 olsr_syslog(OLSR_LOG_ERR, ". error '%s' (%d) auto-add route to %s dev %s", err_msg, errno,
875                     olsr_ip_to_string(&ibuf,&nexthop->gateway), if_ifwithindex_name(nexthop->iif_index));
876               }
877               else if (flag == RT_DELETE_SIMILAR_ROUTE) {
878                 olsr_syslog(OLSR_LOG_ERR, ". error '%s' (%d) auto-delete route to %s dev %s", err_msg, errno,
879                     olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix), if_ifwithindex_name(nexthop->iif_index));
880               }
881               else if (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) {
882                 olsr_syslog(OLSR_LOG_ERR, ". . error '%s' (%d) auto-delete similar route to %s dev %s", err_msg, errno,
883                     olsr_ip_to_string(&ibuf,&nexthop->gateway), if_ifwithindex_name(nexthop->iif_index));
884               }
885               else {
886                 /* should never happen */
887                 olsr_syslog(OLSR_LOG_ERR, "# invalid internal route delete/add flag (%d) used!", flag);
888               }
889             }
890             else {
891               /* netlink acks requests with an errno=0 NLMSG_ERROR response! */
892               rt_ret = 1;
893             }
894
895             /* resolve "File exist" (17) propblems (on orig and autogen routes)*/       
896             if ((errno == 17) && (cmd == RTM_NEWROUTE) && ((flag == RT_ORIG_REQUEST) || (flag == RT_AUTO_ADD_GATEWAY_ROUTE))) {
897               /* a similar route going over another gateway may be present, which has to be deleted! */
898               olsr_syslog(OLSR_LOG_ERR, ". auto-deleting similar routes to resolve 'File exists' (17) while adding route!");
899               rt_ret = RT_DELETE_SIMILAR_ROUTE; /* processing will contiune after this loop */
900             }
901             /* report success on "No such process" (3) */
902             else if ((errno == 3) && (cmd == RTM_DELROUTE) && (flag == RT_ORIG_REQUEST)) {
903               /* another similar (but slightly different) route may be present at this point
904               * , if so this will get solved when adding new route to this destination */
905               olsr_syslog(OLSR_LOG_ERR, ". ignoring 'No such process' (3) while deleting route!");
906               rt_ret = 0;
907             }
908             /* insert route to gateway on the fly if "Network unreachable" (128) on 2.4 kernels
909              * or on 2.6 kernel No such process (3) or Network unreachable (101) is reported in rtnetlink response
910              * do this only with flat metric, as using metric values inherited from 
911              * a target behind the gateway is really strange, and could lead to multiple routes!
912              * anyways if invalid gateway ips may happen we are f*cked up!!
913              * but if not, these on the fly generated routes are no problem, and will only get used when needed */
914             else if ( ( (errno == 3) || (errno == 101) || (errno == 128) )
915                 && (flag == RT_ORIG_REQUEST) && (FIBM_FLAT == olsr_cnf->fib_metric)
916                      && (cmd == RTM_NEWROUTE) && (rt->rt_dst.prefix.v4.s_addr!=nexthop->gateway.v4.s_addr)) {
917               if (errno == 128)  {
918                 olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (128) while adding route!");
919               }
920               else if (errno == 101) {
921                 olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (101) while adding route!");
922               }
923               else {
924                 olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'No such process' (3) while adding route!");
925               }
926
927               /* processing will contiune after this loop */
928               rt_ret = RT_AUTO_ADD_GATEWAY_ROUTE;
929             }
930           }
931           /* report invalid message size */
932           else {
933             olsr_syslog(OLSR_LOG_INFO,"_received invalid netlink message size %lu != %u",
934                 (unsigned long int)sizeof(struct nlmsgerr), h->nlmsg_len);
935           }
936         }
937         /* log all other messages */
938         else {
939           olsr_syslog(OLSR_LOG_INFO,"_received %u Byte rtnetlink response of type %u with seqnr %u and flags %u from %u (%u)",
940               h->nlmsg_len, h->nlmsg_type, h->nlmsg_seq, h->nlmsg_flags, h->nlmsg_pid, NLMSG_ERROR);
941         }
942 /*
943  * The ARM compile complains about alignment. Copied
944  * from /usr/include/linux/netlink.h and adapted for ARM
945  */
946 #define MY_NLMSG_NEXT(nlh,len)   ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
947                                   (struct nlmsghdr*)(ARM_NOWARN_ALIGN)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
948         h = MY_NLMSG_NEXT(h, ret);
949       }
950     }
951   }
952   if ( rt_ret == RT_DELETE_SIMILAR_ROUTE ) {
953     /* delete all routes that may collide */
954
955     /* recursive call to delete simlar routes, using flag 2 to invoke deletion of similar, not only exact matches*/
956     rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_DELROUTE, 
957         flag == RT_AUTO_ADD_GATEWAY_ROUTE ? RT_DELETE_SIMILAR_AUTO_ROUTE : RT_DELETE_SIMILAR_ROUTE);
958
959     /* retry insert original route, if deleting similar succeeded, using flag=1 to prevent recursions */
960     if (rt_ret > 0) {
961       rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_RETRY_AFTER_DELETE_SIMILAR);
962     }
963     else {
964       olsr_syslog(OLSR_LOG_ERR, ". failed on auto-deleting similar route conflicting with above route!");
965     }
966
967     /* set appropriate return code for original request, while returning simple -1/1 if called recursive */
968     if (flag != RT_AUTO_ADD_GATEWAY_ROUTE) {
969       if (rt_ret > 0) {
970         /* successful recovery */
971         rt_ret = 0;
972       }
973       else {
974         /* unrecoverable error */
975         rt_ret = -1;
976       }
977     }
978   }
979   if ( rt_ret == RT_AUTO_ADD_GATEWAY_ROUTE ) {
980     /* autoadd route via gateway */
981
982     /* recursive call to invoke creation of a route to the gateway */
983     rt_ret = olsr_netlink_route_int(rt, family, olsr_cnf->rttable, RTM_NEWROUTE, RT_AUTO_ADD_GATEWAY_ROUTE);
984
985     /* retry insert original route, if above succeeded without problems */
986     if (rt_ret > 0) {
987       rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_RETRY_AFTER_ADD_GATEWAY);
988     }
989     else {
990       olsr_syslog(OLSR_LOG_ERR, ". failed on inserting auto-generated route to gateway of above route!");
991     }
992
993     /* set appropriate return code for original request*/
994     if (rt_ret > 0) {
995       /* successful recovery */
996       rt_ret = 0;
997     }
998     else {
999       /* unrecoverable error */
1000       rt_ret = -1;
1001     }
1002   }
1003   /* send ipc update on success */
1004   if ( ( cmd != RTM_NEWRULE ) && ( cmd != RTM_DELRULE )
1005       && (flag == RT_ORIG_REQUEST) && (0 <= rt_ret && olsr_cnf->ipc_connections > 0) ) {
1006     ipc_route_send_rtentry(&rt->rt_dst.prefix, &nexthop->gateway, metric,
1007         RTM_NEWROUTE == cmd, if_ifwithindex_name(nexthop->iif_index));
1008   }
1009   if (rt_ret == -2) {
1010     olsr_syslog(OLSR_LOG_ERR,"no rtnetlink response! (no system ressources left?, everything may happen now ...)");
1011   }
1012   return rt_ret;
1013 }
1014
1015 /* external wrapper function for above patched multi purpose rtnetlink function */
1016 int
1017 olsr_netlink_rule(uint8_t family, uint8_t rttable, uint16_t cmd, uint32_t priority, char* dev)
1018 {
1019   return olsr_netlink_route_int((const struct rt_entry *) dev, family, rttable, cmd, priority);
1020 }
1021
1022
1023 /* internal wrapper function for above patched function */
1024 /* added smartgw and niit route creation*/
1025 static int
1026 olsr_netlink_route(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd)
1027 {
1028   /*check if this rule is relevant for smartgw*/
1029   if ((olsr_cnf->smart_gw_active) && (rt->rt_dst.prefix_len == 0) )
1030   { 
1031     if (cmd == RTM_DELROUTE){ /*should we do something sane here!!??*/
1032       printf("ignoreing deletion of default route for smart gateway!!\n");
1033     }
1034     else
1035     {
1036       if (!olsr_cnf->ipip_if_index) {
1037 int r;
1038         printf("creating tunnel %s\n",olsr_cnf->ipip_name);
1039         /*create tunnel*/
1040         set_tunl(SIOCADDTUNNEL,rt->rt_best->rtp_originator.v4.s_addr);
1041         olsr_cnf->ipip_if_up=false;/*rtnetlink monitoring will detect it up*/
1042         /*!!?? currently it gets never deleted on shutdown, anyways reusing existing tunnel might be a safe approach if creating fails?*/
1043         /*set tunnel up with originator ip*/
1044         r=olsr_if_setip(olsr_cnf->ipip_name, &olsr_cnf->main_addr, 0);
1045 printf("result of ifup is %i\n",r);
1046         /*find out iifindex (maybe it works even if above failed (old tunnel))*/
1047         olsr_cnf->ipip_if_index=if_nametoindex(olsr_cnf->ipip_name);
1048 printf("index of new olsrtunl is %i\n",olsr_cnf->ipip_if_index);
1049       }
1050       else
1051       {
1052         printf("changing tunnel %s:\n",olsr_cnf->ipip_name);
1053         /*change tunnel to new originator or potentially new gateway*/
1054         if ((olsr_cnf->ipip_remote_address != rt->rt_best->rtp_originator.v4.s_addr) && (rt->rt_best->rtp_originator.v4.s_addr != 0x00000000) ) {
1055           struct ipaddr_str buf;
1056           printf("changing tunnel to %s\n",olsr_ip_to_string(&buf,&rt->rt_best->rtp_originator));
1057           olsr_cnf->ipip_remote_address = rt->rt_best->rtp_originator.v4.s_addr;
1058           set_tunl(SIOCCHGTUNNEL,olsr_cnf->ipip_remote_address);
1059         }
1060       }
1061       /*create route into tunnel*/
1062       olsr_netlink_route_int(rt, family, olsr_cnf->rttable_smartgw, cmd, RT_SMARTGW);
1063     }
1064   }
1065   /*normal route in default route table*/
1066
1067   /*create/delete niit route if we have an niit device*/
1068   if ((olsr_cnf->niit4to6_if_index!=0) && (family != AF_INET) && (olsr_is_niit_ipv6(&rt->rt_dst.prefix))) {
1069     olsr_netlink_route_int(rt, family, rttable, cmd, RT_NIIT);
1070   }
1071
1072   return olsr_netlink_route_int(rt, family, rttable, cmd, RT_ORIG_REQUEST);
1073 }
1074 #endif
1075
1076 #endif /* LINUX_POLICY_ROUTING */
1077
1078 /**
1079  * Insert a route in the kernel routing table
1080  *
1081  * @param destination the route to add
1082  *
1083  * @return negative on error
1084  */
1085 int
1086 olsr_ioctl_add_route(const struct rt_entry *rt)
1087 {
1088 #if !LINUX_POLICY_ROUTING
1089   struct rtentry kernel_route;
1090   union olsr_ip_addr mask;
1091   int rslt;
1092 #endif /* LINUX_POLICY_ROUTING */
1093
1094   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
1095
1096 #if !LINUX_POLICY_ROUTING
1097   memset(&kernel_route, 0, sizeof(struct rtentry));
1098
1099   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
1100   ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
1101   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
1102
1103   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4;
1104
1105   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
1106     return -1;
1107   }
1108   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4;
1109
1110   if (rt->rt_dst.prefix.v4.s_addr != rt->rt_best->rtp_nexthop.gateway.v4.s_addr) {
1111     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr = rt->rt_best->rtp_nexthop.gateway.v4;
1112   }
1113
1114   kernel_route.rt_flags = olsr_rt_flags(rt);
1115   kernel_route.rt_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
1116
1117   /*
1118    * Set interface
1119    */
1120   kernel_route.rt_dev = if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index);
1121
1122   /* delete existing default route before ? */
1123   if ((olsr_cnf->del_gws) && (rt->rt_dst.prefix.v4.s_addr == INADDR_ANY) && (rt->rt_dst.prefix_len == INADDR_ANY)) {
1124     delete_all_inet_gws();
1125     olsr_cnf->del_gws = false;
1126   }
1127
1128   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) {
1129
1130     /*
1131      * Send IPC route update message
1132      */
1133     ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, rt->rt_best->rtp_metric.hops, 1,
1134                            if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
1135   }
1136
1137   return rslt;
1138 #else /* !LINUX_POLICY_ROUTING */
1139 #if 0
1140   /*put large hnas also into RtTabledefault (if smartgateway is active) as they may be used to replace (huge parts) of a normal default route*/
1141   if (0 == olsr_cnf->rttable_default && 0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable) {
1142     /*
1143      * Users start whining about not having internet with policy
1144      * routing activated and no static default route in table 254.
1145      * We maintain a fallback defroute in the default=253 table.
1146      *
1147      * which was always insane but togehter with smartgateways policy routing its too insane
1148      */
1149     if (!olsr_cnf->smart_gw_active) olsr_netlink_route(rt, AF_INET, 253, RTM_NEWROUTE);
1150   }
1151   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0) {
1152     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable_default, RTM_NEWROUTE);
1153   }
1154   else {
1155     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable, RTM_NEWROUTE);
1156   }
1157 #endif
1158
1159   return olsr_netlink_process_rt_entry(rt, true);
1160 #endif /* LINUX_POLICY_ROUTING */
1161 }
1162
1163 /**
1164  *Insert a route in the kernel routing table
1165  *
1166  *@param destination the route to add
1167  *
1168  *@return negative on error
1169  */
1170 int
1171 olsr_ioctl_add_route6(const struct rt_entry *rt)
1172 {
1173 #if !LINUX_POLICY_ROUTING
1174   struct in6_rtmsg kernel_route;
1175   int rslt;
1176
1177   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
1178
1179   memset(&kernel_route, 0, sizeof(struct in6_rtmsg));
1180
1181   kernel_route.rtmsg_dst = rt->rt_dst.prefix.v6;
1182   kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len;
1183
1184   kernel_route.rtmsg_gateway = rt->rt_best->rtp_nexthop.gateway.v6;
1185
1186   kernel_route.rtmsg_flags = olsr_rt_flags(rt);
1187   kernel_route.rtmsg_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
1188
1189   /*
1190    * set interface
1191    */
1192   kernel_route.rtmsg_ifindex = rt->rt_best->rtp_nexthop.iif_index;
1193
1194   /* XXX delete 0/0 route before ? */
1195
1196   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) {
1197
1198     /*
1199      * Send IPC route update message
1200      */
1201     ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, rt->rt_best->rtp_metric.hops, 1,
1202                            if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
1203   }
1204   return rslt;
1205 #else /* !LINUX_POLICY_ROUTING */
1206
1207 #if 0
1208   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0) {
1209     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable_default, RTM_NEWROUTE);
1210   }
1211   else {
1212     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable, RTM_NEWROUTE);
1213   }
1214 #endif
1215
1216   return olsr_netlink_process_rt_entry(rt, true);
1217 #endif /* LINUX_POLICY_ROUTING */
1218 }
1219
1220 /**
1221  *Remove a route from the kernel
1222  *
1223  *@param destination the route to remove
1224  *
1225  *@return negative on error
1226  */
1227 int
1228 olsr_ioctl_del_route(const struct rt_entry *rt)
1229 {
1230 #if !LINUX_POLICY_ROUTING
1231   struct rtentry kernel_route;
1232   union olsr_ip_addr mask;
1233   int rslt;
1234 #endif /* LINUX_POLICY_ROUTING */
1235
1236   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
1237
1238 #if !LINUX_POLICY_ROUTING
1239   memset(&kernel_route, 0, sizeof(struct rtentry));
1240
1241   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
1242   ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
1243   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
1244
1245   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4;
1246
1247   if (rt->rt_dst.prefix.v4.s_addr != rt->rt_nexthop.gateway.v4.s_addr) {
1248     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr = rt->rt_nexthop.gateway.v4;
1249   }
1250
1251   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
1252     return -1;
1253   } else {
1254     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4;
1255   }
1256
1257   kernel_route.rt_flags = olsr_rt_flags(rt);
1258   kernel_route.rt_metric = olsr_fib_metric(&rt->rt_metric.hops);
1259
1260   /*
1261    * Set interface
1262    */
1263   kernel_route.rt_dev = NULL;
1264
1265   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route)) >= 0) {
1266
1267     /*
1268      * Send IPC route update message
1269      */
1270     ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
1271   }
1272
1273   return rslt;
1274 #else /* !LINUX_POLICY_ROUTING */
1275
1276 #if 0
1277   if (0 == olsr_cnf->rttable_default && 0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable) {
1278     /*
1279      * Also remove the fallback default route
1280      */
1281     olsr_netlink_route(rt, AF_INET, 253, RTM_DELROUTE);
1282   }
1283   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0) {
1284     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable_default, RTM_DELROUTE);
1285   }
1286   else {
1287     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable, RTM_DELROUTE);
1288   }
1289 #endif
1290   return olsr_netlink_process_rt_entry(rt, false);
1291 #endif /* LINUX_POLICY_ROUTING */
1292 }
1293
1294 /**
1295  *Remove a route from the kernel
1296  *
1297  *@param destination the route to remove
1298  *
1299  *@return negative on error
1300  */
1301 int
1302 olsr_ioctl_del_route6(const struct rt_entry *rt)
1303 {
1304 #if !LINUX_POLICY_ROUTING
1305   struct in6_rtmsg kernel_route;
1306   int rslt;
1307 #endif /* LINUX_POLICY_ROUTING */
1308
1309   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
1310
1311 #if !LINUX_POLICY_ROUTING
1312   memset(&kernel_route, 0, sizeof(struct in6_rtmsg));
1313
1314   kernel_route.rtmsg_dst = rt->rt_dst.prefix.v6;
1315   kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len;
1316
1317   kernel_route.rtmsg_gateway = rt->rt_best->rtp_nexthop.gateway.v6;
1318
1319   kernel_route.rtmsg_flags = olsr_rt_flags(rt);
1320   kernel_route.rtmsg_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
1321
1322   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route) >= 0)) {
1323
1324     /*
1325      * Send IPC route update message
1326      */
1327     ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
1328   }
1329
1330   return rslt;
1331 #else /* !LINUX_POLICY_ROUTING */
1332 #if 0
1333   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0) {
1334     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable_default, RTM_DELROUTE);
1335   }
1336   else {
1337     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable, RTM_DELROUTE);
1338   }
1339 #endif
1340   return olsr_netlink_process_rt_entry(rt, false);
1341 #endif /* LINUX_POLICY_ROUTING */
1342 }
1343
1344 #if !LINUX_POLICY_ROUTING
1345 static int
1346 delete_all_inet_gws(void)
1347 {
1348   int s;
1349   char buf[BUFSIZ], *cp, *cplim;
1350   struct ifconf ifc;
1351   struct ifreq *ifr;
1352
1353   OLSR_PRINTF(1, "Internet gateway detected...\nTrying to delete default gateways\n");
1354
1355   /* Get a socket */
1356   if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1357     olsr_syslog(OLSR_LOG_ERR, "socket: %m");
1358     return -1;
1359   }
1360
1361   ifc.ifc_len = sizeof(buf);
1362   ifc.ifc_buf = buf;
1363   if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
1364     olsr_syslog(OLSR_LOG_ERR, "ioctl (get interface configuration)");
1365     close(s);
1366     return -1;
1367   }
1368
1369   ifr = ifc.ifc_req;
1370   cplim = buf + ifc.ifc_len;    /*skip over if's with big ifr_addr's */
1371   for (cp = buf; cp < cplim; cp += sizeof(ifr->ifr_name) + sizeof(ifr->ifr_addr)) {
1372     struct rtentry kernel_route;
1373     ifr = (struct ifreq *)cp;
1374
1375     if (strcmp(ifr->ifr_ifrn.ifrn_name, "lo") == 0) {
1376       OLSR_PRINTF(1, "Skipping loopback...\n");
1377       continue;
1378     }
1379
1380     OLSR_PRINTF(1, "Trying 0.0.0.0/0 %s...", ifr->ifr_ifrn.ifrn_name);
1381
1382     memset(&kernel_route, 0, sizeof(struct rtentry));
1383
1384     ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr = 0;
1385     ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
1386     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = 0;
1387     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
1388
1389     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr.s_addr = INADDR_ANY;
1390     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
1391
1392     kernel_route.rt_flags = RTF_UP | RTF_GATEWAY;
1393
1394     kernel_route.rt_dev = ifr->ifr_ifrn.ifrn_name;
1395
1396     if ((ioctl(s, SIOCDELRT, &kernel_route)) < 0)
1397       OLSR_PRINTF(1, "NO\n");
1398     else
1399       OLSR_PRINTF(1, "YES\n");
1400   }
1401   close(s);
1402   return 0;
1403 }
1404 #endif /* LINUX_POLICY_ROUTING */
1405
1406 /*
1407  * Local Variables:
1408  * c-basic-offset: 2
1409  * indent-tabs-mode: nil
1410  * End:
1411  */