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