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