- Create socket handler
由于这两类调用都要使用socket handler,我们先建立一个socket handler用于下面的系统
调用。
/--------------------------------------------------------------------------/
/**
@brief Detect eth link status from ETHTOOL API and MII reg.
@param ifname -- interface name.
@return Return true if link is up, return false if link is down,
or return -1 if errors occur.
This function will first try to get eth link status from ETHTOOL API.
If it fails, it will try to get eth link status from MII reg.
*/
/--------------------------------------------------------------------------/
int get_netlink_status(char *ifname)
{
int skfd = -1;
int link_status;
if (ifname == NULL) {
ifname = "eth0";
}
if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
nl_err("socket error\n");
return -1;
}
link_status = detect_ethtool(skfd, ifname);
if (link_status < 0)
link_status = detect_mii(skfd, ifname);
close(skfd);
return link_status;
}
- SIOCETHTOOL ioctl
下面是SIOCETHTOLL系统调用的用法。
/--------------------------------------------------------------------------/
/**
@brief Detect eth link status from ETHTOOL API.
@param skfd -- socket handler.
@param ifname -- interface name.
@return Return true if link is up, return false if link is down,
or return -1 if errors occur.
*/
/--------------------------------------------------------------------------/
int detect_ethtool(int skfd, char *ifname)
{
struct ifreq ifr;
struct ethtool_value edata;
memset(&ifr, 0, sizeof(ifr));
edata.cmd = ETHTOOL_GLINK;
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)-1);
ifr.ifr_data = (char *) &edata;
if (ioctl(skfd, SIOCETHTOOL, &ifr) == -1) {
nl_err("ETHTOOL_GLINK failed: %s\n", strerror(errno));
return -1;
}
return (edata.data ? 1 : 0);
}
对应内核代码[linux/net/core/dev.c]中dev_ioctl()函数,对应的SIOCETHTOOL,又调用了
[linux/net/core/ethtool.c]中的实现,而dev_ethtool()函数,而这个函数最终又会调用
相应if驱动的ethtool_ops结构体中注册的函数来实现寄存器的操作。当然,不同的PHY驱动
对此有不同的操作,甚至有些PHY驱动根本没有注册这个结构体,这时,我们就要尝试下面
的方法了。
- SIOCxMIIxxx ioctl
下面是SIOCxMIIxxx系统调用的用法。
/--------------------------------------------------------------------------/
/**
@brief Detect eth link status from MII status reg.
@param skfd -- socket handler.
@param ifname -- interface name.
@return Return true if link is up, return false if link is down,
or return -1 if errors occur.
*/
/--------------------------------------------------------------------------/
static int detect_mii(int skfd, char *ifname)
{
struct ifreq ifr;
struct mii_ioctl_data *mii_val;
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(skfd, SIOCGMIIPHY, &ifr) < 0) {
fprintf(stderr, "SIOCGMIIPHY on %s failed: %s\n", ifname,
strerror(errno));
(void) close(skfd);
return -1;
}
mii_val = (struct mii_ioctl_data *)(&ifr.ifr_data);
mii_val->reg_num = MII_BMSR;
if (ioctl(skfd, SIOCGMIIREG, &ifr) < 0) {
nl_err("SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
strerror(errno));
return -1;
}
if ((!(mii_val->val_out & BMSR_RFAULT)) &&
(mii_val->val_out & BMSR_LSTATUS) &&
(!(mii_val->val_out & BMSR_JCD))) {
return 1;
} else {
return 0;
}
}
对应内核代码[linux/net/core/dev.c]中dev_ioctl()函数,对应的SIOCxMIIxxx,又调用了
dev_ifsioc()函数,这个函数最终调用PHY驱动中注册的do_ioctl()函数来实现PHY寄存器的
读写。