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