Add framework for changing unicast src-ip
[olsrd.git] / src / linux / kernel_routes_nl.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 #include "ifnet.h"
47
48 #include <assert.h>
49 #include <linux/types.h>
50 #include <linux/rtnetlink.h>
51
52 //ipip includes
53 #include <netinet/in.h>
54 #include <sys/ioctl.h>
55 #include <net/if.h>
56 #include <linux/ip.h>
57 #include <linux/if_tunnel.h>
58
59 //ifup includes
60 #include <sys/socket.h>
61 #include <sys/ioctl.h>
62 #include <sys/types.h>
63 #include <net/if.h>
64
65 /*
66  * This file contains the rtnetlink version of the linux routing code.
67  * You will find the old ioctl version in kernel_routes_ioctl.c
68  *
69  * You can deactivate this code (and activating the ioctl one)
70  * by removing the -DLINUX_NETLINK_ROUTING from make/Makefile.linux
71  */
72 #ifdef LINUX_NETLINK_ROUTING
73 /*
74  * The ARM compile complains about alignment. Copied
75  * from /usr/include/linux/netlink.h and adapted for ARM
76  */
77 #define MY_NLMSG_NEXT(nlh,len)   ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
78           (struct nlmsghdr*)(ARM_NOWARN_ALIGN)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
79
80
81 static void rtnetlink_read(int sock, void *, unsigned int);
82
83 struct olsr_rtreq {
84   struct nlmsghdr n;
85   struct rtmsg r;
86   char buf[512];
87 };
88
89 struct olsr_ipadd_req {
90   struct nlmsghdr n;
91   struct ifaddrmsg ifa;
92   char buf[256];
93 };
94
95 int rtnetlink_register_socket(int rtnl_mgrp)
96 {
97   int sock = socket(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE);
98   struct sockaddr_nl addr;
99
100   if (sock<0) {
101     OLSR_PRINTF(1,"could not create rtnetlink socket! %s (%d)", strerror(errno), errno);
102     return -1;
103   }
104
105   memset(&addr, 0, sizeof(addr));
106   addr.nl_family = AF_NETLINK;
107   addr.nl_pid = 0; //kernel will assign appropiate number instead of pid (which is already used by primaray rtnetlink socket to add/delete routes)
108   addr.nl_groups = rtnl_mgrp;
109
110   if (bind(sock,(struct sockaddr *)&addr,sizeof(addr))<0) {
111     OLSR_PRINTF(1,"could not bind rtnetlink socket! %s (%d)",strerror(errno), errno);
112     return -1;
113   }
114
115   add_olsr_socket(sock, NULL, &rtnetlink_read, NULL, SP_IMM_READ);
116   return sock;
117 }
118
119 static void netlink_process_link(struct nlmsghdr *h)
120 {
121   struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(h);
122   struct interface *iface;
123   struct olsr_if *oif;
124
125   iface = if_ifwithindex(ifi->ifi_index);
126   oif = NULL;
127   if (iface == NULL && (ifi->ifi_flags & IFF_UP) != 0) {
128     char namebuffer[IF_NAMESIZE];
129
130     if (if_indextoname(ifi->ifi_index, namebuffer)) {
131       if ((oif = olsrif_ifwithname(namebuffer)) != NULL) {
132         /* try to take interface up, will trigger ifchange */
133         chk_if_up(oif, 3);
134       }
135     }
136   }
137   else if (iface != NULL && (ifi->ifi_flags & IFF_UP) == 0) {
138     /* try to take interface down, will trigger ifchange */
139     olsr_remove_interface(iface->olsr_if);
140   }
141
142   if (iface == NULL && oif == NULL) {
143     /* this is not an OLSR interface */
144     olsr_trigger_ifchange(ifi->ifi_index, NULL,
145         (ifi->ifi_flags & IFF_UP) == 0 ? IFCHG_IF_REMOVE : IFCHG_IF_ADD);
146   }
147 }
148
149 static void rtnetlink_read(int sock, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused)))
150 {
151   int len, plen;
152   struct iovec iov;
153   struct sockaddr_nl nladdr;
154   struct msghdr msg = {
155     &nladdr,
156     sizeof(nladdr),
157     &iov,
158     1,
159     NULL,
160     0,
161     0
162   };
163
164   char buffer[4096];
165   struct nlmsghdr *nlh = (struct nlmsghdr *)(ARM_NOWARN_ALIGN) buffer;
166   int ret;
167
168   iov.iov_base = (void *) buffer;
169   iov.iov_len = sizeof(buffer);
170
171   while ((ret = recvmsg(sock, &msg, MSG_DONTWAIT)) >= 0) {
172     /*check message*/
173     len = nlh->nlmsg_len;
174     plen = len - sizeof(nlh);
175     if (len > ret || plen < 0) {
176       OLSR_PRINTF(1,"Malformed netlink message: "
177              "len=%d left=%d plen=%d\n",
178               len, ret, plen);
179       return;
180     }
181     if ((nlh->nlmsg_type == RTM_NEWLINK) || ( nlh->nlmsg_type == RTM_DELLINK)) {
182       /* handle ifup/ifdown */
183       netlink_process_link(nlh);
184     }
185   }
186
187   if (errno != EAGAIN) {
188     OLSR_PRINTF(1,"netlink listen error %u - %s\n",errno,strerror(errno));
189   }
190 }
191
192 static void
193 olsr_netlink_addreq(struct nlmsghdr *n, size_t reqSize __attribute__ ((unused)), int type, const void *data, int len)
194 {
195   struct rtattr *rta = (struct rtattr *)(ARM_NOWARN_ALIGN)(((char *)n) + NLMSG_ALIGN(n->nlmsg_len));
196   n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_LENGTH(len);
197   //produces strange compile error
198   //assert(n->nlmsg_len < reqSize);
199   rta->rta_type = type;
200   rta->rta_len = RTA_LENGTH(len);
201   memcpy(RTA_DATA(rta), data, len);
202 }
203
204 /*rt_entry and nexthop and family and table must only be specified with an flag != RT_NONE  && != RT_LO_IP*/
205 static int
206 olsr_netlink_send(struct nlmsghdr *nl_hdr)
207 {
208   char rcvbuf[1024];
209   struct iovec iov;
210   struct sockaddr_nl nladdr;
211   struct msghdr msg;
212   struct nlmsghdr *h;
213   struct nlmsgerr *l_err;
214   int ret;
215
216   memset(&nladdr, 0, sizeof(nladdr));
217   memset(&msg, 0, sizeof(msg));
218
219   nladdr.nl_family = AF_NETLINK;
220
221   msg.msg_name = &nladdr;
222   msg.msg_namelen = sizeof(nladdr);
223   msg.msg_iov = &iov;
224   msg.msg_iovlen = 1;
225
226   iov.iov_base = nl_hdr;
227   iov.iov_len = nl_hdr->nlmsg_len;
228   ret = sendmsg(olsr_cnf->rtnl_s, &msg, 0);
229   if (ret <= 0) {
230     olsr_syslog(OLSR_LOG_ERR, "Cannot send data to netlink socket (%d: %s)", errno, strerror(errno));
231     return -1;
232   }
233
234   iov.iov_base = rcvbuf;
235   iov.iov_len = sizeof(rcvbuf);
236   ret = recvmsg(olsr_cnf->rtnl_s, &msg, 0);
237   if (ret <= 0) {
238     olsr_syslog(OLSR_LOG_ERR, "Error while reading answer to netlink message (%d: %s)", errno, strerror(errno));
239     return -1;
240   }
241
242   h = (struct nlmsghdr *)(ARM_NOWARN_ALIGN)rcvbuf;
243   if (!NLMSG_OK(h, (unsigned int)ret)) {
244     olsr_syslog(OLSR_LOG_ERR, "Received netlink message was malformed (ret=%d, %u)", ret, h->nlmsg_len);
245     return -1;
246   }
247
248   if (h->nlmsg_type != NLMSG_ERROR) {
249     olsr_syslog(OLSR_LOG_INFO,
250         "Received unknown netlink response: %u bytes, type %u (not %u) with seqnr %u and flags %u from %u",
251         h->nlmsg_len, h->nlmsg_type, NLMSG_ERROR, h->nlmsg_seq, h->nlmsg_flags, h->nlmsg_pid);
252     return -1;
253   }
254   if (NLMSG_LENGTH(sizeof(struct nlmsgerr)) > h->nlmsg_len) {
255     olsr_syslog(OLSR_LOG_INFO,"Received invalid netlink message size %lu != %u",
256         (unsigned long int)sizeof(struct nlmsgerr), h->nlmsg_len);
257     return -1;
258   }
259
260   l_err = (struct nlmsgerr *)NLMSG_DATA(h);
261
262   if (l_err->error) {
263     olsr_syslog(OLSR_LOG_INFO,"Received netlink error code %s (%d)", strerror(-l_err->error), l_err->error);
264   }
265   return -l_err->error;
266 }
267
268 int olsr_os_policy_rule(int family, int rttable, uint32_t priority, const char *if_name, bool set) {
269   struct olsr_rtreq req;
270   int err;
271
272   memset(&req, 0, sizeof(req));
273
274   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
275   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
276
277   req.n.nlmsg_type = set ? RTM_NEWRULE : RTM_DELRULE;
278   req.r.rtm_family = family;
279   req.r.rtm_table = rttable;
280
281   /* RTN_UNSPEC would be the wildcard, but blackhole broadcast or nat roules should usually not conflict */
282   /* -> olsr only adds deletes unicast routes */
283   req.r.rtm_type = RTN_UNICAST;
284
285   /* wildcard to delete routes of all protos if no simlar-delete correct proto will get set below */
286   req.r.rtm_protocol = RTPROT_UNSPEC;
287
288   req.r.rtm_scope = RT_SCOPE_UNIVERSE;
289
290   olsr_netlink_addreq(&req.n, sizeof(req), RTA_PRIORITY, &priority, sizeof(priority));
291
292   if (if_name != NULL) {
293     /*add interface name to rule*/
294     olsr_netlink_addreq(&req.n, sizeof(req), RTA_IIF, if_name, strlen(if_name)+1);
295   }
296
297   err = olsr_netlink_send(&req.n);
298   if (err) {
299     olsr_syslog(OLSR_LOG_ERR,"Error on %s empty policy rule aimed to activate RtTable %u!",
300         set ? "inserting" : "deleting", rttable);
301   }
302
303   return err;
304 }
305
306 int
307 olsr_os_localhost_if(union olsr_ip_addr *ip, bool create)
308 {
309   struct olsr_ipadd_req req;
310   static char l[] = "lo:olsr";
311
312   memset(&req, 0, sizeof(req));
313
314   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
315   if (create) {
316    req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | NLM_F_ACK;
317    req.n.nlmsg_type = RTM_NEWADDR;
318   } else {
319    req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
320    req.n.nlmsg_type = RTM_DELADDR;
321   }
322   req.ifa.ifa_family = olsr_cnf->ip_version;
323
324   olsr_netlink_addreq(&req.n, sizeof(req), IFA_LABEL, l, strlen(l) + 1);
325   olsr_netlink_addreq(&req.n, sizeof(req), IFA_LOCAL, ip, olsr_cnf->ipsize);
326
327   req.ifa.ifa_prefixlen = olsr_cnf->ipsize * 8;
328
329   req.ifa.ifa_index = if_nametoindex("lo");
330
331   return olsr_netlink_send(&req.n);
332 }
333
334 static int olsr_new_netlink_route(int family, int rttable, int if_index, int metric, int protocol,
335     const union olsr_ip_addr *src, const union olsr_ip_addr *gw, const struct olsr_ip_prefix *dst,
336     bool set, bool del_similar) {
337
338   struct olsr_rtreq req;
339   int family_size;
340   int err;
341
342   if (0) {
343     struct ipaddr_str buf1, buf2;
344
345     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",
346         family, rttable, if_index, metric, protocol, src == NULL ? "" : olsr_ip_to_string(&buf1, src),
347         gw == NULL ? "" : olsr_ip_to_string(&buf2, gw), olsr_ip_prefix_to_string(dst),
348         set ? "true" : "false", del_similar ? "true" : "false");
349   }
350   family_size = family == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr);
351
352   memset(&req, 0, sizeof(req));
353
354   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
355   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
356   if (set) {
357     req.n.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
358   }
359
360   req.n.nlmsg_type = set ? RTM_NEWROUTE : RTM_DELROUTE;
361   req.r.rtm_family = family;
362   req.r.rtm_table = rttable;
363
364   /* RTN_UNSPEC would be the wildcard, but blackhole broadcast or nat roules should usually not conflict */
365   /* -> olsr only adds deletes unicast routes */
366   req.r.rtm_type = RTN_UNICAST;
367
368   req.r.rtm_dst_len = dst->prefix_len;
369
370   if (set) {
371     /* add protocol for setting a route */
372     req.r.rtm_protocol = protocol;
373   }
374
375   /* calculate scope of operation */
376   if (!set && del_similar) {
377     /* as wildcard for fuzzy deletion */
378     req.r.rtm_scope = RT_SCOPE_NOWHERE;
379   }
380   else if (gw) {
381     /* for multihop routes */
382     req.r.rtm_scope = RT_SCOPE_UNIVERSE;
383   }
384   else {
385     /* for link neighbor routes */
386     req.r.rtm_scope = RT_SCOPE_LINK;
387   }
388
389   if (set || !del_similar) {
390     /* add interface*/
391     olsr_netlink_addreq(&req.n, sizeof(req), RTA_OIF, &if_index, sizeof(if_index));
392   }
393
394   if (set && src != NULL) {
395     /* add src-ip */
396     olsr_netlink_addreq(&req.n, sizeof(req), RTA_PREFSRC, src, family_size);
397   }
398
399   if (metric != -1) {
400     /* add metric */
401     olsr_netlink_addreq(&req.n, sizeof(req), RTA_PRIORITY, &metric, sizeof(metric));
402   }
403
404   if (gw) {
405     /* add gateway */
406     olsr_netlink_addreq(&req.n, sizeof(req), RTA_GATEWAY, gw, family_size);
407   }
408
409   /* add destination */
410   olsr_netlink_addreq(&req.n, sizeof(req), RTA_DST, &dst->prefix, family_size);
411
412   err = olsr_netlink_send(&req.n);
413   if (err) {
414     if (gw) {
415       struct ipaddr_str buf;
416       olsr_syslog(OLSR_LOG_ERR, ". error: %s route to %s via %s dev %s (%s %d)",
417           set ? "add" : "del",
418           olsr_ip_prefix_to_string(dst), olsr_ip_to_string(&buf, gw),
419           if_ifwithindex_name(if_index), strerror(errno), errno);
420     }
421     else {
422       olsr_syslog(OLSR_LOG_ERR, ". error: %s route to %s dev %s (%s %d)",
423           set ? "add" : "del",
424           olsr_ip_prefix_to_string(dst), if_ifwithindex_name(if_index),
425           strerror(errno), errno);
426     }
427   }
428
429   return err;
430 }
431
432 void olsr_os_niit_6to4_route(const struct olsr_ip_prefix *dst_v6, bool set) {
433   /* TODO: in welche Table kommen die NIIT-Routen ? ne eigene ? */
434   if (olsr_new_netlink_route(AF_INET6, olsr_cnf->rt_table, olsr_cnf->niit6to4_if_index,
435       RT_METRIC_DEFAULT, olsr_cnf->rt_proto, NULL, NULL, dst_v6, set, false)) {
436     olsr_syslog(OLSR_LOG_ERR, ". error while %s static niit route to %s",
437         set ? "setting" : "removing", olsr_ip_prefix_to_string(dst_v6));
438   }
439 }
440
441 void olsr_os_niit_4to6_route(const struct olsr_ip_prefix *dst_v4, bool set) {
442   /* TODO: in welche Table kommen die NIIT-Routen ? ne eigene ? */
443   if (olsr_new_netlink_route(AF_INET, olsr_cnf->rt_table, olsr_cnf->niit4to6_if_index,
444       RT_METRIC_DEFAULT, olsr_cnf->rt_proto, NULL, NULL, dst_v4, set, false)) {
445     olsr_syslog(OLSR_LOG_ERR, ". error while %s niit route to %s",
446         set ? "setting" : "removing", olsr_ip_prefix_to_string(dst_v4));
447   }
448 }
449
450 void olsr_os_inetgw_tunnel_route(uint32_t if_idx, bool ipv4, bool set) {
451   const struct olsr_ip_prefix *dst;
452
453   assert(olsr_cnf->ip_version == AF_INET6 || ipv4);
454
455   dst = ipv4 ? &ipv4_internet_route : &ipv6_internet_route;
456
457   if (olsr_new_netlink_route(ipv4 ? AF_INET : AF_INET6, olsr_cnf->rt_table_tunnel,
458       if_idx, RT_METRIC_DEFAULT, olsr_cnf->rt_proto, NULL, NULL, dst, set, false)) {
459     olsr_syslog(OLSR_LOG_ERR, ". error while %s inetgw tunnel route to %s for if %d",
460         set ? "setting" : "removing", olsr_ip_prefix_to_string(dst), if_idx);
461   }
462 }
463
464 static int olsr_os_process_rt_entry(int af_family, const struct rt_entry *rt, bool set) {
465   int metric, table;
466   const struct rt_nexthop *nexthop;
467   union olsr_ip_addr *src;
468   bool hostRoute;
469   int err;
470
471   /* calculate metric */
472   if (FIBM_FLAT == olsr_cnf->fib_metric) {
473     metric = RT_METRIC_DEFAULT;
474   }
475   else {
476     metric = set ? rt->rt_best->rtp_metric.hops : rt->rt_metric.hops;
477   }
478
479   if (olsr_cnf->smart_gw_active && is_prefix_inetgw(&rt->rt_dst)) {
480     /* make space for the tunnel gateway route */
481     metric += 2;
482   }
483
484   /* get table */
485   table = is_prefix_inetgw(&rt->rt_dst)
486       ? olsr_cnf->rt_table_default : olsr_cnf->rt_table;
487
488   /* get next hop */
489   if (rt->rt_best && set) {
490     nexthop = &rt->rt_best->rtp_nexthop;
491   }
492   else {
493     nexthop = &rt->rt_nexthop;
494   }
495
496   /* detect 1-hop hostroute */
497   hostRoute = rt->rt_dst.prefix_len == olsr_cnf->ipsize * 8
498       && ipequal(&nexthop->gateway, &rt->rt_dst.prefix);
499
500 #if 0
501   {
502     struct ipaddr_str buf1, buf2;
503     olsr_syslog(OLSR_LOG_INFO, "hostroute (%s) = %d == %d && %s == %s",
504         hostRoute ? "true" : "false",
505         rt->rt_dst.prefix_len, (int)(olsr_cnf->ipsize * 8),
506         olsr_ip_to_string(&buf1, &nexthop->gateway),
507         olsr_ip_to_string(&buf2, &rt->rt_dst.prefix));
508   }
509 #endif
510
511   /* get src ip */
512   if (olsr_cnf->use_src_ip_routes) {
513     src = &olsr_cnf->unicast_src_ip;
514   }
515   else {
516     src = NULL;
517   }
518
519   /* create route */
520   err = olsr_new_netlink_route(af_family, table, nexthop->iif_index, metric, olsr_cnf->rt_proto,
521       src, hostRoute ? NULL : &nexthop->gateway, &rt->rt_dst, set, false);
522
523   /* resolve "File exist" (17) propblems (on orig and autogen routes)*/
524   if (set && err == 17) {
525     /* a similar route going over another gateway may be present, which has to be deleted! */
526     olsr_syslog(OLSR_LOG_ERR, ". auto-deleting similar routes to resolve 'File exists' (17) while adding route!");
527
528     /* erase similar rule */
529     err = olsr_new_netlink_route(af_family, table, 0, 0, -1, NULL, NULL, &rt->rt_dst, false, true);
530
531     if (!err) {
532       /* create this rule a second time if delete worked*/
533       err = olsr_new_netlink_route(af_family, table, nexthop->iif_index, metric, olsr_cnf->rt_proto,
534           src, hostRoute ? NULL : &nexthop->gateway, &rt->rt_dst, set, false);
535     }
536     olsr_syslog(OLSR_LOG_ERR, ". %s (%d)", err == 0 ? "successful" : "failed", err);
537   }
538
539   /* report success on "No such process" (3) */
540   else if (!set && err == 3) {
541     /* another similar (but slightly different) route may be present at this point,
542      * if so this will get solved when adding new route to this destination */
543     olsr_syslog(OLSR_LOG_ERR, ". ignoring 'No such process' (3) while deleting route!");
544     err = 0;
545   }
546   /* insert route to gateway on the fly if "Network unreachable" (128) on 2.4 kernels
547    * or on 2.6 kernel No such process (3) or Network unreachable (101) is reported in rtnetlink response
548    * do this only with flat metric, as using metric values inherited from
549    * a target behind the gateway is really strange, and could lead to multiple routes!
550    * anyways if invalid gateway ips may happen we are f*cked up!!
551    * but if not, these on the fly generated routes are no problem, and will only get used when needed */
552   else if (!hostRoute && olsr_cnf->fib_metric == FIBM_FLAT
553       && (err == 128 || err == 101 || err == 3)) {
554     struct olsr_ip_prefix hostPrefix;
555
556     if (err == 128)  {
557       olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (128) while adding route!");
558     }
559     else if (err == 101) {
560       olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (101) while adding route!");
561     }
562     else {
563       olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'No such process' (3) while adding route!");
564     }
565
566     /* create hostroute */
567     hostPrefix.prefix = nexthop->gateway;
568     hostPrefix.prefix_len = olsr_cnf->ipsize * 8;
569
570     err = olsr_new_netlink_route(af_family, olsr_cnf->rt_table, nexthop->iif_index,
571         metric, olsr_cnf->rt_proto, src, NULL, &hostPrefix, true, false);
572     if (err == 0) {
573       /* create this rule a second time if hostrule generation was successful */
574       err = olsr_new_netlink_route(af_family, table, nexthop->iif_index, metric, olsr_cnf->rt_proto,
575           src, hostRoute ? NULL : &nexthop->gateway, &rt->rt_dst, set, false);
576     }
577     olsr_syslog(OLSR_LOG_ERR, ". %s (%d)", err == 0 ? "successful" : "failed", err);
578   }
579
580   return err;
581 }
582
583 /**
584  * Insert a route in the kernel routing table
585  *
586  * @param destination the route to add
587  *
588  * @return negative on error
589  */
590 int
591 olsr_ioctl_add_route(const struct rt_entry *rt)
592 {
593   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
594   return olsr_os_process_rt_entry(AF_INET, rt, true);
595 }
596
597 /**
598  *Insert a route in the kernel routing table
599  *
600  *@param destination the route to add
601  *
602  *@return negative on error
603  */
604 int
605 olsr_ioctl_add_route6(const struct rt_entry *rt)
606 {
607   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
608   return olsr_os_process_rt_entry(AF_INET6, rt, true);
609 }
610
611 /**
612  *Remove a route from the kernel
613  *
614  *@param destination the route to remove
615  *
616  *@return negative on error
617  */
618 int
619 olsr_ioctl_del_route(const struct rt_entry *rt)
620 {
621   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
622   return olsr_os_process_rt_entry(AF_INET, rt, false);
623 }
624
625 /**
626  *Remove a route from the kernel
627  *
628  *@param destination the route to remove
629  *
630  *@return negative on error
631  */
632 int
633 olsr_ioctl_del_route6(const struct rt_entry *rt)
634 {
635   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
636   return olsr_os_process_rt_entry(AF_INET6, rt, false);
637 }
638
639 #endif
640
641 #if 0
642 /* values for control flag to handle recursive route corrections
643  *  currently only requires in linux specific kernel_routes.c */
644
645 // #define RT_ORIG_REQUEST 0
646 // #define RT_RETRY_AFTER_ADD_GATEWAY 1
647 // #define RT_RETRY_AFTER_DELETE_SIMILAR 2
648 // #define RT_DELETE_SIMILAR_ROUTE 3
649 // #define RT_AUTO_ADD_GATEWAY_ROUTE 4
650 // #define RT_DELETE_SIMILAR_AUTO_ROUTE 5
651 // #define RT_NIIT 6
652 // #define RT_SMARTGW 7
653
654 /* returns
655  * -1 on unrecoverable error (calling function will have to handle it)
656  *  0 on unexpected but recoverable rtnetlink behaviour
657  *    but some of the implemented recovery methods only cure symptoms, 
658  *    not the cause, like unintelligent ordering of inserted routes.
659  *  1 on success */
660 static int
661 olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd, uint32_t flag)
662 {
663   int ret = 1; /* helper variable for rtnetlink_message processing */
664   int rt_ret = -2;  /* if no response from rtnetlink it must be considered as failed! */
665   struct olsr_rtreq req;
666   struct iovec iov;
667   struct sockaddr_nl nladdr;
668   struct msghdr msg = {
669     &nladdr,
670     sizeof(nladdr),
671     &iov,
672     1,
673     NULL,
674     0,
675     0
676   };
677
678   uint32_t metric = 0;
679   const struct rt_nexthop *nexthop = NULL;
680   if ( ( cmd != RTM_NEWRULE ) && ( cmd != RTM_DELRULE ) ) {
681     if (FIBM_FLAT == olsr_cnf->fib_metric) {
682       metric = RT_METRIC_DEFAULT;
683     }
684     else {
685       metric = (RTM_NEWROUTE == cmd) ? rt->rt_best->rtp_metric.hops : rt->rt_metric.hops;
686     }
687
688     if (( RTM_NEWROUTE == cmd ) ||
689         (( RTM_DELROUTE == cmd ) && ( RT_DELETE_SIMILAR_ROUTE == flag || RT_DELETE_SIMILAR_AUTO_ROUTE == flag ))) {
690       nexthop = &rt->rt_best->rtp_nexthop;
691     }
692     else {
693       nexthop = &rt->rt_nexthop;
694     }
695   }
696
697   memset(&req, 0, sizeof(req));
698
699   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
700   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
701   req.n.nlmsg_type = cmd;
702   
703   /*sanity check for niit ipv4 over ipv6 routes*/
704   if (family == AF_INET && flag == RT_NIIT) {
705     olsr_syslog(OLSR_LOG_ERR,"niit makes no sense with olsrd running on ipv4!");
706     return -1;
707   }
708
709   if (flag == RT_NIIT) {
710     req.r.rtm_family=AF_INET; /*we create an ipv4 niit route*/
711   }
712   else {
713     req.r.rtm_family = family;
714   }
715
716   req.r.rtm_table = rttable;
717
718   /* RTN_UNSPEC would be the wildcard, but blackhole broadcast or nat roules should usually not conflict */
719   /* -> olsr only adds deletes unicast routes */
720   req.r.rtm_type = RTN_UNICAST;
721
722   /* wildcard to delete routes of all protos if no simlar-delete correct proto will get set below */
723   req.r.rtm_protocol = RTPROT_UNSPEC;
724
725   /* as wildcard for deletion */
726   req.r.rtm_scope = RT_SCOPE_NOWHERE;
727
728   if ( ( cmd == RTM_NEWRULE ) || ( cmd == RTM_DELRULE ) ) {
729     /* add or delete a rule */
730     req.r.rtm_scope = RT_SCOPE_UNIVERSE;
731     olsr_netlink_addreq(&req, RTA_PRIORITY, &flag, sizeof(flag));
732     if (rt!=NULL) {
733       /*add interface name to rule*/
734       olsr_netlink_addreq(&req, RTA_IIF, rt, strlen((const char*) rt)+1);
735       //printf("\nrule to interface %s!",(const char*) rt);
736     } 
737   }
738   else {
739     req.r.rtm_dst_len = rt->rt_dst.prefix_len;
740
741     /* do not specify much as we wanna delete similar/conflicting routes */
742     if ( ( flag != RT_DELETE_SIMILAR_ROUTE ) && ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE )) {
743       /* 0 gets replaced by OS-specifc default (3)
744        * 1 is reserved so we take 0 instead (this really makes some sense)
745        * other numbers are used 1:1 */
746       req.r.rtm_protocol = ( (olsr_cnf->rtproto<1) ? RTPROT_BOOT : ( (olsr_cnf->rtproto==1) ? 0 : olsr_cnf->rtproto) );
747       req.r.rtm_scope = RT_SCOPE_LINK;
748
749       /*add interface*/
750       if ((olsr_cnf->smart_gw_active) && family != AF_INET)
751       {
752         printf("smart gateway not available for ipv6 currently\n");
753         return -1;
754       }
755       else if(flag == RT_SMARTGW)
756       //else if ((olsr_cnf->smart_gateway_active) && (rt->rt_dst.prefix_len == 0) && (&olsr_cnf->ipip_if_index))
757       {
758         //add interface (without nexthop if possible (if not use &rt->rt_best->rtp_originator))
759         olsr_netlink_addreq(&req, RTA_OIF, &olsr_cnf->ipip_if_index, sizeof(&olsr_cnf->ipip_if_index));
760       }
761       else if (flag == RT_NIIT) {
762         olsr_netlink_addreq(&req, RTA_OIF, &olsr_cnf->niit4to6_if_index, sizeof(&olsr_cnf->niit4to6_if_index));
763       }
764       else {
765         olsr_netlink_addreq(&req, RTA_OIF, &nexthop->iif_index, sizeof(nexthop->iif_index));
766       }
767
768 #if SOURCE_IP_ROUTES
769       /**
770        * source ip here is based on now static olsr_cnf->main_addr in this olsr-0.5.6-r4,
771        * should be based on orignator-id in newer olsrds
772        **/
773       if (flag != RT_NIIT) {
774         if (AF_INET == family) {
775           olsr_netlink_addreq(&req, RTA_PREFSRC, &olsr_cnf->main_addr.v4.s_addr, sizeof(olsr_cnf->main_addr.v4.s_addr));
776         }
777         else {
778           olsr_netlink_addreq(&req, RTA_PREFSRC, &olsr_cnf->main_addr.v6.s6_addr, sizeof(olsr_cnf->main_addr.v6.s6_addr));
779         }
780       }
781 #endif
782     }
783
784     /* metric is specified always as we can only delete one route per iteration, and wanna hit the correct one first */
785     if (FIBM_APPROX != olsr_cnf->fib_metric || (RTM_NEWROUTE == cmd) ) {
786       olsr_netlink_addreq(&req, RTA_PRIORITY, &metric, sizeof(metric));
787     }
788
789     /* make sure that netmask = maxplen (32 or 128) as this is an autogenarated (host)route */
790     if (( flag == RT_AUTO_ADD_GATEWAY_ROUTE ) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) {
791       req.r.rtm_dst_len = olsr_cnf->maxplen;
792     }
793
794     /**
795      * for ipv4 or ipv6 we add gateway if one is specified,
796      * or leave gateway away if we want to delete similar routes aswell,
797      * or even use the gateway as target if we add a auto-generated route,
798      * or if delete-similar to make insertion of auto-generated route possible
799      **/
800     if (AF_INET == family) {
801       if ( ( flag != RT_SMARTGW )
802            && ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE) && 
803            ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) && (rt->rt_dst.prefix.v4.s_addr != nexthop->gateway.v4.s_addr) ) {
804         olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v4, sizeof(nexthop->gateway.v4));
805         req.r.rtm_scope = RT_SCOPE_UNIVERSE;
806       }
807       olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
808                           &nexthop->gateway.v4 : &rt->rt_dst.prefix.v4, sizeof(rt->rt_dst.prefix.v4));
809     } else {
810       if (flag == RT_NIIT) {
811         union olsr_ip_addr ipv4_addr;
812         /* create an ipv4 route */
813         olsr_syslog(OLSR_LOG_ERR,"niit suport not fully implemented!!\n");
814
815         /* fix prefix length */
816         req.r.rtm_dst_len = rt->rt_dst.prefix_len - 96;
817         olsr_netlink_addreq(&req, RTA_DST, olsr_ipv6_to_ipv4(&rt->rt_dst.prefix, &ipv4_addr), sizeof(ipv4_addr.v4));
818       }
819       else {
820         if ( ( flag != RT_SMARTGW ) 
821             && ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE ) && ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) 
822             && (0 != memcmp(&rt->rt_dst.prefix.v6, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6))) ) {
823           olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6));
824           req.r.rtm_scope = RT_SCOPE_UNIVERSE;
825         }
826         olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
827                             &nexthop->gateway.v6 : &rt->rt_dst.prefix.v6, sizeof(rt->rt_dst.prefix.v6));
828       }
829     }
830   }
831
832   iov.iov_base = &req.n;
833   iov.iov_len = req.n.nlmsg_len;
834   memset(&nladdr, 0, sizeof(nladdr));
835   nladdr.nl_family = AF_NETLINK;
836   if (0 <= (ret = sendmsg(olsr_cnf->rtnl_s, &msg, 0))) {
837     iov.iov_base = req.buf;
838     iov.iov_len = sizeof(req.buf);
839     if (0 < (ret = recvmsg(olsr_cnf->rtnl_s, &msg, 0))) {
840       struct nlmsghdr *h = (struct nlmsghdr *)(ARM_NOWARN_ALIGN)req.buf;
841       while (NLMSG_OK(h, (unsigned int)ret)) {
842         if (NLMSG_DONE == h->nlmsg_type) {
843           /* seems to reached never */
844           olsr_syslog(OLSR_LOG_INFO, "_received NLMSG_DONE");
845           break;
846         }
847         if (NLMSG_ERROR == h->nlmsg_type) {
848           if (NLMSG_LENGTH(sizeof(struct nlmsgerr) <= h->nlmsg_len)) {
849             struct ipaddr_str ibuf;
850             struct ipaddr_str gbuf;
851             struct nlmsgerr *l_err = (struct nlmsgerr *)NLMSG_DATA(h);
852             errno = -l_err->error;
853             if (0 != errno) {
854               const char *const err_msg = strerror(errno);
855               struct ipaddr_str buf;
856               rt_ret = -1;
857
858               /* syslog debug output for various situations */
859               if ( cmd == RTM_NEWRULE ) {
860                 olsr_syslog(OLSR_LOG_ERR,"Error '%s' (%d) on inserting empty policy rule aimed to activate RtTable %u!", err_msg, errno, rttable);
861               }
862               else if ( cmd == RTM_DELRULE ) {
863                 olsr_syslog(OLSR_LOG_ERR,"Error '%s' (%d) on deleting empty policy rule aimed to activate rtTable %u!", err_msg, errno, rttable);
864               }
865               else if ( flag == RT_NIIT ) {
866                 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));
867               }
868               else if ( flag <= RT_RETRY_AFTER_DELETE_SIMILAR ) {
869                 if (rt->rt_dst.prefix.v4.s_addr!=nexthop->gateway.v4.s_addr) {
870                   olsr_syslog(OLSR_LOG_ERR, "error '%s' (%d) %s route to %s/%d via %s dev %s",
871                       err_msg, errno, (cmd == RTM_NEWROUTE) ? "add" : "del",
872                       olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix), req.r.rtm_dst_len,
873                       olsr_ip_to_string(&gbuf,&nexthop->gateway), if_ifwithindex_name(nexthop->iif_index));
874                 }
875                 else {
876                   olsr_syslog(OLSR_LOG_ERR, "error '%s' (%d) %s route to %s/%d dev %s",
877                       err_msg, errno, (cmd == RTM_NEWROUTE) ? "add" : "del",
878                       olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix), req.r.rtm_dst_len, if_ifwithindex_name(nexthop->iif_index));
879                 }
880               }
881               else if (flag == RT_AUTO_ADD_GATEWAY_ROUTE) {
882                 olsr_syslog(OLSR_LOG_ERR, ". error '%s' (%d) auto-add route to %s dev %s", err_msg, errno,
883                     olsr_ip_to_string(&ibuf,&nexthop->gateway), if_ifwithindex_name(nexthop->iif_index));
884               }
885               else if (flag == RT_DELETE_SIMILAR_ROUTE) {
886                 olsr_syslog(OLSR_LOG_ERR, ". error '%s' (%d) auto-delete route to %s dev %s", err_msg, errno,
887                     olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix), if_ifwithindex_name(nexthop->iif_index));
888               }
889               else if (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) {
890                 olsr_syslog(OLSR_LOG_ERR, ". . error '%s' (%d) auto-delete similar route to %s dev %s", err_msg, errno,
891                     olsr_ip_to_string(&ibuf,&nexthop->gateway), if_ifwithindex_name(nexthop->iif_index));
892               }
893               else {
894                 /* should never happen */
895                 olsr_syslog(OLSR_LOG_ERR, "# invalid internal route delete/add flag (%d) used!", flag);
896               }
897             }
898             else {
899               /* netlink acks requests with an errno=0 NLMSG_ERROR response! */
900               rt_ret = 1;
901             }
902
903             /* resolve "File exist" (17) propblems (on orig and autogen routes)*/
904             if ((errno == 17) && (cmd == RTM_NEWROUTE) && ((flag == RT_ORIG_REQUEST) || (flag == RT_AUTO_ADD_GATEWAY_ROUTE))) {
905               /* a similar route going over another gateway may be present, which has to be deleted! */
906               olsr_syslog(OLSR_LOG_ERR, ". auto-deleting similar routes to resolve 'File exists' (17) while adding route!");
907               rt_ret = RT_DELETE_SIMILAR_ROUTE; /* processing will contiune after this loop */
908             }
909             /* report success on "No such process" (3) */
910             else if ((errno == 3) && (cmd == RTM_DELROUTE) && (flag == RT_ORIG_REQUEST)) {
911               /* another similar (but slightly different) route may be present at this point
912               * , if so this will get solved when adding new route to this destination */
913               olsr_syslog(OLSR_LOG_ERR, ". ignoring 'No such process' (3) while deleting route!");
914               rt_ret = 0;
915             }
916             /* insert route to gateway on the fly if "Network unreachable" (128) on 2.4 kernels
917              * or on 2.6 kernel No such process (3) or Network unreachable (101) is reported in rtnetlink response
918              * do this only with flat metric, as using metric values inherited from 
919              * a target behind the gateway is really strange, and could lead to multiple routes!
920              * anyways if invalid gateway ips may happen we are f*cked up!!
921              * but if not, these on the fly generated routes are no problem, and will only get used when needed */
922             else if ( ( (errno == 3) || (errno == 101) || (errno == 128) )
923                 && (flag == RT_ORIG_REQUEST) && (FIBM_FLAT == olsr_cnf->fib_metric)
924                      && (cmd == RTM_NEWROUTE) && (rt->rt_dst.prefix.v4.s_addr!=nexthop->gateway.v4.s_addr)) {
925               if (errno == 128)  {
926                 olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (128) while adding route!");
927               }
928               else if (errno == 101) {
929                 olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (101) while adding route!");
930               }
931               else {
932                 olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'No such process' (3) while adding route!");
933               }
934
935               /* processing will contiune after this loop */
936               rt_ret = RT_AUTO_ADD_GATEWAY_ROUTE;
937             }
938           }
939           /* report invalid message size */
940           else {
941             olsr_syslog(OLSR_LOG_INFO,"_received invalid netlink message size %lu != %u",
942                 (unsigned long int)sizeof(struct nlmsgerr), h->nlmsg_len);
943           }
944         }
945         /* log all other messages */
946         else {
947           olsr_syslog(OLSR_LOG_INFO,"_received %u Byte rtnetlink response of type %u with seqnr %u and flags %u from %u (%u)",
948               h->nlmsg_len, h->nlmsg_type, h->nlmsg_seq, h->nlmsg_flags, h->nlmsg_pid, NLMSG_ERROR);
949         }
950 /*
951  * The ARM compile complains about alignment. Copied
952  * from /usr/include/linux/netlink.h and adapted for ARM
953  */
954 #define MY_NLMSG_NEXT(nlh,len)   ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
955           (struct nlmsghdr*)(ARM_NOWARN_ALIGN)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
956         h = MY_NLMSG_NEXT(h, ret);
957       }
958     }
959   }
960   if ( rt_ret == RT_DELETE_SIMILAR_ROUTE ) {
961     /* delete all routes that may collide */
962
963     /* recursive call to delete simlar routes, using flag 2 to invoke deletion of similar, not only exact matches*/
964     rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_DELROUTE, 
965         flag == RT_AUTO_ADD_GATEWAY_ROUTE ? RT_DELETE_SIMILAR_AUTO_ROUTE : RT_DELETE_SIMILAR_ROUTE);
966
967     /* retry insert original route, if deleting similar succeeded, using flag=1 to prevent recursions */
968     if (rt_ret > 0) {
969       rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_RETRY_AFTER_DELETE_SIMILAR);
970     }
971     else {
972       olsr_syslog(OLSR_LOG_ERR, ". failed on auto-deleting similar route conflicting with above route!");
973     }
974
975     /* set appropriate return code for original request, while returning simple -1/1 if called recursive */
976     if (flag != RT_AUTO_ADD_GATEWAY_ROUTE) {
977       if (rt_ret > 0) {
978         /* successful recovery */
979         rt_ret = 0;
980       }
981       else {
982         /* unrecoverable error */
983         rt_ret = -1;
984       }
985     }
986   }
987   if ( rt_ret == RT_AUTO_ADD_GATEWAY_ROUTE ) {
988     /* autoadd route via gateway */
989
990     /* recursive call to invoke creation of a route to the gateway */
991     rt_ret = olsr_netlink_route_int(rt, family, olsr_cnf->rttable, RTM_NEWROUTE, RT_AUTO_ADD_GATEWAY_ROUTE);
992
993     /* retry insert original route, if above succeeded without problems */
994     if (rt_ret > 0) {
995       rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_RETRY_AFTER_ADD_GATEWAY);
996     }
997     else {
998       olsr_syslog(OLSR_LOG_ERR, ". failed on inserting auto-generated route to gateway of above route!");
999     }
1000
1001     /* set appropriate return code for original request*/
1002     if (rt_ret > 0) {
1003       /* successful recovery */
1004       rt_ret = 0;
1005     }
1006     else {
1007       /* unrecoverable error */
1008       rt_ret = -1;
1009     }
1010   }
1011   /* send ipc update on success */
1012   if ( ( cmd != RTM_NEWRULE ) && ( cmd != RTM_DELRULE )
1013       && (flag == RT_ORIG_REQUEST) && (0 <= rt_ret && olsr_cnf->ipc_connections > 0) ) {
1014     ipc_route_send_rtentry(&rt->rt_dst.prefix, &nexthop->gateway, metric,
1015         RTM_NEWROUTE == cmd, if_ifwithindex_name(nexthop->iif_index));
1016   }
1017   if (rt_ret == -2) {
1018     olsr_syslog(OLSR_LOG_ERR,"no rtnetlink response! (no system ressources left?, everything may happen now ...)");
1019   }
1020   return rt_ret;
1021 }
1022
1023 /* external wrapper function for above patched multi purpose rtnetlink function */
1024 int
1025 olsr_os_policy_rule(uint8_t family, uint8_t rttable, uint16_t cmd, uint32_t priority, char* dev)
1026 {
1027   return olsr_netlink_route_int((const struct rt_entry *) dev, family, rttable, cmd, priority);
1028 }
1029
1030
1031 /* internal wrapper function for above patched function */
1032 /* added smartgw and niit route creation*/
1033 static int
1034 olsr_netlink_route(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd)
1035 {
1036   /*check if this rule is relevant for smartgw*/
1037   if ((olsr_cnf->smart_gw_active) && (rt->rt_dst.prefix_len == 0) )
1038   { 
1039     if (cmd == RTM_DELROUTE){ /*should we do something sane here!!??*/
1040       printf("ignoreing deletion of default route for smart gateway!!\n");
1041     }
1042     else
1043     {
1044       if (!olsr_cnf->ipip_if_index) {
1045 int r;
1046         printf("creating tunnel %s\n",olsr_cnf->ipip_name);
1047         /*create tunnel*/
1048         set_tunl(SIOCADDTUNNEL,rt->rt_best->rtp_originator.v4.s_addr);
1049         olsr_cnf->ipip_if_up=false;/*rtnetlink monitoring will detect it up*/
1050         /*!!?? currently it gets never deleted on shutdown, anyways reusing existing tunnel might be a safe approach if creating fails?*/
1051         /*set tunnel up with originator ip*/
1052         r=olsr_if_setip(olsr_cnf->ipip_name, &olsr_cnf->main_addr, 0);
1053 printf("result of ifup is %i\n",r);
1054         /*find out iifindex (maybe it works even if above failed (old tunnel))*/
1055         olsr_cnf->ipip_if_index=if_nametoindex(olsr_cnf->ipip_name);
1056 printf("index of new olsrtunl is %i\n",olsr_cnf->ipip_if_index);
1057       }
1058       else
1059       {
1060         printf("changing tunnel %s:\n",olsr_cnf->ipip_name);
1061         /*change tunnel to new originator or potentially new gateway*/
1062         if ((olsr_cnf->ipip_remote_address != rt->rt_best->rtp_originator.v4.s_addr) && (rt->rt_best->rtp_originator.v4.s_addr != 0x00000000) ) {
1063           struct ipaddr_str buf;
1064           printf("changing tunnel to %s\n",olsr_ip_to_string(&buf,&rt->rt_best->rtp_originator));
1065           olsr_cnf->ipip_remote_address = rt->rt_best->rtp_originator.v4.s_addr;
1066           set_tunl(SIOCCHGTUNNEL,olsr_cnf->ipip_remote_address);
1067         }
1068       }
1069       /*create route into tunnel*/
1070       olsr_netlink_route_int(rt, family, olsr_cnf->rttable_smartgw, cmd, RT_SMARTGW);
1071     }
1072   }
1073   /*normal route in default route table*/
1074
1075   /*create/delete niit route if we have an niit device*/
1076   if ((olsr_cnf->niit4to6_if_index!=0) && (family != AF_INET) && (olsr_is_niit_ipv6(&rt->rt_dst.prefix))) {
1077     olsr_netlink_route_int(rt, family, rttable, cmd, RT_NIIT);
1078   }
1079
1080   return olsr_netlink_route_int(rt, family, rttable, cmd, RT_ORIG_REQUEST);
1081 }
1082 #endif
1083 /*
1084  * Local Variables:
1085  * c-basic-offset: 2
1086  * indent-tabs-mode: nil
1087  * End:
1088  */