Final conversions from using olsr_printf to using OLSR_PRINTF
[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.23 2005/02/27 10:43:38 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 /*
537  *From net-tools lib/interface.c
538  *
539  */
540
541 int
542 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int scope_in)
543 {
544   char addr6[40], devname[IFNAMSIZ];
545   char addr6p[8][5];
546   int plen, scope, dad_status, if_idx;
547   FILE *f;
548   struct sockaddr_in6 tmp_sockaddr6;
549
550   if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) 
551     {
552       while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
553                     addr6p[0], addr6p[1], addr6p[2], addr6p[3],
554                     addr6p[4], addr6p[5], addr6p[6], addr6p[7],
555                     &if_idx, &plen, &scope, &dad_status, devname) != EOF) 
556         {
557           if (!strcmp(devname, ifname)) 
558             {
559               sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
560                       addr6p[0], addr6p[1], addr6p[2], addr6p[3],
561                       addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
562               OLSR_PRINTF(5, "\tinet6 addr: %s\n", addr6)
563               OLSR_PRINTF(5, "\tScope: %d", scope)
564               if(scope == scope_in)
565                 {
566                   OLSR_PRINTF(4, "IPv6 addr:\n")
567                   inet_pton(AF_INET6,addr6,&tmp_sockaddr6);
568                   memcpy(&saddr6->sin6_addr, &tmp_sockaddr6, sizeof(struct in6_addr));    
569                   fclose(f);
570                   return 1;
571                 }
572             }
573         }
574       fclose(f);
575     }
576   
577   return 0;
578 }
579
580
581 /**
582  * Wrapper for sendto(2)
583  */
584
585 ssize_t
586 olsr_sendto(int s, 
587             const void *buf, 
588             size_t len, 
589             int flags, 
590             const struct sockaddr *to, 
591             socklen_t tolen)
592 {
593   return sendto(s, buf, len, flags, to, tolen);
594 }
595
596 /**
597  * Wrapper for recvfrom(2)
598  */
599
600 ssize_t  
601 olsr_recvfrom(int  s, 
602               void *buf, 
603               size_t len, 
604               int flags, 
605               struct sockaddr *from,
606               socklen_t *fromlen)
607 {
608   return recvfrom(s, 
609                   buf, 
610                   len, 
611                   0, 
612                   from, 
613                   fromlen);
614 }
615
616 /**
617  * Wrapper for select(2)
618  */
619
620 int
621 olsr_select(int nfds,
622             fd_set *readfds,
623             fd_set *writefds,
624             fd_set *exceptfds,
625             struct timeval *timeout)
626 {
627   return select(nfds,
628                 readfds,
629                 writefds,
630                 exceptfds,
631                 timeout);
632 }
633
634 int
635 check_wireless_interface(char *ifname)
636 {
637   struct ifreq ifr;
638
639   memset(&ifr, 0, sizeof(ifr));
640   strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
641
642   return (ioctl(ioctl_s, SIOCGIWNAME, &ifr) >= 0) ? 1 : 0;
643 }
644
645 #if 0
646
647 #include <linux/sockios.h>
648 #include <linux/types.h>
649
650 /* This data structure is used for all the MII ioctl's */
651 struct mii_data {
652     __u16       phy_id;
653     __u16       reg_num;
654     __u16       val_in;
655     __u16       val_out;
656 };
657
658
659 /* Basic Mode Control Register */
660 #define MII_BMCR                0x00
661 #define  MII_BMCR_RESET         0x8000
662 #define  MII_BMCR_LOOPBACK      0x4000
663 #define  MII_BMCR_100MBIT       0x2000
664 #define  MII_BMCR_AN_ENA        0x1000
665 #define  MII_BMCR_ISOLATE       0x0400
666 #define  MII_BMCR_RESTART       0x0200
667 #define  MII_BMCR_DUPLEX        0x0100
668 #define  MII_BMCR_COLTEST       0x0080
669
670 /* Basic Mode Status Register */
671 #define MII_BMSR                0x01
672 #define  MII_BMSR_CAP_MASK      0xf800
673 #define  MII_BMSR_100BASET4     0x8000
674 #define  MII_BMSR_100BASETX_FD  0x4000
675 #define  MII_BMSR_100BASETX_HD  0x2000
676 #define  MII_BMSR_10BASET_FD    0x1000
677 #define  MII_BMSR_10BASET_HD    0x0800
678 #define  MII_BMSR_NO_PREAMBLE   0x0040
679 #define  MII_BMSR_AN_COMPLETE   0x0020
680 #define  MII_BMSR_REMOTE_FAULT  0x0010
681 #define  MII_BMSR_AN_ABLE       0x0008
682 #define  MII_BMSR_LINK_VALID    0x0004
683 #define  MII_BMSR_JABBER        0x0002
684 #define  MII_BMSR_EXT_CAP       0x0001
685
686 int
687 calculate_if_metric(char *ifname)
688 {
689   if(check_wireless_interface(ifname))
690     {
691       struct ifreq ifr;
692       strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
693       
694       /* Get bit rate */
695       if(ioctl(ioctl_s, SIOCGIWRATE, &ifr) < 0)
696         {
697           OLSR_PRINTF(1, "Not able to find rate for WLAN interface %s\n", ifname)
698           return WEIGHT_WLAN_11MB;
699         }
700       
701       OLSR_PRINTF(1, "Bitrate %d\n", ifr.ifr_ifru.ifru_ivalue)
702
703       //WEIGHT_WLAN_LOW,          /* <11Mb WLAN     */
704       //WEIGHT_WLAN_11MB,         /* 11Mb 802.11b   */
705       //WEIGHT_WLAN_54MB,         /* 54Mb 802.11g   */
706       return WEIGHT_WLAN_LOW;
707     }
708   else
709     {
710       /* Ethernet */
711       /* Mii wizardry */
712       struct ifreq ifr;
713       struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
714       int bmcr;
715       memset(&ifr, 0, sizeof(ifr));
716       strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
717
718       if (ioctl(ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
719         if (errno != ENODEV)
720           OLSR_PRINTF(1, "SIOCGMIIPHY on '%s' failed: %s\n",
721                       ifr.ifr_name, strerror(errno))
722         return WEIGHT_ETHERNET_DEFAULT;
723       }
724
725       mii->reg_num = MII_BMCR;
726       if (ioctl(ioctl_s, SIOCGMIIREG, &ifr) < 0) {
727         OLSR_PRINTF(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
728                     strerror(errno))
729         return WEIGHT_ETHERNET_DEFAULT;
730       }
731       bmcr = mii->val_out;
732
733
734       OLSR_PRINTF(1, "%s: ", ifr.ifr_name)
735       OLSR_PRINTF(1, "%s Mbit, %s duplex\n",
736                   (bmcr & MII_BMCR_100MBIT) ? "100" : "10",
737                   (bmcr & MII_BMCR_DUPLEX) ? "full" : "half")
738     
739       is_if_link_up(ifname);
740
741       if(mii->val_out & MII_BMCR_100MBIT)
742         return WEIGHT_ETHERNET_100MB;
743       else
744         return WEIGHT_ETHERNET_10MB;
745       //WEIGHT_ETHERNET_1GB,      /* Ethernet 1Gb   */
746
747     }
748 }
749
750
751 olsr_bool
752 is_if_link_up(char *ifname)
753 {
754   if(check_wireless_interface(ifname))
755     {
756       /* No link checking on wireless devices */
757       return OLSR_TRUE;
758     }
759   else
760     {
761       /* Mii wizardry */
762       struct ifreq ifr;
763       struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
764       int bmsr;
765       memset(&ifr, 0, sizeof(ifr));
766       strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
767
768       if (ioctl(ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
769         if (errno != ENODEV)
770           OLSR_PRINTF(1, "SIOCGMIIPHY on '%s' failed: %s\n",
771                       ifr.ifr_name, strerror(errno))
772         return WEIGHT_ETHERNET_DEFAULT;
773       }
774       mii->reg_num = MII_BMSR;
775       if (ioctl(ioctl_s, SIOCGMIIREG, &ifr) < 0) {
776         OLSR_PRINTF(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
777                     strerror(errno))
778         return WEIGHT_ETHERNET_DEFAULT;
779       }
780       bmsr = mii->val_out;
781
782       OLSR_PRINTF(1, "%s: ", ifr.ifr_name)
783       OLSR_PRINTF(1, "%s\n", (bmsr & MII_BMSR_LINK_VALID) ? "link ok " : "no link ")
784     
785       return (bmsr & MII_BMSR_LINK_VALID);
786
787     }
788 }
789
790 #else
791 int
792 calculate_if_metric(char *ifname)
793 {
794   return check_wireless_interface(ifname);
795 }
796 #endif
797