10 #include <sys/types.h>
11 #include <sys/socket.h>
13 #include <netinet/in.h>
15 #include <linux/sockios.h>
16 #include <linux/if_ether.h>
18 #include "if_status.h"
20 /*#define USE_ETHTOOL_INTERFACE*/
22 #ifdef USE_ETHTOOL_INTERFACE
23 #include <linux/ethtool.h>
26 #define USE_WIRELESS_INTERFACE
28 #ifdef USE_WIRELESS_INTERFACE
29 #include <linux/wireless.h>
32 /*#define USE_MII_INTERFACE*/
33 /*#define USE_PRIV_INTERFACE*/
35 /*#define DEBUG_IF_STATUS */
36 /*#define DEBUG_IF_STATUS_ERRORS */
38 #ifdef DEBUG_IF_STATUS_C
39 #define PRINT_DEBUG(if_name, msg, err) \
41 printf("%s -- (%s) %s: %s\n", __func__, (if_name), (msg), (err)); \
44 #define PRINT_DEBUG(if_name, msg, err)
47 #ifdef DEBUG_IF_STATUS
48 static void net_debug_status(const char *if_name
, const int status
)
52 printf("%s: Link beat detected\n", if_name
);
55 printf("%s: Unplugged\n", if_name
);
58 printf("%s: Not supported%s\n", if_name
, getuid() != 0 ? " (Retry as root?)" : "");
63 #define net_debug_status(if_name, status)
67 static void interface_up(int fd
, const char *iface
)
71 memset(&ifr
, 0, sizeof(ifr
));
72 strncpy(ifr
.ifr_name
, iface
, sizeof(ifr
.ifr_name
)-1);
74 if (ioctl(fd
, SIOCGIFFLAGS
, &ifr
) < 0) {
75 PRINT_DEBUG(iface
, "Could not get interface flags.", "\n");
79 if ((ifr
.ifr_flags
& IFF_UP
) == IFF_UP
)
82 if (ioctl(fd
, SIOCGIFADDR
, &ifr
) < 0) {
83 /* Could not get interface address */
84 PRINT_DEBUG(iface
, "SIOCGIFADDR", strerror(errno
));
85 } else if (ifr
.ifr_addr
.sa_family
!= AF_INET
) {
86 PRINT_DEBUG(iface
, "The interface is not IP-based.", "\n");
88 ((struct sockaddr_in
*)(&ifr
.ifr_addr
))->sin_addr
.s_addr
= INADDR_ANY
;
89 if (ioctl(fd
, SIOCSIFADDR
, &ifr
) < 0) {
90 /* Could not set interface address */
91 PRINT_DEBUG(iface
, "SIOCSIFADDR", strerror(errno
));
95 if (ioctl(fd
, SIOCGIFFLAGS
, &ifr
) < 0) {
96 /* Could not get interface flags. */
97 PRINT_DEBUG(iface
, "SIOCGIFFLAGS", strerror(errno
));
101 ifr
.ifr_flags
|= IFF_UP
;
103 if (ioctl(fd
, SIOCSIFFLAGS
, &ifr
) < 0) {
104 /* Could not set interface flags */
105 PRINT_DEBUG(iface
, "SIOCSIFFLAGS", strerror(errno
));
111 *======================================================================
113 *======================================================================
115 #ifdef USE_MII_INTERFACE
116 static int interface_detect_beat_mii(int fd
, const char *iface
)
120 memset(&ifr
, 0, sizeof(ifr
));
121 strncpy(ifr
.ifr_name
, iface
, sizeof(ifr
.ifr_name
) - 1);
123 if (ioctl(fd
, SIOCGMIIPHY
, &ifr
) == -1) {
124 PRINT_DEBUG(iface
, "SIOCGMIIPHY", strerror(errno
));
128 ((unsigned short *) &ifr
.ifr_data
)[1] = 1;
130 if (ioctl(fd
, SIOCGMIIREG
, &ifr
) == -1) {
131 PRINT_DEBUG(iface
, "SIOCGMIIREG", strerror(errno
));
135 return (((unsigned short*) &ifr
.ifr_data
)[3] & 0x0004) ? IFSTATUS_UP
: IFSTATUS_DOWN
;
139 #ifdef USE_PRIV_INTERFACE
140 static int interface_detect_beat_priv(int fd
, const char *iface
)
144 memset(&ifr
, 0, sizeof(ifr
));
145 strncpy(ifr
.ifr_name
, iface
, sizeof(ifr
.ifr_name
) - 1);
147 if (ioctl(fd
, SIOCDEVPRIVATE
, &ifr
) == -1) {
148 PRINT_DEBUG(iface
, "SIOCDEVPRIVATE", strerror(errno
));
152 ((unsigned short*) &ifr
.ifr_data
)[1] = 1;
154 if (ioctl(fd
, SIOCDEVPRIVATE
+1, &ifr
) == -1) {
155 PRINT_DEBUG(iface
, "SIOCDEVPRIVATE+1", strerror(errno
));
159 return (((unsigned short*) &ifr
.ifr_data
)[3] & 0x0004) ? IFSTATUS_UP
: IFSTATUS_DOWN
;
163 #ifdef USE_ETHTOOL_INTERFACE
164 static int interface_detect_beat_ethtool(int fd
, const char *iface
)
167 struct ethtool_value edata
;
169 memset(&ifr
, 0, sizeof(ifr
));
170 strncpy(ifr
.ifr_name
, iface
, sizeof(ifr
.ifr_name
)-1);
172 edata
.cmd
= ETHTOOL_GLINK
;
173 ifr
.ifr_data
= (caddr_t
) &edata
;
175 if (ioctl(fd
, SIOCETHTOOL
, &ifr
) == -1) {
176 PRINT_DEBUG(iface
, "ETHTOOL_GLINK", strerror(errno
));
180 return (edata
.data
) ? IFSTATUS_UP
: IFSTATUS_DOWN
;
184 static int interface_detect_beat_iff(int fd
, const char *iface
)
188 memset(&ifr
, 0, sizeof(ifr
));
189 strncpy(ifr
.ifr_name
, iface
, sizeof(ifr
.ifr_name
)-1);
191 if (ioctl(fd
, SIOCGIFFLAGS
, &ifr
) == -1) {
192 PRINT_DEBUG(iface
, "SIOCGIFFLAGS", strerror(errno
));
196 return (ifr
.ifr_flags
& IFF_RUNNING
) ? IFSTATUS_UP
: IFSTATUS_DOWN
;
200 *======================================================================
202 *======================================================================
204 #ifdef USE_WIRELESS_INTERFACE
205 static int get_wlan_qual_old(const char *iface
)
214 f
= fopen("/proc/net/wireless", "r");
216 PRINT_DEBUG(iface
, "Open /proc/net/wireless", strerror(errno
));
220 while (fgets(buf
, sizeof(buf
)-1, f
)) {
223 while (*bp
&& isspace(*bp
))
226 if (!strncmp(bp
, iface
, l
) && bp
[l
]==':') {
227 /* skip device name */
228 if (!(bp
= strchr(bp
, ' ')))
233 if (!(bp
= strchr(bp
, ' ')))
244 PRINT_DEBUG(iface
, "Failed to find interface in /proc/net/wireless", "\n");
250 static int get_wlan_qual_new(int fd
, const char *iface
)
253 struct iw_statistics q
;
254 static struct iw_range range
;
256 memset(&req
, 0, sizeof(req
));
257 strncpy(req
.ifr_ifrn
.ifrn_name
, iface
, IFNAMSIZ
);
259 req
.u
.data
.pointer
= (caddr_t
) &q
;
260 req
.u
.data
.length
= sizeof(q
);
261 req
.u
.data
.flags
= 1;
263 /* Get interface quality */
264 if (ioctl(fd
, SIOCGIWSTATS
, &req
) < 0) {
265 PRINT_DEBUG(iface
, "SIOCGIWSTATS", strerror(errno
));
269 memset(&req
, 0, sizeof(req
));
270 strncpy(req
.ifr_ifrn
.ifrn_name
, iface
, IFNAMSIZ
);
272 memset(&range
, 0, sizeof(struct iw_range
));
273 req
.u
.data
.pointer
= (caddr_t
) &range
;
274 req
.u
.data
.length
= sizeof(struct iw_range
);
275 req
.u
.data
.flags
= 0;
277 if (ioctl(fd
, SIOCGIWRANGE
, &req
) < 0) {
278 PRINT_DEBUG(iface
, "SIOCGIWRANGE", strerror(errno
));
282 /* Test if both qual and level are on their lowest level */
283 if (q
.qual
.qual
<= 0 &&
284 (q
.qual
.level
> range
.max_qual
.level
? q
.qual
.level
<= 156 : q
.qual
.level
<= 0))
290 static int is_assoc_ap(uint8_t mac
[ETH_ALEN
])
295 for (j
= 1; j
< ETH_ALEN
; j
++)
296 if (mac
[j
] != mac
[0]) {
301 return !b
|| (mac
[0] != 0xFF && mac
[0] != 0x44 && mac
[0] != 0x00);
304 static int interface_detect_beat_wlan(int fd
, const char *iface
)
310 memset(&req
, 0, sizeof(req
));
311 strncpy(req
.ifr_ifrn
.ifrn_name
, iface
, IFNAMSIZ
);
313 if (ioctl(fd
, SIOCGIWAP
, &req
) < 0) {
314 PRINT_DEBUG(iface
, "Get AP address", strerror(errno
));
318 memcpy(mac
, &(req
.u
.ap_addr
.sa_data
), ETH_ALEN
);
320 if (!is_assoc_ap(mac
))
321 return IFSTATUS_DOWN
;
323 /* Use new method for get the signal quality */
324 q
= get_wlan_qual_new(fd
, iface
);
326 /* Fallback to the old method for get the signal quality */
327 q
= get_wlan_qual_old(iface
);
329 PRINT_DEBUG(iface
, "Failed to get wireless link quality.", "\n");
334 return q
> 0 ? IFSTATUS_UP
: IFSTATUS_DOWN
;
339 *======================================================================
341 *======================================================================
343 int net_monitor_interface(const char *if_name
, const int wlan
)
352 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
358 if (interface_auto_up
)
359 interface_up(fd
, iface
);
362 #ifdef USE_ETHTOOL_INTERFACE
363 rc
= interface_detect_beat_ethtool(fd
, if_name
);
364 if (rc
!= IFSTATUS_ERR
) {
365 net_debug_status(if_name
, rc
);
370 #ifdef USE_MII_INTERFACE
371 rc
= interface_detect_beat_mii(fd
, if_name
);
372 if (rc
!= IFSTATUS_ERR
) {
373 net_debug_status(if_name
, rc
);
378 #ifdef USE_PRIV_INTERFACE
379 rc
= interface_detect_beat_priv(fd
, if_name
);
380 if (rc
!= IFSTATUS_ERR
) {
381 net_debug_status(if_name
, rc
);
386 #ifdef USE_WIRELESS_INTERFACE
388 rc
= interface_detect_beat_wlan(fd
, if_name
);
389 if (rc
!= IFSTATUS_ERR
) {
390 net_debug_status(if_name
, rc
);
396 rc
= interface_detect_beat_iff(fd
, if_name
);
400 net_debug_status(if_name
, rc
);