#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/sockios.h>
#include <linux/ethtool.h>

//---------------------------------------------------------------
/*
 * 功能描述: 通过MII接口,访问PHY寄存器来确认网络连接状态
 * 参数说明: if_name - 网络接口名("eth0")
 * 返 回 值: 1 - 连接正常
 *            0 - 断开连接
 *           -1 - 错误
 */
int mii_link_status(char *ifname)
{
  int skfd;
  struct ifreq ifr;
  uint16_t *pdata;
  uint16_t mii_val;
  uint16_t phy_id;

  if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) == 0)
  {
    return -1;
  }

  /* Get the vitals from the interface. */
  strncpy(ifr.ifr_name, ifname, IFNAMSIZ);

  if (ioctl(skfd, SIOCGMIIPHY, &ifr) < 0)
  {
    fprintf(stderr, "SIOCGMIIPHY on %s failed: %s\n", ifname, strerror(errno));
    close(skfd);
    return -2;
  }

  pdata    = (uint16_t *)(&ifr.ifr_data);
  phy_id   = pdata[0];
  pdata[1] = 1;
  if (ioctl(skfd, SIOCGMIIREG, &ifr) < 0)
  {
    fprintf(stderr, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name, strerror(errno));
    return -3;
  }

  close(skfd);

  mii_val = pdata[3];
  return (((mii_val & 0x0016) == 0x0004) ? 0 : 1);
}
//---------------------------------------------------------------
/*
 * 功能描述: 通过SIOCETHTOOL命令获取网络连接状态
 * 参数说明: if_name - 网络接口名("eth0")
 * 返 回 值: 1 - 连接正常
 *            0 - 断开连接
 *           -1 - 错误
 */
int get_netlink_status(const char *if_name)
{
  int skfd;
  struct ifreq ifr;
  struct ethtool_value edata;
  edata.cmd = ETHTOOL_GLINK;
  edata.data = 0;
  memset(&ifr, 0, sizeof(ifr));
  strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name) - 1);
  ifr.ifr_data = (char *)&edata;
  if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) == 0)
  {
    return -1;
  }
  if (ioctl(skfd, SIOCETHTOOL, &ifr) == -1)
  {
    close(skfd);
    return -1;
  }
  close(skfd);
  return edata.data;
}
//---------------------------------------------------------------
int main(int argc, char* argv[])
{
  int ret;
  
  if (argc != 2)
  {
    fprintf(stderr, "usage: %s eth0 \r\n", argv[0]);
    return -1;
  }
  
  // 只有超级用户才有权限操作
  if (getuid() != 0)
  {
    fprintf(stderr, "only root can do it.\n");
    return 1;
  }
  while(1)
  {
    // 方法一:SIOCETHTOOL
    ret = get_netlink_status(argv[1]);
    if(ret == 1)
    {
      printf("[SIOCETHTOOL] net link up.\r\n");
    }
    else
    {
      printf("[SIOCETHTOOL] net link down.\r\n");
    }

    // 方法二:读取PHY寄存器方式
    ret = mii_link_status(argv[1]);
    if(ret == 0)
    {
      printf("[SIOCGMIIREG] net link up.\r\n"); 
    }
    else
    {
      printf("[SIOCGMIIREG] net link down.\r\n"); 
    }

    sleep(2);
  }
  return 0;
}
//---------------------------------------------------------------