You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

122 lines
2.6 KiB

  1. /* The best bits of mii-diag and ethtool mixed into one big jelly roll. */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <errno.h>
  7. #include <net/if.h>
  8. #include <sys/types.h>
  9. #include <sys/ioctl.h>
  10. #ifndef TEST
  11. # include <debian-installer/log.h>
  12. # define CONNECTED 1
  13. # define DISCONNECTED 2
  14. # define UNKNOWN 3
  15. #else
  16. # define di_info(fmt, ...) printf(fmt, ## __VA_ARGS__)
  17. # define di_warning(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
  18. # define CONNECTED 0
  19. # define DISCONNECTED 0
  20. # define UNKNOWN 1
  21. #endif
  22. #if defined(__linux__)
  23. #define SYSCLASSNET "/sys/class/net/"
  24. #elif defined(__FreeBSD_kernel__)
  25. #include <net/if_media.h>
  26. #endif
  27. #ifdef TEST
  28. int main(int argc, char** argv)
  29. #else
  30. int ethtool_lite (const char * iface)
  31. #endif
  32. {
  33. #ifdef TEST
  34. char* iface;
  35. #endif
  36. #if defined(__linux__)
  37. int len = strlen(SYSCLASSNET) + strlen(iface) + strlen("/carrier") + 1;
  38. char* filename = malloc(len);
  39. snprintf(filename, len, SYSCLASSNET "%s/carrier", iface);
  40. FILE* fp = fopen(filename, "r");
  41. free(filename);
  42. char result[2];
  43. if (fgets(result, sizeof(result), fp) == NULL) {
  44. fclose(fp);
  45. if (errno == EINVAL) {
  46. di_info("ethtool-lite: %s is down", iface);
  47. return DISCONNECTED;
  48. }
  49. di_error("ethtool-lite: getting carrier failed: %s",
  50. strerror(errno));
  51. return UNKNOWN;
  52. }
  53. fclose(fp);
  54. switch (result[0]) {
  55. case '1':
  56. di_info("ethtool-lite: %s: carrier up", iface);
  57. return CONNECTED;
  58. case '0':
  59. di_info("ethtool-lite: %s: carrier down", iface);
  60. return DISCONNECTED;
  61. }
  62. di_info("ethtool-lite: %s: could not determine carrier state; got \"%s\"",
  63. iface, result);
  64. return UNKNOWN;
  65. #elif defined(__FreeBSD_kernel__)
  66. int fd = socket(AF_INET, SOCK_DGRAM, 0);
  67. if (fd < 0)
  68. {
  69. di_warning("ethtool-lite: could not open control socket\n");
  70. return UNKNOWN;
  71. }
  72. #ifdef TEST
  73. if (argc < 2)
  74. {
  75. fprintf(stderr, "ethtool-lite: Error: must pass an interface name\n");
  76. close(fd);
  77. return 1;
  78. }
  79. iface = argv[1];
  80. #endif
  81. struct ifmediareq ifmr;
  82. memset(&ifmr, 0, sizeof(ifmr));
  83. strncpy(ifmr.ifm_name, iface, sizeof(ifmr.ifm_name));
  84. if (ioctl(fd, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
  85. di_warning("ethtool-lite: SIOCGIFMEDIA ioctl on %s failed\n", iface);
  86. close(fd);
  87. return UNKNOWN;
  88. }
  89. close(fd);
  90. if (ifmr.ifm_status & IFM_AVALID) {
  91. if (ifmr.ifm_status & IFM_ACTIVE) {
  92. di_info("ethtool-lite: %s is connected.\n", iface);
  93. return CONNECTED;
  94. } else {
  95. di_info("ethtool-lite: %s is disconnected.\n", iface);
  96. return DISCONNECTED;
  97. }
  98. }
  99. di_warning("ethtool-lite: couldn't determine status for %s\n", iface);
  100. #elif defined(__GNU__)
  101. di_warning("ethtool-lite: unsupported on GNU/Hurd for %s\n", iface);
  102. #endif
  103. return UNKNOWN;
  104. }