Added bitrate detection for linux
[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.20 2005/02/17 19:47:10 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
455
456   //#ifdef SO_BROADCAST
457   /*
458   if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof (on)) < 0)
459     {
460       perror("setsockopt");
461       syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
462       close(sock);
463       return (-1);
464     }
465   */
466   //#endif
467
468
469
470
471 #ifdef SO_RCVBUF
472   for (on = bufspace; ; on -= 1024) 
473     {
474       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
475                      &on, sizeof (on)) == 0)
476         break;
477       if (on <= 8*1024) 
478         {
479           perror("setsockopt");
480           syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
481           break;
482         }
483     }
484
485
486 #endif
487
488   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 
489     {
490       perror("SO_REUSEADDR failed");
491       return (-1);
492     }
493
494
495   /*
496    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
497    */
498
499   /* Bind to device */
500   if(bind_socket_to_device(sock, int_name) < 0)
501     {
502       fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
503       syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
504       return -1;
505     }
506
507
508   if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0) 
509     {
510       perror("bind");
511       syslog(LOG_ERR, "bind: %m");
512       close(sock);
513       return (-1);
514     }
515
516   /*
517    *One should probably fetch the flags first
518    *using F_GETFL....
519    */
520   if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
521     syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
522
523
524
525   return (sock);
526 }
527
528
529 /*
530  *From net-tools lib/interface.c
531  *
532  */
533
534 int
535 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int scope_in)
536 {
537   char addr6[40], devname[IFNAMSIZ];
538   char addr6p[8][5];
539   int plen, scope, dad_status, if_idx;
540   FILE *f;
541   struct sockaddr_in6 tmp_sockaddr6;
542
543   if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) 
544     {
545       while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
546                     addr6p[0], addr6p[1], addr6p[2], addr6p[3],
547                     addr6p[4], addr6p[5], addr6p[6], addr6p[7],
548                     &if_idx, &plen, &scope, &dad_status, devname) != EOF) 
549         {
550           if (!strcmp(devname, ifname)) 
551             {
552               sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
553                       addr6p[0], addr6p[1], addr6p[2], addr6p[3],
554                       addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
555               olsr_printf(5, "\tinet6 addr: %s\n", addr6);
556               olsr_printf(5, "\tScope: %d", scope);
557               if(scope == scope_in)
558                 {
559                   olsr_printf(4, "IPv6 addr:\n");
560                   inet_pton(AF_INET6,addr6,&tmp_sockaddr6);
561                   memcpy(&saddr6->sin6_addr, &tmp_sockaddr6, sizeof(struct in6_addr));    
562                   fclose(f);
563                   return 1;
564                 }
565             }
566         }
567       fclose(f);
568     }
569   
570   return 0;
571 }
572
573
574 /**
575  * Wrapper for sendto(2)
576  */
577
578 ssize_t
579 olsr_sendto(int s, 
580             const void *buf, 
581             size_t len, 
582             int flags, 
583             const struct sockaddr *to, 
584             socklen_t tolen)
585 {
586   return sendto(s, buf, len, flags, to, tolen);
587 }
588
589 /**
590  * Wrapper for recvfrom(2)
591  */
592
593 ssize_t  
594 olsr_recvfrom(int  s, 
595               void *buf, 
596               size_t len, 
597               int flags, 
598               struct sockaddr *from,
599               socklen_t *fromlen)
600 {
601   return recvfrom(s, 
602                   buf, 
603                   len, 
604                   0, 
605                   from, 
606                   fromlen);
607 }
608
609
610
611 int
612 check_wireless_interface(char *ifname)
613 {
614   struct ifreq ifr;
615
616   memset(&ifr, 0, sizeof(ifr));
617   strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
618
619   return (ioctl(ioctl_s, SIOCGIWNAME, &ifr) >= 0) ? 1 : 0;
620 }
621
622 #if 0
623
624 #include <linux/sockios.h>
625 #include <linux/types.h>
626
627 /* This data structure is used for all the MII ioctl's */
628 struct mii_data {
629     __u16       phy_id;
630     __u16       reg_num;
631     __u16       val_in;
632     __u16       val_out;
633 };
634
635
636 /* Basic Mode Control Register */
637 #define MII_BMCR                0x00
638 #define  MII_BMCR_RESET         0x8000
639 #define  MII_BMCR_LOOPBACK      0x4000
640 #define  MII_BMCR_100MBIT       0x2000
641 #define  MII_BMCR_AN_ENA        0x1000
642 #define  MII_BMCR_ISOLATE       0x0400
643 #define  MII_BMCR_RESTART       0x0200
644 #define  MII_BMCR_DUPLEX        0x0100
645 #define  MII_BMCR_COLTEST       0x0080
646
647 /* Basic Mode Status Register */
648 #define MII_BMSR                0x01
649 #define  MII_BMSR_CAP_MASK      0xf800
650 #define  MII_BMSR_100BASET4     0x8000
651 #define  MII_BMSR_100BASETX_FD  0x4000
652 #define  MII_BMSR_100BASETX_HD  0x2000
653 #define  MII_BMSR_10BASET_FD    0x1000
654 #define  MII_BMSR_10BASET_HD    0x0800
655 #define  MII_BMSR_NO_PREAMBLE   0x0040
656 #define  MII_BMSR_AN_COMPLETE   0x0020
657 #define  MII_BMSR_REMOTE_FAULT  0x0010
658 #define  MII_BMSR_AN_ABLE       0x0008
659 #define  MII_BMSR_LINK_VALID    0x0004
660 #define  MII_BMSR_JABBER        0x0002
661 #define  MII_BMSR_EXT_CAP       0x0001
662
663 int
664 calculate_if_metric(char *ifname)
665 {
666   if(check_wireless_interface(ifname))
667     {
668       struct ifreq ifr;
669       strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
670       
671       /* Get bit rate */
672       if(ioctl(ioctl_s, SIOCGIWRATE, &ifr) < 0)
673         {
674           olsr_printf(1, "Not able to find rate for WLAN interface %s\n", ifname);
675           return WEIGHT_WLAN_11MB;
676         }
677       
678       olsr_printf(1, "Bitrate %d\n", ifr.ifr_ifru.ifru_ivalue);
679
680       //WEIGHT_WLAN_LOW,          /* <11Mb WLAN     */
681       //WEIGHT_WLAN_11MB,         /* 11Mb 802.11b   */
682       //WEIGHT_WLAN_54MB,         /* 54Mb 802.11g   */
683       return WEIGHT_WLAN_LOW;
684     }
685   else
686     {
687       /* Ethernet */
688       /* Mii wizardry */
689       struct ifreq ifr;
690       struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
691       int bmcr;
692       memset(&ifr, 0, sizeof(ifr));
693       strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
694
695       if (ioctl(ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
696         if (errno != ENODEV)
697           olsr_printf(1, "SIOCGMIIPHY on '%s' failed: %s\n",
698                       ifr.ifr_name, strerror(errno));
699         return WEIGHT_ETHERNET_DEFAULT;
700       }
701
702       mii->reg_num = MII_BMCR;
703       if (ioctl(ioctl_s, SIOCGMIIREG, &ifr) < 0) {
704         olsr_printf(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
705                     strerror(errno));
706         return WEIGHT_ETHERNET_DEFAULT;
707       }
708       bmcr = mii->val_out;
709
710
711       olsr_printf(1, "%s: ", ifr.ifr_name);
712       olsr_printf(1, "%s Mbit, %s duplex\n",
713                   (bmcr & MII_BMCR_100MBIT) ? "100" : "10",
714                   (bmcr & MII_BMCR_DUPLEX) ? "full" : "half");
715     
716       is_if_link_up(ifname);
717
718       if(mii->val_out & MII_BMCR_100MBIT)
719         return WEIGHT_ETHERNET_100MB;
720       else
721         return WEIGHT_ETHERNET_10MB;
722       //WEIGHT_ETHERNET_1GB,      /* Ethernet 1Gb   */
723
724     }
725 }
726
727
728 olsr_bool
729 is_if_link_up(char *ifname)
730 {
731   if(check_wireless_interface(ifname))
732     {
733       /* No link checking on wireless devices */
734       return OLSR_TRUE;
735     }
736   else
737     {
738       /* Mii wizardry */
739       struct ifreq ifr;
740       struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
741       int bmsr;
742       memset(&ifr, 0, sizeof(ifr));
743       strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
744
745       if (ioctl(ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
746         if (errno != ENODEV)
747           olsr_printf(1, "SIOCGMIIPHY on '%s' failed: %s\n",
748                       ifr.ifr_name, strerror(errno));
749         return WEIGHT_ETHERNET_DEFAULT;
750       }
751       mii->reg_num = MII_BMSR;
752       if (ioctl(ioctl_s, SIOCGMIIREG, &ifr) < 0) {
753         olsr_printf(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
754                     strerror(errno));
755         return WEIGHT_ETHERNET_DEFAULT;
756       }
757       bmsr = mii->val_out;
758
759       olsr_printf(1, "%s: ", ifr.ifr_name);
760       olsr_printf(1, "%s\n", (bmsr & MII_BMSR_LINK_VALID) ? "link ok " : "no link ");      
761     
762       return (bmsr & MII_BMSR_LINK_VALID);
763
764     }
765 }
766
767 #else
768 int
769 calculate_if_metric(char *ifname)
770 {
771   return check_wireless_interface(ifname);
772 }
773 #endif
774