0 | 0 |
/* The best bits of mii-diag and ethtool mixed into one big jelly roll. */
|
1 | 1 |
|
2 | 2 |
#include <stdio.h>
|
|
3 |
#include <stdlib.h>
|
3 | 4 |
#include <string.h>
|
4 | 5 |
#include <unistd.h>
|
|
6 |
#include <errno.h>
|
5 | 7 |
#include <net/if.h>
|
6 | 8 |
#include <sys/types.h>
|
7 | 9 |
#include <sys/ioctl.h>
|
|
20 | 22 |
|
21 | 23 |
#if defined(__linux__)
|
22 | 24 |
|
23 | |
#ifndef ETHTOOL_GLINK
|
24 | |
# define ETHTOOL_GLINK 0x0000000a
|
25 | |
#endif
|
26 | |
|
27 | |
#ifndef SIOCETHTOOL
|
28 | |
# define SIOCETHTOOL 0x8946
|
29 | |
#endif
|
30 | |
|
31 | |
struct ethtool_value
|
32 | |
{
|
33 | |
u_int32_t cmd;
|
34 | |
u_int32_t data;
|
35 | |
};
|
|
25 |
#define SYSCLASSNET "/sys/class/net/"
|
36 | 26 |
|
37 | 27 |
#elif defined(__FreeBSD_kernel__)
|
38 | 28 |
|
|
49 | 39 |
#ifdef TEST
|
50 | 40 |
char* iface;
|
51 | 41 |
#endif
|
|
42 |
|
|
43 |
#if defined(__linux__)
|
|
44 |
int len = strlen(SYSCLASSNET) + strlen(iface) + strlen("/carrier") + 1;
|
|
45 |
char* filename = malloc(len);
|
|
46 |
snprintf(filename, len, SYSCLASSNET "%s/carrier", iface);
|
|
47 |
FILE* fp = fopen(filename, "r");
|
|
48 |
free(filename);
|
|
49 |
|
|
50 |
char result[2];
|
|
51 |
if (fgets(result, sizeof(result), fp) == NULL) {
|
|
52 |
fclose(fp);
|
|
53 |
if (errno == EINVAL) {
|
|
54 |
di_info("ethtool-lite: %s is down", iface);
|
|
55 |
return DISCONNECTED;
|
|
56 |
}
|
|
57 |
di_error("ethtool-lite: getting carrier failed: %s",
|
|
58 |
strerror(errno));
|
|
59 |
return UNKNOWN;
|
|
60 |
}
|
|
61 |
fclose(fp);
|
|
62 |
|
|
63 |
switch (result[0]) {
|
|
64 |
case '1':
|
|
65 |
di_info("ethtool-lite: %s: carrier up", iface);
|
|
66 |
return CONNECTED;
|
|
67 |
case '0':
|
|
68 |
di_info("ethtool-lite: %s: carrier down", iface);
|
|
69 |
return DISCONNECTED;
|
|
70 |
}
|
|
71 |
di_info("ethtool-lite: %s: could not determine carrier state; got \"%s\"",
|
|
72 |
iface, result);
|
|
73 |
return UNKNOWN;
|
|
74 |
#elif defined(__FreeBSD_kernel__)
|
52 | 75 |
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
53 | 76 |
|
54 | 77 |
if (fd < 0)
|
|
67 | 90 |
iface = argv[1];
|
68 | 91 |
#endif
|
69 | 92 |
|
70 | |
#if defined(__linux__)
|
71 | |
struct ethtool_value edata;
|
72 | |
struct ifreq ifr;
|
73 | |
|
74 | |
memset (&edata, 0, sizeof(struct ethtool_value));
|
75 | |
edata.cmd = ETHTOOL_GLINK;
|
76 | |
ifr.ifr_data = (char *)&edata;
|
77 | |
strncpy (ifr.ifr_name, iface, IFNAMSIZ);
|
78 | |
|
79 | |
if (ioctl (fd, SIOCETHTOOL, &ifr) >= 0)
|
80 | |
{
|
81 | |
di_info("ethtool-lite: %s is %sconnected.\n", iface,
|
82 | |
(edata.data) ? "" : "dis");
|
83 | |
close(fd);
|
84 | |
return (edata.data) ? CONNECTED : DISCONNECTED;
|
85 | |
}
|
86 | |
else
|
87 | |
{
|
88 | |
di_info("ethtool-lite: ethtool ioctl on %s failed\n", iface);
|
89 | |
u_int16_t *data = (u_int16_t *)&ifr.ifr_data;
|
90 | |
int ctl;
|
91 | |
data[0] = 0;
|
92 | |
|
93 | |
if (ioctl (fd, 0x8947, &ifr) >= 0)
|
94 | |
ctl = 0x8948;
|
95 | |
else if (ioctl (fd, SIOCDEVPRIVATE, &ifr) >= 0)
|
96 | |
ctl = SIOCDEVPRIVATE + 1;
|
97 | |
else
|
98 | |
{
|
99 | |
di_warning("ethtool-lite: couldn't determine MII ioctl to use for %s\n", iface);
|
100 | |
close(fd);
|
101 | |
return UNKNOWN;
|
102 | |
}
|
103 | |
|
104 | |
data[1] = 1;
|
105 | |
|
106 | |
if (ioctl (fd, ctl, &ifr) >= 0)
|
107 | |
{
|
108 | |
int ret = !(data[3] & 0x0004);
|
109 | |
|
110 | |
di_info ("ethtool-lite: %s is %sconnected. (MII)\n", iface,
|
111 | |
(ret) ? "dis" : "");
|
112 | |
|
113 | |
close(fd);
|
114 | |
return ret ? DISCONNECTED : CONNECTED;
|
115 | |
}
|
116 | |
}
|
117 | |
|
118 | |
di_warning("ethtool-lite: MII ioctl failed for %s\n", iface);
|
119 | |
|
120 | |
#elif defined(__FreeBSD_kernel__)
|
121 | 93 |
struct ifmediareq ifmr;
|
122 | 94 |
|
123 | 95 |
memset(&ifmr, 0, sizeof(ifmr));
|
|
128 | 100 |
close(fd);
|
129 | 101 |
return UNKNOWN;
|
130 | 102 |
}
|
|
103 |
close(fd);
|
131 | 104 |
|
132 | 105 |
if (ifmr.ifm_status & IFM_AVALID) {
|
133 | 106 |
if (ifmr.ifm_status & IFM_ACTIVE) {
|
134 | 107 |
di_info("ethtool-lite: %s is connected.\n", iface);
|
135 | |
close(fd);
|
136 | 108 |
return CONNECTED;
|
137 | 109 |
} else {
|
138 | 110 |
di_info("ethtool-lite: %s is disconnected.\n", iface);
|
139 | |
close(fd);
|
140 | 111 |
return DISCONNECTED;
|
141 | 112 |
}
|
142 | 113 |
}
|
|
145 | 116 |
#elif defined(__GNU__)
|
146 | 117 |
di_warning("ethtool-lite: unsupported on GNU/Hurd for %s\n", iface);
|
147 | 118 |
#endif
|
148 | |
close(fd);
|
149 | 119 |
return UNKNOWN;
|
150 | 120 |
}
|