0f401f6786512cc8420751522e1f0bfc5686c305
[olsrd.git] / src / linux / net.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright 
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright 
13  *   notice, this list of conditions and the following disclaimer in 
14  *   the documentation and/or other materials provided with the 
15  *   distribution.
16  * * Neither the name of olsr.org, olsrd nor the names of its 
17  *   contributors may be used to endorse or promote products derived 
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Visit http://www.olsr.org for more information.
34  *
35  * If you find this software useful feel free to make a donation
36  * to the project. For more information see the website or contact
37  * the copyright holders.
38  *
39  */
40
41
42 /*
43  * Linux spesific code
44  */
45
46 #include "../net_os.h"
47 #include "../ipcalc.h"
48 #include "../common/string.h"
49 #include "../olsr_protocol.h"
50 #include "../misc.h"
51
52 #include <net/if.h>
53
54 #include <sys/ioctl.h>
55
56 #include <fcntl.h>
57 #include <string.h>
58 #include <stdio.h>
59 #include <syslog.h>
60 #include <errno.h>
61 #include <unistd.h>
62
63
64 /* Redirect proc entry */
65 #define REDIRECT_PROC "/proc/sys/net/ipv4/conf/%s/send_redirects"
66
67 /* IP spoof proc entry */
68 #define SPOOF_PROC "/proc/sys/net/ipv4/conf/%s/rp_filter"
69
70 /*
71  *Wireless definitions for ioctl calls
72  *(from linux/wireless.h)
73  */
74 #define SIOCGIWNAME     0x8B01          /* get name == wireless protocol */
75 #define SIOCGIWRATE     0x8B21          /* get default bit rate (bps) */
76
77 /* The original state of the IP forwarding proc entry */
78 static char orig_fwd_state;
79 static char orig_global_redirect_state;
80
81 /**
82  *Bind a socket to a device
83  *
84  *@param sock the socket to bind
85  *@param dev_name name of the device
86  *
87  *@return negative if error
88  */
89
90 int
91 bind_socket_to_device(int sock, char *dev_name)
92 {
93   /*
94    *Bind to device using the SO_BINDTODEVICE flag
95    */
96   OLSR_PRINTF(3, "Binding socket %d to device %s\n", sock, dev_name);
97   return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, dev_name, strlen(dev_name)+1);
98 }
99
100
101 /**
102  *Enable IP forwarding.
103  *Just writing "1" to the /proc/sys/net/ipv4/ip_forward
104  *if using IPv4 or /proc/sys/net/ipv6/conf/all/forwarding
105  *if using IPv6.
106  *Could probably drop the check for
107  *"0" here and write "1" anyways.
108  *
109  *@param version IP version.
110  *
111  *@return 1 on sucess 0 on failiure
112  */ 
113 int
114 enable_ip_forwarding(int version)
115 {
116   const char * const procfile = version == AF_INET
117       ? "/proc/sys/net/ipv4/ip_forward"
118       : "/proc/sys/net/ipv6/conf/all/forwarding";
119   FILE *proc_fwd = fopen(procfile, "r");
120
121   if (proc_fwd == NULL) {
122     fprintf(stderr,
123             "WARNING! Could not open the %s file to check/enable IP forwarding!\n"
124             "Are you using the procfile filesystem?\nDoes your system support IPv%d?\n"
125             "I will continue(in 3 sec) - but you should manually ensure that IP forwarding is enabled!\n\n",
126             procfile, version == AF_INET ? 4 : 6);
127     sleep(3);
128     return 0;
129   }
130   orig_fwd_state = fgetc(proc_fwd);
131   fclose(proc_fwd);
132
133   if(orig_fwd_state == '1') {
134     OLSR_PRINTF(3, "\nIP forwarding is enabled on this system\n");
135   } else {
136     proc_fwd = fopen(procfile, "w");
137     if (proc_fwd == NULL) {
138       fprintf(stderr, "Could not open %s for writing!\n", procfile);
139       fprintf(stderr, "I will continue(in 3 sec) - but you should manually ensure that IP forwarding is enabeled!\n\n");
140       sleep(3);
141       return 0;
142     }
143     syslog(LOG_INFO, "Writing \"1\" to %s\n", procfile);
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     fprintf(stderr,
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     fprintf(stderr, "Could not open %s for writing!\n", procfile);
178     fprintf(stderr, "I will continue(in 3 sec) - but you should manually ensure that ICMP redirect is disabled!\n\n");
179     sleep(3);
180     return 0;
181   }
182   syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
183   fputs("0", proc_redirect);
184   fclose(proc_redirect);  
185   return 1;
186 }
187
188 /**
189  *
190  *@return 1 on sucess 0 on failiure
191  */ 
192 int
193 disable_redirects(const char *if_name, struct interface *iface, int version)
194 {
195   FILE *proc_redirect;
196   char procfile[FILENAME_MAX];
197
198   if (version == AF_INET6) {
199     return -1;
200   }
201
202   /* Generate the procfile name */
203   snprintf(procfile, sizeof(procfile), REDIRECT_PROC, if_name);
204
205   proc_redirect = fopen(procfile, "r");
206   if (proc_redirect == NULL) {
207     fprintf(stderr,
208             "WARNING! Could not open the %s file to check/disable ICMP redirects!\n"
209             "Are you using the procfile filesystem?\n"
210             "Does your system support IPv4?\n"
211             "I will continue(in 3 sec) - but you should manually ensure that ICMP redirects are disabled!\n\n", procfile);      
212     sleep(3);
213     return 0;
214   }
215   iface->nic_state.redirect = fgetc(proc_redirect);
216   fclose(proc_redirect);      
217
218   proc_redirect = fopen(procfile, "w");
219   if (proc_redirect == NULL) {
220     fprintf(stderr, "Could not open %s for writing!\n", procfile);
221     fprintf(stderr, "I will continue(in 3 sec) - but you should manually ensure that ICMP redirect is disabled!\n\n");
222     sleep(3);
223     return 0;
224   }
225   syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
226   fputs("0", proc_redirect);
227   fclose(proc_redirect);
228   return 1;
229 }
230
231 /**
232  *
233  *@return 1 on sucess 0 on failiure
234  */ 
235 int
236 deactivate_spoof(const char *if_name, struct interface *iface, int version)
237 {
238   FILE *proc_spoof;
239   char procfile[FILENAME_MAX];
240
241   if(version == AF_INET6) {
242     return -1;
243   }
244
245   /* Generate the procfile name */
246   sprintf(procfile, SPOOF_PROC, if_name);
247
248   proc_spoof = fopen(procfile, "r");
249   if (proc_spoof == NULL) {
250     fprintf(stderr,
251             "WARNING! Could not open the %s file to check/disable the IP spoof filter!\n"
252             "Are you using the procfile filesystem?\n"
253             "Does your system support IPv4?\n"
254             "I will continue(in 3 sec) - but you should manually ensure that IP spoof filtering is disabled!\n\n", procfile);
255     sleep(3);
256     return 0;
257   }
258   iface->nic_state.spoof = fgetc(proc_spoof);
259   fclose(proc_spoof);
260
261   proc_spoof = fopen(procfile, "w");
262   if (proc_spoof == NULL) {
263     fprintf(stderr, "Could not open %s for writing!\n", procfile);
264     fprintf(stderr, "I will continue(in 3 sec) - but you should manually ensure that IP spoof filtering is disabled!\n\n");
265     sleep(3);
266     return 0;
267   }
268   syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
269   fputs("0", proc_spoof);
270   fclose(proc_spoof);
271   return 1;
272 }
273
274 /**
275  *Resets the spoof filter and ICMP redirect settings
276  */
277 int
278 restore_settings(int version)
279 {
280   struct interface *ifs;
281
282   OLSR_PRINTF(1, "Restoring network state\n");
283
284   /* Restore IP forwarding to "off" */
285   if (orig_fwd_state == '0') {
286     const char * const procfile = version == AF_INET
287         ? "/proc/sys/net/ipv4/ip_forward"
288         : "/proc/sys/net/ipv6/conf/all/forwarding";
289     FILE *proc_fd = fopen(procfile, "w");
290
291     if (proc_fd == NULL) {
292       fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
293     } else {
294       syslog(LOG_INFO, "Resetting %s to %c\n", procfile, orig_fwd_state);
295       fputc(orig_fwd_state, proc_fd);
296       fclose(proc_fd);
297     }
298   }
299
300   /* Restore global ICMP redirect setting */
301   if(orig_global_redirect_state != '0') {
302     if(version == AF_INET) {
303       const char * const procfile = "/proc/sys/net/ipv4/conf/all/send_redirects";
304       FILE *proc_fd = fopen(procfile, "w");
305
306       if (proc_fd == NULL) {
307         fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
308       } else {
309         syslog(LOG_INFO, "Resetting %s to %c\n", procfile, orig_global_redirect_state);
310         fputc(orig_global_redirect_state, proc_fd);
311         fclose(proc_fd);
312       }
313     }
314   }
315
316   if (version == AF_INET6) {
317     return 0;
318   }
319
320   for(ifs = ifnet; ifs != NULL; ifs = ifs->int_next) {
321     char procfile[FILENAME_MAX];
322     FILE *proc_fd;
323     /* Ignore host-emulation interfaces */
324     if (ifs->is_hcif) {
325         continue;
326     }
327     /* ICMP redirects */
328       
329     /* Generate the procfile name */
330     snprintf(procfile, sizeof(procfile), REDIRECT_PROC, ifs->int_name);
331     proc_fd = fopen(procfile, "w");
332     if (proc_fd == NULL) {
333       fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
334     } else {
335       syslog(LOG_INFO, "Resetting %s to %c\n", procfile, ifs->nic_state.redirect);
336
337       fputc(ifs->nic_state.redirect, proc_fd);
338       fclose(proc_fd);
339     }
340       
341     /* Spoof filter */
342       
343     /* Generate the procfile name */
344     sprintf(procfile, SPOOF_PROC, ifs->int_name);
345     proc_fd = fopen(procfile, "w");
346     if (proc_fd == NULL) {
347       fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
348     } else {
349       syslog(LOG_INFO, "Resetting %s to %c\n", procfile, ifs->nic_state.spoof);
350
351       fputc(ifs->nic_state.spoof, proc_fd);
352       fclose(proc_fd);
353     }
354   }
355   return 1;
356 }
357
358 /**
359  *Creates a blocking tcp socket for communication with switch daemon.
360  *@param sa sockaddr struct. Used for bind(2).
361  *@return the FD of the socket or -1 on error.
362  */
363 int
364 gethemusocket(struct sockaddr_in *pin)
365 {
366   int sock, on;
367
368   OLSR_PRINTF(1, "       Connecting to switch daemon port 10150...");
369   if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
370     perror("hcsocket");
371     syslog(LOG_ERR, "hcsocket: %m");
372     return -1;
373   }
374
375   on = 1;
376   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
377     perror("SO_REUSEADDR failed");
378     close(sock);
379     return -1;
380   }
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 /**
399  *Creates a nonblocking broadcast socket.
400  *@param sa sockaddr struct. Used for bind(2).
401  *@return the FD of the socket or -1 on error.
402  */
403 int
404 getsocket(int bufspace, char *int_name)
405 {
406   struct sockaddr_in sin4;
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
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
431 #ifdef SO_RCVBUF
432   for (on = bufspace; ; on -= 1024) {
433     if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) {
434       break;
435     }
436     if (on <= 8*1024) {
437       perror("setsockopt");
438       syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
439       break;
440     }
441   }
442 #endif
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, 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(&sin4, 0, sizeof(sin4));
457   sin4.sin_family = AF_INET;
458   sin4.sin_port = htons(OLSRPORT);
459   sin4.sin_addr.s_addr = INADDR_ANY;
460   if (bind(sock, (struct sockaddr *)&sin4, sizeof(sin4)) < 0) {
461     perror("bind");
462     syslog(LOG_ERR, "bind: %m");
463     close(sock);
464     return -1;
465   }
466
467   set_nonblocking(sock);
468   return sock;
469 }
470
471
472 /**
473  *Creates a nonblocking IPv6 socket
474  *@param sin sockaddr_in6 struct. Used for bind(2).
475  *@return the FD of the socket or -1 on error.
476  */
477 int
478 getsocket6(int bufspace, char *int_name)
479 {
480   struct sockaddr_in6 sin6;
481   int on;
482   int sock = socket(AF_INET6, SOCK_DGRAM, 0);
483   if (sock < 0) {
484     perror("socket");
485     syslog(LOG_ERR, "socket: %m");
486     return (-1);
487   }
488
489 #ifdef IPV6_V6ONLY
490   on = 1;
491   if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
492     perror("setsockopt(IPV6_V6ONLY)");
493     syslog(LOG_ERR, "setsockopt(IPV6_V6ONLY): %m");
494   }
495 #endif
496
497
498   //#ifdef SO_BROADCAST
499   /*
500   if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof(on)) < 0)
501     {
502       perror("setsockopt");
503       syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
504       close(sock);
505       return (-1);
506     }
507   */
508   //#endif
509
510 #ifdef SO_RCVBUF
511   for (on = bufspace; ; on -= 1024) {
512     if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) {
513       break;
514     }
515     if (on <= 8*1024) {
516       perror("setsockopt");
517       syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
518       break;
519     }
520   }
521 #endif
522
523   on = 1;
524   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
525     perror("SO_REUSEADDR failed");
526     close(sock);
527     return (-1);
528   }
529
530   /*
531    * we are abusing "on" here. The value is 1 which is our intended
532    * hop limit value.
533    */
534   if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &on, sizeof(on)) < 0) {
535     perror ("setsockopt");
536     close(sock);
537     return (-1);
538   }
539
540
541   /*
542    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
543    */
544
545   /* Bind to device */
546   if(bind_socket_to_device(sock, int_name) < 0) {
547     fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
548     syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
549     close(sock);
550     return -1;
551   }
552
553   memset(&sin6, 0, sizeof(sin6));
554   sin6.sin6_family = AF_INET6;
555   sin6.sin6_port = htons(OLSRPORT);
556   //(addrsock6.sin6_addr).s_addr = IN6ADDR_ANY_INIT;
557   if (bind(sock, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
558     perror("bind");
559     syslog(LOG_ERR, "bind: %m");
560     close(sock);
561     return (-1);
562   }
563
564   set_nonblocking(sock);
565   return sock;
566 }
567
568 int
569 join_mcast(struct interface *ifs, int sock)
570 {
571   /* See linux/in6.h */
572   struct ipaddr_str buf;
573   struct ipv6_mreq mcastreq;
574
575   mcastreq.ipv6mr_multiaddr = ifs->int6_multaddr.sin6_addr;
576   mcastreq.ipv6mr_interface = ifs->if_index;
577
578 #if !defined __FreeBSD__ && !defined __MacOSX__ && !defined __NetBSD__
579   OLSR_PRINTF(3, "Interface %s joining multicast %s...", ifs->int_name, ip6_to_string(&buf, &ifs->int6_multaddr.sin6_addr));
580   /* Send multicast */
581   if(setsockopt(sock, 
582                 IPPROTO_IPV6, 
583                 IPV6_ADD_MEMBERSHIP, 
584                 (char *)&mcastreq, 
585                 sizeof(struct ipv6_mreq)) 
586      < 0)
587     {
588       perror("Join multicast");
589       return -1;
590     }
591 #else
592 #warning implement IPV6_ADD_MEMBERSHIP
593 #endif
594
595   /* Old libc fix */
596 #ifdef IPV6_JOIN_GROUP
597   /* Join reciever group */
598   if(setsockopt(sock, 
599                 IPPROTO_IPV6, 
600                 IPV6_JOIN_GROUP, 
601                 (char *)&mcastreq, 
602                 sizeof(struct ipv6_mreq)) 
603      < 0)
604 #else
605   /* Join reciever group */
606   if(setsockopt(sock, 
607                 IPPROTO_IPV6, 
608                 IPV6_ADD_MEMBERSHIP, 
609                 (char *)&mcastreq, 
610                 sizeof(struct ipv6_mreq)) 
611      < 0)
612 #endif 
613     {
614       perror("Join multicast send");
615       return -1;
616     }  
617
618   if(setsockopt(sock, 
619                 IPPROTO_IPV6, 
620                 IPV6_MULTICAST_IF, 
621                 (char *)&mcastreq.ipv6mr_interface, 
622                 sizeof(mcastreq.ipv6mr_interface)) 
623      < 0)
624     {
625       perror("Set multicast if");
626       return -1;
627     }
628
629
630   OLSR_PRINTF(3, "OK\n");
631   return 0;
632 }
633
634 /*
635  *From net-tools lib/interface.c
636  *
637  */
638 int
639 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int addrtype6)
640 {
641   int rv = 0;
642   FILE *f = fopen(_PATH_PROCNET_IFINET6, "r");
643   if (f != NULL) {
644     char devname[IFNAMSIZ];
645     char addr6p[8][5];
646     int plen, scope, dad_status, if_idx;
647     olsr_bool found = OLSR_FALSE;
648     while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
649                   addr6p[0], addr6p[1], addr6p[2], addr6p[3],
650                   addr6p[4], addr6p[5], addr6p[6], addr6p[7],
651                   &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
652       if (strcmp(devname, ifname) == 0) {
653         char addr6[40];
654         sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
655                 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
656                 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
657         OLSR_PRINTF(5, "\tinet6 addr: %s\n", addr6);
658         OLSR_PRINTF(5, "\tScope: %d\n", scope);
659
660         if (addrtype6 == OLSR_IP6T_SITELOCAL && scope == IPV6_ADDR_SITELOCAL) found = OLSR_TRUE;
661         else if (addrtype6 == OLSR_IP6T_UNIQUELOCAL && scope == IPV6_ADDR_GLOBAL) found = OLSR_TRUE;
662         else if (addrtype6 == OLSR_IP6T_GLOBAL && scope == IPV6_ADDR_GLOBAL) found = OLSR_TRUE;
663
664         if (found == OLSR_TRUE) {
665           found = OLSR_FALSE;
666           if (addr6p[0][0] == 'F' || addr6p[0][0] == 'f') {
667             if (addr6p[0][1] == 'C' || addr6p[0][1] == 'c' ||
668                 addr6p[0][1] == 'D' || addr6p[0][1] == 'd') found = OLSR_TRUE;
669           }
670           if(addrtype6 == OLSR_IP6T_SITELOCAL) found = OLSR_TRUE;
671           else if(addrtype6 == OLSR_IP6T_UNIQUELOCAL && found == OLSR_TRUE) found = OLSR_TRUE;
672           else if(addrtype6 == OLSR_IP6T_GLOBAL && found == OLSR_FALSE) found = OLSR_TRUE;
673           else found = OLSR_FALSE;
674         }
675
676         if (found == OLSR_TRUE) {
677           OLSR_PRINTF(4, "Found addr: %s:%s:%s:%s:%s:%s:%s:%s\n",
678                       addr6p[0], addr6p[1], addr6p[2], addr6p[3],
679                       addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
680           inet_pton(AF_INET6, addr6, saddr6);
681           rv = 1;
682           break;
683         }
684       }
685     }
686     fclose(f);
687   }
688   return rv;
689 }
690
691
692 /**
693  * Wrapper for sendto(2)
694  */
695 ssize_t
696 olsr_sendto(int s, 
697             const void *buf, 
698             size_t len, 
699             int flags, 
700             const struct sockaddr *to, 
701             socklen_t tolen)
702 {
703   return sendto(s, buf, len, flags, to, tolen);
704 }
705
706 /**
707  * Wrapper for recvfrom(2)
708  */
709
710 ssize_t  
711 olsr_recvfrom(int  s, 
712               void *buf, 
713               size_t len, 
714               int flags, 
715               struct sockaddr *from,
716               socklen_t *fromlen)
717 {
718   return recvfrom(s, 
719                   buf, 
720                   len, 
721                   flags, 
722                   from, 
723                   fromlen);
724 }
725
726 /**
727  * Wrapper for select(2)
728  */
729
730 int
731 olsr_select(int nfds,
732             fd_set *readfds,
733             fd_set *writefds,
734             fd_set *exceptfds,
735             struct timeval *timeout)
736 {
737   return select(nfds,
738                 readfds,
739                 writefds,
740                 exceptfds,
741                 timeout);
742 }
743
744 int
745 check_wireless_interface(char * ifname)
746 {
747   struct ifreq ifr;
748
749   memset(&ifr, 0, sizeof(ifr));
750   strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
751
752   return (ioctl(olsr_cnf->ioctl_s, SIOCGIWNAME, &ifr) >= 0) ? 1 : 0;
753 }
754
755 #if 0
756
757 #include <linux/sockios.h>
758 #include <linux/types.h>
759
760 /* This data structure is used for all the MII ioctl's */
761 struct mii_data {
762     __u16       phy_id;
763     __u16       reg_num;
764     __u16       val_in;
765     __u16       val_out;
766 };
767
768
769 /* Basic Mode Control Register */
770 #define MII_BMCR                0x00
771 #define  MII_BMCR_RESET         0x8000
772 #define  MII_BMCR_LOOPBACK      0x4000
773 #define  MII_BMCR_100MBIT       0x2000
774 #define  MII_BMCR_AN_ENA        0x1000
775 #define  MII_BMCR_ISOLATE       0x0400
776 #define  MII_BMCR_RESTART       0x0200
777 #define  MII_BMCR_DUPLEX        0x0100
778 #define  MII_BMCR_COLTEST       0x0080
779
780 /* Basic Mode Status Register */
781 #define MII_BMSR                0x01
782 #define  MII_BMSR_CAP_MASK      0xf800
783 #define  MII_BMSR_100BASET4     0x8000
784 #define  MII_BMSR_100BASETX_FD  0x4000
785 #define  MII_BMSR_100BASETX_HD  0x2000
786 #define  MII_BMSR_10BASET_FD    0x1000
787 #define  MII_BMSR_10BASET_HD    0x0800
788 #define  MII_BMSR_NO_PREAMBLE   0x0040
789 #define  MII_BMSR_AN_COMPLETE   0x0020
790 #define  MII_BMSR_REMOTE_FAULT  0x0010
791 #define  MII_BMSR_AN_ABLE       0x0008
792 #define  MII_BMSR_LINK_VALID    0x0004
793 #define  MII_BMSR_JABBER        0x0002
794 #define  MII_BMSR_EXT_CAP       0x0001
795
796 int
797 calculate_if_metric(char *ifname)
798 {
799   if(check_wireless_interface(ifname))
800     {
801       struct ifreq ifr;
802       strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
803       
804       /* Get bit rate */
805       if(ioctl(olsr_cnf->ioctl_s, SIOCGIWRATE, &ifr) < 0)
806         {
807           OLSR_PRINTF(1, "Not able to find rate for WLAN interface %s\n", ifname);
808           return WEIGHT_WLAN_11MB;
809         }
810       
811       OLSR_PRINTF(1, "Bitrate %d\n", ifr.ifr_ifru.ifru_ivalue);
812
813       //WEIGHT_WLAN_LOW,          /* <11Mb WLAN     */
814       //WEIGHT_WLAN_11MB,         /* 11Mb 802.11b   */
815       //WEIGHT_WLAN_54MB,         /* 54Mb 802.11g   */
816       return WEIGHT_WLAN_LOW;
817     }
818   else
819     {
820       /* Ethernet */
821       /* Mii wizardry */
822       struct ifreq ifr;
823       struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
824       int bmcr;
825       memset(&ifr, 0, sizeof(ifr));
826       strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
827
828       if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
829         if (errno != ENODEV)
830           OLSR_PRINTF(1, "SIOCGMIIPHY on '%s' failed: %s\n",
831                       ifr.ifr_name, strerror(errno));
832         return WEIGHT_ETHERNET_DEFAULT;
833       }
834
835       mii->reg_num = MII_BMCR;
836       if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIREG, &ifr) < 0) {
837         OLSR_PRINTF(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
838                     strerror(errno));
839         return WEIGHT_ETHERNET_DEFAULT;
840       }
841       bmcr = mii->val_out;
842
843
844       OLSR_PRINTF(1, "%s: ", ifr.ifr_name);
845       OLSR_PRINTF(1, "%s Mbit, %s duplex\n",
846                   (bmcr & MII_BMCR_100MBIT) ? "100" : "10",
847                   (bmcr & MII_BMCR_DUPLEX) ? "full" : "half");
848     
849       is_if_link_up(ifname);
850
851       if(mii->val_out & MII_BMCR_100MBIT)
852         return WEIGHT_ETHERNET_100MB;
853       else
854         return WEIGHT_ETHERNET_10MB;
855       //WEIGHT_ETHERNET_1GB,      /* Ethernet 1Gb   */
856
857     }
858 }
859
860
861 olsr_bool
862 is_if_link_up(char *ifname)
863 {
864   if(check_wireless_interface(ifname))
865     {
866       /* No link checking on wireless devices */
867       return OLSR_TRUE;
868     }
869   else
870     {
871       /* Mii wizardry */
872       struct ifreq ifr;
873       struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
874       int bmsr;
875       memset(&ifr, 0, sizeof(ifr));
876       strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
877
878       if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
879         if (errno != ENODEV)
880           OLSR_PRINTF(1, "SIOCGMIIPHY on '%s' failed: %s\n",
881                       ifr.ifr_name, strerror(errno));
882         return WEIGHT_ETHERNET_DEFAULT;
883       }
884       mii->reg_num = MII_BMSR;
885       if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIREG, &ifr) < 0) {
886         OLSR_PRINTF(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
887                     strerror(errno));
888         return WEIGHT_ETHERNET_DEFAULT;
889       }
890       bmsr = mii->val_out;
891
892       OLSR_PRINTF(1, "%s: ", ifr.ifr_name);
893       OLSR_PRINTF(1, "%s\n", (bmsr & MII_BMSR_LINK_VALID) ? "link ok " : "no link ");
894     
895       return (bmsr & MII_BMSR_LINK_VALID);
896
897     }
898 }
899
900 #else
901 int
902 calculate_if_metric(char *ifname)
903 {
904   return check_wireless_interface(ifname);
905 }
906 #endif
907   
908 /*
909  * Local Variables:
910  * c-basic-offset: 2
911  * indent-tabs-mode: nil
912  * End:
913  */