all: use the getInterfaceLinkState function
[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 #ifdef __linux__
43
44 #include "kernel_routes.h"
45 #include "ipc_frontend.h"
46 #include "log.h"
47 #include "net_os.h"
48 #include "ifnet.h"
49
50 #include <assert.h>
51 #include <linux/types.h>
52 #include <linux/rtnetlink.h>
53
54 //ipip includes
55 #include <netinet/in.h>
56 #include <sys/ioctl.h>
57 #include <net/if.h>
58 #include <linux/ip.h>
59 #include <linux/if_tunnel.h>
60
61 //ifup includes
62 #include <sys/socket.h>
63 #include <sys/ioctl.h>
64 #include <sys/types.h>
65 #include <net/if.h>
66
67 /*
68  * The ARM compile complains about alignment. Copied
69  * from /usr/include/linux/netlink.h and adapted for ARM
70  */
71 #define MY_NLMSG_NEXT(nlh,len)   ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
72           (struct nlmsghdr*)ARM_NOWARN_ALIGN((((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
73
74
75 static void rtnetlink_read(int sock, void *, unsigned int);
76
77 struct olsr_rtreq {
78   struct nlmsghdr n;
79   struct rtmsg r;
80   char buf[1024];
81 };
82
83 struct olsr_ipadd_req {
84   struct nlmsghdr n;
85   struct ifaddrmsg ifa;
86   char buf[256];
87 };
88
89 int rtnetlink_register_socket(int rtnl_mgrp)
90 {
91   int sock = socket(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE);
92   struct sockaddr_nl addr;
93
94   if (sock<0) {
95     OLSR_PRINTF(1,"could not create rtnetlink socket! %s (%d)", strerror(errno), errno);
96     return -1;
97   }
98
99   memset(&addr, 0, sizeof(addr));
100   addr.nl_family = AF_NETLINK;
101   addr.nl_pid = 0; //kernel will assign appropriate number instead of pid (which is already used by primary rtnetlink socket to add/delete routes)
102   addr.nl_groups = rtnl_mgrp;
103
104   if (bind(sock,(struct sockaddr *)&addr,sizeof(addr))<0) {
105     OLSR_PRINTF(1,"could not bind rtnetlink socket! %s (%d)",strerror(errno), errno);
106     close (sock);
107     return -1;
108   }
109
110   add_olsr_socket(sock, NULL, &rtnetlink_read, NULL, SP_IMM_READ);
111   return sock;
112 }
113
114 static void netlink_process_link(struct nlmsghdr *h)
115 {
116   struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(h);
117   struct interface_olsr *iface;
118   struct olsr_if *oif;
119   char namebuffer[IF_NAMESIZE];
120   char * ifaceName = NULL;
121   bool up;
122
123   iface = if_ifwithindex(ifi->ifi_index);
124
125   if (!iface) {
126     ifaceName = if_indextoname(ifi->ifi_index, namebuffer);
127   } else {
128     ifaceName = iface->int_name;
129   }
130
131   oif = ifaceName ? olsrif_ifwithname(ifaceName) : NULL;
132   up = (getInterfaceLinkState(ifaceName) != LINKSTATE_DOWN) && ((ifi->ifi_flags & IFF_UP) != 0);
133
134   if (!iface && up) {
135     if (oif) {
136       /* try to take interface up, will trigger ifchange */
137       chk_if_up(oif, 3);
138     }
139   } else if (iface && !up) {
140     /* try to take interface down, will trigger ifchange */
141     olsr_remove_interface(iface->olsr_if);
142   }
143
144   if (!iface && !oif) {
145     /* this is not an OLSR interface */
146     olsr_trigger_ifchange(ifi->ifi_index, NULL, up ? IFCHG_IF_ADD : IFCHG_IF_REMOVE);
147   }
148 }
149
150 static void rtnetlink_read(int sock, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused)))
151 {
152   int len, plen;
153   struct iovec iov;
154   struct sockaddr_nl nladdr;
155   struct msghdr msg = {
156     &nladdr,
157     sizeof(nladdr),
158     &iov,
159     1,
160     NULL,
161     0,
162     0
163   };
164
165   char buffer[4096];
166   struct nlmsghdr *nlh = (struct nlmsghdr *)ARM_NOWARN_ALIGN(buffer);
167   int ret;
168
169   iov.iov_base = (void *) buffer;
170   iov.iov_len = sizeof(buffer);
171
172   while ((ret = recvmsg(sock, &msg, MSG_DONTWAIT)) >= 0) {
173     /*check message*/
174     len = nlh->nlmsg_len;
175     plen = len - sizeof(nlh);
176     if (len > ret || plen < 0) {
177       OLSR_PRINTF(1,"Malformed netlink message: "
178              "len=%d left=%d plen=%d\n",
179               len, ret, plen);
180       return;
181     }
182
183     OLSR_PRINTF(3, "Netlink message received: type 0x%x\n", nlh->nlmsg_type);
184     if ((nlh->nlmsg_type == RTM_NEWLINK) || ( nlh->nlmsg_type == RTM_DELLINK)) {
185       /* handle ifup/ifdown */
186       netlink_process_link(nlh);
187     }
188   }
189
190   if (errno != EAGAIN) {
191     OLSR_PRINTF(1,"netlink listen error %u - %s\n",errno,strerror(errno));
192   }
193 }
194
195 static void
196 olsr_netlink_addreq(struct nlmsghdr *n, size_t reqSize __attribute__ ((unused)), int type, const void *data, int len)
197 {
198   struct rtattr *rta = (struct rtattr *)ARM_NOWARN_ALIGN(((char *)n) + NLMSG_ALIGN(n->nlmsg_len));
199   n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_LENGTH(len);
200   //produces strange compile error
201   //assert(n->nlmsg_len < reqSize);
202   rta->rta_type = type;
203   rta->rta_len = RTA_LENGTH(len);
204   memcpy(RTA_DATA(rta), data, len);
205 }
206
207 /*rt_entry and nexthop and family and table must only be specified with an flag != RT_NONE  && != RT_LO_IP*/
208 static int
209 olsr_netlink_send(struct nlmsghdr *nl_hdr)
210 {
211   char rcvbuf[1024];
212   struct iovec iov;
213   struct sockaddr_nl nladdr;
214   struct msghdr msg;
215   struct nlmsghdr *h;
216   struct nlmsgerr *l_err;
217   int ret;
218
219   memset(&nladdr, 0, sizeof(nladdr));
220   memset(&msg, 0, sizeof(msg));
221
222   nladdr.nl_family = AF_NETLINK;
223
224   msg.msg_name = &nladdr;
225   msg.msg_namelen = sizeof(nladdr);
226   msg.msg_iov = &iov;
227   msg.msg_iovlen = 1;
228
229   iov.iov_base = nl_hdr;
230   iov.iov_len = nl_hdr->nlmsg_len;
231   ret = sendmsg(olsr_cnf->rtnl_s, &msg, 0);
232   if (ret <= 0) {
233     olsr_syslog(OLSR_LOG_ERR, "Cannot send data to netlink socket (%d: %s)", errno, strerror(errno));
234     return -1;
235   }
236
237   iov.iov_base = rcvbuf;
238   iov.iov_len = sizeof(rcvbuf);
239   ret = recvmsg(olsr_cnf->rtnl_s, &msg, 0);
240   if (ret <= 0) {
241     olsr_syslog(OLSR_LOG_ERR, "Error while reading answer to netlink message (%d: %s)", errno, strerror(errno));
242     return -1;
243   }
244
245   h = (struct nlmsghdr *)ARM_NOWARN_ALIGN(rcvbuf);
246   if (!NLMSG_OK(h, (unsigned int)ret)) {
247     olsr_syslog(OLSR_LOG_ERR, "Received netlink message was malformed (ret=%d, %u)", ret, h->nlmsg_len);
248     return -1;
249   }
250
251   if (h->nlmsg_type != NLMSG_ERROR) {
252     olsr_syslog(OLSR_LOG_INFO,
253         "Received unknown netlink response: %u bytes, type %u (not %u) with seqnr %u and flags %u from %u",
254         h->nlmsg_len, h->nlmsg_type, NLMSG_ERROR, h->nlmsg_seq, h->nlmsg_flags, h->nlmsg_pid);
255     return -1;
256   }
257   if (NLMSG_LENGTH(sizeof(struct nlmsgerr)) > h->nlmsg_len) {
258     olsr_syslog(OLSR_LOG_INFO,"Received invalid netlink message size %lu != %u",
259         (unsigned long int)sizeof(struct nlmsgerr), h->nlmsg_len);
260     return -1;
261   }
262
263   l_err = (struct nlmsgerr *)NLMSG_DATA(h);
264
265   if (l_err->error) {
266     olsr_syslog(OLSR_LOG_INFO,"Received netlink error code %s (%d)", strerror(-l_err->error), l_err->error);
267   }
268   return -l_err->error;
269 }
270
271 int olsr_os_policy_rule(int family, int rttable, uint32_t priority, const char *if_name, bool set) {
272   struct olsr_rtreq req;
273   int err;
274
275   memset(&req, 0, sizeof(req));
276
277   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
278   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
279
280   req.n.nlmsg_type = set ? RTM_NEWRULE : RTM_DELRULE;
281   req.r.rtm_family = family;
282   req.r.rtm_table = rttable;
283
284   /* probably unneeded */
285   req.r.rtm_type = RTN_UNICAST;
286
287   olsr_netlink_addreq(&req.n, sizeof(req), RTA_PRIORITY, &priority, sizeof(priority));
288
289   if (if_name != NULL) {
290     /*add interface name to rule*/
291     olsr_netlink_addreq(&req.n, sizeof(req), RTA_IIF, if_name, strlen(if_name)+1);
292   }
293
294   err = olsr_netlink_send(&req.n);
295   if (err) {
296     olsr_syslog(OLSR_LOG_ERR,"Error on %s policy rule aimed to activate RtTable %u!",
297         set ? "inserting" : "deleting", rttable);
298   }
299
300   return err;
301 }
302
303 static int
304 olsr_add_ip(int ifindex, union olsr_ip_addr *ip, const char *l, bool create)
305 {
306   struct olsr_ipadd_req req;
307
308   memset(&req, 0, sizeof(req));
309
310   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
311   if (create) {
312    req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | NLM_F_ACK;
313    req.n.nlmsg_type = RTM_NEWADDR;
314   } else {
315    req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
316    req.n.nlmsg_type = RTM_DELADDR;
317   }
318   req.ifa.ifa_family = olsr_cnf->ip_version;
319
320   olsr_netlink_addreq(&req.n, sizeof(req), IFA_LOCAL, ip, olsr_cnf->ipsize);
321   if (l) {
322     olsr_netlink_addreq(&req.n, sizeof(req), IFA_LABEL, l, strlen(l) + 1);
323   }
324
325   req.ifa.ifa_prefixlen = olsr_cnf->ipsize * 8;
326
327   req.ifa.ifa_index = ifindex;
328
329   return olsr_netlink_send(&req.n);
330 }
331
332 int
333 olsr_os_localhost_if(union olsr_ip_addr *ip, bool create)
334 {
335   static char l[] = "lo:olsr";
336   return olsr_add_ip(if_nametoindex("lo"), ip, l, create);
337 }
338
339 int olsr_os_ifip(int ifindex, union olsr_ip_addr *ip, bool create) {
340   return olsr_add_ip(ifindex, ip, NULL, create);
341 }
342
343 int olsr_new_netlink_route(unsigned char family, uint32_t rttable, unsigned int flags, unsigned char scope, int if_index, int metric, int protocol,
344     const union olsr_ip_addr *src, const union olsr_ip_addr *gw, const struct olsr_ip_prefix *dst,
345     bool set, bool del_similar, bool blackhole) {
346
347   struct olsr_rtreq req;
348   int family_size;
349   int err;
350
351   if (0) {
352     struct ipaddr_str buf1, buf2;
353
354     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",
355         family, rttable, if_index, metric, protocol, src == NULL ? "" : olsr_ip_to_string(&buf1, src),
356         gw == NULL ? "" : olsr_ip_to_string(&buf2, gw), olsr_ip_prefix_to_string(dst),
357         set ? "true" : "false", del_similar ? "true" : "false");
358   }
359   family_size = family == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr);
360
361   memset(&req, 0, sizeof(req));
362
363   req.r.rtm_flags = flags;
364   req.r.rtm_family = family;
365 #ifndef __ANDROID__
366   if (rttable < 256)
367     req.r.rtm_table = rttable;
368   else {
369     req.r.rtm_table = RT_TABLE_UNSPEC;
370     olsr_netlink_addreq(&req.n, sizeof(req), RTA_TABLE, &rttable, sizeof(rttable));
371   }
372 #else
373   req.r.rtm_table = rttable;
374 #endif
375
376   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
377   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
378
379   if (set) {
380     req.n.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
381     req.n.nlmsg_type = RTM_NEWROUTE;
382   } else {
383     req.n.nlmsg_type = RTM_DELROUTE;
384   }
385
386   /* RTN_UNSPEC would be the wildcard, but blackhole broadcast or nat roules should usually not conflict */
387   /* -> olsr only adds deletes unicast routes */
388   if (blackhole) {
389     req.r.rtm_type = RTN_BLACKHOLE;
390   } else {
391     req.r.rtm_type = RTN_UNICAST;
392   }
393
394   req.r.rtm_dst_len = dst->prefix_len;
395
396   if (set) {
397     /* add protocol for setting a route */
398     req.r.rtm_protocol = protocol;
399   }
400
401   /* calculate scope of operation */
402   if (!set && del_similar) {
403     /* as wildcard for fuzzy deletion */
404     req.r.rtm_scope = RT_SCOPE_NOWHERE;
405   }
406   else {
407     /* for all our routes */
408     req.r.rtm_scope = scope;
409   }
410
411   if ((set || !del_similar) && !blackhole) {
412     /* add interface*/
413     olsr_netlink_addreq(&req.n, sizeof(req), RTA_OIF, &if_index, sizeof(if_index));
414   }
415
416   if (set && src != NULL) {
417     /* add src-ip */
418     olsr_netlink_addreq(&req.n, sizeof(req), RTA_PREFSRC, src, family_size);
419   }
420
421   if (metric >= 0) {
422     /* add metric */
423     olsr_netlink_addreq(&req.n, sizeof(req), RTA_PRIORITY, &metric, sizeof(metric));
424   }
425
426   if (gw) {
427     /* add gateway */
428     olsr_netlink_addreq(&req.n, sizeof(req), RTA_GATEWAY, gw, family_size);
429   }
430   else {
431     if ( dst->prefix_len == 32 ) {
432       /* use destination as gateway, to 'force' linux kernel to do proper source address selection */
433       olsr_netlink_addreq(&req.n, sizeof(req), RTA_GATEWAY, &dst->prefix, family_size);
434     }
435     else {
436       /*do not use onlink on such routes(no gateway, but no hostroute aswell) -  e.g. smartgateway default route over an ptp tunnel interface*/
437       req.r.rtm_flags &= (~RTNH_F_ONLINK);
438     }
439   }
440
441    /* add destination */
442   olsr_netlink_addreq(&req.n, sizeof(req), RTA_DST, &dst->prefix, family_size);
443
444   err = olsr_netlink_send(&req.n);
445   if (err) {
446       struct ipaddr_str buf;
447     if (gw) {
448       olsr_syslog(OLSR_LOG_ERR, ". error: %s route to %s via %s dev %s onlink (%s %d)",
449           set ? "add" : "del",
450           olsr_ip_prefix_to_string(dst), olsr_ip_to_string(&buf, gw),
451           if_ifwithindex_name(if_index), strerror(errno), errno);
452     }
453     else {
454       olsr_syslog(OLSR_LOG_ERR, ". error: %s route to %s via %s dev %s onlink (%s %d)",
455           set ? "add" : "del",
456           olsr_ip_prefix_to_string(dst), olsr_ip_to_string(&buf, &dst->prefix), if_ifwithindex_name(if_index),
457           strerror(errno), errno);
458     }
459   }
460
461   return err;
462 }
463
464 void olsr_os_niit_6to4_route(const struct olsr_ip_prefix *dst_v6, bool set) {
465   if (olsr_new_netlink_route(AF_INET6,
466       ip_prefix_is_mappedv4_inetgw(dst_v6) ? olsr_cnf->rt_table_default : olsr_cnf->rt_table,
467       RTNH_F_ONLINK, RT_SCOPE_UNIVERSE, olsr_cnf->niit6to4_if_index,
468       olsr_cnf->fib_metric_default, olsr_cnf->rt_proto, NULL, NULL, dst_v6, set, false, false)) {
469     olsr_syslog(OLSR_LOG_ERR, ". error while %s static niit route to %s",
470         set ? "setting" : "removing", olsr_ip_prefix_to_string(dst_v6));
471   }
472 }
473
474 void olsr_os_niit_4to6_route(const struct olsr_ip_prefix *dst_v4, bool set) {
475   if (olsr_new_netlink_route(AF_INET,
476       ip_prefix_is_v4_inetgw(dst_v4) ? olsr_cnf->rt_table_default : olsr_cnf->rt_table,
477       RTNH_F_ONLINK, RT_SCOPE_UNIVERSE, olsr_cnf->niit4to6_if_index,
478       olsr_cnf->fib_metric_default, olsr_cnf->rt_proto, NULL, NULL, dst_v4, set, false, false)) {
479     olsr_syslog(OLSR_LOG_ERR, ". error while %s niit route to %s",
480         set ? "setting" : "removing", olsr_ip_prefix_to_string(dst_v4));
481   }
482 }
483
484 void olsr_os_inetgw_tunnel_route(uint32_t if_idx, bool ipv4, bool set, uint8_t table) {
485   const struct olsr_ip_prefix *dst;
486
487   assert(olsr_cnf->ip_version == AF_INET6 || ipv4);
488
489   dst = ipv4 ? &ipv4_internet_route : &ipv6_internet_route;
490
491   if (olsr_new_netlink_route(ipv4 ? AF_INET : AF_INET6, table, RTNH_F_ONLINK, RT_SCOPE_UNIVERSE,
492       if_idx, olsr_cnf->fib_metric_default, olsr_cnf->rt_proto, NULL, NULL, dst, set, false, false)) {
493     olsr_syslog(OLSR_LOG_ERR, ". error while %s inetgw tunnel route to %s for if %d",
494         set ? "setting" : "removing", olsr_ip_prefix_to_string(dst), if_idx);
495   }
496 }
497
498 static int olsr_os_process_rt_entry(unsigned char af_family, const struct rt_entry *rt, bool set) {
499   int metric;
500   uint32_t table;
501   const struct rt_nexthop *nexthop;
502   union olsr_ip_addr *src;
503   bool hostRoute;
504   int err;
505
506   /* calculate metric */
507   if (FIBM_FLAT == olsr_cnf->fib_metric) {
508     metric = olsr_cnf->fib_metric_default;
509   }
510   else {
511     metric = set ? rt->rt_best->rtp_metric.hops : rt->rt_metric.hops;
512   }
513
514   if (olsr_cnf->smart_gw_active && is_prefix_inetgw(&rt->rt_dst)) {
515     /* make space for the tunnel gateway route */
516     metric += 2;
517   }
518
519   /* get table */
520   table = is_prefix_inetgw(&rt->rt_dst)
521       ? olsr_cnf->rt_table_default : olsr_cnf->rt_table;
522
523   /* get next hop */
524   if (rt->rt_best && set) {
525     nexthop = &rt->rt_best->rtp_nexthop;
526   }
527   else {
528     nexthop = &rt->rt_nexthop;
529   }
530
531   /* detect 1-hop hostroute */
532   hostRoute = rt->rt_dst.prefix_len == olsr_cnf->ipsize * 8
533       && ipequal(&nexthop->gateway, &rt->rt_dst.prefix);
534
535   /* get src ip */
536   if (olsr_cnf->use_src_ip_routes) {
537     src = &olsr_cnf->unicast_src_ip;
538   }
539   else {
540     src = NULL;
541   }
542
543   /* create route */
544   err = olsr_new_netlink_route(af_family, table, RTNH_F_ONLINK, RT_SCOPE_UNIVERSE, nexthop->iif_index, metric, olsr_cnf->rt_proto,
545       src, hostRoute ? NULL : &nexthop->gateway, &rt->rt_dst, set, false, false);
546
547   /* resolve "File exist" (17) propblems (on orig and autogen routes)*/
548   if (set && err == 17) {
549     /* a similar route going over another gateway may be present, which has to be deleted! */
550     olsr_syslog(OLSR_LOG_ERR, ". auto-deleting similar routes to resolve 'File exists' (17) while adding route!");
551
552     /* erase similar rule */
553     err = olsr_new_netlink_route(af_family, table, RTNH_F_ONLINK, RT_SCOPE_UNIVERSE, 0, 0, -1, NULL, NULL, &rt->rt_dst, false, true, false);
554
555     if (!err) {
556       /* create this rule a second time if delete worked*/
557       err = olsr_new_netlink_route(af_family, table, RTNH_F_ONLINK, RT_SCOPE_UNIVERSE, nexthop->iif_index, metric, olsr_cnf->rt_proto,
558           src, hostRoute ? NULL : &nexthop->gateway, &rt->rt_dst, set, false, false);
559     }
560     olsr_syslog(OLSR_LOG_ERR, ". %s (%d)", err == 0 ? "successful" : "failed", err);
561   }
562
563   /* report success on "No such process" (3) */
564   else if (!set && err == 3) {
565     /* another similar (but slightly different) route may be present at this point,
566      * if so this will get solved when adding new route to this destination */
567     olsr_syslog(OLSR_LOG_ERR, ". ignoring 'No such process' (3) while deleting route!");
568     err = 0;
569   }
570   /* insert route to gateway on the fly if "Network unreachable" (128) on 2.4 kernels
571    * or on 2.6 kernel No such process (3) or Network unreachable (101) is reported in rtnetlink response
572    * do this only with flat metric, as using metric values inherited from
573    * a target behind the gateway is really strange, and could lead to multiple routes!
574    * anyways if invalid gateway ips may happen we are f*cked up!!
575    * but if not, these on the fly generated routes are no problem, and will only get used when needed */
576   else if (!hostRoute && olsr_cnf->fib_metric == FIBM_FLAT
577       && (err == 128 || err == 101 || err == 3)) {
578     struct olsr_ip_prefix hostPrefix;
579
580     if (err == 128)  {
581       olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (128) while adding route!");
582     }
583     else if (err == 101) {
584       olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (101) while adding route!");
585     }
586     else {
587       olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'No such process' (3) while adding route!");
588     }
589
590     /* create hostroute */
591     hostPrefix.prefix = nexthop->gateway;
592     hostPrefix.prefix_len = olsr_cnf->ipsize * 8;
593
594     err = olsr_new_netlink_route(af_family, olsr_cnf->rt_table, RTNH_F_ONLINK, RT_SCOPE_UNIVERSE, nexthop->iif_index,
595         metric, olsr_cnf->rt_proto, src, NULL, &hostPrefix, true, false, false);
596     if (err == 0) {
597       /* create this rule a second time if hostrule generation was successful */
598       err = olsr_new_netlink_route(af_family, table, RTNH_F_ONLINK, RT_SCOPE_UNIVERSE, nexthop->iif_index, metric, olsr_cnf->rt_proto,
599           src, &nexthop->gateway, &rt->rt_dst, set, false, false);
600     }
601     olsr_syslog(OLSR_LOG_ERR, ". %s (%d)", err == 0 ? "successful" : "failed", err);
602   }
603
604   return err;
605 }
606
607 /**
608  * Insert a route in the kernel routing table
609  *
610  * @param rt the route to add
611  *
612  * @return negative on error
613  */
614 int
615 olsr_ioctl_add_route(const struct rt_entry *rt)
616 {
617   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
618   return olsr_os_process_rt_entry(AF_INET, rt, true);
619 }
620
621 /**
622  *Insert a route in the kernel routing table
623  *
624  *@param rt the route to add
625  *
626  *@return negative on error
627  */
628 int
629 olsr_ioctl_add_route6(const struct rt_entry *rt)
630 {
631   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
632   return olsr_os_process_rt_entry(AF_INET6, rt, true);
633 }
634
635 /**
636  *Remove a route from the kernel
637  *
638  *@param rt the route to remove
639  *
640  *@return negative on error
641  */
642 int
643 olsr_ioctl_del_route(const struct rt_entry *rt)
644 {
645   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
646   return olsr_os_process_rt_entry(AF_INET, rt, false);
647 }
648
649 /**
650  *Remove a route from the kernel
651  *
652  *@param rt the route to remove
653  *
654  *@return negative on error
655  */
656 int
657 olsr_ioctl_del_route6(const struct rt_entry *rt)
658 {
659   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
660   return olsr_os_process_rt_entry(AF_INET6, rt, false);
661 }
662 #endif /* __linux__ */
663
664 /*
665  * Local Variables:
666  * c-basic-offset: 2
667  * indent-tabs-mode: nil
668  * End:
669  */