c25e9299bdf71d5a21b52700d335839117db2bbf
[olsrd.git] / src / linux / net.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
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 /*
44  * Linux spesific code
45  */
46
47 #include "../net_os.h"
48 #include "../ipcalc.h"
49 #include "../common/string.h"
50 #include "../olsr_protocol.h"
51 #include "../misc.h"
52 #include "../olsr_logging.h"
53 #include "../olsr.h"
54
55 #include <net/if.h>
56
57 #include <sys/ioctl.h>
58
59 #include <fcntl.h>
60 #include <string.h>
61 #include <stdio.h>
62 #include <syslog.h>
63 #include <errno.h>
64 #include <unistd.h>
65 #include <assert.h>
66
67 /* Redirect proc entry */
68 #define REDIRECT_PROC "/proc/sys/net/ipv4/conf/%s/send_redirects"
69
70 /* IP spoof proc entry */
71 #define SPOOF_PROC "/proc/sys/net/ipv4/conf/%s/rp_filter"
72
73 /*
74  *Wireless definitions for ioctl calls
75  *(from linux/wireless.h)
76  */
77 #define SIOCGIWNAME     0x8B01  /* get name == wireless protocol */
78 #define SIOCGIWRATE     0x8B21  /* get default bit rate (bps) */
79
80 /* The original state of the IP forwarding proc entry */
81 static char orig_fwd_state;
82 static char orig_global_redirect_state;
83
84 /**
85  *Bind a socket to a device
86  *
87  *@param sock the socket to bind
88  *@param dev_name name of the device
89  *
90  *@return negative if error
91  */
92
93 static int
94 bind_socket_to_device(int sock, char *dev_name)
95 {
96   /*
97    *Bind to device using the SO_BINDTODEVICE flag
98    */
99   OLSR_DEBUG(LOG_NETWORKING, "Binding socket %d to device %s\n", sock, dev_name);
100   return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, dev_name, strlen(dev_name) + 1);
101 }
102
103
104 /**
105  *Enable IP forwarding.
106  *Just writing "1" to the /proc/sys/net/ipv4/ip_forward
107  *if using IPv4 or /proc/sys/net/ipv6/conf/all/forwarding
108  *if using IPv6.
109  *Could probably drop the check for
110  *"0" here and write "1" anyways.
111  *
112  *@param version IP version.
113  *
114  *@return 1 on sucess 0 on failiure
115  */
116 int
117 enable_ip_forwarding(int version)
118 {
119   const char *const procfile = version == AF_INET ? "/proc/sys/net/ipv4/ip_forward" : "/proc/sys/net/ipv6/conf/all/forwarding";
120   FILE *proc_fwd = fopen(procfile, "r");
121
122   if (proc_fwd == NULL) {
123     OLSR_WARN(LOG_NETWORKING,
124               "WARNING! Could not open the %s file to check/enable IP forwarding!\n"
125               "Are you using the procfile filesystem?\nDoes your system support IPv%d?\n"
126               "I will continue(in 3 sec) - but you should manually ensure that IP forwarding is enabled!\n\n",
127               procfile, version == AF_INET ? 4 : 6);
128     sleep(3);
129     return 0;
130   }
131   orig_fwd_state = fgetc(proc_fwd);
132   fclose(proc_fwd);
133
134   if (orig_fwd_state == '1') {
135     OLSR_INFO(LOG_NETWORKING, "\nIP forwarding is enabled on this system\n");
136   } else {
137     proc_fwd = fopen(procfile, "w");
138     if (proc_fwd == NULL) {
139       OLSR_WARN(LOG_NETWORKING, "Could not open %s for writing!\n"
140                 "I will continue(in 3 sec) - but you should manually ensure that IP forwarding is enabeled!\n\n", procfile);
141       sleep(3);
142       return 0;
143     }
144     fputs("1", proc_fwd);
145     fclose(proc_fwd);
146   }
147   return 1;
148 }
149
150 int
151 disable_redirects_global(int version)
152 {
153   FILE *proc_redirect;
154   const char *const procfile = "/proc/sys/net/ipv4/conf/all/send_redirects";
155
156   if (version == AF_INET6) {
157     return -1;
158   }
159   proc_redirect = fopen(procfile, "r");
160   if (proc_redirect == NULL) {
161     OLSR_WARN(LOG_NETWORKING,
162               "WARNING! Could not open the %s file to check/disable ICMP redirects!\n"
163               "Are you using the procfile filesystem?\n"
164               "Does your system support IPv4?\n"
165               "I will continue(in 3 sec) - but you should manually ensure that ICMP redirects are disabled!\n\n", procfile);
166     sleep(3);
167     return -1;
168   }
169   orig_global_redirect_state = fgetc(proc_redirect);
170   fclose(proc_redirect);
171
172   if (orig_global_redirect_state == '0') {
173     return 0;
174   }
175   proc_redirect = fopen(procfile, "w");
176   if (proc_redirect == NULL) {
177     OLSR_WARN(LOG_NETWORKING, "Could not open %s for writing!\n"
178               "I will continue(in 3 sec) - but you should manually ensure that ICMP redirect is disabled!\n\n", procfile);
179     sleep(3);
180     return 0;
181   }
182   fputs("0", proc_redirect);
183   fclose(proc_redirect);
184   return 1;
185 }
186
187 /**
188  *
189  *@return 1 on sucess 0 on failiure
190  */
191 int
192 disable_redirects(const char *if_name, struct interface *iface, int version)
193 {
194   FILE *proc_redirect;
195   char procfile[FILENAME_MAX];
196
197   if (version == AF_INET6) {
198     return -1;
199   }
200
201   /* Generate the procfile name */
202   snprintf(procfile, sizeof(procfile), REDIRECT_PROC, if_name);
203
204   proc_redirect = fopen(procfile, "r");
205   if (proc_redirect == NULL) {
206     OLSR_WARN(LOG_NETWORKING,
207               "WARNING! Could not open the %s file to check/disable ICMP redirects!\n"
208               "Are you using the procfile filesystem?\n"
209               "Does your system support IPv4?\n"
210               "I will continue(in 3 sec) - but you should manually ensure that ICMP redirects are disabled!\n\n", procfile);
211     sleep(3);
212     return 0;
213   }
214   iface->nic_state.redirect = fgetc(proc_redirect);
215   fclose(proc_redirect);
216
217   proc_redirect = fopen(procfile, "w");
218   if (proc_redirect == NULL) {
219     OLSR_WARN(LOG_NETWORKING, "Could not open %s for writing!\n"
220               "I will continue(in 3 sec) - but you should manually ensure that ICMP redirect is disabled!\n\n", procfile);
221     sleep(3);
222     return 0;
223   }
224   fputs("0", proc_redirect);
225   fclose(proc_redirect);
226   return 1;
227 }
228
229 /**
230  *
231  *@return 1 on sucess 0 on failiure
232  */
233 int
234 deactivate_spoof(const char *if_name, struct interface *iface, int version)
235 {
236   FILE *proc_spoof;
237   char procfile[FILENAME_MAX];
238
239   if (version == AF_INET6) {
240     return -1;
241   }
242
243   /* Generate the procfile name */
244   sprintf(procfile, SPOOF_PROC, if_name);
245
246   proc_spoof = fopen(procfile, "r");
247   if (proc_spoof == NULL) {
248     OLSR_WARN(LOG_NETWORKING,
249               "WARNING! Could not open the %s file to check/disable the IP spoof filter!\n"
250               "Are you using the procfile filesystem?\n"
251               "Does your system support IPv4?\n"
252               "I will continue(in 3 sec) - but you should manually ensure that IP spoof filtering is disabled!\n\n", procfile);
253     sleep(3);
254     return 0;
255   }
256   iface->nic_state.spoof = fgetc(proc_spoof);
257   fclose(proc_spoof);
258
259   proc_spoof = fopen(procfile, "w");
260   if (proc_spoof == NULL) {
261     OLSR_WARN(LOG_NETWORKING, "Could not open %s for writing!\n"
262               "I will continue(in 3 sec) - but you should manually ensure that IP spoof filtering is disabled!\n\n", procfile);
263     sleep(3);
264     return 0;
265   }
266   fputs("0", proc_spoof);
267   fclose(proc_spoof);
268   return 1;
269 }
270
271 /**
272  *Resets the spoof filter and ICMP redirect settings
273  */
274 int
275 restore_settings(int version)
276 {
277   struct interface *ifs;
278
279   OLSR_INFO(LOG_NETWORKING, "Restoring network state\n");
280
281   /* Restore IP forwarding to "off" */
282   if (orig_fwd_state == '0') {
283     const char *const procfile = version == AF_INET ? "/proc/sys/net/ipv4/ip_forward" : "/proc/sys/net/ipv6/conf/all/forwarding";
284     FILE *proc_fd = fopen(procfile, "w");
285
286     if (proc_fd == NULL) {
287       OLSR_WARN(LOG_NETWORKING, "Could not open %s for writing!\nSettings not restored!\n", procfile);
288     } else {
289       fputc(orig_fwd_state, proc_fd);
290       fclose(proc_fd);
291     }
292   }
293
294   /* Restore global ICMP redirect setting */
295   if (orig_global_redirect_state != '0') {
296     if (version == AF_INET) {
297       const char *const procfile = "/proc/sys/net/ipv4/conf/all/send_redirects";
298       FILE *proc_fd = fopen(procfile, "w");
299
300       if (proc_fd == NULL) {
301         OLSR_WARN(LOG_NETWORKING, "Could not open %s for writing!\nSettings not restored!\n", procfile);
302       } else {
303         fputc(orig_global_redirect_state, proc_fd);
304         fclose(proc_fd);
305       }
306     }
307   }
308
309   if (version == AF_INET6) {
310     return 0;
311   }
312
313   OLSR_FOR_ALL_INTERFACES(ifs) {
314     char procfile[FILENAME_MAX];
315     FILE *proc_fd;
316     /* Ignore host-emulation interfaces */
317     if (ifs->is_hcif) {
318       continue;
319     }
320     /* ICMP redirects */
321
322     /* Generate the procfile name */
323     snprintf(procfile, sizeof(procfile), REDIRECT_PROC, ifs->int_name);
324     proc_fd = fopen(procfile, "w");
325     if (proc_fd == NULL) {
326       OLSR_WARN(LOG_NETWORKING, "Could not open %s for writing!\nSettings not restored!\n", procfile);
327     } else {
328       fputc(ifs->nic_state.redirect, proc_fd);
329       fclose(proc_fd);
330     }
331
332     /* Spoof filter */
333
334     /* Generate the procfile name */
335     sprintf(procfile, SPOOF_PROC, ifs->int_name);
336     proc_fd = fopen(procfile, "w");
337     if (proc_fd == NULL) {
338       OLSR_WARN(LOG_NETWORKING, "Could not open %s for writing!\nSettings not restored!\n", procfile);
339     } else {
340       fputc(ifs->nic_state.spoof, proc_fd);
341       fclose(proc_fd);
342     }
343   }
344   OLSR_FOR_ALL_INTERFACES_END(ifs);
345
346   return 1;
347 }
348
349 /**
350  *Creates a blocking tcp socket for communication with switch daemon.
351  *@param sa sockaddr struct. Used for bind(2).
352  *@return the FD of the socket or -1 on error.
353  */
354 int
355 gethemusocket(struct sockaddr_in *pin)
356 {
357   int sock, on;
358
359   OLSR_INFO(LOG_NETWORKING, "       Connecting to switch daemon port %d\n", pin->sin_port);
360   if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
361     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for emulation (%s)\n", strerror(errno));
362     olsr_exit(EXIT_FAILURE);
363   }
364
365   on = 1;
366   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
367     OLSR_ERROR(LOG_NETWORKING, "Cannot reuse address for socket for emulation (%s)\n", strerror(errno));
368     close(sock);
369     olsr_exit(EXIT_FAILURE);
370   }
371
372   /* connect to PORT on HOST */
373   if (connect(sock, (struct sockaddr *)pin, sizeof(*pin)) < 0) {
374     OLSR_ERROR(LOG_NETWORKING, "Cannot connect socket for emulation (%s)\n", strerror(errno));
375     close(sock);
376     olsr_exit(EXIT_FAILURE);
377   }
378
379   /* Keep TCP socket blocking */
380   return sock;
381 }
382
383
384 /**
385  *Creates a nonblocking broadcast socket.
386  *@param sa sockaddr struct. Used for bind(2).
387  *@return the FD of the socket or -1 on error.
388  */
389 int
390 getsocket(int bufspace, char *int_name)
391 {
392   struct sockaddr_in sin4;
393   int on;
394   int sock = socket(AF_INET, SOCK_DGRAM, 0);
395   if (sock < 0) {
396     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
397     olsr_exit(EXIT_FAILURE);
398   }
399
400   on = 1;
401 #ifdef SO_BROADCAST
402   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
403     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
404     close(sock);
405     olsr_exit(EXIT_FAILURE);
406   }
407 #endif
408
409   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
410     OLSR_ERROR(LOG_NETWORKING, "Cannot reuse address for OLSR PDUs (%s)\n", strerror(errno));
411     close(sock);
412     olsr_exit(EXIT_FAILURE);
413   }
414 #ifdef SO_RCVBUF
415   for (on = bufspace;; on -= 1024) {
416     if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) {
417       OLSR_DEBUG(LOG_NETWORKING, "Set socket buffer space to %d\n", on);
418       break;
419     }
420     if (on <= 8 * 1024) {
421       OLSR_WARN(LOG_NETWORKING, "Could not set a socket buffer space for OLSR PDUs (%s)\n", strerror(errno));
422       break;
423     }
424   }
425 #endif
426
427   /*
428    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
429    */
430
431   /* Bind to device */
432   if (bind_socket_to_device(sock, int_name) < 0) {
433     OLSR_ERROR(LOG_NETWORKING, "Could not bind socket for OLSR PDUs to device (%s)\n", strerror(errno));
434     close(sock);
435     olsr_exit(EXIT_FAILURE);
436   }
437
438   memset(&sin4, 0, sizeof(sin4));
439   sin4.sin_family = AF_INET;
440   sin4.sin_port = htons(olsr_cnf->olsr_port);
441   assert(sin4.sin_addr.s_addr == INADDR_ANY);
442   if (bind(sock, (struct sockaddr *)&sin4, sizeof(sin4)) < 0) {
443     OLSR_ERROR(LOG_NETWORKING, "Coult not bind socket for OLSR PDUs to port (%s)\n", strerror(errno));
444     close(sock);
445     olsr_exit(EXIT_FAILURE);
446   }
447
448   set_nonblocking(sock);
449   return sock;
450 }
451
452
453 /**
454  *Creates a nonblocking IPv6 socket
455  *@param sin sockaddr_in6 struct. Used for bind(2).
456  *@return the FD of the socket or -1 on error.
457  */
458 int
459 getsocket6(int bufspace, char *int_name)
460 {
461   struct sockaddr_in6 sin6;
462   int on;
463   int sock = socket(AF_INET6, SOCK_DGRAM, 0);
464   if (sock < 0) {
465     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
466     olsr_exit(EXIT_FAILURE);
467   }
468 #ifdef IPV6_V6ONLY
469   on = 1;
470   if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
471     OLSR_WARN(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to ipv6 only (%s)\n", strerror(errno));
472   }
473 #endif
474
475
476   //#ifdef SO_BROADCAST
477   /*
478      if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof(on)) < 0)
479      {
480      perror("setsockopt");
481      syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
482      close(sock);
483      return (-1);
484      }
485    */
486   //#endif
487
488 #ifdef SO_RCVBUF
489   for (on = bufspace;; on -= 1024) {
490     if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) {
491       OLSR_DEBUG(LOG_NETWORKING, "Set socket buffer space to %d\n", on);
492       break;
493     }
494     if (on <= 8 * 1024) {
495       OLSR_WARN(LOG_NETWORKING, "Could not set a socket buffer space for OLSR PDUs (%s)\n", strerror(errno));
496       break;
497     }
498   }
499 #endif
500
501   on = 1;
502   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
503     OLSR_ERROR(LOG_NETWORKING, "Cannot reuse address for socket for OLSR PDUs (%s)\n", strerror(errno));
504     close(sock);
505     olsr_exit(EXIT_FAILURE);
506   }
507
508   /*
509    * we are abusing "on" here. The value is 1 which is our intended
510    * hop limit value.
511    */
512   if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &on, sizeof(on)) < 0) {
513     OLSR_ERROR(LOG_NETWORKING, "Cannot set multicast hops to 1 for socket for OLSR PDUs (%s)\n", strerror(errno));
514     close(sock);
515     olsr_exit(EXIT_FAILURE);
516   }
517
518
519   /*
520    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
521    */
522
523   /* Bind to device */
524   if (bind_socket_to_device(sock, int_name) < 0) {
525     OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs to interface %s (%s)\n", int_name, strerror(errno));
526     close(sock);
527     olsr_exit(EXIT_FAILURE);
528   }
529
530   memset(&sin6, 0, sizeof(sin6));
531   sin6.sin6_family = AF_INET6;
532   sin6.sin6_port = htons(olsr_cnf->olsr_port);
533   assert(0 == memcmp(&sin6.sin6_addr, &in6addr_any, sizeof(sin6.sin6_addr)));   /* == IN6ADDR_ANY_INIT */
534   if (bind(sock, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
535     OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs (%s)\n", strerror(errno));
536     close(sock);
537     olsr_exit(EXIT_FAILURE);
538   }
539
540   set_nonblocking(sock);
541   return sock;
542 }
543
544 int
545 join_mcast(struct interface *ifs, int sock)
546 {
547   /* See linux/in6.h */
548 #if !defined REMOVE_LOG_INFO
549   struct ipaddr_str buf;
550 #endif
551   struct ipv6_mreq mcastreq;
552
553   mcastreq.ipv6mr_multiaddr = ifs->int6_multaddr.sin6_addr;
554   mcastreq.ipv6mr_interface = ifs->if_index;
555
556   OLSR_INFO(LOG_NETWORKING, "Interface %s joining multicast %s\n", ifs->int_name,
557             ip6_to_string(&buf, &ifs->int6_multaddr.sin6_addr));
558   /* Send multicast */
559   if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
560       < 0) {
561     OLSR_WARN(LOG_NETWORKING, "Cannot join multicast group (%s)\n", strerror(errno));
562     return -1;
563   }
564 #if 0
565   /* Old libc fix */
566 #ifdef IPV6_JOIN_GROUP
567   /* Join reciever group */
568   if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
569       < 0)
570 #else
571   /* Join reciever group */
572   if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
573       < 0)
574 #endif
575   {
576     perror("Join multicast send");
577     return -1;
578   }
579 #endif
580   if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&mcastreq.ipv6mr_interface, sizeof(mcastreq.ipv6mr_interface))
581       < 0) {
582     OLSR_WARN(LOG_NETWORKING, "Cannot set multicast interface (%s)\n", strerror(errno));
583     return -1;
584   }
585
586   return 0;
587 }
588
589 /*
590  *From net-tools lib/interface.c
591  *
592  */
593 int
594 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int addrtype6)
595 {
596   int rv = 0;
597   FILE *f = fopen(_PATH_PROCNET_IFINET6, "r");
598   if (f != NULL) {
599     char devname[IFNAMSIZ];
600     char addr6p[8][5];
601     int plen, scope, dad_status, if_idx;
602     bool found = false;
603     while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
604                   addr6p[0], addr6p[1], addr6p[2], addr6p[3],
605                   addr6p[4], addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
606       if (strcmp(devname, ifname) == 0) {
607         char addr6[40];
608         sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
609                 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
610
611         if (addrtype6 == OLSR_IP6T_SITELOCAL && scope == IPV6_ADDR_SITELOCAL)
612           found = true;
613         else if (addrtype6 == OLSR_IP6T_UNIQUELOCAL && scope == IPV6_ADDR_GLOBAL)
614           found = true;
615         else if (addrtype6 == OLSR_IP6T_GLOBAL && scope == IPV6_ADDR_GLOBAL)
616           found = true;
617
618         if (found) {
619           found = false;
620           if (addr6p[0][0] == 'F' || addr6p[0][0] == 'f') {
621             if (addr6p[0][1] == 'C' || addr6p[0][1] == 'c' || addr6p[0][1] == 'D' || addr6p[0][1] == 'd')
622               found = true;
623           }
624           if (addrtype6 == OLSR_IP6T_SITELOCAL)
625             found = true;
626           else if (addrtype6 == OLSR_IP6T_UNIQUELOCAL && found)
627             found = true;
628           else if (addrtype6 == OLSR_IP6T_GLOBAL && !found)
629             found = true;
630           else
631             found = false;
632         }
633
634         if (found) {
635           inet_pton(AF_INET6, addr6, &saddr6->sin6_addr);
636           rv = 1;
637           break;
638         }
639       }
640     }
641     fclose(f);
642   }
643   return rv;
644 }
645
646
647 /**
648  * Wrapper for sendto(2)
649  */
650 ssize_t
651 olsr_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr * to, socklen_t tolen)
652 {
653   return sendto(s, buf, len, flags, to, tolen);
654 }
655
656 /**
657  * Wrapper for recvfrom(2)
658  */
659
660 ssize_t
661 olsr_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr * from, socklen_t * fromlen)
662 {
663   return recvfrom(s, buf, len, flags, from, fromlen);
664 }
665
666 /**
667  * Wrapper for select(2)
668  */
669
670 int
671 olsr_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
672 {
673   return select(nfds, readfds, writefds, exceptfds, timeout);
674 }
675
676 int
677 check_wireless_interface(char *ifname)
678 {
679   struct ifreq ifr;
680
681   memset(&ifr, 0, sizeof(ifr));
682   strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
683
684   return (ioctl(olsr_cnf->ioctl_s, SIOCGIWNAME, &ifr) >= 0) ? 1 : 0;
685 }
686
687 #if 0
688
689 #include <linux/sockios.h>
690 #include <linux/types.h>
691
692 /* This data structure is used for all the MII ioctl's */
693 struct mii_data {
694   __u16 phy_id;
695   __u16 reg_num;
696   __u16 val_in;
697   __u16 val_out;
698 };
699
700
701 /* Basic Mode Control Register */
702 #define MII_BMCR                0x00
703 #define  MII_BMCR_RESET         0x8000
704 #define  MII_BMCR_LOOPBACK      0x4000
705 #define  MII_BMCR_100MBIT       0x2000
706 #define  MII_BMCR_AN_ENA        0x1000
707 #define  MII_BMCR_ISOLATE       0x0400
708 #define  MII_BMCR_RESTART       0x0200
709 #define  MII_BMCR_DUPLEX        0x0100
710 #define  MII_BMCR_COLTEST       0x0080
711
712 /* Basic Mode Status Register */
713 #define MII_BMSR                0x01
714 #define  MII_BMSR_CAP_MASK      0xf800
715 #define  MII_BMSR_100BASET4     0x8000
716 #define  MII_BMSR_100BASETX_FD  0x4000
717 #define  MII_BMSR_100BASETX_HD  0x2000
718 #define  MII_BMSR_10BASET_FD    0x1000
719 #define  MII_BMSR_10BASET_HD    0x0800
720 #define  MII_BMSR_NO_PREAMBLE   0x0040
721 #define  MII_BMSR_AN_COMPLETE   0x0020
722 #define  MII_BMSR_REMOTE_FAULT  0x0010
723 #define  MII_BMSR_AN_ABLE       0x0008
724 #define  MII_BMSR_LINK_VALID    0x0004
725 #define  MII_BMSR_JABBER        0x0002
726 #define  MII_BMSR_EXT_CAP       0x0001
727
728 int
729 calculate_if_metric(char *ifname)
730 {
731   if (check_wireless_interface(ifname)) {
732     struct ifreq ifr;
733     strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
734
735     /* Get bit rate */
736     if (ioctl(olsr_cnf->ioctl_s, SIOCGIWRATE, &ifr) < 0) {
737       OLSR_PRINTF(1, "Not able to find rate for WLAN interface %s\n", ifname);
738       return WEIGHT_WLAN_11MB;
739     }
740
741     OLSR_PRINTF(1, "Bitrate %d\n", ifr.ifr_ifru.ifru_ivalue);
742
743     //WEIGHT_WLAN_LOW,          /* <11Mb WLAN     */
744     //WEIGHT_WLAN_11MB,         /* 11Mb 802.11b   */
745     //WEIGHT_WLAN_54MB,         /* 54Mb 802.11g   */
746     return WEIGHT_WLAN_LOW;
747   } else {
748     /* Ethernet */
749     /* Mii wizardry */
750     struct ifreq ifr;
751     struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
752     int bmcr;
753     memset(&ifr, 0, sizeof(ifr));
754     strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
755
756     if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
757       if (errno != ENODEV)
758         OLSR_PRINTF(1, "SIOCGMIIPHY on '%s' failed: %s\n", ifr.ifr_name, strerror(errno));
759       return WEIGHT_ETHERNET_DEFAULT;
760     }
761
762     mii->reg_num = MII_BMCR;
763     if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIREG, &ifr) < 0) {
764       OLSR_PRINTF(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name, strerror(errno));
765       return WEIGHT_ETHERNET_DEFAULT;
766     }
767     bmcr = mii->val_out;
768
769
770     OLSR_PRINTF(1, "%s: ", ifr.ifr_name);
771     OLSR_PRINTF(1, "%s Mbit, %s duplex\n", (bmcr & MII_BMCR_100MBIT) ? "100" : "10", (bmcr & MII_BMCR_DUPLEX) ? "full" : "half");
772
773     is_if_link_up(ifname);
774
775     if (mii->val_out & MII_BMCR_100MBIT)
776       return WEIGHT_ETHERNET_100MB;
777     else
778       return WEIGHT_ETHERNET_10MB;
779     //WEIGHT_ETHERNET_1GB,      /* Ethernet 1Gb   */
780
781   }
782 }
783
784
785 bool
786 is_if_link_up(char *ifname)
787 {
788   if (check_wireless_interface(ifname)) {
789     /* No link checking on wireless devices */
790     return true;
791   } else {
792     /* Mii wizardry */
793     struct ifreq ifr;
794     struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
795     int bmsr;
796     memset(&ifr, 0, sizeof(ifr));
797     strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
798
799     if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
800       if (errno != ENODEV)
801         OLSR_PRINTF(1, "SIOCGMIIPHY on '%s' failed: %s\n", ifr.ifr_name, strerror(errno));
802       return WEIGHT_ETHERNET_DEFAULT;
803     }
804     mii->reg_num = MII_BMSR;
805     if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIREG, &ifr) < 0) {
806       OLSR_PRINTF(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name, strerror(errno));
807       return WEIGHT_ETHERNET_DEFAULT;
808     }
809     bmsr = mii->val_out;
810
811     OLSR_PRINTF(1, "%s: ", ifr.ifr_name);
812     OLSR_PRINTF(1, "%s\n", (bmsr & MII_BMSR_LINK_VALID) ? "link ok " : "no link ");
813
814     return (bmsr & MII_BMSR_LINK_VALID);
815
816   }
817 }
818
819 #else
820 int
821 calculate_if_metric(char *ifname)
822 {
823   return check_wireless_interface(ifname);
824 }
825 #endif
826
827 /*
828  * Local Variables:
829  * c-basic-offset: 2
830  * indent-tabs-mode: nil
831  * End:
832  */