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