Integrate test_header in test_view_mail and various coding style modifications
[rmail.git] / src / network / if_status.c
blob63a08ca416c67f3a28bb24374eeffd9d76e39914
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
6 #include <errno.h>
7 #include <ctype.h>
9 #include <sys/ioctl.h>
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>
24 #endif
26 #define USE_WIRELESS_INTERFACE
28 #ifdef USE_WIRELESS_INTERFACE
29 #include <linux/wireless.h>
30 #endif
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) \
40 do { \
41 printf("%s -- (%s) %s: %s\n", __func__, (if_name), (msg), (err)); \
42 } while (0);
43 #else
44 #define PRINT_DEBUG(if_name, msg, err)
45 #endif
47 #ifdef DEBUG_IF_STATUS
48 static void net_debug_status(const char *if_name, const int status)
50 switch (status) {
51 case IFSTATUS_UP:
52 printf("%s: Link beat detected\n", if_name);
53 break;
54 case IFSTATUS_DOWN:
55 printf("%s: Unplugged\n", if_name);
56 break;
57 default:
58 printf("%s: Not supported%s\n", if_name, getuid() != 0 ? " (Retry as root?)" : "");
59 break;
62 #else
63 #define net_debug_status(if_name, status)
64 #endif
66 #if 0
67 static void interface_up(int fd, const char *iface)
69 struct ifreq ifr;
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");
76 return;
79 if ((ifr.ifr_flags & IFF_UP) == IFF_UP)
80 return;
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");
87 } else {
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));
98 return;
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));
108 #endif
111 *======================================================================
112 * CABLE
113 *======================================================================
115 #ifdef USE_MII_INTERFACE
116 static int interface_detect_beat_mii(int fd, const char *iface)
118 struct ifreq ifr;
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));
125 return IFSTATUS_ERR;
128 ((unsigned short *) &ifr.ifr_data)[1] = 1;
130 if (ioctl(fd, SIOCGMIIREG, &ifr) == -1) {
131 PRINT_DEBUG(iface, "SIOCGMIIREG", strerror(errno));
132 return IFSTATUS_ERR;
135 return (((unsigned short*) &ifr.ifr_data)[3] & 0x0004) ? IFSTATUS_UP : IFSTATUS_DOWN;
137 #endif
139 #ifdef USE_PRIV_INTERFACE
140 static int interface_detect_beat_priv(int fd, const char *iface)
142 struct ifreq ifr;
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));
149 return IFSTATUS_ERR;
152 ((unsigned short*) &ifr.ifr_data)[1] = 1;
154 if (ioctl(fd, SIOCDEVPRIVATE+1, &ifr) == -1) {
155 PRINT_DEBUG(iface, "SIOCDEVPRIVATE+1", strerror(errno));
156 return IFSTATUS_ERR;
159 return (((unsigned short*) &ifr.ifr_data)[3] & 0x0004) ? IFSTATUS_UP : IFSTATUS_DOWN;
161 #endif
163 #ifdef USE_ETHTOOL_INTERFACE
164 static int interface_detect_beat_ethtool(int fd, const char *iface)
166 struct ifreq ifr;
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));
177 return IFSTATUS_ERR;
180 return (edata.data) ? IFSTATUS_UP : IFSTATUS_DOWN;
182 #endif
184 static int interface_detect_beat_iff(int fd, const char *iface)
186 struct ifreq ifr;
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));
193 return IFSTATUS_ERR;
196 return (ifr.ifr_flags & IFF_RUNNING) ? IFSTATUS_UP : IFSTATUS_DOWN;
200 *======================================================================
201 * WLAN
202 *======================================================================
204 #ifdef USE_WIRELESS_INTERFACE
205 static int get_wlan_qual_old(const char *iface)
207 FILE *f;
208 char buf[256];
209 char *bp;
210 int l, q = -1;
212 l = strlen(iface);
214 f = fopen("/proc/net/wireless", "r");
215 if (f == NULL) {
216 PRINT_DEBUG(iface, "Open /proc/net/wireless", strerror(errno));
217 return -1;
220 while (fgets(buf, sizeof(buf)-1, f)) {
221 bp = buf;
223 while (*bp && isspace(*bp))
224 bp++;
226 if (!strncmp(bp, iface, l) && bp[l]==':') {
227 /* skip device name */
228 if (!(bp = strchr(bp, ' ')))
229 break;
230 bp++;
232 /* skip status */
233 if (!(bp = strchr(bp, ' ')))
234 break;
236 q = atoi(bp);
237 break;
241 fclose(f);
243 if (q < 0) {
244 PRINT_DEBUG(iface, "Failed to find interface in /proc/net/wireless", "\n");
247 return q;
250 static int get_wlan_qual_new(int fd, const char *iface)
252 struct iwreq req;
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));
266 return -1;
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));
279 return -1;
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))
285 return 0;
287 return 1;
290 static int is_assoc_ap(uint8_t mac[ETH_ALEN])
292 int b, j;
293 b = 1;
295 for (j = 1; j < ETH_ALEN; j++)
296 if (mac[j] != mac[0]) {
297 b = 0;
298 break;
301 return !b || (mac[0] != 0xFF && mac[0] != 0x44 && mac[0] != 0x00);
304 static int interface_detect_beat_wlan(int fd, const char *iface)
306 uint8_t mac[6];
307 int q;
308 struct iwreq req;
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));
315 return IFSTATUS_ERR;
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);
325 if (q < 0) {
326 /* Fallback to the old method for get the signal quality */
327 q = get_wlan_qual_old(iface);
328 if (q < 0) {
329 PRINT_DEBUG(iface, "Failed to get wireless link quality.", "\n");
330 return IFSTATUS_ERR;
334 return q > 0 ? IFSTATUS_UP : IFSTATUS_DOWN;
336 #endif
339 *======================================================================
340 * PUBLIC FUNCTIONS
341 *======================================================================
343 int net_monitor_interface(const char *if_name, const int wlan)
345 int rc;
346 int fd;
348 if (!if_name) {
349 return IFSTATUS_ERR;
352 fd = socket(PF_INET, SOCK_DGRAM, 0);
353 if (fd < 0) {
354 return IFSTATUS_ERR;
357 #if 0
358 if (interface_auto_up)
359 interface_up(fd, iface);
360 #endif
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);
366 return rc;
368 #endif
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);
374 return rc;
376 #endif
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);
382 return rc;
384 #endif
386 #ifdef USE_WIRELESS_INTERFACE
387 if (wlan) {
388 rc = interface_detect_beat_wlan(fd, if_name);
389 if (rc != IFSTATUS_ERR) {
390 net_debug_status(if_name, rc);
391 return rc;
394 #endif
396 rc = interface_detect_beat_iff(fd, if_name);
398 close(fd);
400 net_debug_status(if_name, rc);
402 return rc;