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