Fix bug in glibc in IPTOS_CLASS(x) macro (netinet/ip.h file)
[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 spesific code
44  */
45
46 #include "ipcalc.h"
47 #include "common/string.h"
48 #include "olsr_protocol.h"
49 #include "olsr_logging.h"
50 #include "olsr.h"
51 #include "os_kernel_tunnel.h"
52 #include "os_net.h"
53 #include "linux/linux_net.h"
54
55 #include <net/if.h>
56 #include <netinet/ip.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
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
92 /* list of IPv6 interfaces */
93 #define PATH_PROCNET_IFINET6           "/proc/net/if_inet6"
94
95 /*
96  *Wireless definitions for ioctl calls
97  *(from linux/wireless.h)
98  */
99 #define SIOCGIWNAME     0x8B01  /* get name == wireless protocol */
100 #define SIOCGIWRATE     0x8B21  /* get default bit rate (bps) */
101
102 /* The original state of the IP forwarding proc entry */
103 static char orig_fwd_state;
104 static char orig_global_redirect_state;
105 static char orig_global_rp_filter;
106 static char orig_tunnel_rp_filter;
107 #if 0 // should not be necessary for IPv6 */
108 static char orig_tunnel6_rp_filter;
109 #endif
110
111 static int writeToProc(const char *file, char *old, char value) {
112   int fd;
113   char rv;
114
115   if ((fd = open(file, O_RDWR)) < 0) {
116     OLSR_WARN(LOG_INTERFACE, "Cannot open proc entry %s: %s (%d)\n", file, strerror(errno), errno);
117     return -1;
118   }
119
120   if (read(fd, &rv, 1) != 1) {
121     OLSR_WARN(LOG_INTERFACE, "Cannot read proc entry %s: %s (%d)\n", file, strerror(errno), errno);
122     return -1;
123   }
124
125   if (rv != value) {
126     if (lseek(fd, SEEK_SET, 0) == -1) {
127       OLSR_WARN(LOG_INTERFACE, "Cannot rewind proc entry %s: %s (%d)\n", file, strerror(errno), errno);
128       return -1;
129     }
130
131     if (write(fd, &value, 1) != 1) {
132       OLSR_WARN(LOG_INTERFACE, "Cannot write proc entry %s: %s (%d)\n", file, strerror(errno), errno);
133       return -1;
134     }
135   }
136
137   if (close(fd) != 0) {
138     OLSR_WARN(LOG_INTERFACE, "Cannot close proc entry %s: %s (%d)\n", file, strerror(errno), errno);
139     return -1;
140   }
141
142   if (old) {
143     *old = rv;
144   }
145   OLSR_DEBUG(LOG_INTERFACE, "Writing '%c' (was %c) to %s", value, rv, file);
146   return 0;
147 }
148
149 static bool is_at_least_linuxkernel_2_6_31(void) {
150   struct utsname uts;
151
152   memset(&uts, 0, sizeof(uts));
153   if (uname(&uts)) {
154     OLSR_WARN(LOG_NETWORKING, "Cannot not read kernel version: %s (%d)\n", strerror(errno), errno);
155     return false;
156   }
157
158   if (strncmp(uts.release, "2.6.",4) != 0) {
159     return false;
160   }
161   return atoi(&uts.release[4]) >= 31;
162 }
163
164 /**
165  * Setup global interface options (icmp redirect, ip forwarding, rp_filter)
166  * @return 1 on success 0 on failure
167  */
168 void
169 os_init_global_ifoptions(void) {
170   if (writeToProc(olsr_cnf->ip_version == AF_INET ? PROC_IPFORWARD_V4 : PROC_IPFORWARD_V6, &orig_fwd_state, '1')) {
171     OLSR_WARN(LOG_INTERFACE, "Warning, could not enable IP forwarding!\n"
172         "you should manually ensure that IP forwarding is enabled!\n\n");
173     // TODO olsr_startup_sleep(3);
174   }
175
176   if (olsr_cnf->smart_gw_active) {
177     char procfile[FILENAME_MAX];
178
179     /* Generate the procfile name */
180     if (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit) {
181       snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF);
182       if (writeToProc(procfile, &orig_tunnel_rp_filter, '0')) {
183         OLSR_WARN(LOG_INTERFACE, "WARNING! Could not disable the IP spoof filter for tunnel!\n"
184             "you should mannually ensure that IP spoof filtering is disabled!\n\n");
185
186         // TODO olsr_startup_sleep(3);
187       }
188     }
189   }
190
191   if (olsr_cnf->ip_version == AF_INET) {
192     if (writeToProc(PROC_ALL_REDIRECT, &orig_global_redirect_state, '0')) {
193       OLSR_WARN(LOG_INTERFACE, "WARNING! Could not disable ICMP redirects!\n"
194           "you should manually ensure that ICMP redirects are disabled!\n\n");
195
196       // TODO olsr_startup_sleep(3);
197     }
198
199     /* check kernel version and disable global rp_filter */
200     if (is_at_least_linuxkernel_2_6_31()) {
201       if (writeToProc(PROC_ALL_SPOOF, &orig_global_rp_filter, '0')) {
202         OLSR_WARN(LOG_INTERFACE, "WARNING! Could not disable global rp_filter (necessary for kernel 2.6.31 and higher!\n"
203             "you should manually ensure that rp_filter is disabled!\n\n");
204
205         // TODO olsr_startup_sleep(3);
206       }
207     }
208   }
209   return;
210 }
211
212 /**
213  *
214  *@return 1 on sucess 0 on failiure
215  */
216 int
217 net_os_set_ifoptions(const char *if_name, struct interface *iface)
218 {
219   char procfile[FILENAME_MAX];
220   if (olsr_cnf->ip_version == AF_INET6)
221     return -1;
222
223   /* Generate the procfile name */
224   snprintf(procfile, sizeof(procfile), PROC_IF_REDIRECT, if_name);
225
226   if (writeToProc(procfile, &iface->nic_state.redirect, '0')) {
227     OLSR_WARN(LOG_INTERFACE, "WARNING! Could not disable ICMP redirects!\n"
228         "you should mannually ensure that ICMP redirects are disabled!\n\n");
229     // TODO olsr_startup_sleep(3);
230     return 0;
231   }
232
233   /* Generate the procfile name */
234   snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, if_name);
235
236   if (writeToProc(procfile, &iface->nic_state.spoof, '0')) {
237     OLSR_WARN(LOG_INTERFACE, "WARNING! Could not disable the IP spoof filter!\n"
238         "you should mannually ensure that IP spoof filtering is disabled!\n\n");
239
240     // TODO olsr_startup_sleep(3);
241     return 0;
242   }
243   return 1;
244 }
245
246 void net_os_restore_ifoption(struct interface *ifs) {
247   char procfile[FILENAME_MAX];
248
249   /* ICMP redirects */
250   snprintf(procfile, sizeof(procfile), PROC_IF_REDIRECT, ifs->int_name);
251   if (writeToProc(procfile, NULL, ifs->nic_state.redirect)) {
252     OLSR_WARN(LOG_INTERFACE, "Could not restore icmp_redirect for interface %s\n", ifs->int_name);
253   }
254
255   /* Spoof filter */
256   sprintf(procfile, PROC_IF_SPOOF, ifs->int_name);
257   if (writeToProc(procfile, NULL, ifs->nic_state.spoof)) {
258     OLSR_WARN(LOG_INTERFACE, "Could not restore rp_filter for interface %s\n", ifs->int_name);
259   }
260 }
261 /**
262  *Resets the spoof filter and ICMP redirect settings
263  */
264 void
265 os_cleanup_global_ifoptions(void)
266 {
267   char procfile[FILENAME_MAX];
268   OLSR_DEBUG(LOG_INTERFACE, "Restoring network state\n");
269
270   /* Restore IP forwarding to "off" */
271   if (writeToProc(olsr_cnf->ip_version == AF_INET ? PROC_IPFORWARD_V4 : PROC_IPFORWARD_V6, NULL, orig_fwd_state)) {
272     OLSR_WARN(LOG_INTERFACE, "Could not restore ip_forward settings\n");
273   }
274
275   if (olsr_cnf->smart_gw_active && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit)) {
276     /* Generate the procfile name */
277     snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF);
278     if (writeToProc(procfile, NULL, orig_tunnel_rp_filter)) {
279       OLSR_WARN(LOG_INTERFACE, "WARNING! Could not restore the IP spoof filter for tunnel!\n");
280     }
281   }
282
283   if (olsr_cnf->ip_version == AF_INET) {
284     /* Restore global ICMP redirect setting */
285     if (writeToProc(PROC_ALL_REDIRECT, NULL, orig_global_redirect_state)) {
286       OLSR_WARN(LOG_INTERFACE, "Could not restore global icmp_redirect setting\n");
287     }
288
289     /* Restore global rp_filter setting for linux 2.6.31+ */
290     if (is_at_least_linuxkernel_2_6_31()) {
291       if (writeToProc(PROC_ALL_SPOOF, NULL, orig_global_rp_filter)) {
292         OLSR_WARN(LOG_INTERFACE, "Could not restore global rp_filter setting\n");
293       }
294     }
295   }
296 }
297
298 /**
299  *Bind a socket to a device
300  *
301  *@param sock the socket to bind
302  *@param dev_name name of the device
303  *
304  *@return negative if error
305  */
306
307 static int
308 bind_socket_to_device(int sock, const char *dev_name)
309 {
310   /*
311    *Bind to device using the SO_BINDTODEVICE flag
312    */
313   OLSR_DEBUG(LOG_NETWORKING, "Binding socket %d to device %s\n", sock, dev_name);
314   return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, dev_name, strlen(dev_name) + 1);
315 }
316
317
318 /**
319  *Creates a nonblocking broadcast socket.
320  *@param sa sockaddr struct. Used for bind(2).
321  *@return the FD of the socket or -1 on error.
322  */
323 int
324 os_getsocket4(const char *if_name, uint16_t port, int bufspace, union olsr_sockaddr *bindto)
325 {
326   struct sockaddr_in sin4;
327   int on;
328   int sock = socket(AF_INET, SOCK_DGRAM, 0);
329   if (sock < 0) {
330     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
331     olsr_exit(EXIT_FAILURE);
332   }
333
334   on = 1;
335 #ifdef SO_BROADCAST
336   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
337     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
338     close(sock);
339     olsr_exit(EXIT_FAILURE);
340   }
341 #endif
342
343   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
344     OLSR_ERROR(LOG_NETWORKING, "Cannot reuse address for OLSR PDUs (%s)\n", strerror(errno));
345     close(sock);
346     olsr_exit(EXIT_FAILURE);
347   }
348 #ifdef SO_RCVBUF
349   if(bufspace > 0) {
350     for (on = bufspace;; on -= 1024) {
351       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) {
352         OLSR_DEBUG(LOG_NETWORKING, "Set socket buffer space to %d\n", on);
353         break;
354       }
355       if (on <= 8 * 1024) {
356         OLSR_WARN(LOG_NETWORKING, "Could not set a socket buffer space for OLSR PDUs (%s)\n", strerror(errno));
357         break;
358       }
359     }
360   }
361 #endif
362
363   /*
364    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
365    */
366
367   /* Bind to device */
368   if (bind_socket_to_device(sock, if_name) < 0) {
369     OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs to interface %s: %s (%d)\n", if_name, strerror(errno), errno);
370     close(sock);
371     olsr_exit(EXIT_FAILURE);
372   }
373
374   if (bindto == NULL) {
375     memset(&sin4, 0, sizeof(sin4));
376     sin4.sin_family = AF_INET;
377     sin4.sin_port = htons(port);
378     sin4.sin_addr.s_addr = 0;
379     bindto = (union olsr_sockaddr *)&sin4;
380   }
381   if (bind(sock, &bindto->std, sizeof(*bindto)) < 0) {
382     OLSR_ERROR(LOG_NETWORKING, "Coult not bind socket for OLSR PDUs to port (%s)\n", strerror(errno));
383     close(sock);
384     olsr_exit(EXIT_FAILURE);
385   }
386
387   os_socket_set_nonblocking(sock);
388   return sock;
389 }
390
391
392 /**
393  *Creates a nonblocking IPv6 socket
394  *@param sin sockaddr_in6 struct. Used for bind(2).
395  *@return the FD of the socket or -1 on error.
396  */
397 int
398 os_getsocket6(const char *if_name, uint16_t port, int bufspace, union olsr_sockaddr *bindto)
399 {
400   struct sockaddr_in6 sin6;
401   int on;
402   int sock = socket(AF_INET6, SOCK_DGRAM, 0);
403   if (sock < 0) {
404     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
405     olsr_exit(EXIT_FAILURE);
406   }
407 #ifdef IPV6_V6ONLY
408   on = 1;
409   if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
410     OLSR_WARN(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to ipv6 only (%s)\n", strerror(errno));
411   }
412 #endif
413
414
415   //#ifdef SO_BROADCAST
416   /*
417      if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof(on)) < 0)
418      {
419      perror("setsockopt");
420      syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
421      close(sock);
422      return (-1);
423      }
424    */
425   //#endif
426
427 #ifdef SO_RCVBUF
428   if(bufspace > 0) {
429     for (on = bufspace;; on -= 1024) {
430       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) {
431         OLSR_DEBUG(LOG_NETWORKING, "Set socket buffer space to %d\n", on);
432         break;
433       }
434       if (on <= 8 * 1024) {
435         OLSR_WARN(LOG_NETWORKING, "Could not set a socket buffer space for OLSR PDUs (%s)\n", strerror(errno));
436         break;
437       }
438     }
439   }
440 #endif
441
442   on = 1;
443   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
444     OLSR_ERROR(LOG_NETWORKING, "Cannot reuse address for socket for OLSR PDUs (%s)\n", strerror(errno));
445     close(sock);
446     olsr_exit(EXIT_FAILURE);
447   }
448
449   /*
450    * we are abusing "on" here. The value is 1 which is our intended
451    * hop limit value.
452    */
453   if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &on, sizeof(on)) < 0) {
454     OLSR_ERROR(LOG_NETWORKING, "Cannot set multicast hops to 1 for socket for OLSR PDUs (%s)\n", strerror(errno));
455     close(sock);
456     olsr_exit(EXIT_FAILURE);
457   }
458
459
460   /*
461    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
462    */
463
464   /* Bind to device */
465   if (bind_socket_to_device(sock, if_name) < 0) {
466     OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs to interface %s: %s (%d)\n", if_name, strerror(errno), errno);
467     close(sock);
468     olsr_exit(EXIT_FAILURE);
469   }
470
471   if (bindto == NULL) {
472     memset(&sin6, 0, sizeof(sin6));
473     sin6.sin6_family = AF_INET6;
474     sin6.sin6_port = htons(port);
475     bindto = (union olsr_sockaddr *)&sin6;
476   }
477   if (bind(sock, &bindto->std, sizeof(*bindto)) < 0) {
478     OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs (%s)\n", strerror(errno));
479     close(sock);
480     olsr_exit(EXIT_FAILURE);
481   }
482
483   os_socket_set_nonblocking(sock);
484   return sock;
485 }
486
487
488 static int
489 join_mcast(struct interface *ifs, int sock)
490 {
491   /* See linux/in6.h */
492 #if !defined REMOVE_LOG_INFO
493   struct ipaddr_str buf;
494 #endif
495   struct ipv6_mreq mcastreq;
496
497   if (olsr_cnf->ip_version == AF_INET) {
498     return 0;
499   }
500   mcastreq.ipv6mr_multiaddr = ifs->int_multicast.v6.sin6_addr;
501   mcastreq.ipv6mr_interface = ifs->if_index;
502
503   OLSR_INFO(LOG_NETWORKING, "Interface %s joining multicast %s\n", ifs->int_name,
504             olsr_sockaddr_to_string(&buf, &ifs->int_multicast));
505   /* Send multicast */
506   if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
507       < 0) {
508     OLSR_WARN(LOG_NETWORKING, "Cannot join multicast group (%s)\n", strerror(errno));
509     return -1;
510   }
511 #if 0
512   /* Old libc fix */
513 #ifdef IPV6_JOIN_GROUP
514   /* Join reciever group */
515   if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
516       < 0)
517 #else
518   /* Join reciever group */
519   if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
520       < 0)
521 #endif
522   {
523     perror("Join multicast send");
524     return -1;
525   }
526 #endif
527   if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&mcastreq.ipv6mr_interface, sizeof(mcastreq.ipv6mr_interface))
528       < 0) {
529     OLSR_WARN(LOG_NETWORKING, "Cannot set multicast interface (%s)\n", strerror(errno));
530     return -1;
531   }
532
533   return 0;
534 }
535
536 void
537 os_socket_set_olsr_options(struct interface * ifs, int sock) {
538   /* Set TOS */
539   int data = IPTOS_PREC(olsr_cnf->tos);
540   if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (char *)&data, sizeof(data)) < 0) {
541     OLSR_WARN(LOG_INTERFACE, "setsockopt(SO_PRIORITY) error %s", strerror(errno));
542   }
543   data = IPTOS_TOS(olsr_cnf->tos);
544   if (setsockopt(sock, SOL_IP, IP_TOS, (char *)&data, sizeof(data)) < 0) {
545     OLSR_WARN(LOG_INTERFACE, "setsockopt(IP_TOS) error %s", strerror(errno));
546   }
547
548   join_mcast(ifs, sock);
549 }
550
551 /*
552  *From net-tools lib/interface.c
553  *
554  */
555 int
556 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int addrtype6)
557 {
558   int rv = 0;
559   FILE *f = fopen(_PATH_PROCNET_IFINET6, "r");
560   if (f != NULL) {
561     char devname[IFNAMSIZ];
562     char addr6p[8][5];
563     int plen, scope, dad_status, if_idx;
564     bool found = false;
565     while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
566                   addr6p[0], addr6p[1], addr6p[2], addr6p[3],
567                   addr6p[4], addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
568       if (strcmp(devname, ifname) == 0) {
569         char addr6[40];
570         sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
571                 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
572
573         if (addrtype6 == OLSR_IP6T_SITELOCAL && scope == IPV6_ADDR_SITELOCAL)
574           found = true;
575         else if (addrtype6 == OLSR_IP6T_UNIQUELOCAL && scope == IPV6_ADDR_GLOBAL)
576           found = true;
577         else if (addrtype6 == OLSR_IP6T_GLOBAL && scope == IPV6_ADDR_GLOBAL)
578           found = true;
579
580         if (found) {
581           found = false;
582           if (addr6p[0][0] == 'F' || addr6p[0][0] == 'f') {
583             if (addr6p[0][1] == 'C' || addr6p[0][1] == 'c' || addr6p[0][1] == 'D' || addr6p[0][1] == 'd')
584               found = true;
585           }
586           if (addrtype6 == OLSR_IP6T_SITELOCAL)
587             found = true;
588           else if (addrtype6 == OLSR_IP6T_UNIQUELOCAL && found)
589             found = true;
590           else if (addrtype6 == OLSR_IP6T_GLOBAL && !found)
591             found = true;
592           else
593             found = false;
594         }
595
596         if (found) {
597           inet_pton(AF_INET6, addr6, &saddr6->sin6_addr);
598           rv = 1;
599           break;
600         }
601       }
602     }
603     fclose(f);
604   }
605   return rv;
606 }
607
608
609 /**
610  * Wrapper for sendto(2)
611  */
612 ssize_t
613 os_sendto(int s, const void *buf, size_t len, int flags, const union olsr_sockaddr *sockaddr)
614 {
615   return sendto(s, buf, len, flags, &sockaddr->std, sizeof(*sockaddr));
616 }
617
618 /**
619  * Wrapper for recvfrom(2)
620  */
621
622 ssize_t
623 os_recvfrom(int s, void *buf, size_t len, int flags,
624     union olsr_sockaddr *sockaddr, socklen_t *socklen)
625 {
626   return recvfrom(s, buf, len, flags, &sockaddr->std, socklen);
627 }
628
629 /**
630  * Wrapper for select(2)
631  */
632
633 int
634 os_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
635 {
636   return select(nfds, readfds, writefds, exceptfds, timeout);
637 }
638
639 bool os_is_interface_up(const char * dev)
640 {
641   struct ifreq ifr;
642
643   memset(&ifr, 0, sizeof(ifr));
644   strscpy(ifr.ifr_name, dev, IFNAMSIZ);
645
646   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
647     OLSR_WARN(LOG_INTERFACE, "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
648         dev, strerror(errno), errno);
649     return 1;
650   }
651   return (ifr.ifr_flags & IFF_UP) != 0;
652 }
653
654 int os_interface_set_state(const char *dev, bool up) {
655   int oldflags;
656   struct ifreq ifr;
657
658   memset(&ifr, 0, sizeof(ifr));
659   strscpy(ifr.ifr_name, dev, IFNAMSIZ);
660
661   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
662     OLSR_WARN(LOG_INTERFACE, "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
663         dev, strerror(errno), errno);
664     return 1;
665   }
666
667   oldflags = ifr.ifr_flags;
668   if (up) {
669     ifr.ifr_flags |= IFF_UP;
670   }
671   else {
672     ifr.ifr_flags &= ~IFF_UP;
673   }
674
675   if (oldflags == ifr.ifr_flags) {
676     /* interface is already up/down */
677     return 0;
678   }
679
680   if (ioctl(olsr_cnf->ioctl_s, SIOCSIFFLAGS, &ifr) < 0) {
681     OLSR_WARN(LOG_INTERFACE, "ioctl SIOCSIFFLAGS (set flags %s) error on device %s: %s (%d)\n",
682         up ? "up" : "down", dev, strerror(errno), errno);
683     return 1;
684   }
685   return 0;
686 }
687
688 /*
689  * Local Variables:
690  * c-basic-offset: 2
691  * indent-tabs-mode: nil
692  * End:
693  */