preserve old if-flags
[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
46 /* values for control flag to handle recursive route corrections 
47  *  currently only requires in linux specific kernel_routes.c */
48
49 #define RT_ORIG_REQUEST 0
50 #define RT_RETRY_AFTER_ADD_GATEWAY 1
51 #define RT_RETRY_AFTER_DELETE_SIMILAR 2
52 #define RT_DELETE_SIMILAR_ROUTE 3
53 #define RT_AUTO_ADD_GATEWAY_ROUTE 4
54 #define RT_DELETE_SIMILAR_AUTO_ROUTE 5
55 #define RT_NIIT 6
56
57 #if !LINUX_POLICY_ROUTING
58
59 static int delete_all_inet_gws(void);
60
61 #else /* !LINUX_POLICY_ROUTING */
62
63 #include <assert.h>
64 #include <linux/types.h>
65 #include <linux/rtnetlink.h>
66
67 //ipip includes
68 #include <netinet/in.h>
69 #include <sys/ioctl.h>
70 #include <net/if.h>
71 #include <linux/ip.h>
72 #include <linux/if_tunnel.h>
73
74 //ifup includes
75 #include <sys/socket.h>
76 #include <sys/ioctl.h>
77 #include <sys/types.h>
78 #include <net/if.h>
79
80 extern struct rtnl_handle rth;
81
82 struct olsr_rtreq {
83   struct nlmsghdr n;
84   struct rtmsg r;
85   char buf[512];
86 };
87
88 /*takes up an interface*/
89 int olsr_dev_up(const char * dev,bool set_ip)
90 {
91   int s, r;
92   struct ifreq ifr;
93   s = socket(PF_INET, SOCK_DGRAM, 0);
94   if (s < 0) {
95     perror("socket");
96     return(-1);
97   }
98   memset(&ifr, 0, sizeof(ifr));
99   strncpy(ifr.ifr_name, dev, IFNAMSIZ);
100
101   if (set_ip){
102     struct sockaddr_in sin;
103     memset(&sin, 0, sizeof(struct sockaddr_in));
104     sin.sin_family = AF_INET;
105     sin.sin_addr.s_addr = 0x01020304;//!!??use originator address
106     memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr_in));
107
108     r = ioctl(s, SIOCSIFADDR, &ifr);
109     if (r < 0){
110       perror("ioctl");
111       return false;
112     }
113     /*reset ifreq fuild for IFFLGAS*/
114     memset(&sin, 0, sizeof( struct sockaddr_in) );
115   }
116
117   ifr.ifr_flags = IFF_UP; //!!?? read old flags and before setting new ones
118   r = ioctl(s, SIOCGIFFLAGS, &ifr);
119   /*check if already up*/
120   if ((short int)ifr.ifr_flags & IFF_UP) return true;
121   /*set to UP now*/
122   ifr.ifr_flags |= IFF_UP;
123   r = ioctl(s, SIOCSIFFLAGS, &ifr);
124   if (r < 0) {
125     perror("ioctl");
126     return false;
127   }
128   return true;
129 }
130                                         
131 #if LINUX_RTNETLINK_LISTEN
132 #include "ifnet.h"
133 #include "socket_parser.h"
134
135 int rtnetlink_register_socket(int rtnl_mgrp)
136 {
137   int sock = socket(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE);
138   struct sockaddr_nl addr;
139
140   if (sock<0) {
141     OLSR_PRINTF(1,"could not create rtnetlink socket! %d",sock);
142   }
143   else {
144     memset(&addr, 0, sizeof(addr));
145
146     addr.nl_family = AF_NETLINK;
147     addr.nl_pid = 0; //kernel will assign appropiate number instead of pid (which is already used by primaray rtnetlink socket to add/delete routes)
148     addr.nl_groups = rtnl_mgrp;
149     if (bind(sock,(struct sockaddr *)&addr,sizeof(addr))<0) {
150       OLSR_PRINTF(1,"could not bind socket! (%d %s)",errno,strerror(errno));
151     }
152     else {
153       add_olsr_socket(sock, &rtnetlink_read);
154     }
155     fcntl(sock, F_SETFL, O_NONBLOCK);
156   }
157   return sock;
158 }
159
160 static void netlink_process_link(struct nlmsghdr *h)
161 {
162   struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(h);
163   struct interface *iface;
164   struct olsr_if *tmp_if;
165
166   iface = if_ifwithindex(ifi->ifi_index);
167   if (iface == NULL) {
168     return;
169   }
170   
171   //all IFF flags: LOOPBACK,BROADCAST;POINTOPOINT;MULTICAST;NOARP;ALLMULTI;PROMISC;MASTER;SLAVE;DEBUG;DYNAMIC;AUTOMEDIA;PORTSEL;NOTRAILERS;UP;LOWER_UP;DORMANT
172   /* check if interface is up and running? (a not running interface keeps its routes, so better not react like on ifdown!!??) */
173   if (ifi->ifi_flags&IFF_UP) {
174     OLSR_PRINTF(3,"interface %s changed but is still up! ", iface->int_name);
175     return; //we are currently only interested in interfaces that are/go down
176   } else {
177     OLSR_PRINTF(1,"interface %s is down! ", iface->int_name);
178   }
179
180   //only for still configured interfaces (ifup has to be detected with regular interface polling)
181   for (tmp_if = olsr_cnf->interfaces; tmp_if != NULL; tmp_if = tmp_if->next) {
182     if (tmp_if->interf==iface) {
183       OLSR_PRINTF(1,"-> removing %s from olsr config! ", iface->int_name);
184       RemoveInterface(tmp_if,true);
185       break;
186     }
187   }
188 }
189
190 void rtnetlink_read(int sock)
191 {
192   int len, plen;
193   struct iovec iov;
194   struct sockaddr_nl nladdr;
195   struct msghdr msg = {
196     &nladdr,
197     sizeof(nladdr),
198     &iov,
199     1,
200     NULL,
201     0,
202     0
203   };
204
205   char buffer[4096];
206   struct nlmsghdr *nlh = (struct nlmsghdr *)(ARM_NOWARN_ALIGN) buffer;
207   int ret;
208
209   iov.iov_base = (void *) buffer;
210   iov.iov_len = sizeof(buffer);
211
212   while (true) { //read until ret<0;
213     ret=recvmsg(sock, &msg, 0);
214     if (ret<0) {
215       if (errno != EAGAIN) OLSR_PRINTF(1,"\nnetlink listen error %u - %s",errno,strerror(errno));
216       return;
217     }
218     /*check message*/
219     len = nlh->nlmsg_len;
220     plen = len - sizeof(nlh);
221     if (len > ret || plen < 0) {
222       OLSR_PRINTF(1,"Malformed netlink message: "
223              "len=%d left=%d plen=%d",
224               len, ret, plen);
225       return;
226     }
227     if ( (nlh->nlmsg_type == RTM_NEWLINK) || ( nlh->nlmsg_type == RTM_DELLINK) ) netlink_process_link(nlh);
228   }
229 }
230
231 //!!?? listen on our own tunlx interfaces aswell
232
233 #endif /*linux_rtnetlink_listen*/
234
235 /*create or change a ipip tunnel ipv4 only*/
236 static int set_tunl(int cmd, unsigned long int ipv4)
237 {
238   struct ifreq ifr;
239   int fd;
240   int err;
241   struct ip_tunnel_parm p;
242
243   p.iph.version = 4;
244   p.iph.ihl = 5;
245   p.iph.protocol=IPPROTO_IPIP; //IPPROTO_IPV6
246   p.iph.saddr=0x00000000;
247   p.iph.daddr=ipv4;
248
249   strncpy(p.name, olsr_cnf->ipip_name, IFNAMSIZ);
250
251   //specify existing interface name
252   if (cmd!=SIOCADDTUNNEL) strncpy(ifr.ifr_name, olsr_cnf->ipip_name, IFNAMSIZ);
253
254   ifr.ifr_ifru.ifru_data = (void *) &p;
255   fd = socket(AF_INET, SOCK_DGRAM, 0);//warning hardcoded AF_INET
256   err = ioctl(fd, cmd, &ifr);
257   if (err) perror("ioctl");
258   close(fd);
259   return err;
260 }
261
262 static void
263 olsr_netlink_addreq(struct olsr_rtreq *req, int type, const void *data, int len)
264 {
265   struct rtattr *rta = (struct rtattr *)(ARM_NOWARN_ALIGN)(((char *)req) + NLMSG_ALIGN(req->n.nlmsg_len));
266   req->n.nlmsg_len = NLMSG_ALIGN(req->n.nlmsg_len) + RTA_LENGTH(len);
267   assert(req->n.nlmsg_len < sizeof(struct olsr_rtreq));
268   rta->rta_type = type;
269   rta->rta_len = RTA_LENGTH(len);
270   memcpy(RTA_DATA(rta), data, len);
271 }
272
273 /* returns
274  * -1 on unrecoverable error (calling function will have to handle it)
275  *  0 on unexpected but recoverable rtnetlink behaviour
276  *    but some of the implemented recovery methods only cure symptoms, 
277  *    not the cause, like unintelligent ordering of inserted routes.
278  *  1 on success */
279 static int
280 olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd, uint16_t flag)
281 {
282   int ret = 1; /* helper variable for rtnetlink_message processing */
283   int rt_ret = -2;  /* if no response from rtnetlink it must be considered as failed! */
284   struct olsr_rtreq req;
285   struct iovec iov;
286   struct sockaddr_nl nladdr;
287   struct msghdr msg = {
288     &nladdr,
289     sizeof(nladdr),
290     &iov,
291     1,
292     NULL,
293     0,
294     0
295   };
296
297   uint32_t metric = 0;
298   const struct rt_nexthop *nexthop = NULL;
299   if ( ( cmd != RTM_NEWRULE ) && ( cmd != RTM_DELRULE ) ) {
300     if (FIBM_FLAT == olsr_cnf->fib_metric) {
301       metric = RT_METRIC_DEFAULT;
302     }
303     else {
304       metric = (RTM_NEWROUTE == cmd) ? rt->rt_best->rtp_metric.hops : rt->rt_metric.hops;
305     }
306
307     if (( RTM_NEWROUTE == cmd ) ||
308         (( RTM_DELROUTE == cmd ) && ( RT_DELETE_SIMILAR_ROUTE == flag || RT_DELETE_SIMILAR_AUTO_ROUTE == flag ))) {
309       nexthop = &rt->rt_best->rtp_nexthop;
310     }
311     else {
312       nexthop = &rt->rt_nexthop;
313     }
314   }
315
316   memset(&req, 0, sizeof(req));
317
318   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
319   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
320   req.n.nlmsg_type = cmd;
321   
322   /*sanity check for niit ipv4 over ipv6 routes*/
323   if (family == AF_INET && flag == RT_NIIT) {
324     olsr_syslog(OLSR_LOG_ERR,"niit makes no sense with olsrd running on ipv4!");
325     return -1;
326   }
327
328   if (flag == RT_NIIT) {
329     req.r.rtm_family=AF_INET; /*we create an ipv4 niit route*/
330   }
331   else {
332     req.r.rtm_family = family;
333   }
334
335   req.r.rtm_table = rttable;
336
337   /* RTN_UNSPEC would be the wildcard, but blackhole broadcast or nat roules should usually not conflict */
338   /* -> olsr only adds deletes unicast routes */
339   req.r.rtm_type = RTN_UNICAST;
340
341   /* wildcard to delete routes of all protos if no simlar-delete correct proto will get set below */
342   req.r.rtm_protocol = RTPROT_UNSPEC;
343
344   /* as wildcard for deletion */
345   req.r.rtm_scope = RT_SCOPE_NOWHERE;
346
347   if ( ( cmd == RTM_NEWRULE ) || ( cmd == RTM_DELRULE ) ) {
348     /* add or delete a rule */
349     req.r.rtm_scope = RT_SCOPE_UNIVERSE;
350     olsr_netlink_addreq(&req, RTA_PRIORITY, &flag, sizeof(flag));
351     if (rt!=NULL) {
352       /*add interface name to rule*/
353       //olsr_netlink_addreq(&req, RTA_interface, &rt, sizeof(?));
354       printf("rule interface %s ignored!",(const char *) rt);
355     } 
356   }
357   else {
358     req.r.rtm_dst_len = rt->rt_dst.prefix_len;
359
360     /* do not specify much as we wanna delete similar/conflicting routes */
361     if ( ( flag != RT_DELETE_SIMILAR_ROUTE ) && ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE )) {
362       /* 0 gets replaced by OS-specifc default (3)
363        * 1 is reserved so we take 0 instead (this really makes some sense)
364        * other numbers are used 1:1 */
365       req.r.rtm_protocol = ( (olsr_cnf->rtproto<1) ? RTPROT_BOOT : ( (olsr_cnf->rtproto==1) ? 0 : olsr_cnf->rtproto) );
366       req.r.rtm_scope = RT_SCOPE_LINK;
367
368       /*add interface*/
369       if ((&olsr_cnf->smart_gateway_active) && (rt->rt_dst.prefix_len == 0) && (&olsr_cnf->ipip_if_index==NULL))
370       {
371         //create tunnel
372         set_tunl(SIOCADDTUNNEL,rt->rt_best->rtp_originator.v4.s_addr);
373 //!!?? currently it gets never deleted at shutdown, anyways reusing existing tunnel might be a safe approach if creating fails?
374         //set tunnel up with originator ip
375         olsr_dev_up(olsr_cnf->ipip_name,true);
376         //find out iifindex (maybe it works even if above failed (old tunnel))
377         olsr_cnf->ipip_if_index=if_nametoindex(olsr_cnf->ipip_name);
378       }
379
380       /*add interface*/
381       if ((&olsr_cnf->smart_gateway_active) && family != AF_INET)
382       {
383         printf("smart gateway not available for ipv6 currently");
384         return -1;
385       }
386       else if ((&olsr_cnf->smart_gateway_active) && (rt->rt_dst.prefix_len == 0) && (&olsr_cnf->ipip_if_index))
387       {
388         //change tunnel to new originator og potentially new gateway
389         if (olsr_cnf->ipip_remote_address != rt->rt_best->rtp_originator.v4.s_addr)
390         {
391           struct ipaddr_str buf;
392           printf("changing tunnel to %s",olsr_ip_to_string(&buf,&rt->rt_best->rtp_originator));
393           olsr_cnf->ipip_remote_address = rt->rt_best->rtp_originator.v4.s_addr;
394           set_tunl(SIOCCHGTUNNEL,olsr_cnf->ipip_remote_address);
395         }
396         //add interface
397         olsr_netlink_addreq(&req, RTA_OIF, &olsr_cnf->niit_if_index, sizeof(&olsr_cnf->ipip_if_index));
398       }
399       else if (flag == RT_NIIT) {
400         olsr_netlink_addreq(&req, RTA_OIF, &olsr_cnf->niit_if_index, sizeof(&olsr_cnf->niit_if_index));
401       }
402       else {
403         olsr_netlink_addreq(&req, RTA_OIF, &nexthop->iif_index, sizeof(nexthop->iif_index));
404       }
405
406 #if SOURCE_IP_ROUTES
407       /**
408        * source ip here is based on now static olsr_cnf->main_addr in this olsr-0.5.6-r4,
409        * should be based on orignator-id in newer olsrds
410        **/
411       if (flag != RT_NIIT) {
412         if (AF_INET == family) {
413           olsr_netlink_addreq(&req, RTA_PREFSRC, &olsr_cnf->main_addr.v4.s_addr, sizeof(olsr_cnf->main_addr.v4.s_addr));
414         }
415         else {
416           olsr_netlink_addreq(&req, RTA_PREFSRC, &olsr_cnf->main_addr.v6.s6_addr, sizeof(olsr_cnf->main_addr.v6.s6_addr));
417         }
418       }
419 #endif
420     }
421
422     /* metric is specified always as we can only delete one route per iteration, and wanna hit the correct one first */
423     if (FIBM_APPROX != olsr_cnf->fib_metric || (RTM_NEWROUTE == cmd) ) {
424       olsr_netlink_addreq(&req, RTA_PRIORITY, &metric, sizeof(metric));
425     }
426
427     /* make sure that netmask = maxplen (32 or 128) as this is an autogenarated (host)route */
428     if (( flag == RT_AUTO_ADD_GATEWAY_ROUTE ) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) {
429       req.r.rtm_dst_len = olsr_cnf->maxplen;
430     }
431
432     /**
433      * for ipv4 or ipv6 we add gateway if one is specified,
434      * or leave gateway away if we want to delete similar routes aswell,
435      * or even use the gateway as target if we add a auto-generated route,
436      * or if delete-similar to make insertion of auto-generated route possible
437      **/
438     if (AF_INET == family) {
439       if ( !( (rt->rt_dst.prefix_len == 0) && (olsr_cnf->smart_gateway_active) )
440            && ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE) && 
441            ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) && (rt->rt_dst.prefix.v4.s_addr != nexthop->gateway.v4.s_addr) ) {
442         olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v4, sizeof(nexthop->gateway.v4));
443         req.r.rtm_scope = RT_SCOPE_UNIVERSE;
444       }
445       olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
446                           &nexthop->gateway.v4 : &rt->rt_dst.prefix.v4, sizeof(rt->rt_dst.prefix.v4));
447     } else {
448       if (flag == RT_NIIT) {
449         union olsr_ip_addr ipv4_addr;
450         /* create an ipv4 route */
451         olsr_syslog(OLSR_LOG_ERR,"niit suport not fully implemented!!"); 
452         olsr_netlink_addreq(&req, RTA_DST, olsr_ipv6_to_ipv4(&rt->rt_dst.prefix, &ipv4_addr), sizeof(ipv4_addr.v4));
453       }
454       else {
455         if ( !( (rt->rt_dst.prefix_len == 0) && (olsr_cnf->smart_gateway_active) ) 
456             && ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE ) && ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) 
457             && (0 != memcmp(&rt->rt_dst.prefix.v6, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6))) ) {
458           olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6));
459           req.r.rtm_scope = RT_SCOPE_UNIVERSE;
460         }
461         olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
462                             &nexthop->gateway.v6 : &rt->rt_dst.prefix.v6, sizeof(rt->rt_dst.prefix.v6));
463       }
464     }
465   }
466
467   iov.iov_base = &req.n;
468   iov.iov_len = req.n.nlmsg_len;
469   memset(&nladdr, 0, sizeof(nladdr));
470   nladdr.nl_family = AF_NETLINK;
471   if (0 <= (ret = sendmsg(olsr_cnf->rtnl_s, &msg, 0))) {
472     iov.iov_base = req.buf;
473     iov.iov_len = sizeof(req.buf);
474     if (0 < (ret = recvmsg(olsr_cnf->rtnl_s, &msg, 0))) {
475       struct nlmsghdr *h = (struct nlmsghdr *)(ARM_NOWARN_ALIGN)req.buf;
476       while (NLMSG_OK(h, (unsigned int)ret)) {
477         if (NLMSG_DONE == h->nlmsg_type) {
478           /* seems to reached never */
479           olsr_syslog(OLSR_LOG_INFO, "_received NLMSG_DONE");
480           break;
481         }
482         if (NLMSG_ERROR == h->nlmsg_type) {
483           if (NLMSG_LENGTH(sizeof(struct nlmsgerr) <= h->nlmsg_len)) {
484             struct ipaddr_str ibuf;
485             struct ipaddr_str gbuf;
486             struct nlmsgerr *l_err = (struct nlmsgerr *)NLMSG_DATA(h);
487             errno = -l_err->error;
488             if (0 != errno) {
489               const char *const err_msg = strerror(errno);
490               struct ipaddr_str buf;
491               rt_ret = -1;
492
493               /* syslog debug output for various situations */
494               if ( cmd == RTM_NEWRULE ) {
495                 olsr_syslog(OLSR_LOG_ERR,"Error '%s' (%d) on inserting empty policy rule aimed to activate RtTable %u!", err_msg, errno, rttable);
496               }
497               else if ( cmd == RTM_DELRULE ) {
498                 olsr_syslog(OLSR_LOG_ERR,"Error '%s' (%d) on deleting empty policy rule aimed to activate rtTable %u!", err_msg, errno, rttable);
499               }
500               else if ( flag == RT_NIIT ) {
501                 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));
502               }
503               else if ( flag <= RT_RETRY_AFTER_DELETE_SIMILAR ) {
504                 if (rt->rt_dst.prefix.v4.s_addr!=nexthop->gateway.v4.s_addr) {
505                   olsr_syslog(OLSR_LOG_ERR, "error '%s' (%d) %s route to %s/%d via %s dev %s",
506                       err_msg, errno, (cmd == RTM_NEWROUTE) ? "add" : "del",
507                       olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix), req.r.rtm_dst_len,
508                       olsr_ip_to_string(&gbuf,&nexthop->gateway), if_ifwithindex_name(nexthop->iif_index));
509                 }
510                 else {
511                   olsr_syslog(OLSR_LOG_ERR, "error '%s' (%d) %s route to %s/%d dev %s",
512                       err_msg, errno, (cmd == RTM_NEWROUTE) ? "add" : "del",
513                       olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix), req.r.rtm_dst_len, if_ifwithindex_name(nexthop->iif_index));
514                 }
515               }
516               else if (flag == RT_AUTO_ADD_GATEWAY_ROUTE) {
517                 olsr_syslog(OLSR_LOG_ERR, ". error '%s' (%d) auto-add route to %s dev %s", err_msg, errno,
518                     olsr_ip_to_string(&ibuf,&nexthop->gateway), if_ifwithindex_name(nexthop->iif_index));
519               }
520               else if (flag == RT_DELETE_SIMILAR_ROUTE) {
521                 olsr_syslog(OLSR_LOG_ERR, ". error '%s' (%d) auto-delete route to %s dev %s", err_msg, errno,
522                     olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix), if_ifwithindex_name(nexthop->iif_index));
523               }
524               else if (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) {
525                 olsr_syslog(OLSR_LOG_ERR, ". . error '%s' (%d) auto-delete similar route to %s dev %s", err_msg, errno,
526                     olsr_ip_to_string(&ibuf,&nexthop->gateway), if_ifwithindex_name(nexthop->iif_index));
527               }
528               else {
529                 /* should never happen */
530                 olsr_syslog(OLSR_LOG_ERR, "# invalid internal route delete/add flag (%d) used!", flag);
531               }
532             }
533             else {
534               /* netlink acks requests with an errno=0 NLMSG_ERROR response! */
535               rt_ret = 1;
536             }
537
538             /* resolve "File exist" (17) propblems (on orig and autogen routes)*/       
539             if ((errno == 17) && (cmd == RTM_NEWROUTE) && ((flag == RT_ORIG_REQUEST) || (flag == RT_AUTO_ADD_GATEWAY_ROUTE))) {
540               /* a similar route going over another gateway may be present, which has to be deleted! */
541               olsr_syslog(OLSR_LOG_ERR, ". auto-deleting similar routes to resolve 'File exists' (17) while adding route!");
542               rt_ret = RT_DELETE_SIMILAR_ROUTE; /* processing will contiune after this loop */
543             }
544             /* report success on "No such process" (3) */
545             else if ((errno == 3) && (cmd == RTM_DELROUTE) && (flag == RT_ORIG_REQUEST)) {
546               /* another similar (but slightly different) route may be present at this point
547               * , if so this will get solved when adding new route to this destination */
548               olsr_syslog(OLSR_LOG_ERR, ". ignoring 'No such process' (3) while deleting route!");
549               rt_ret = 0;
550             }
551             /* insert route to gateway on the fly if "Network unreachable" (128) on 2.4 kernels
552              * or on 2.6 kernel No such process (3) or Network unreachable (101) is reported in rtnetlink response
553              * do this only with flat metric, as using metric values inherited from 
554              * a target behind the gateway is really strange, and could lead to multiple routes!
555              * anyways if invalid gateway ips may happen we are f*cked up!!
556              * but if not, these on the fly generated routes are no problem, and will only get used when needed */
557             else if ( ( (errno == 3) || (errno == 101) || (errno == 128) )
558                 && (flag == RT_ORIG_REQUEST) && (FIBM_FLAT == olsr_cnf->fib_metric)
559                      && (cmd == RTM_NEWROUTE) && (rt->rt_dst.prefix.v4.s_addr!=nexthop->gateway.v4.s_addr)) {
560               if (errno == 128)  {
561                 olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (128) while adding route!");
562               }
563               else if (errno == 101) {
564                 olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'Network unreachable' (101) while adding route!");
565               }
566               else {
567                 olsr_syslog(OLSR_LOG_ERR, ". autogenerating route to handle 'No such process' (3) while adding route!");
568               }
569
570               /* processing will contiune after this loop */
571               rt_ret = RT_AUTO_ADD_GATEWAY_ROUTE;
572             }
573           }
574           /* report invalid message size */
575           else {
576             olsr_syslog(OLSR_LOG_INFO,"_received invalid netlink message size %lu != %u",
577                 (unsigned long int)sizeof(struct nlmsgerr), h->nlmsg_len);
578           }
579         }
580         /* log all other messages */
581         else {
582           olsr_syslog(OLSR_LOG_INFO,"_received %u Byte rtnetlink response of type %u with seqnr %u and flags %u from %u (%u)",
583               h->nlmsg_len, h->nlmsg_type, h->nlmsg_seq, h->nlmsg_flags, h->nlmsg_pid, NLMSG_ERROR);
584         }
585 /*
586  * The ARM compile complains about alignment. Copied
587  * from /usr/include/linux/netlink.h and adapted for ARM
588  */
589 #define MY_NLMSG_NEXT(nlh,len)   ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
590                                   (struct nlmsghdr*)(ARM_NOWARN_ALIGN)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
591         h = MY_NLMSG_NEXT(h, ret);
592       }
593     }
594   }
595   if ( rt_ret == RT_DELETE_SIMILAR_ROUTE ) {
596     /* delete all routes that may collide */
597
598     /* recursive call to delete simlar routes, using flag 2 to invoke deletion of similar, not only exact matches*/
599     rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_DELROUTE, 
600         flag == RT_AUTO_ADD_GATEWAY_ROUTE ? RT_DELETE_SIMILAR_AUTO_ROUTE : RT_DELETE_SIMILAR_ROUTE);
601
602     /* retry insert original route, if deleting similar succeeded, using flag=1 to prevent recursions */
603     if (rt_ret > 0) {
604       rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_RETRY_AFTER_DELETE_SIMILAR);
605     }
606     else {
607       olsr_syslog(OLSR_LOG_ERR, ". failed on auto-deleting similar route conflicting with above route!");
608     }
609
610     /* set appropriate return code for original request, while returning simple -1/1 if called recursive */
611     if (flag != RT_AUTO_ADD_GATEWAY_ROUTE) {
612       if (rt_ret > 0) {
613         /* successful recovery */
614         rt_ret = 0;
615       }
616       else {
617         /* unrecoverable error */
618         rt_ret = -1;
619       }
620     }
621   }
622   if ( rt_ret == RT_AUTO_ADD_GATEWAY_ROUTE ) {
623     /* autoadd route via gateway */
624
625     /* recursive call to invoke creation of a route to the gateway */
626     rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_AUTO_ADD_GATEWAY_ROUTE);
627
628     /* retry insert original route, if above succeeded without problems */
629     if (rt_ret > 0) {
630       rt_ret = olsr_netlink_route_int(rt, family, rttable, RTM_NEWROUTE, RT_RETRY_AFTER_ADD_GATEWAY);
631     }
632     else {
633       olsr_syslog(OLSR_LOG_ERR, ". failed on inserting auto-generated route to gateway of above route!");
634     }
635
636     /* set appropriate return code for original request*/
637     if (rt_ret > 0) {
638       /* successful recovery */
639       rt_ret = 0;
640     }
641     else {
642       /* unrecoverable error */
643       rt_ret = -1;
644     }
645   }
646   /* send ipc update on success */
647   if ( ( cmd != RTM_NEWRULE ) && ( cmd != RTM_DELRULE )
648       && (flag == RT_ORIG_REQUEST) && (0 <= rt_ret && olsr_cnf->ipc_connections > 0) ) {
649     ipc_route_send_rtentry(&rt->rt_dst.prefix, &nexthop->gateway, metric,
650         RTM_NEWROUTE == cmd, if_ifwithindex_name(nexthop->iif_index));
651   }
652   if (rt_ret == -2) {
653     olsr_syslog(OLSR_LOG_ERR,"no rtnetlink response! (no system ressources left?, everything may happen now ...)");
654   }
655   return rt_ret;
656 }
657
658 /* external wrapper function for above patched multi purpose rtnetlink function */
659 int
660 olsr_netlink_rule(uint8_t family, uint8_t rttable, uint16_t cmd, uint32_t priority, char* dev)
661 {
662   printf("rule priority not supported");
663   return olsr_netlink_route_int((const struct rt_entry *) dev, family, rttable, cmd, priority);
664 }
665
666 /* internal wrapper function for above patched function */
667 static int
668 olsr_netlink_route(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd)
669 {
670   /*create/delete niit route if we have an niit device*/
671   if ((olsr_cnf->niit_if_index!=0) && (family != AF_INET) && (olsr_is_niit_ip(&rt->rt_dst.prefix))) {
672     olsr_netlink_route_int(rt, family, rttable, cmd, RT_NIIT);
673   }
674
675   return olsr_netlink_route_int(rt, family, rttable, cmd, RT_ORIG_REQUEST);
676 }
677
678 #endif /* LINUX_POLICY_ROUTING */
679
680 /**
681  * Insert a route in the kernel routing table
682  *
683  * @param destination the route to add
684  *
685  * @return negative on error
686  */
687 int
688 olsr_ioctl_add_route(const struct rt_entry *rt)
689 {
690 #if !LINUX_POLICY_ROUTING
691   struct rtentry kernel_route;
692   union olsr_ip_addr mask;
693   int rslt;
694 #endif /* LINUX_POLICY_ROUTING */
695
696   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
697
698 #if !LINUX_POLICY_ROUTING
699   memset(&kernel_route, 0, sizeof(struct rtentry));
700
701   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
702   ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
703   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
704
705   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4;
706
707   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
708     return -1;
709   }
710   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4;
711
712   if (rt->rt_dst.prefix.v4.s_addr != rt->rt_best->rtp_nexthop.gateway.v4.s_addr) {
713     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr = rt->rt_best->rtp_nexthop.gateway.v4;
714   }
715
716   kernel_route.rt_flags = olsr_rt_flags(rt);
717   kernel_route.rt_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
718
719   /*
720    * Set interface
721    */
722   kernel_route.rt_dev = if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index);
723
724   /* delete existing default route before ? */
725   if ((olsr_cnf->del_gws) && (rt->rt_dst.prefix.v4.s_addr == INADDR_ANY) && (rt->rt_dst.prefix_len == INADDR_ANY)) {
726     delete_all_inet_gws();
727     olsr_cnf->del_gws = false;
728   }
729
730   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) {
731
732     /*
733      * Send IPC route update message
734      */
735     ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, rt->rt_best->rtp_metric.hops, 1,
736                            if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
737   }
738
739   return rslt;
740 #else /* !LINUX_POLICY_ROUTING */
741   if (0 == olsr_cnf->rttable_default && 0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable) {
742     /*
743      * Users start whining about not having internet with policy
744      * routing activated and no static default route in table 254.
745      * We maintain a fallback defroute in the default=253 table.
746      */
747     olsr_netlink_route(rt, AF_INET, 253, RTM_NEWROUTE);
748   }
749   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0) {
750     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable_default, RTM_NEWROUTE);
751   }
752   else {
753     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable, RTM_NEWROUTE);
754   }
755 #endif /* LINUX_POLICY_ROUTING */
756 }
757
758 /**
759  *Insert a route in the kernel routing table
760  *
761  *@param destination the route to add
762  *
763  *@return negative on error
764  */
765 int
766 olsr_ioctl_add_route6(const struct rt_entry *rt)
767 {
768 #if !LINUX_POLICY_ROUTING
769   struct in6_rtmsg kernel_route;
770   int rslt;
771
772   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
773
774   memset(&kernel_route, 0, sizeof(struct in6_rtmsg));
775
776   kernel_route.rtmsg_dst = rt->rt_dst.prefix.v6;
777   kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len;
778
779   kernel_route.rtmsg_gateway = rt->rt_best->rtp_nexthop.gateway.v6;
780
781   kernel_route.rtmsg_flags = olsr_rt_flags(rt);
782   kernel_route.rtmsg_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
783
784   /*
785    * set interface
786    */
787   kernel_route.rtmsg_ifindex = rt->rt_best->rtp_nexthop.iif_index;
788
789   /* XXX delete 0/0 route before ? */
790
791   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) {
792
793     /*
794      * Send IPC route update message
795      */
796     ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, rt->rt_best->rtp_metric.hops, 1,
797                            if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
798   }
799   return rslt;
800 #else /* !LINUX_POLICY_ROUTING */
801   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0) {
802     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable_default, RTM_NEWROUTE);
803   }
804   else {
805     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable, RTM_NEWROUTE);
806   }
807 #endif /* LINUX_POLICY_ROUTING */
808 }
809
810 /**
811  *Remove a route from the kernel
812  *
813  *@param destination the route to remove
814  *
815  *@return negative on error
816  */
817 int
818 olsr_ioctl_del_route(const struct rt_entry *rt)
819 {
820 #if !LINUX_POLICY_ROUTING
821   struct rtentry kernel_route;
822   union olsr_ip_addr mask;
823   int rslt;
824 #endif /* LINUX_POLICY_ROUTING */
825
826   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
827
828 #if !LINUX_POLICY_ROUTING
829   memset(&kernel_route, 0, sizeof(struct rtentry));
830
831   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
832   ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
833   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
834
835   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4;
836
837   if (rt->rt_dst.prefix.v4.s_addr != rt->rt_nexthop.gateway.v4.s_addr) {
838     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr = rt->rt_nexthop.gateway.v4;
839   }
840
841   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
842     return -1;
843   } else {
844     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4;
845   }
846
847   kernel_route.rt_flags = olsr_rt_flags(rt);
848   kernel_route.rt_metric = olsr_fib_metric(&rt->rt_metric.hops);
849
850   /*
851    * Set interface
852    */
853   kernel_route.rt_dev = NULL;
854
855   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route)) >= 0) {
856
857     /*
858      * Send IPC route update message
859      */
860     ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
861   }
862
863   return rslt;
864 #else /* !LINUX_POLICY_ROUTING */
865   if (0 == olsr_cnf->rttable_default && 0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable) {
866     /*
867      * Also remove the fallback default route
868      */
869     olsr_netlink_route(rt, AF_INET, 253, RTM_DELROUTE);
870   }
871   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0) {
872     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable_default, RTM_DELROUTE);
873   }
874   else {
875     return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable, RTM_DELROUTE);
876   }
877 #endif /* LINUX_POLICY_ROUTING */
878 }
879
880 /**
881  *Remove a route from the kernel
882  *
883  *@param destination the route to remove
884  *
885  *@return negative on error
886  */
887 int
888 olsr_ioctl_del_route6(const struct rt_entry *rt)
889 {
890 #if !LINUX_POLICY_ROUTING
891   struct in6_rtmsg kernel_route;
892   int rslt;
893 #endif /* LINUX_POLICY_ROUTING */
894
895   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
896
897 #if !LINUX_POLICY_ROUTING
898   memset(&kernel_route, 0, sizeof(struct in6_rtmsg));
899
900   kernel_route.rtmsg_dst = rt->rt_dst.prefix.v6;
901   kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len;
902
903   kernel_route.rtmsg_gateway = rt->rt_best->rtp_nexthop.gateway.v6;
904
905   kernel_route.rtmsg_flags = olsr_rt_flags(rt);
906   kernel_route.rtmsg_metric = olsr_fib_metric(&rt->rt_best->rtp_metric.hops);
907
908   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route) >= 0)) {
909
910     /*
911      * Send IPC route update message
912      */
913     ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
914   }
915
916   return rslt;
917 #else /* !LINUX_POLICY_ROUTING */
918   if (0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0) {
919     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable_default, RTM_DELROUTE);
920   }
921   else {
922     return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable, RTM_DELROUTE);
923   }
924 #endif /* LINUX_POLICY_ROUTING */
925 }
926
927 #if !LINUX_POLICY_ROUTING
928 static int
929 delete_all_inet_gws(void)
930 {
931   int s;
932   char buf[BUFSIZ], *cp, *cplim;
933   struct ifconf ifc;
934   struct ifreq *ifr;
935
936   OLSR_PRINTF(1, "Internet gateway detected...\nTrying to delete default gateways\n");
937
938   /* Get a socket */
939   if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
940     olsr_syslog(OLSR_LOG_ERR, "socket: %m");
941     return -1;
942   }
943
944   ifc.ifc_len = sizeof(buf);
945   ifc.ifc_buf = buf;
946   if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
947     olsr_syslog(OLSR_LOG_ERR, "ioctl (get interface configuration)");
948     close(s);
949     return -1;
950   }
951
952   ifr = ifc.ifc_req;
953   cplim = buf + ifc.ifc_len;    /*skip over if's with big ifr_addr's */
954   for (cp = buf; cp < cplim; cp += sizeof(ifr->ifr_name) + sizeof(ifr->ifr_addr)) {
955     struct rtentry kernel_route;
956     ifr = (struct ifreq *)cp;
957
958     if (strcmp(ifr->ifr_ifrn.ifrn_name, "lo") == 0) {
959       OLSR_PRINTF(1, "Skipping loopback...\n");
960       continue;
961     }
962
963     OLSR_PRINTF(1, "Trying 0.0.0.0/0 %s...", ifr->ifr_ifrn.ifrn_name);
964
965     memset(&kernel_route, 0, sizeof(struct rtentry));
966
967     ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr = 0;
968     ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
969     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = 0;
970     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;
971
972     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr.s_addr = INADDR_ANY;
973     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
974
975     kernel_route.rt_flags = RTF_UP | RTF_GATEWAY;
976
977     kernel_route.rt_dev = ifr->ifr_ifrn.ifrn_name;
978
979     if ((ioctl(s, SIOCDELRT, &kernel_route)) < 0)
980       OLSR_PRINTF(1, "NO\n");
981     else
982       OLSR_PRINTF(1, "YES\n");
983   }
984   close(s);
985   return 0;
986 }
987 #endif /* LINUX_POLICY_ROUTING */
988
989 /*
990  * Local Variables:
991  * c-basic-offset: 2
992  * indent-tabs-mode: nil
993  * End:
994  */