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