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