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