all: use the getInterfaceLinkState function
[olsrd.git] / src / linux / net.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
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 /*
43  * Linux specific code
44  */
45
46 #ifdef __linux__
47 #define __BSD_SOURCE 1
48
49 #include "../net_os.h"
50 #include "../ipcalc.h"
51 #include "../olsr.h"
52 #include "../log.h"
53 #include "kernel_tunnel.h"
54 #include "ifnet.h"
55
56 #include <net/if.h>
57
58 #include <sys/ioctl.h>
59 #include <sys/utsname.h>
60
61 #include <fcntl.h>
62 #include <string.h>
63 #include <stdio.h>
64 #include <syslog.h>
65 #include <unistd.h>
66
67 /**
68  * Fix bug in GLIBC, see https://bugzilla.redhat.com/show_bug.cgi?id=635260
69  */
70 #ifdef IPTOS_CLASS
71 #undef IPTOS_CLASS
72 #endif /* IPTOS_CLASS */
73 #define IPTOS_CLASS(class)    ((class) & IPTOS_CLASS_MASK)
74
75 #define IPV6_ADDR_LOOPBACK      0x0010U
76 #define IPV6_ADDR_LINKLOCAL     0x0020U
77 #define IPV6_ADDR_SITELOCAL     0x0040U
78
79 /* ip forwarding */
80 #define PROC_IPFORWARD_V4 "/proc/sys/net/ipv4/ip_forward"
81 #define PROC_IPFORWARD_V6 "/proc/sys/net/ipv6/conf/all/forwarding"
82
83 /* Redirect proc entry */
84 #define PROC_IF_REDIRECT "/proc/sys/net/ipv4/conf/%s/send_redirects"
85 #define PROC_ALL_REDIRECT "/proc/sys/net/ipv4/conf/all/send_redirects"
86
87 /* IP spoof proc entry */
88 #define PROC_IF_SPOOF "/proc/sys/net/ipv4/conf/%s/rp_filter"
89 #define PROC_ALL_SPOOF "/proc/sys/net/ipv4/conf/all/rp_filter"
90
91 /* list of IPv6 interfaces */
92 #define PATH_PROCNET_IFINET6           "/proc/net/if_inet6"
93
94 /* values olsrd wants in procfs */
95 #define OLSRD_FORWARD_VALUE '1'
96 #define OLSRD_REDIRECT_VALUE '0'
97 #define OLSRD_SPOOF_VALUE '0'
98
99 /*
100  *Wireless definitions for ioctl calls
101  *(from linux/wireless.h)
102  */
103 #define SIOCGIWNAME     0x8B01  /* get name == wireless protocol */
104 #define SIOCGIWRATE     0x8B21  /* get default bit rate (bps) */
105
106 /* The original state of the IP forwarding proc entry */
107 static char orig_fwd_state;
108 static char orig_global_redirect_state;
109 static char orig_global_rp_filter;
110 static char orig_tunnel_rp_filter;
111
112 /**
113  *Bind a socket to a device
114  *
115  *@param sock the socket to bind
116  *@param dev_name name of the device
117  *
118  *@return negative if error
119  */
120
121 int
122 bind_socket_to_device(int sock, char *dev_name)
123 {
124   /*
125    *Bind to device using the SO_BINDTODEVICE flag
126    */
127   OLSR_PRINTF(3, "Binding socket %d to device %s\n", sock, dev_name);
128   return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, dev_name, strlen(dev_name) + 1);
129 }
130
131 static int writeToProc(const char *file, char *old, char value) {
132   int fd;
133   char rv;
134
135   if ((fd = open(file, O_RDWR)) < 0) {
136     OLSR_PRINTF(0, "Error, cannot open proc entry %s: %s (%d)\n", file, strerror(errno), errno);
137     return -1;
138   }
139
140   if (read(fd, &rv, 1) != 1) {
141     OLSR_PRINTF(0, "Error, cannot read proc entry %s: %s (%d)\n", file, strerror(errno), errno);
142     goto writeToProcError;
143   }
144
145   if (rv != value && value != 0) {
146     if (lseek(fd, SEEK_SET, 0) == -1) {
147       OLSR_PRINTF(0, "Error, cannot rewind proc entry %s: %s (%d)\n", file, strerror(errno), errno);
148       goto writeToProcError;
149     }
150
151     if (write(fd, &value, 1) != 1) {
152       OLSR_PRINTF(0, "Error, cannot write proc entry %s: %s (%d)\n", file, strerror(errno), errno);
153       goto writeToProcError;
154     }
155   }
156
157   close(fd);
158
159   if (old) {
160     *old = rv;
161   }
162
163   if (value) {
164     olsr_syslog(OLSR_LOG_INFO, "Writing '%c' (was %c) to %s", value, rv, file);
165   }
166   return 0;
167
168 writeToProcError:
169   close (fd);
170   return -1;
171 }
172
173 /* write new value to proc file if current value is different*/
174 static int restoreProc(const char *file, char original, char value) {
175   if ( original == value ) return 0;
176   else return writeToProc(file, NULL, original);
177 }
178
179 static bool is_at_least_linuxkernel_2_6_31(void) {
180   struct utsname uts;
181   char *next;
182   int first = 0, second = 0, third = 0;
183
184   memset(&uts, 0, sizeof(uts));
185   if (uname(&uts)) {
186     OLSR_PRINTF(1, "Error, could not read kernel version: %s (%d)\n", strerror(errno), errno);
187     return false;
188   }
189
190   first = strtol(uts.release, &next, 10);
191   /* check for linux 3.x */
192   if (first >= 3) {
193     return true;
194   }
195
196   if (*next != '.') {
197     goto kernel_parse_error;
198   }
199
200   second = strtol(next+1, &next, 10);
201   if (*next != '.') {
202     goto kernel_parse_error;
203   }
204
205   third = strtol(next+1, NULL, 10);
206
207   /* better or equal than linux 2.6.31 ? */
208   return first == 2 && second == 6 && third >= 31;
209
210 kernel_parse_error:
211   OLSR_PRINTF(1, "Error, cannot parse kernel version: %s\n", uts.release);
212   return false;
213 }
214
215 /**
216  * Setup global interface options (icmp redirect, ip forwarding, rp_filter)
217  * @return 1 on success 0 on failure
218  */
219 void
220 net_os_set_global_ifoptions(void) {
221
222   if (writeToProc(olsr_cnf->ip_version == AF_INET ? PROC_IPFORWARD_V4 : PROC_IPFORWARD_V6, &orig_fwd_state,
223           olsr_cnf->set_ip_forward ? OLSRD_FORWARD_VALUE : 0 )) {
224     OLSR_PRINTF(1, "Warning, could not enable IP forwarding!\n"
225         "you should manually ensure that IP forwarding is enabled!\n\n");
226     olsr_startup_sleep(3);
227   }
228   else if ((!olsr_cnf->set_ip_forward) && (orig_fwd_state != OLSRD_FORWARD_VALUE)) {
229     olsr_exit("IP forwarding not activated", EXIT_FAILURE);
230   }
231
232   if (olsr_cnf->smart_gw_active) {
233     char procfile[FILENAME_MAX];
234
235     /* Generate the procfile name */
236     if (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit) {
237       snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF);
238       if (writeToProc(procfile, &orig_tunnel_rp_filter, OLSRD_SPOOF_VALUE)) {
239         OLSR_PRINTF(0, "WARNING! Could not disable the IP spoof filter for tunnel!\n"
240             "you should manually ensure that IP spoof filtering is disabled!\n\n");
241
242         olsr_startup_sleep(3);
243       }
244     }
245   }
246
247   if (olsr_cnf->ip_version == AF_INET) {
248     if (writeToProc(PROC_ALL_REDIRECT, &orig_global_redirect_state, OLSRD_REDIRECT_VALUE)) {
249       OLSR_PRINTF(1, "WARNING! Could not disable ICMP redirects!\n"
250           "you should manually ensure that ICMP redirects are disabled!\n\n");
251
252       olsr_startup_sleep(3);
253     }
254
255     /* check kernel version and disable global rp_filter */
256     if (is_at_least_linuxkernel_2_6_31()) {
257       if (writeToProc(PROC_ALL_SPOOF, &orig_global_rp_filter, OLSRD_SPOOF_VALUE)) {
258         OLSR_PRINTF(1, "WARNING! Could not disable global rp_filter (necessary for kernel 2.6.31 and higher!\n"
259             "you should manually ensure that rp_filter is disabled!\n\n");
260
261         olsr_startup_sleep(3);
262       }
263     }
264   }
265   return;
266 }
267
268 /**
269  *
270  *@return 1 on sucess 0 on failiure
271  */
272 int
273 net_os_set_ifoptions(const char *if_name, struct interface_olsr *iface)
274 {
275   char procfile[FILENAME_MAX];
276   if (olsr_cnf->ip_version == AF_INET6)
277     return -1;
278
279   /* Generate the procfile name */
280   snprintf(procfile, sizeof(procfile), PROC_IF_REDIRECT, if_name);
281
282   if (writeToProc(procfile, &iface->nic_state.redirect, OLSRD_REDIRECT_VALUE)) {
283     OLSR_PRINTF(0, "WARNING! Could not disable ICMP redirects!\n"
284         "you should manually ensure that ICMP redirects are disabled!\n\n");
285     olsr_startup_sleep(3);
286     return 0;
287   }
288
289   /* Generate the procfile name */
290   snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, if_name);
291
292   if (writeToProc(procfile, &iface->nic_state.spoof, OLSRD_SPOOF_VALUE)) {
293     OLSR_PRINTF(0, "WARNING! Could not disable the IP spoof filter!\n"
294         "you should manually ensure that IP spoof filtering is disabled!\n\n");
295
296     olsr_startup_sleep(3);
297     return 0;
298   }
299   return 1;
300 }
301
302 /**
303  *Resets the spoof filter and ICMP redirect settings
304  */
305 int
306 net_os_restore_ifoptions(void)
307 {
308   struct interface_olsr *ifs;
309   char procfile[FILENAME_MAX];
310
311   OLSR_PRINTF(1, "Restoring network state\n");
312
313   /* Restore IP forwarding to original value */
314   if (olsr_cnf->set_ip_forward) {
315     if (restoreProc(olsr_cnf->ip_version == AF_INET ? PROC_IPFORWARD_V4 : PROC_IPFORWARD_V6, orig_fwd_state, OLSRD_FORWARD_VALUE)) {
316       OLSR_PRINTF(1, "Error, could not restore ip_forward settings\n");
317     }
318   }
319
320   if (olsr_cnf->smart_gw_active && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit)) {
321     /* Generate the procfile name */
322     snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF);
323     if (restoreProc(procfile, orig_tunnel_rp_filter, OLSRD_SPOOF_VALUE)) {
324       OLSR_PRINTF(0, "WARNING! Could not restore the IP spoof filter for tunnel!\n");
325     }
326   }
327
328   if (olsr_cnf->ip_version == AF_INET) {
329     /* Restore global ICMP redirect setting */
330     if (restoreProc(PROC_ALL_REDIRECT, orig_global_redirect_state, OLSRD_REDIRECT_VALUE)) {
331       OLSR_PRINTF(1, "Error, could not restore global icmp_redirect setting\n");
332     }
333
334     /* Restore global rp_filter setting for linux 2.6.31+ */
335     if (is_at_least_linuxkernel_2_6_31()) {
336       if (restoreProc(PROC_ALL_SPOOF, orig_global_rp_filter, OLSRD_SPOOF_VALUE)) {
337         OLSR_PRINTF(1, "Error, could not restore global rp_filter setting\n");
338       }
339     }
340     for (ifs = ifnet; ifs != NULL; ifs = ifs->int_next) {
341       /* Discard host-emulation interfaces */
342       if (ifs->is_hcif)
343         continue;
344
345       /* ICMP redirects */
346       snprintf(procfile, sizeof(procfile), PROC_IF_REDIRECT, ifs->int_name);
347       if (restoreProc(procfile, ifs->nic_state.redirect, OLSRD_REDIRECT_VALUE)) {
348         OLSR_PRINTF(1, "Error, could not restore icmp_redirect for interface %s\n", ifs->int_name);
349       }
350
351       /* Spoof filter */
352       sprintf(procfile, PROC_IF_SPOOF, ifs->int_name);
353       if (restoreProc(procfile, ifs->nic_state.spoof, OLSRD_SPOOF_VALUE)) {
354         OLSR_PRINTF(1, "Error, could not restore rp_filter for interface %s\n", ifs->int_name);
355       }
356     }
357   }
358   return 1;
359 }
360
361 /**
362  *Creates a blocking tcp socket for communication with switch daemon.
363  *@param pin sockaddr struct. Used for bind(2).
364  *@return the FD of the socket or -1 on error.
365  */
366 int
367 gethemusocket(struct sockaddr_in *pin)
368 {
369   int sock, on = 1;
370
371   OLSR_PRINTF(1, "       Connecting to switch daemon port 10150...");
372   if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
373     perror("hcsocket");
374     syslog(LOG_ERR, "hcsocket: %m");
375     return -1;
376   }
377
378   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
379     perror("SO_REUSEADDR failed");
380     close(sock);
381     return -1;
382   }
383   /* connect to PORT on HOST */
384   if (connect(sock, (struct sockaddr *)pin, sizeof(*pin)) < 0) {
385     printf("FAILED\n");
386     fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
387     printf("connection refused\n");
388     close(sock);
389     return -1;
390   }
391
392   printf("OK\n");
393
394   /* Keep TCP socket blocking */
395   return sock;
396 }
397
398 /**
399  *Creates a nonblocking broadcast socket.
400  *@param bufspace the number of bytes in the buffer
401  *@param ifp interface struct. Used for bind(2).
402  *@return the FD of the socket or -1 on error.
403  */
404 int
405 getsocket(int bufspace, struct interface_olsr *ifp)
406 {
407   struct sockaddr_in sin;
408   int on;
409   int sock = socket(AF_INET, SOCK_DGRAM, 0);
410   if (sock < 0) {
411     perror("socket");
412     syslog(LOG_ERR, "socket: %m");
413     return -1;
414   }
415
416   on = 1;
417 #ifdef SO_BROADCAST
418   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
419     perror("setsockopt");
420     syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
421     close(sock);
422     return -1;
423   }
424 #endif /* SO_BROADCAST */
425
426   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
427     perror("SO_REUSEADDR failed");
428     close(sock);
429     return -1;
430   }
431 #ifdef SO_RCVBUF
432   if(bufspace > 0) {
433     for (on = bufspace;; on -= 1024) {
434       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0)
435         break;
436       if (on <= 8 * 1024) {
437         perror("setsockopt");
438         syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
439         break;
440       }
441     }
442   }
443 #endif /* SO_RCVBUF */
444
445   /*
446    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
447    */
448
449   /* Bind to device */
450   if (bind_socket_to_device(sock, ifp->int_name) < 0) {
451     fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
452     syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
453     close(sock);
454     return -1;
455   }
456
457   memset(&sin, 0, sizeof(sin));
458   sin.sin_family = AF_INET;
459   sin.sin_port = htons(olsr_cnf->olsrport);
460
461   if(bufspace <= 0) {
462     sin.sin_addr.s_addr = ifp->int_addr.sin_addr.s_addr;
463   }
464
465   if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
466     perror("bind");
467     syslog(LOG_ERR, "bind: %m");
468     close(sock);
469     return -1;
470   }
471
472   on = fcntl(sock, F_GETFL);
473   if (on == -1) {
474     syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
475   } else {
476     if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
477       syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
478     }
479   }
480   return sock;
481 }
482
483 /**
484  *Creates a nonblocking IPv6 socket
485  *@param bufspace the number of bytes in the buffer
486  *@param ifp interface struct. Used for bind(2).
487  *@return the FD of the socket or -1 on error.
488  */
489 int
490 getsocket6(int bufspace, struct interface_olsr *ifp)
491 {
492   struct sockaddr_in6 sin;
493   int on;
494   int sock = socket(AF_INET6, SOCK_DGRAM, 0);
495   if (sock < 0) {
496     perror("socket");
497     syslog(LOG_ERR, "socket: %m");
498     return (-1);
499   }
500 #ifdef IPV6_V6ONLY
501   on = 1;
502   if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
503     perror("setsockopt(IPV6_V6ONLY)");
504     syslog(LOG_ERR, "setsockopt(IPV6_V6ONLY): %m");
505   }
506 #endif /* IPV6_V6ONLY */
507
508   //#ifdef SO_BROADCAST
509   /*
510      if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof (on)) < 0)
511      {
512      perror("setsockopt");
513      syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
514      close(sock);
515      return (-1);
516      }
517    */
518   //#endif /* SO_BROADCAST */
519
520 #ifdef SO_RCVBUF
521   if(bufspace > 0) {
522     for (on = bufspace;; on -= 1024) {
523       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0)
524         break;
525       if (on <= 8 * 1024) {
526         perror("setsockopt");
527         syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
528         break;
529       }
530     }
531   }
532 #endif /* SO_RCVBUF */
533
534   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
535     perror("SO_REUSEADDR failed");
536     close(sock);
537     return (-1);
538   }
539
540   /*
541    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
542    */
543
544   /* Bind to device */
545   if (bind_socket_to_device(sock, ifp->int_name) < 0) {
546     fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
547     syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
548     close(sock);
549     return -1;
550   }
551
552   memset(&sin, 0, sizeof(sin));
553   sin.sin6_family = AF_INET6;
554   sin.sin6_port = htons(olsr_cnf->olsrport);
555   sin.sin6_scope_id = ifp->if_index;
556
557   if(bufspace <= 0) {
558     memcpy(&sin.sin6_addr, &ifp->int6_addr.sin6_addr, sizeof(struct in6_addr));
559   }
560
561   if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
562     struct ipaddr_str buf;
563     OLSR_PRINTF(1, "Error, cannot bind address %s to %s-socket: %s (%d)\n",
564         inet_ntop(sin.sin6_family, &sin.sin6_addr, buf.buf, sizeof(buf)),
565         bufspace <= 0 ? "transmit" : "receive",
566         strerror(errno), errno);
567     syslog(LOG_ERR, "bind: %m");
568     close(sock);
569     return (-1);
570   }
571
572   on = fcntl(sock, F_GETFL);
573   if (on == -1) {
574     syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
575   } else {
576     if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
577       syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
578     }
579   }
580   return sock;
581 }
582
583 int
584 join_mcast(struct interface_olsr *ifs, int sock)
585 {
586   /* See linux/in6.h */
587   struct ipaddr_str buf;
588   struct ipv6_mreq mcastreq;
589
590   mcastreq.ipv6mr_multiaddr = ifs->int6_multaddr.sin6_addr;
591   mcastreq.ipv6mr_interface = ifs->if_index;
592
593   OLSR_PRINTF(3, "Interface %s joining multicast %s...", ifs->int_name, ip6_to_string(&buf, &ifs->int6_multaddr.sin6_addr));
594
595   /* Old libc fix */
596 #ifdef IPV6_JOIN_GROUP
597   /* Join receiver group */
598   if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0)
599 #else /* IPV6_JOIN_GROUP */
600   /* Join receiver group */
601   if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0)
602 #endif /* IPV6_JOIN_GROUP */
603   {
604     perror("Join multicast group for receiving socket");
605     return -1;
606   }
607
608   if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&mcastreq.ipv6mr_interface, sizeof(mcastreq.ipv6mr_interface)) < 0) {
609     perror("Set multicast if");
610     return -1;
611   }
612
613   OLSR_PRINTF(3, "OK\n");
614   return 0;
615 }
616
617 /*
618  *From net-tools lib/interface.c
619  *
620  */
621 int
622 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, struct olsr_ip_prefix *prefix)
623 {
624   char addr6[40], devname[IFNAMSIZ];
625   char addr6p[8][5];
626   int plen, scope, dad_status, if_idx;
627   FILE *f;
628   union olsr_ip_addr tmp_ip;
629
630   if ((f = fopen(PATH_PROCNET_IFINET6, "r")) != NULL) {
631     while (fscanf
632            (f, "%4s%4s%4s%4s%4s%4s%4s%4s %x %02x %02x %02x %16s\n", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
633             addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
634       if (!strcmp(devname, ifname)) {
635         bool isNetWide = false;
636         sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6],
637                 addr6p[7]);
638         OLSR_PRINTF(5, "\tinet6 addr: %s\n", addr6);
639         OLSR_PRINTF(5, "\tScope: %d\n", scope);
640
641         if (inet_pton(AF_INET6, addr6, &tmp_ip.v6) != 1) {
642           continue;
643         }
644
645         isNetWide = (scope != IPV6_ADDR_LOOPBACK) && (scope != IPV6_ADDR_LINKLOCAL) && (scope != IPV6_ADDR_SITELOCAL);
646
647         if ((prefix == NULL && isNetWide) || (prefix != NULL && ip_in_net(&tmp_ip, prefix))) {
648           OLSR_PRINTF(4, "Found addr: %s:%s:%s:%s:%s:%s:%s:%s\n", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5],
649                       addr6p[6], addr6p[7]);
650           memcpy(&saddr6->sin6_addr, &tmp_ip.v6, sizeof(struct in6_addr));
651           fclose(f);
652           return 1;
653         }
654       }
655     }
656     fclose(f);
657   }
658   return 0;
659 }
660
661 /**
662  * Wrapper for sendto(2)
663  */
664 ssize_t
665 olsr_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr * to, socklen_t tolen)
666 {
667   return sendto(s, buf, len, flags, to, tolen);
668 }
669
670 /**
671  * Wrapper for recvfrom(2)
672  */
673
674 ssize_t
675 olsr_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr * from, socklen_t * fromlen)
676 {
677   return recvfrom(s, buf, len, flags, from, fromlen);
678 }
679
680 /**
681  * Wrapper for select(2)
682  */
683
684 int
685 olsr_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
686 {
687   return select(nfds, readfds, writefds, exceptfds, timeout);
688 }
689
690 int
691 check_wireless_interface(char *ifname)
692 {
693   struct ifreq ifr;
694
695   memset(&ifr, 0, sizeof(ifr));
696   strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
697
698   return (ioctl(olsr_cnf->ioctl_s, SIOCGIWNAME, &ifr) >= 0) ? 1 : 0;
699 }
700
701 int
702 calculate_if_metric(char *ifname)
703 {
704   return check_wireless_interface(ifname);
705 }
706
707 bool olsr_if_isup(const char * dev)
708 {
709   struct ifreq ifr;
710
711   if (!dev || (getInterfaceLinkState(dev) == LINKSTATE_DOWN)) {
712     return false;
713   }
714
715   memset(&ifr, 0, sizeof(ifr));
716   strscpy(ifr.ifr_name, dev, IFNAMSIZ);
717
718   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
719     OLSR_PRINTF(1, "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
720         dev, strerror(errno), errno);
721     return false;
722   }
723   return (ifr.ifr_flags & IFF_UP) != 0;
724 }
725
726 int olsr_if_set_state(const char *dev, bool up) {
727   int oldflags;
728   struct ifreq ifr;
729
730   memset(&ifr, 0, sizeof(ifr));
731   strscpy(ifr.ifr_name, dev, IFNAMSIZ);
732
733   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
734     OLSR_PRINTF(1, "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
735         dev, strerror(errno), errno);
736     return 1;
737   }
738
739   oldflags = ifr.ifr_flags;
740   if (up) {
741     ifr.ifr_flags |= IFF_UP;
742   }
743   else {
744     ifr.ifr_flags &= ~IFF_UP;
745   }
746
747   if (oldflags == ifr.ifr_flags) {
748     /* interface is already up/down */
749     return 0;
750   }
751
752   if (ioctl(olsr_cnf->ioctl_s, SIOCSIFFLAGS, &ifr) < 0) {
753     OLSR_PRINTF(1, "ioctl SIOCSIFFLAGS (set flags %s) error on device %s: %s (%d)\n",
754         up ? "up" : "down", dev, strerror(errno), errno);
755     return 1;
756   }
757   return 0;
758 }
759 #endif /* __linux__ */
760
761 /*
762  * Local Variables:
763  * c-basic-offset: 2
764  * indent-tabs-mode: nil
765  * End:
766  */