3 != 2
[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 /**
64  * Fix bug in GLIBC, see https://bugzilla.redhat.com/show_bug.cgi?id=635260
65  */
66 #ifdef IPTOS_CLASS
67 #undef IPTOS_CLASS
68 #endif
69 #define IPTOS_CLASS(class)    ((class) & IPTOS_CLASS_MASK)
70
71 #define IPV6_ADDR_LOOPBACK      0x0010U
72 #define IPV6_ADDR_LINKLOCAL     0x0020U
73 #define IPV6_ADDR_SITELOCAL     0x0040U
74
75 /* ip forwarding */
76 #define PROC_IPFORWARD_V4 "/proc/sys/net/ipv4/ip_forward"
77 #define PROC_IPFORWARD_V6 "/proc/sys/net/ipv6/conf/all/forwarding"
78
79 /* Redirect proc entry */
80 #define PROC_IF_REDIRECT "/proc/sys/net/ipv4/conf/%s/send_redirects"
81 #define PROC_ALL_REDIRECT "/proc/sys/net/ipv4/conf/all/send_redirects"
82
83 /* IP spoof proc entry */
84 #define PROC_IF_SPOOF "/proc/sys/net/ipv4/conf/%s/rp_filter"
85 #define PROC_ALL_SPOOF "/proc/sys/net/ipv4/conf/all/rp_filter"
86
87
88 /* list of IPv6 interfaces */
89 #define PATH_PROCNET_IFINET6           "/proc/net/if_inet6"
90
91 /*
92  *Wireless definitions for ioctl calls
93  *(from linux/wireless.h)
94  */
95 #define SIOCGIWNAME     0x8B01  /* get name == wireless protocol */
96 #define SIOCGIWRATE     0x8B21  /* get default bit rate (bps) */
97
98 /* The original state of the IP forwarding proc entry */
99 static char orig_fwd_state;
100 static char orig_global_redirect_state;
101 static char orig_global_rp_filter;
102 static char orig_tunnel_rp_filter;
103 #if 0 // should not be necessary for IPv6 */
104 static char orig_tunnel6_rp_filter;
105 #endif
106
107 /**
108  *Bind a socket to a device
109  *
110  *@param sock the socket to bind
111  *@param dev_name name of the device
112  *
113  *@return negative if error
114  */
115
116 int
117 bind_socket_to_device(int sock, char *dev_name)
118 {
119   /*
120    *Bind to device using the SO_BINDTODEVICE flag
121    */
122   OLSR_PRINTF(3, "Binding socket %d to device %s\n", sock, dev_name);
123   return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, dev_name, strlen(dev_name) + 1);
124 }
125
126 static int writeToProc(const char *file, char *old, char value) {
127   int fd;
128   char rv;
129
130   if ((fd = open(file, O_RDWR)) < 0) {
131     OLSR_PRINTF(0, "Error, cannot open proc entry %s: %s (%d)\n", file, strerror(errno), errno);
132     return -1;
133   }
134
135   if (read(fd, &rv, 1) != 1) {
136     OLSR_PRINTF(0, "Error, cannot read proc entry %s: %s (%d)\n", file, strerror(errno), errno);
137     return -1;
138   }
139
140   if (rv != value) {
141     if (lseek(fd, SEEK_SET, 0) == -1) {
142       OLSR_PRINTF(0, "Error, cannot rewind proc entry %s: %s (%d)\n", file, strerror(errno), errno);
143       return -1;
144     }
145
146     if (write(fd, &value, 1) != 1) {
147       OLSR_PRINTF(0, "Error, cannot write proc entry %s: %s (%d)\n", file, strerror(errno), errno);
148       return -1;
149     }
150   }
151
152   if (close(fd) != 0) {
153     OLSR_PRINTF(0, "Error while closing proc entry %s: %s (%d)\n", file, strerror(errno), errno);
154     return -1;
155   }
156
157   if (old) {
158     *old = rv;
159   }
160   olsr_syslog(OLSR_LOG_INFO, "Writing '%c' (was %c) to %s", value, rv, file);
161   return 0;
162 }
163
164 static bool is_at_least_linuxkernel_2_6_31(void) {
165   struct utsname uts;
166
167   memset(&uts, 0, sizeof(uts));
168   if (uname(&uts)) {
169     OLSR_PRINTF(1, "Error, could not read kernel version: %s (%d)\n", strerror(errno), errno);
170     return false;
171   }
172
173   if (strncmp(uts.release, "3", 1) >= 0) {
174     return true;
175   }
176   if (strncmp(uts.release, "2.6.", 4) != 0) {
177     return false;
178   }
179   return atoi(&uts.release[4]) >= 31;
180 }
181
182 /**
183  * Setup global interface options (icmp redirect, ip forwarding, rp_filter)
184  * @return 1 on success 0 on failure
185  */
186 void
187 net_os_set_global_ifoptions(void) {
188   if (writeToProc(olsr_cnf->ip_version == AF_INET ? PROC_IPFORWARD_V4 : PROC_IPFORWARD_V6, &orig_fwd_state, '1')) {
189     OLSR_PRINTF(1, "Warning, could not enable IP forwarding!\n"
190         "you should manually ensure that IP forwarding is enabled!\n\n");
191     olsr_startup_sleep(3);
192   }
193
194   if (olsr_cnf->smart_gw_active) {
195     char procfile[FILENAME_MAX];
196
197     /* Generate the procfile name */
198     if (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit) {
199       snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF);
200       if (writeToProc(procfile, &orig_tunnel_rp_filter, '0')) {
201         OLSR_PRINTF(0, "WARNING! Could not disable the IP spoof filter for tunnel!\n"
202             "you should mannually ensure that IP spoof filtering is disabled!\n\n");
203
204         olsr_startup_sleep(3);
205       }
206     }
207
208 #if 0 // should not be necessary for IPv6
209     if (olsr_cnf->ip_version == AF_INET6) {
210       snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF6);
211       if (writeToProc(procfile, &orig_tunnel6_rp_filter, '0')) {
212         OLSR_PRINTF(0, "WARNING! Could not disable the IP spoof filter for tunnel6!\n"
213             "you should mannually ensure that IP spoof filtering is disabled!\n\n");
214
215         olsr_startup_sleep(3);
216       }
217     }
218 #endif
219   }
220
221   if (olsr_cnf->ip_version == AF_INET) {
222     if (writeToProc(PROC_ALL_REDIRECT, &orig_global_redirect_state, '0')) {
223       OLSR_PRINTF(1, "WARNING! Could not disable ICMP redirects!\n"
224           "you should manually ensure that ICMP redirects are disabled!\n\n");
225
226       olsr_startup_sleep(3);
227     }
228
229     /* check kernel version and disable global rp_filter */
230     if (is_at_least_linuxkernel_2_6_31()) {
231       if (writeToProc(PROC_ALL_SPOOF, &orig_global_rp_filter, '0')) {
232         OLSR_PRINTF(1, "WARNING! Could not disable global rp_filter (necessary for kernel 2.6.31 and higher!\n"
233             "you should manually ensure that rp_filter is disabled!\n\n");
234
235         olsr_startup_sleep(3);
236       }
237     }
238   }
239   return;
240 }
241
242 /**
243  *
244  *@return 1 on sucess 0 on failiure
245  */
246 int
247 net_os_set_ifoptions(const char *if_name, struct interface *iface)
248 {
249   char procfile[FILENAME_MAX];
250   if (olsr_cnf->ip_version == AF_INET6)
251     return -1;
252
253   /* Generate the procfile name */
254   snprintf(procfile, sizeof(procfile), PROC_IF_REDIRECT, if_name);
255
256   if (writeToProc(procfile, &iface->nic_state.redirect, '0')) {
257     OLSR_PRINTF(0, "WARNING! Could not disable ICMP redirects!\n"
258         "you should mannually ensure that ICMP redirects are disabled!\n\n");
259     olsr_startup_sleep(3);
260     return 0;
261   }
262
263   /* Generate the procfile name */
264   snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, if_name);
265
266   if (writeToProc(procfile, &iface->nic_state.spoof, '0')) {
267     OLSR_PRINTF(0, "WARNING! Could not disable the IP spoof filter!\n"
268         "you should mannually ensure that IP spoof filtering is disabled!\n\n");
269
270     olsr_startup_sleep(3);
271     return 0;
272   }
273   return 1;
274 }
275
276 /**
277  *Resets the spoof filter and ICMP redirect settings
278  */
279 int
280 net_os_restore_ifoptions(void)
281 {
282   struct interface *ifs;
283   char procfile[FILENAME_MAX];
284
285   OLSR_PRINTF(1, "Restoring network state\n");
286
287   /* Restore IP forwarding to "off" */
288   if (writeToProc(olsr_cnf->ip_version == AF_INET ? PROC_IPFORWARD_V4 : PROC_IPFORWARD_V6, NULL, orig_fwd_state)) {
289     OLSR_PRINTF(1, "Error, could not restore ip_forward settings\n");
290   }
291
292   if (olsr_cnf->smart_gw_active && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit)) {
293     /* Generate the procfile name */
294     snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF);
295     if (writeToProc(procfile, NULL, orig_tunnel_rp_filter)) {
296       OLSR_PRINTF(0, "WARNING! Could not restore the IP spoof filter for tunnel!\n");
297     }
298
299 #if 0 // should not be necessary for IPv6
300     if (olsr_cnf->ip_version == AF_INET6) {
301       snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF6);
302       if (writeToProc(procfile, NULL, orig_tunnel6_rp_filter)) {
303         OLSR_PRINTF(0, "WARNING! Could not restore the IP spoof filter for tunnel6!\n");
304       }
305     }
306 #endif
307   }
308
309   if (olsr_cnf->ip_version == AF_INET) {
310     /* Restore global ICMP redirect setting */
311     if (writeToProc(PROC_ALL_REDIRECT, NULL, orig_global_redirect_state)) {
312       OLSR_PRINTF(1, "Error, could not restore global icmp_redirect setting\n");
313     }
314
315     /* Restore global rp_filter setting for linux 2.6.31+ */
316     if (is_at_least_linuxkernel_2_6_31()) {
317       if (writeToProc(PROC_ALL_SPOOF, NULL, orig_global_rp_filter)) {
318         OLSR_PRINTF(1, "Error, could not restore global rp_filter setting\n");
319       }
320     }
321     for (ifs = ifnet; ifs != NULL; ifs = ifs->int_next) {
322       /* Discard host-emulation interfaces */
323       if (ifs->is_hcif)
324         continue;
325
326       /* ICMP redirects */
327       snprintf(procfile, sizeof(procfile), PROC_IF_REDIRECT, ifs->int_name);
328       if (writeToProc(procfile, NULL, ifs->nic_state.redirect)) {
329         OLSR_PRINTF(1, "Error, could not restore icmp_redirect for interface %s\n", ifs->int_name);
330       }
331
332       /* Spoof filter */
333       sprintf(procfile, PROC_IF_SPOOF, ifs->int_name);
334       if (writeToProc(procfile, NULL, ifs->nic_state.spoof)) {
335         OLSR_PRINTF(1, "Error, could not restore rp_filter for interface %s\n", ifs->int_name);
336       }
337     }
338   }
339   return 1;
340 }
341
342 /**
343  *Creates a blocking tcp socket for communication with switch daemon.
344  *@param sa sockaddr struct. Used for bind(2).
345  *@return the FD of the socket or -1 on error.
346  */
347 int
348 gethemusocket(struct sockaddr_in *pin)
349 {
350   int sock, on = 1;
351
352   OLSR_PRINTF(1, "       Connecting to switch daemon port 10150...");
353   if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
354     perror("hcsocket");
355     syslog(LOG_ERR, "hcsocket: %m");
356     return -1;
357   }
358
359   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
360     perror("SO_REUSEADDR failed");
361     close(sock);
362     return -1;
363   }
364   /* connect to PORT on HOST */
365   if (connect(sock, (struct sockaddr *)pin, sizeof(*pin)) < 0) {
366     printf("FAILED\n");
367     fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
368     printf("connection refused\n");
369     close(sock);
370     return -1;
371   }
372
373   printf("OK\n");
374
375   /* Keep TCP socket blocking */
376   return sock;
377 }
378
379 /**
380  *Creates a nonblocking broadcast socket.
381  *@param sa sockaddr struct. Used for bind(2).
382  *@return the FD of the socket or -1 on error.
383  */
384 int
385 getsocket(int bufspace, struct interface *ifp)
386 {
387   struct sockaddr_in sin;
388   int on;
389   int sock = socket(AF_INET, SOCK_DGRAM, 0);
390   if (sock < 0) {
391     perror("socket");
392     syslog(LOG_ERR, "socket: %m");
393     return -1;
394   }
395
396   on = 1;
397 #ifdef SO_BROADCAST
398   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
399     perror("setsockopt");
400     syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
401     close(sock);
402     return -1;
403   }
404 #endif
405
406   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
407     perror("SO_REUSEADDR failed");
408     close(sock);
409     return -1;
410   }
411 #ifdef SO_RCVBUF
412   if(bufspace > 0) {
413     for (on = bufspace;; on -= 1024) {
414       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0)
415         break;
416       if (on <= 8 * 1024) {
417         perror("setsockopt");
418         syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
419         break;
420       }
421     }
422   }
423 #endif
424
425   /*
426    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
427    */
428
429   /* Bind to device */
430   if (bind_socket_to_device(sock, ifp->int_name) < 0) {
431     fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
432     syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
433     close(sock);
434     return -1;
435   }
436
437   memset(&sin, 0, sizeof(sin));
438   sin.sin_family = AF_INET;
439   sin.sin_port = htons(olsr_cnf->olsrport);
440
441   if(bufspace <= 0) {
442     sin.sin_addr.s_addr = ifp->int_addr.sin_addr.s_addr;
443   }
444
445   if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
446     perror("bind");
447     syslog(LOG_ERR, "bind: %m");
448     close(sock);
449     return -1;
450   }
451
452   on = fcntl(sock, F_GETFL);
453   if (on == -1) {
454     syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
455   } else {
456     if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
457       syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
458     }
459   }
460   return sock;
461 }
462
463 /**
464  *Creates a nonblocking IPv6 socket
465  *@param sin sockaddr_in6 struct. Used for bind(2).
466  *@return the FD of the socket or -1 on error.
467  */
468 int
469 getsocket6(int bufspace, struct interface *ifp)
470 {
471   struct sockaddr_in6 sin;
472   int on;
473   int sock = socket(AF_INET6, SOCK_DGRAM, 0);
474   if (sock < 0) {
475     perror("socket");
476     syslog(LOG_ERR, "socket: %m");
477     return (-1);
478   }
479 #ifdef IPV6_V6ONLY
480   on = 1;
481   if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
482     perror("setsockopt(IPV6_V6ONLY)");
483     syslog(LOG_ERR, "setsockopt(IPV6_V6ONLY): %m");
484   }
485 #endif
486
487   //#ifdef SO_BROADCAST
488   /*
489      if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof (on)) < 0)
490      {
491      perror("setsockopt");
492      syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
493      close(sock);
494      return (-1);
495      }
496    */
497   //#endif
498
499 #ifdef SO_RCVBUF
500   if(bufspace > 0) {
501     for (on = bufspace;; on -= 1024) {
502       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0)
503         break;
504       if (on <= 8 * 1024) {
505         perror("setsockopt");
506         syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
507         break;
508       }
509     }
510   }
511 #endif
512
513   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
514     perror("SO_REUSEADDR failed");
515     close(sock);
516     return (-1);
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, ifp->int_name) < 0) {
525     fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
526     syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
527     close(sock);
528     return -1;
529   }
530
531   memset(&sin, 0, sizeof(sin));
532   sin.sin6_family = AF_INET6;
533   sin.sin6_port = htons(olsr_cnf->olsrport);
534   sin.sin6_scope_id = ifp->if_index;
535
536   if(bufspace <= 0) {
537     memcpy(&sin.sin6_addr, &ifp->int6_addr.sin6_addr, sizeof(struct in6_addr));
538   }
539
540   if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
541     struct ipaddr_str buf;
542     OLSR_PRINTF(1, "Error, cannot bind address %s to %s-socket: %s (%d)\n",
543         inet_ntop(sin.sin6_family, &sin.sin6_addr, buf.buf, sizeof(buf)),
544         bufspace <= 0 ? "transmit" : "receive",
545         strerror(errno), errno);
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 %x %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     OLSR_PRINTF(1, "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
833         dev, strerror(errno), errno);
834     return 1;
835   }
836   return (ifr.ifr_flags & IFF_UP) != 0;
837 }
838
839 int olsr_if_set_state(const char *dev, bool up) {
840   int oldflags;
841   struct ifreq ifr;
842
843   memset(&ifr, 0, sizeof(ifr));
844   strscpy(ifr.ifr_name, dev, IFNAMSIZ);
845
846   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
847     OLSR_PRINTF(1, "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
848         dev, strerror(errno), errno);
849     return 1;
850   }
851
852   oldflags = ifr.ifr_flags;
853   if (up) {
854     ifr.ifr_flags |= IFF_UP;
855   }
856   else {
857     ifr.ifr_flags &= ~IFF_UP;
858   }
859
860   if (oldflags == ifr.ifr_flags) {
861     /* interface is already up/down */
862     return 0;
863   }
864
865   if (ioctl(olsr_cnf->ioctl_s, SIOCSIFFLAGS, &ifr) < 0) {
866     OLSR_PRINTF(1, "ioctl SIOCSIFFLAGS (set flags %s) error on device %s: %s (%d)\n",
867         up ? "up" : "down", dev, strerror(errno), errno);
868     return 1;
869   }
870   return 0;
871 }
872
873 /*
874  * Local Variables:
875  * c-basic-offset: 2
876  * indent-tabs-mode: nil
877  * End:
878  */