820c2c4ba8903afe2cf9799d4229c4c8f95c1d55
[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 "../net_os.h"
47 #include "../ipcalc.h"
48 #include "../olsr.h"
49
50 #include <net/if.h>
51
52 #include <sys/ioctl.h>
53
54 #include <fcntl.h>
55 #include <string.h>
56 #include <stdio.h>
57 #include <syslog.h>
58 #include <unistd.h>
59
60 #define IPV6_ADDR_LOOPBACK      0x0010U
61 #define IPV6_ADDR_LINKLOCAL     0x0020U
62 #define IPV6_ADDR_SITELOCAL     0x0040U
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 /* list of IPv6 interfaces */
71 #define PATH_PROCNET_IFINET6           "/proc/net/if_inet6"
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 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_PRINTF(3, "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  *Enable IP forwarding.
105  *Just writing "1" to the /proc/sys/net/ipv4/ip_forward
106  *if using IPv4 or /proc/sys/net/ipv6/conf/all/forwarding
107  *if using IPv6.
108  *Could probably drop the check for
109  *"0" here and write "1" anyways.
110  *
111  *@param version IP version.
112  *
113  *@return 1 on sucess 0 on failiure
114  */
115 int
116 enable_ip_forwarding(int version)
117 {
118   FILE *proc_fwd;
119   const char *const procfile = version == AF_INET ? "/proc/sys/net/ipv4/ip_forward" : "/proc/sys/net/ipv6/conf/all/forwarding";
120
121   if ((proc_fwd = fopen(procfile, "r")) == NULL) {
122     /* IPv4 */
123     if (version == AF_INET)
124       fprintf(stderr,
125               "WARNING! Could not open the %s file to check/enable IP forwarding!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that IP forwarding is enabeled!\n\n",
126               procfile);
127     /* IPv6 */
128     else
129       fprintf(stderr,
130               "WARNING! Could not open the %s file to check/enable IP forwarding!\nAre you using the procfile filesystem?\nDoes your system support IPv6?\nI will continue(in 3 sec) - but you should mannually ensure that IP forwarding is enabeled!\n\n",
131               procfile);
132
133     olsr_startup_sleep(3);
134     return 0;
135   }
136
137   orig_fwd_state = fgetc(proc_fwd);
138   fclose(proc_fwd);
139   if (orig_fwd_state == '1') {
140     OLSR_PRINTF(3, "\nIP forwarding is enabled on this system\n");
141   } else {
142     if ((proc_fwd = fopen(procfile, "w")) == NULL) {
143       fprintf(stderr, "Could not open %s for writing!\n", procfile);
144       fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that IP forwarding is enabeled!\n\n");
145       olsr_startup_sleep(3);
146       return 0;
147     } else {
148       syslog(LOG_INFO, "Writing \"1\" to %s\n", procfile);
149       fputs("1", proc_fwd);
150     }
151     fclose(proc_fwd);
152   }
153   return 1;
154 }
155
156 int
157 disable_redirects_global(int version)
158 {
159   FILE *proc_redirect;
160   const char *const procfile = "/proc/sys/net/ipv4/conf/all/send_redirects";
161
162   if (version == AF_INET6)
163     return -1;
164
165   if ((proc_redirect = fopen(procfile, "r")) == NULL) {
166     fprintf(stderr,
167             "WARNING! Could not open the %s file to check/disable ICMP redirects!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that ICMP redirects are disabled!\n\n",
168             procfile);
169
170     olsr_startup_sleep(3);
171     return -1;
172   }
173   orig_global_redirect_state = fgetc(proc_redirect);
174   fclose(proc_redirect);
175
176   if (orig_global_redirect_state == '0')
177     return 0;
178
179   if ((proc_redirect = fopen(procfile, "w")) == NULL) {
180     fprintf(stderr, "Could not open %s for writing!\n", procfile);
181     fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that ICMP redirect is disabeled!\n\n");
182     olsr_startup_sleep(3);
183     return 0;
184   }
185   syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
186   fputs("0", proc_redirect);
187   fclose(proc_redirect);
188   return 1;
189 }
190
191 /**
192  *
193  *@return 1 on sucess 0 on failiure
194  */
195 int
196 disable_redirects(const char *if_name, struct interface *iface, int version)
197 {
198   FILE *proc_redirect;
199   char procfile[FILENAME_MAX];
200
201   if (version == AF_INET6)
202     return -1;
203
204   /* Generate the procfile name */
205   snprintf(procfile, sizeof(procfile), REDIRECT_PROC, if_name);
206
207   if ((proc_redirect = fopen(procfile, "r")) == NULL) {
208     fprintf(stderr,
209             "WARNING! Could not open the %s file to check/disable ICMP redirects!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that ICMP redirects are disabled!\n\n",
210             procfile);
211     olsr_startup_sleep(3);
212     return 0;
213   }
214   iface->nic_state.redirect = fgetc(proc_redirect);
215   fclose(proc_redirect);
216
217   if ((proc_redirect = fopen(procfile, "w")) == NULL) {
218     fprintf(stderr, "Could not open %s for writing!\n", procfile);
219     fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that ICMP redirect is disabeled!\n\n");
220     olsr_startup_sleep(3);
221     return 0;
222   }
223   syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
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   /* Generate the procfile name */
243   sprintf(procfile, SPOOF_PROC, if_name);
244
245   if ((proc_spoof = fopen(procfile, "r")) == NULL) {
246     fprintf(stderr,
247             "WARNING! Could not open the %s file to check/disable the IP spoof filter!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that IP spoof filtering is disabled!\n\n",
248             procfile);
249
250     olsr_startup_sleep(3);
251     return 0;
252   }
253   iface->nic_state.spoof = fgetc(proc_spoof);
254   fclose(proc_spoof);
255
256   if ((proc_spoof = fopen(procfile, "w")) == NULL) {
257     fprintf(stderr, "Could not open %s for writing!\n", procfile);
258     fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that IP spoof filtering is disabeled!\n\n");
259     olsr_startup_sleep(3);
260     return 0;
261   }
262   syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
263   fputs("0", proc_spoof);
264   fclose(proc_spoof);
265   return 1;
266 }
267
268 /**
269  *Resets the spoof filter and ICMP redirect settings
270  */
271 int
272 restore_settings(int version)
273 {
274   struct interface *ifs;
275
276   OLSR_PRINTF(1, "Restoring network state\n");
277
278   /* Restore IP forwarding to "off" */
279   if (orig_fwd_state == '0') {
280     const char *const procfile = version == AF_INET ? "/proc/sys/net/ipv4/ip_forward" : "/proc/sys/net/ipv6/conf/all/forwarding";
281     FILE *proc_fd;
282
283     if ((proc_fd = fopen(procfile, "w")) == NULL) {
284       fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
285     } else {
286       syslog(LOG_INFO, "Resetting %s to %c\n", procfile, orig_fwd_state);
287       fputc(orig_fwd_state, proc_fd);
288       fclose(proc_fd);
289     }
290   }
291
292   /* Restore global ICMP redirect setting */
293   if (orig_global_redirect_state != '0') {
294     if (version == AF_INET) {
295       const char *const procfile = "/proc/sys/net/ipv4/conf/all/send_redirects";
296       FILE *proc_fd;
297
298       if ((proc_fd = fopen(procfile, "w")) == NULL) {
299         fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
300       } else {
301         syslog(LOG_INFO, "Resetting %s to %c\n", procfile, orig_global_redirect_state);
302         fputc(orig_global_redirect_state, proc_fd);
303         fclose(proc_fd);
304       }
305     }
306   }
307
308   if (version == AF_INET6)
309     return 0;
310
311   for (ifs = ifnet; ifs != NULL; ifs = ifs->int_next) {
312     char procfile[FILENAME_MAX];
313     FILE *proc_fd;
314     /* Discard host-emulation interfaces */
315     if (ifs->is_hcif)
316       continue;
317     /* ICMP redirects */
318
319     /* Generate the procfile name */
320     snprintf(procfile, sizeof(procfile), REDIRECT_PROC, ifs->int_name);
321
322     if ((proc_fd = fopen(procfile, "w")) == NULL)
323       fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
324     else {
325       syslog(LOG_INFO, "Resetting %s to %c\n", procfile, ifs->nic_state.redirect);
326
327       fputc(ifs->nic_state.redirect, proc_fd);
328       fclose(proc_fd);
329     }
330
331     /* Spoof filter */
332
333     /* Generate the procfile name */
334     sprintf(procfile, SPOOF_PROC, ifs->int_name);
335     if ((proc_fd = fopen(procfile, "w")) == NULL)
336       fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
337     else {
338       syslog(LOG_INFO, "Resetting %s to %c\n", procfile, ifs->nic_state.spoof);
339
340       fputc(ifs->nic_state.spoof, proc_fd);
341       fclose(proc_fd);
342     }
343   }
344   return 1;
345 }
346
347 /**
348  *Creates a blocking tcp socket for communication with switch daemon.
349  *@param sa sockaddr struct. Used for bind(2).
350  *@return the FD of the socket or -1 on error.
351  */
352 int
353 gethemusocket(struct sockaddr_in *pin)
354 {
355   int sock, on = 1;
356
357   OLSR_PRINTF(1, "       Connecting to switch daemon port 10150...");
358   if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
359     perror("hcsocket");
360     syslog(LOG_ERR, "hcsocket: %m");
361     return -1;
362   }
363
364   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
365     perror("SO_REUSEADDR failed");
366     close(sock);
367     return -1;
368   }
369   /* connect to PORT on HOST */
370   if (connect(sock, (struct sockaddr *)pin, sizeof(*pin)) < 0) {
371     printf("FAILED\n");
372     fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
373     printf("connection refused\n");
374     close(sock);
375     return -1;
376   }
377
378   printf("OK\n");
379
380   /* Keep TCP socket blocking */
381   return sock;
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, struct interface *ifp)
391 {
392   struct sockaddr_in sin;
393   int on;
394   int sock = socket(AF_INET, SOCK_DGRAM, 0);
395   if (sock < 0) {
396     perror("socket");
397     syslog(LOG_ERR, "socket: %m");
398     return -1;
399   }
400
401   on = 1;
402 #ifdef SO_BROADCAST
403   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
404     perror("setsockopt");
405     syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
406     close(sock);
407     return -1;
408   }
409 #endif
410
411   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
412     perror("SO_REUSEADDR failed");
413     close(sock);
414     return -1;
415   }
416 #ifdef SO_RCVBUF
417   if(bufspace > 0) {
418     for (on = bufspace;; on -= 1024) {
419       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0)
420         break;
421       if (on <= 8 * 1024) {
422         perror("setsockopt");
423         syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
424         break;
425       }
426     }
427   }
428 #endif
429
430   /*
431    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
432    */
433
434   /* Bind to device */
435   if (bind_socket_to_device(sock, ifp->int_name) < 0) {
436     fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
437     syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
438     close(sock);
439     return -1;
440   }
441
442   memset(&sin, 0, sizeof(sin));
443   sin.sin_family = AF_INET;
444   sin.sin_port = htons(olsr_cnf->olsrport);
445
446   if(bufspace <= 0) {
447     sin.sin_addr.s_addr = ifp->int_addr.sin_addr.s_addr;
448   }
449
450   if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
451     perror("bind");
452     syslog(LOG_ERR, "bind: %m");
453     close(sock);
454     return -1;
455   }
456
457   on = fcntl(sock, F_GETFL);
458   if (on == -1) {
459     syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
460   } else {
461     if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
462       syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
463     }
464   }
465   return sock;
466 }
467
468 /**
469  *Creates a nonblocking IPv6 socket
470  *@param sin sockaddr_in6 struct. Used for bind(2).
471  *@return the FD of the socket or -1 on error.
472  */
473 int
474 getsocket6(int bufspace, struct interface *ifp)
475 {
476   struct sockaddr_in6 sin;
477   int on;
478   int sock = socket(AF_INET6, SOCK_DGRAM, 0);
479   if (sock < 0) {
480     perror("socket");
481     syslog(LOG_ERR, "socket: %m");
482     return (-1);
483   }
484 #ifdef IPV6_V6ONLY
485   on = 1;
486   if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
487     perror("setsockopt(IPV6_V6ONLY)");
488     syslog(LOG_ERR, "setsockopt(IPV6_V6ONLY): %m");
489   }
490 #endif
491
492   //#ifdef SO_BROADCAST
493   /*
494      if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof (on)) < 0)
495      {
496      perror("setsockopt");
497      syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
498      close(sock);
499      return (-1);
500      }
501    */
502   //#endif
503
504 #ifdef SO_RCVBUF
505   if(bufspace > 0) {
506     for (on = bufspace;; on -= 1024) {
507       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0)
508         break;
509       if (on <= 8 * 1024) {
510         perror("setsockopt");
511         syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
512         break;
513       }
514     }
515   }
516 #endif
517
518   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
519     perror("SO_REUSEADDR failed");
520     close(sock);
521     return (-1);
522   }
523
524   /*
525    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
526    */
527
528   /* Bind to device */
529   if (bind_socket_to_device(sock, ifp->int_name) < 0) {
530     fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
531     syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
532     close(sock);
533     return -1;
534   }
535
536   memset(&sin, 0, sizeof(sin));
537   sin.sin6_family = AF_INET6;
538   sin.sin6_port = htons(olsr_cnf->olsrport);
539
540   if(bufspace <= 0) {
541     memcpy(&sin.sin6_addr, &ifp->int6_addr.sin6_addr, sizeof(struct in6_addr));
542   }
543
544   if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
545     perror("bind");
546     syslog(LOG_ERR, "bind: %m");
547     close(sock);
548     return (-1);
549   }
550
551   on = fcntl(sock, F_GETFL);
552   if (on == -1) {
553     syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
554   } else {
555     if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
556       syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
557     }
558   }
559   return sock;
560 }
561
562 int
563 join_mcast(struct interface *ifs, int sock)
564 {
565   /* See linux/in6.h */
566   struct ipaddr_str buf;
567   struct ipv6_mreq mcastreq;
568
569   mcastreq.ipv6mr_multiaddr = ifs->int6_multaddr.sin6_addr;
570   mcastreq.ipv6mr_interface = ifs->if_index;
571
572 #if !defined __FreeBSD__ && !defined __FreeBSD_kernel__ && !defined __MacOSX__ && !defined __NetBSD__
573   OLSR_PRINTF(3, "Interface %s joining multicast %s...", ifs->int_name, ip6_to_string(&buf, &ifs->int6_multaddr.sin6_addr));
574   /* Send multicast */
575   if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0) {
576     perror("Join multicast");
577     return -1;
578   }
579 #else
580 #warning implement IPV6_ADD_MEMBERSHIP
581 #endif
582
583   /* Old libc fix */
584 #ifdef IPV6_JOIN_GROUP
585   /* Join reciever group */
586   if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0)
587 #else
588   /* Join reciever group */
589   if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0)
590 #endif
591   {
592     perror("Join multicast send");
593     return -1;
594   }
595
596   if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&mcastreq.ipv6mr_interface, sizeof(mcastreq.ipv6mr_interface)) < 0) {
597     perror("Set multicast if");
598     return -1;
599   }
600
601   OLSR_PRINTF(3, "OK\n");
602   return 0;
603 }
604
605 /*
606  *From net-tools lib/interface.c
607  *
608  */
609 int
610 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, struct olsr_ip_prefix *prefix)
611 {
612   char addr6[40], devname[IFNAMSIZ];
613   char addr6p[8][5];
614   int plen, scope, dad_status, if_idx;
615   FILE *f;
616   union olsr_ip_addr tmp_ip;
617
618   if ((f = fopen(PATH_PROCNET_IFINET6, "r")) != NULL) {
619     while (fscanf
620            (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
621             addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
622       if (!strcmp(devname, ifname)) {
623         bool isNetWide = false;
624         sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6],
625                 addr6p[7]);
626         OLSR_PRINTF(5, "\tinet6 addr: %s\n", addr6);
627         OLSR_PRINTF(5, "\tScope: %d\n", scope);
628
629         inet_pton(AF_INET6, addr6, &tmp_ip.v6);
630
631         isNetWide = (scope != IPV6_ADDR_LOOPBACK) && (scope != IPV6_ADDR_LINKLOCAL) && (scope != IPV6_ADDR_SITELOCAL);
632
633         if ((prefix == NULL && isNetWide) || (prefix != NULL && ip_in_net(&tmp_ip, prefix))) {
634           OLSR_PRINTF(4, "Found addr: %s:%s:%s:%s:%s:%s:%s:%s\n", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5],
635                       addr6p[6], addr6p[7]);
636           memcpy(&saddr6->sin6_addr, &tmp_ip.v6, sizeof(struct in6_addr));
637           fclose(f);
638           return 1;
639         }
640       }
641     }
642     fclose(f);
643   }
644   return 0;
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 /* Basic Mode Control Register */
701 #define MII_BMCR                0x00
702 #define  MII_BMCR_RESET         0x8000
703 #define  MII_BMCR_LOOPBACK      0x4000
704 #define  MII_BMCR_100MBIT       0x2000
705 #define  MII_BMCR_AN_ENA        0x1000
706 #define  MII_BMCR_ISOLATE       0x0400
707 #define  MII_BMCR_RESTART       0x0200
708 #define  MII_BMCR_DUPLEX        0x0100
709 #define  MII_BMCR_COLTEST       0x0080
710
711 /* Basic Mode Status Register */
712 #define MII_BMSR                0x01
713 #define  MII_BMSR_CAP_MASK      0xf800
714 #define  MII_BMSR_100BASET4     0x8000
715 #define  MII_BMSR_100BASETX_FD  0x4000
716 #define  MII_BMSR_100BASETX_HD  0x2000
717 #define  MII_BMSR_10BASET_FD    0x1000
718 #define  MII_BMSR_10BASET_HD    0x0800
719 #define  MII_BMSR_NO_PREAMBLE   0x0040
720 #define  MII_BMSR_AN_COMPLETE   0x0020
721 #define  MII_BMSR_REMOTE_FAULT  0x0010
722 #define  MII_BMSR_AN_ABLE       0x0008
723 #define  MII_BMSR_LINK_VALID    0x0004
724 #define  MII_BMSR_JABBER        0x0002
725 #define  MII_BMSR_EXT_CAP       0x0001
726
727 int
728 calculate_if_metric(char *ifname)
729 {
730   if (check_wireless_interface(ifname)) {
731     struct ifreq ifr;
732     strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
733
734     /* Get bit rate */
735     if (ioctl(olsr_cnf->ioctl_s, SIOCGIWRATE, &ifr) < 0) {
736       OLSR_PRINTF(1, "Not able to find rate for WLAN interface %s\n", ifname);
737       return WEIGHT_WLAN_11MB;
738     }
739
740     OLSR_PRINTF(1, "Bitrate %d\n", ifr.ifr_ifru.ifru_ivalue);
741
742     //WEIGHT_WLAN_LOW,          /* <11Mb WLAN     */
743     //WEIGHT_WLAN_11MB,         /* 11Mb 802.11b   */
744     //WEIGHT_WLAN_54MB,         /* 54Mb 802.11g   */
745     return WEIGHT_WLAN_LOW;
746   } else {
747     /* Ethernet */
748     /* Mii wizardry */
749     struct ifreq ifr;
750     struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
751     int bmcr;
752     memset(&ifr, 0, sizeof(ifr));
753     strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
754
755     if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
756       if (errno != ENODEV)
757         OLSR_PRINTF(1, "SIOCGMIIPHY on '%s' failed: %s\n", ifr.ifr_name, strerror(errno));
758       return WEIGHT_ETHERNET_DEFAULT;
759     }
760
761     mii->reg_num = MII_BMCR;
762     if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIREG, &ifr) < 0) {
763       OLSR_PRINTF(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name, strerror(errno));
764       return WEIGHT_ETHERNET_DEFAULT;
765     }
766     bmcr = mii->val_out;
767
768     OLSR_PRINTF(1, "%s: ", ifr.ifr_name);
769     OLSR_PRINTF(1, "%s Mbit, %s duplex\n", (bmcr & MII_BMCR_100MBIT) ? "100" : "10", (bmcr & MII_BMCR_DUPLEX) ? "full" : "half");
770
771     is_if_link_up(ifname);
772
773     if (mii->val_out & MII_BMCR_100MBIT)
774       return WEIGHT_ETHERNET_100MB;
775     else
776       return WEIGHT_ETHERNET_10MB;
777     //WEIGHT_ETHERNET_1GB,      /* Ethernet 1Gb   */
778
779   }
780 }
781
782 bool
783 is_if_link_up(char *ifname)
784 {
785   if (check_wireless_interface(ifname)) {
786     /* No link checking on wireless devices */
787     return true;
788   } else {
789     /* Mii wizardry */
790     struct ifreq ifr;
791     struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
792     int bmsr;
793     memset(&ifr, 0, sizeof(ifr));
794     strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
795
796     if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
797       if (errno != ENODEV)
798         OLSR_PRINTF(1, "SIOCGMIIPHY on '%s' failed: %s\n", ifr.ifr_name, strerror(errno));
799       return WEIGHT_ETHERNET_DEFAULT;
800     }
801     mii->reg_num = MII_BMSR;
802     if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIREG, &ifr) < 0) {
803       OLSR_PRINTF(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name, strerror(errno));
804       return WEIGHT_ETHERNET_DEFAULT;
805     }
806     bmsr = mii->val_out;
807
808     OLSR_PRINTF(1, "%s: ", ifr.ifr_name);
809     OLSR_PRINTF(1, "%s\n", (bmsr & MII_BMSR_LINK_VALID) ? "link ok " : "no link ");
810
811     return (bmsr & MII_BMSR_LINK_VALID);
812
813   }
814 }
815
816 #else
817 int
818 calculate_if_metric(char *ifname)
819 {
820   return check_wireless_interface(ifname);
821 }
822 #endif
823
824 bool olsr_if_isup(const char * dev)
825 {
826   struct ifreq ifr;
827
828   memset(&ifr, 0, sizeof(ifr));
829   strscpy(ifr.ifr_name, dev, IFNAMSIZ);
830
831   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
832     perror("ioctl SIOCGIFFLAGS (get flags)");
833     return 1;
834   }
835   return (ifr.ifr_flags & IFF_UP) != 0;
836 }
837
838 int olsr_if_set_state(const char *dev, bool up) {
839   int oldflags;
840   struct ifreq ifr;
841
842   memset(&ifr, 0, sizeof(ifr));
843   strscpy(ifr.ifr_name, dev, IFNAMSIZ);
844
845   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
846     perror("ioctl SIOCGIFFLAGS (get flags)");
847     return 1;
848   }
849
850   oldflags = ifr.ifr_flags;
851   if (up) {
852     ifr.ifr_flags |= IFF_UP;
853   }
854   else {
855     ifr.ifr_flags &= ~IFF_UP;
856   }
857
858   if (oldflags == ifr.ifr_flags) {
859     /* interface is already up/down */
860     return 0;
861   }
862
863   if (ioctl(olsr_cnf->ioctl_s, SIOCSIFFLAGS, &ifr) < 0) {
864     perror("ioctl SIOCSIFFLAGS (set flags)");
865     return 1;
866   }
867   return 0;
868 }
869
870
871 int olsr_if_setip(const char *dev, union olsr_ip_addr *ip, int ip_version) {
872   struct sockaddr s;
873   struct ifreq ifr;
874
875   /* first activate interface */
876   if (olsr_if_set_state(dev, true)) {
877     return 1;
878   }
879
880   memset(&ifr, 0, sizeof(ifr));
881   strscpy(ifr.ifr_name, dev, IFNAMSIZ);
882
883   memset(&s, 0, sizeof(s));
884   s.sa_family = ip_version == 0 ? olsr_cnf->ip_version : ip_version;
885   if (s.sa_family == AF_INET) {
886     ((struct sockaddr_in *)&s)->sin_addr = ip->v4;
887   }
888   else {
889     ((struct sockaddr_in6 *)&s)->sin6_addr = ip->v6;
890   }
891   memcpy(&ifr.ifr_addr, &s, sizeof(s));
892
893   if (ioctl(olsr_cnf->ioctl_s, SIOCSIFADDR, &ifr) < 0) {
894     perror("ioctl SIOCSIFADDR (set addr)");
895     return 1;
896   }
897   return 0;
898 }
899
900 /*
901  * Local Variables:
902  * c-basic-offset: 2
903  * indent-tabs-mode: nil
904  * End:
905  */