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