/*
* The olsr.org Optimized Link-State Routing daemon(olsrd)
* Copyright (c) 2004, Andreas Tønnesen(andreto@olsr.org)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of olsr.org, olsrd nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Visit http://www.olsr.org for more information.
*
* If you find this software useful feel free to make a donation
* to the project. For more information see the website or contact
* the copyright holders.
*
* $Id: net.c,v 1.34 2007/04/25 22:08:18 bernd67 Exp $
*/
/*
* Linux spesific code
*/
#include "net.h"
#include "../defs.h"
#include "../net_os.h"
#include "../parser.h"
/*
*Wireless definitions for ioctl calls
*(from linux/wireless.h)
*/
#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */
#define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */
/* The original state of the IP forwarding proc entry */
static char orig_fwd_state;
static char orig_global_redirect_state;
/**
*Bind a socket to a device
*
*@param sock the socket to bind
*@param dev_name name of the device
*
*@return negative if error
*/
int
bind_socket_to_device(int sock, char *dev_name)
{
/*
*Bind to device using the SO_BINDTODEVICE flag
*/
OLSR_PRINTF(3, "Binding socket %d to device %s\n", sock, dev_name);
return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, dev_name, strlen(dev_name)+1);
}
/**
*Enable IP forwarding.
*Just writing "1" to the /proc/sys/net/ipv4/ip_forward
*if using IPv4 or /proc/sys/net/ipv6/conf/all/forwarding
*if using IPv6.
*Could probably drop the check for
*"0" here and write "1" anyways.
*
*@param version IP version.
*
*@return 1 on sucess 0 on failiure
*/
int
enable_ip_forwarding(int version)
{
FILE *proc_fwd;
const char * const procfile = version == AF_INET
? "/proc/sys/net/ipv4/ip_forward"
: "/proc/sys/net/ipv6/conf/all/forwarding";
if ((proc_fwd=fopen(procfile, "r"))==NULL)
{
/* IPv4 */
if(version == AF_INET)
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);
/* IPv6 */
else
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);
sleep(3);
return 0;
}
orig_fwd_state = fgetc(proc_fwd);
fclose(proc_fwd);
if(orig_fwd_state == '1')
{
OLSR_PRINTF(3, "\nIP forwarding is enabled on this system\n");
}
else
{
if ((proc_fwd=fopen(procfile, "w"))==NULL)
{
fprintf(stderr, "Could not open %s for writing!\n", procfile);
fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that IP forwarding is enabeled!\n\n");
sleep(3);
return 0;
}
else
{
syslog(LOG_INFO, "Writing \"1\" to %s\n", procfile);
fputs("1", proc_fwd);
}
fclose(proc_fwd);
}
return 1;
}
int
disable_redirects_global(int version)
{
FILE *proc_redirect;
const char * const procfile = "/proc/sys/net/ipv4/conf/all/send_redirects";
if(version == AF_INET6)
return -1;
if((proc_redirect = fopen(procfile, "r")) == NULL)
{
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);
sleep(3);
return -1;
}
orig_global_redirect_state = fgetc(proc_redirect);
fclose(proc_redirect);
if(orig_global_redirect_state == '0')
return 0;
if ((proc_redirect = fopen(procfile, "w"))==NULL)
{
fprintf(stderr, "Could not open %s for writing!\n", procfile);
fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that ICMP redirect is disabeled!\n\n");
sleep(3);
return 0;
}
syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
fputs("0", proc_redirect);
fclose(proc_redirect);
return 1;
}
/**
*
*@return 1 on sucess 0 on failiure
*/
int
disable_redirects(const char *if_name, struct interface *iface, int version)
{
FILE *proc_redirect;
char procfile[FILENAME_MAX];
if(version == AF_INET6)
return -1;
/* Generate the procfile name */
snprintf(procfile, sizeof(procfile), REDIRECT_PROC, if_name);
if((proc_redirect = fopen(procfile, "r")) == NULL)
{
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);
sleep(3);
return 0;
}
iface->nic_state.redirect = fgetc(proc_redirect);
fclose(proc_redirect);
if ((proc_redirect = fopen(procfile, "w"))==NULL)
{
fprintf(stderr, "Could not open %s for writing!\n", procfile);
fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that ICMP redirect is disabeled!\n\n");
sleep(3);
return 0;
}
syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
fputs("0", proc_redirect);
fclose(proc_redirect);
return 1;
}
/**
*
*@return 1 on sucess 0 on failiure
*/
int
deactivate_spoof(const char *if_name, struct interface *iface, int version)
{
FILE *proc_spoof;
char procfile[FILENAME_MAX];
if(version == AF_INET6)
return -1;
/* Generate the procfile name */
sprintf(procfile, SPOOF_PROC, if_name);
if((proc_spoof = fopen(procfile, "r")) == NULL)
{
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);
sleep(3);
return 0;
}
iface->nic_state.spoof = fgetc(proc_spoof);
fclose(proc_spoof);
if ((proc_spoof = fopen(procfile, "w")) == NULL)
{
fprintf(stderr, "Could not open %s for writing!\n", procfile);
fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that IP spoof filtering is disabeled!\n\n");
sleep(3);
return 0;
}
syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
fputs("0", proc_spoof);
fclose(proc_spoof);
return 1;
}
/**
*Resets the spoof filter and ICMP redirect settings
*/
int
restore_settings(int version)
{
struct interface *ifs;
OLSR_PRINTF(1, "Restoring network state\n");
/* Restore IP forwarding to "off" */
if(orig_fwd_state == '0')
{
const char * const procfile = version == AF_INET
? "/proc/sys/net/ipv4/ip_forward"
: "/proc/sys/net/ipv6/conf/all/forwarding";
FILE *proc_fd;
if ((proc_fd = fopen(procfile, "w")) == NULL)
{
fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
}
else
{
syslog(LOG_INFO, "Resetting %s to %c\n", procfile, orig_fwd_state);
fputc(orig_fwd_state, proc_fd);
fclose(proc_fd);
}
}
/* Restore global ICMP redirect setting */
if(orig_global_redirect_state != '0')
{
if(version == AF_INET)
{
const char * const procfile = "/proc/sys/net/ipv4/conf/all/send_redirects";
FILE *proc_fd;
if ((proc_fd = fopen(procfile, "w")) == NULL)
{
fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
}
else
{
syslog(LOG_INFO, "Resetting %s to %c\n", procfile, orig_global_redirect_state);
fputc(orig_global_redirect_state, proc_fd);
fclose(proc_fd);
}
}
}
if(version == AF_INET6)
return 0;
for(ifs = ifnet; ifs != NULL; ifs = ifs->int_next)
{
char procfile[FILENAME_MAX];
FILE *proc_fd;
/* Discard host-emulation interfaces */
if(ifs->is_hcif)
continue;
/* ICMP redirects */
/* Generate the procfile name */
snprintf(procfile, sizeof(procfile), REDIRECT_PROC, ifs->int_name);
if ((proc_fd = fopen(procfile, "w")) == NULL)
fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
else
{
syslog(LOG_INFO, "Resetting %s to %c\n", procfile, ifs->nic_state.redirect);
fputc(ifs->nic_state.redirect, proc_fd);
fclose(proc_fd);
}
/* Spoof filter */
/* Generate the procfile name */
sprintf(procfile, SPOOF_PROC, ifs->int_name);
if ((proc_fd = fopen(procfile, "w")) == NULL)
fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
else
{
syslog(LOG_INFO, "Resetting %s to %c\n", procfile, ifs->nic_state.spoof);
fputc(ifs->nic_state.spoof, proc_fd);
fclose(proc_fd);
}
}
return 1;
}
/**
*Creates a nonblocking broadcast socket.
*@param sa sockaddr struct. Used for bind(2).
*@return the FD of the socket or -1 on error.
*/
int
gethemusocket(struct sockaddr_in *pin)
{
int sock, on = 1;
OLSR_PRINTF(1, " Connecting to switch daemon port 10150...");
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("hcsocket");
syslog(LOG_ERR, "hcsocket: %m");
return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
{
perror("SO_REUSEADDR failed");
close(sock);
return -1;
}
/* connect to PORT on HOST */
if (connect(sock,(struct sockaddr *) pin, sizeof(*pin)) < 0)
{
printf("FAILED\n");
fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
printf("connection refused\n");
close(sock);
return -1;
}
printf("OK\n");
/* Keep TCP socket blocking */
return sock;
}
/**
*Creates a nonblocking broadcast socket.
*@param sa sockaddr struct. Used for bind(2).
*@return the FD of the socket or -1 on error.
*/
int
getsocket(struct sockaddr *sa, int bufspace, char *int_name)
{
struct sockaddr_in *sin=(struct sockaddr_in *)sa;
int sock, on = 1;
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
syslog(LOG_ERR, "socket: %m");
return -1;
}
#ifdef SO_BROADCAST
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0)
{
perror("setsockopt");
syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
close(sock);
return -1;
}
#endif
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
{
perror("SO_REUSEADDR failed");
close(sock);
return -1;
}
#ifdef SO_RCVBUF
for (on = bufspace; ; on -= 1024)
{
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof (on)) == 0)
break;
if (on <= 8*1024)
{
perror("setsockopt");
syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
break;
}
}
#endif
/*
* WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
*/
/* Bind to device */
if(bind_socket_to_device(sock, int_name) < 0)
{
fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
close(sock);
return -1;
}
if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0)
{
perror("bind");
syslog(LOG_ERR, "bind: %m");
close(sock);
return -1;
}
/*
*FIXME: One should probably fetch the flags first
*using F_GETFL....
*/
if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
return sock;
}
/**
*Creates a nonblocking IPv6 socket
*@param sin sockaddr_in6 struct. Used for bind(2).
*@return the FD of the socket or -1 on error.
*/
int
getsocket6(struct sockaddr_in6 *sin, int bufspace, char *int_name)
{
int sock, on = 1;
if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
syslog(LOG_ERR, "socket: %m");
return (-1);
}
#ifdef IPV6_V6ONLY
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
{
perror("setsockopt(IPV6_V6ONLY)");
syslog(LOG_ERR, "setsockopt(IPV6_V6ONLY): %m");
}
#endif
//#ifdef SO_BROADCAST
/*
if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof (on)) < 0)
{
perror("setsockopt");
syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
close(sock);
return (-1);
}
*/
//#endif
#ifdef SO_RCVBUF
for (on = bufspace; ; on -= 1024)
{
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof (on)) == 0)
break;
if (on <= 8*1024)
{
perror("setsockopt");
syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
break;
}
}
#endif
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
{
perror("SO_REUSEADDR failed");
close(sock);
return (-1);
}
/*
* WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
*/
/* Bind to device */
if(bind_socket_to_device(sock, int_name) < 0)
{
fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
close(sock);
return -1;
}
if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0)
{
perror("bind");
syslog(LOG_ERR, "bind: %m");
close(sock);
return (-1);
}
/*
*One should probably fetch the flags first
*using F_GETFL....
*/
if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
return sock;
}
int
join_mcast(struct interface *ifs, int sock)
{
/* See linux/in6.h */
struct ipv6_mreq mcastreq;
COPY_IP(&mcastreq.ipv6mr_multiaddr, &ifs->int6_multaddr.sin6_addr);
mcastreq.ipv6mr_interface = ifs->if_index;
#if !defined __FreeBSD__ && !defined __MacOSX__ && !defined __NetBSD__
OLSR_PRINTF(3, "Interface %s joining multicast %s...", ifs->int_name, olsr_ip_to_string((union olsr_ip_addr *)&ifs->int6_multaddr.sin6_addr));
/* Send multicast */
if(setsockopt(sock,
IPPROTO_IPV6,
IPV6_ADD_MEMBERSHIP,
(char *)&mcastreq,
sizeof(struct ipv6_mreq))
< 0)
{
perror("Join multicast");
return -1;
}
#else
#warning implement IPV6_ADD_MEMBERSHIP
#endif
/* Old libc fix */
#ifdef IPV6_JOIN_GROUP
/* Join reciever group */
if(setsockopt(sock,
IPPROTO_IPV6,
IPV6_JOIN_GROUP,
(char *)&mcastreq,
sizeof(struct ipv6_mreq))
< 0)
#else
/* Join reciever group */
if(setsockopt(sock,
IPPROTO_IPV6,
IPV6_ADD_MEMBERSHIP,
(char *)&mcastreq,
sizeof(struct ipv6_mreq))
< 0)
#endif
{
perror("Join multicast send");
return -1;
}
if(setsockopt(sock,
IPPROTO_IPV6,
IPV6_MULTICAST_IF,
(char *)&mcastreq.ipv6mr_interface,
sizeof(mcastreq.ipv6mr_interface))
< 0)
{
perror("Set multicast if");
return -1;
}
OLSR_PRINTF(3, "OK\n");
return 0;
}
/*
*From net-tools lib/interface.c
*
*/
int
get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int scope_in)
{
char addr6[40], devname[IFNAMSIZ];
char addr6p[8][5];
int plen, scope, dad_status, if_idx;
FILE *f;
struct sockaddr_in6 tmp_sockaddr6;
if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL)
{
while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
addr6p[0], addr6p[1], addr6p[2], addr6p[3],
addr6p[4], addr6p[5], addr6p[6], addr6p[7],
&if_idx, &plen, &scope, &dad_status, devname) != EOF)
{
if (!strcmp(devname, ifname))
{
sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
addr6p[0], addr6p[1], addr6p[2], addr6p[3],
addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
OLSR_PRINTF(5, "\tinet6 addr: %s\n", addr6);
OLSR_PRINTF(5, "\tScope: %d\n", scope);
if(scope == scope_in)
{
OLSR_PRINTF(4, "Found addr: %s:%s:%s:%s:%s:%s:%s:%s\n",
addr6p[0], addr6p[1], addr6p[2], addr6p[3],
addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
inet_pton(AF_INET6,addr6,&tmp_sockaddr6);
memcpy(&saddr6->sin6_addr, &tmp_sockaddr6, sizeof(struct in6_addr));
fclose(f);
return 1;
}
}
}
fclose(f);
}
return 0;
}
/**
* Wrapper for sendto(2)
*/
ssize_t
olsr_sendto(int s,
const void *buf,
size_t len,
int flags,
const struct sockaddr *to,
socklen_t tolen)
{
return sendto(s, buf, len, flags, to, tolen);
}
/**
* Wrapper for recvfrom(2)
*/
ssize_t
olsr_recvfrom(int s,
void *buf,
size_t len,
int flags,
struct sockaddr *from,
socklen_t *fromlen)
{
return recvfrom(s,
buf,
len,
flags,
from,
fromlen);
}
/**
* Wrapper for select(2)
*/
int
olsr_select(int nfds,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
struct timeval *timeout)
{
return select(nfds,
readfds,
writefds,
exceptfds,
timeout);
}
int
check_wireless_interface(char * ifname)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
return (ioctl(olsr_cnf->ioctl_s, SIOCGIWNAME, &ifr) >= 0) ? 1 : 0;
}
#if 0
#include <linux/sockios.h>
#include <linux/types.h>
/* This data structure is used for all the MII ioctl's */
struct mii_data {
__u16 phy_id;
__u16 reg_num;
__u16 val_in;
__u16 val_out;
};
/* Basic Mode Control Register */
#define MII_BMCR 0x00
#define MII_BMCR_RESET 0x8000
#define MII_BMCR_LOOPBACK 0x4000
#define MII_BMCR_100MBIT 0x2000
#define MII_BMCR_AN_ENA 0x1000
#define MII_BMCR_ISOLATE 0x0400
#define MII_BMCR_RESTART 0x0200
#define MII_BMCR_DUPLEX 0x0100
#define MII_BMCR_COLTEST 0x0080
/* Basic Mode Status Register */
#define MII_BMSR 0x01
#define MII_BMSR_CAP_MASK 0xf800
#define MII_BMSR_100BASET4 0x8000
#define MII_BMSR_100BASETX_FD 0x4000
#define MII_BMSR_100BASETX_HD 0x2000
#define MII_BMSR_10BASET_FD 0x1000
#define MII_BMSR_10BASET_HD 0x0800
#define MII_BMSR_NO_PREAMBLE 0x0040
#define MII_BMSR_AN_COMPLETE 0x0020
#define MII_BMSR_REMOTE_FAULT 0x0010
#define MII_BMSR_AN_ABLE 0x0008
#define MII_BMSR_LINK_VALID 0x0004
#define MII_BMSR_JABBER 0x0002
#define MII_BMSR_EXT_CAP 0x0001
int
calculate_if_metric(char *ifname)
{
if(check_wireless_interface(ifname))
{
struct ifreq ifr;
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
/* Get bit rate */
if(ioctl(olsr_cnf->ioctl_s, SIOCGIWRATE, &ifr) < 0)
{
OLSR_PRINTF(1, "Not able to find rate for WLAN interface %s\n", ifname);
return WEIGHT_WLAN_11MB;
}
OLSR_PRINTF(1, "Bitrate %d\n", ifr.ifr_ifru.ifru_ivalue);
//WEIGHT_WLAN_LOW, /* <11Mb WLAN */
//WEIGHT_WLAN_11MB, /* 11Mb 802.11b */
//WEIGHT_WLAN_54MB, /* 54Mb 802.11g */
return WEIGHT_WLAN_LOW;
}
else
{
/* Ethernet */
/* Mii wizardry */
struct ifreq ifr;
struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
int bmcr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
if (errno != ENODEV)
OLSR_PRINTF(1, "SIOCGMIIPHY on '%s' failed: %s\n",
ifr.ifr_name, strerror(errno));
return WEIGHT_ETHERNET_DEFAULT;
}
mii->reg_num = MII_BMCR;
if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIREG, &ifr) < 0) {
OLSR_PRINTF(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
strerror(errno));
return WEIGHT_ETHERNET_DEFAULT;
}
bmcr = mii->val_out;
OLSR_PRINTF(1, "%s: ", ifr.ifr_name);
OLSR_PRINTF(1, "%s Mbit, %s duplex\n",
(bmcr & MII_BMCR_100MBIT) ? "100" : "10",
(bmcr & MII_BMCR_DUPLEX) ? "full" : "half");
is_if_link_up(ifname);
if(mii->val_out & MII_BMCR_100MBIT)
return WEIGHT_ETHERNET_100MB;
else
return WEIGHT_ETHERNET_10MB;
//WEIGHT_ETHERNET_1GB, /* Ethernet 1Gb */
}
}
olsr_bool
is_if_link_up(char *ifname)
{
if(check_wireless_interface(ifname))
{
/* No link checking on wireless devices */
return OLSR_TRUE;
}
else
{
/* Mii wizardry */
struct ifreq ifr;
struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
int bmsr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
if (errno != ENODEV)
OLSR_PRINTF(1, "SIOCGMIIPHY on '%s' failed: %s\n",
ifr.ifr_name, strerror(errno));
return WEIGHT_ETHERNET_DEFAULT;
}
mii->reg_num = MII_BMSR;
if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIREG, &ifr) < 0) {
OLSR_PRINTF(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
strerror(errno));
return WEIGHT_ETHERNET_DEFAULT;
}
bmsr = mii->val_out;
OLSR_PRINTF(1, "%s: ", ifr.ifr_name);
OLSR_PRINTF(1, "%s\n", (bmsr & MII_BMSR_LINK_VALID) ? "link ok " : "no link ");
return (bmsr & MII_BMSR_LINK_VALID);
}
}
#else
int
calculate_if_metric(char *ifname)
{
return check_wireless_interface(ifname);
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1