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