source: trunk/third/ifplugd/src/interface.c @ 20388

Revision 20388, 8.1 KB checked in by amb, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20387, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Id: interface.c,v 1.1.1.1 2004-04-09 20:09:01 amb Exp $ */
2
3/*
4 * This file is part of ifplugd.
5 *
6 * ifplugd is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * ifplugd is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with ifplugd; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 */
20
21#include <linux/sockios.h>
22#include <linux/if_ether.h>
23#include <sys/types.h>
24#include <sys/socket.h>
25#include <sys/ioctl.h>
26#include <linux/if.h>
27#include <syslog.h>
28#include <string.h>
29#include <errno.h>
30#include <netinet/in.h>
31#include <stdio.h>
32#include <ctype.h>
33#include <stdlib.h>
34#include <assert.h>
35
36#include "ethtool-local.h"
37#include "interface.h"
38#include "wireless.h"
39
40#include <libdaemon/dlog.h>
41
42void interface_up(int fd, char *iface) {
43    struct ifreq ifr;
44
45    memset(&ifr, 0, sizeof(ifr));
46    strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)-1);
47   
48    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
49        if (interface_do_message)
50            daemon_log(LOG_WARNING, "Warning: Could not get interface flags.");
51       
52        return;
53    }
54
55    if ((ifr.ifr_flags & IFF_UP) == IFF_UP)
56        return;
57   
58    if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
59        if (interface_do_message)
60            daemon_log(LOG_WARNING, "Warning: Could not get interface address.");
61    } else if (ifr.ifr_addr.sa_family != AF_INET) {
62        if (interface_do_message)
63            daemon_log(LOG_WARNING, "Warning: The interface is not IP-based.");
64    } else {
65        ((struct sockaddr_in *)(&ifr.ifr_addr))->sin_addr.s_addr = INADDR_ANY;
66        if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) {
67            if (interface_do_message)
68                daemon_log(LOG_WARNING, "Warning: Could not set interface address.");
69        }
70    }
71
72    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
73        if (interface_do_message)
74            daemon_log(LOG_WARNING, "Warning: Could not get interface flags.");
75       
76        return;
77    }
78   
79    ifr.ifr_flags |= IFF_UP;
80   
81    if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0)
82        if (interface_do_message)
83            daemon_log(LOG_WARNING, "Warning: Could not set interface flags.");
84}
85
86interface_status_t interface_detect_beat_mii(int fd, char *iface) {
87    struct ifreq ifr;
88   
89    if (interface_auto_up)
90        interface_up(fd, iface);
91   
92    memset(&ifr, 0, sizeof(ifr));
93    strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)-1);
94
95    if (ioctl(fd, SIOCGMIIPHY, &ifr) == -1) {
96        if (interface_do_message)
97            daemon_log(LOG_ERR, "SIOCGMIIPHY failed: %s", strerror(errno));
98       
99        return IFSTATUS_ERR;
100    }
101
102    ((unsigned short*) &ifr.ifr_data)[1] = 1;
103
104    if (ioctl(fd, SIOCGMIIREG, &ifr) == -1) {
105        if (interface_do_message)
106            daemon_log(LOG_ERR, "SIOCGMIIREG failed: %s", strerror(errno));
107       
108        return IFSTATUS_ERR;
109    }
110
111    return (((unsigned short*) &ifr.ifr_data)[3] & 0x0016) == 0x0004 ? IFSTATUS_UP : IFSTATUS_DOWN;
112}
113
114interface_status_t interface_detect_beat_priv(int fd, char *iface) {
115    struct ifreq ifr;
116   
117    if (interface_auto_up)
118        interface_up(fd, iface);
119   
120    memset(&ifr, 0, sizeof(ifr));
121    strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)-1);
122
123    if (ioctl(fd, SIOCDEVPRIVATE, &ifr) == -1) {
124        if (interface_do_message)
125            daemon_log(LOG_ERR, "SIOCDEVPRIVATE failed: %s", strerror(errno));
126       
127        return IFSTATUS_ERR;
128    }
129
130    ((unsigned short*) &ifr.ifr_data)[1] = 1;
131
132    if (ioctl(fd, SIOCDEVPRIVATE+1, &ifr) == -1) {
133        if (interface_do_message)
134            daemon_log(LOG_ERR, "SIOCDEVPRIVATE+1 failed: %s", strerror(errno));
135       
136        return IFSTATUS_ERR;
137    }
138
139    return (((unsigned short*) &ifr.ifr_data)[3] & 0x0016) == 0x0004 ? IFSTATUS_UP : IFSTATUS_DOWN;
140}
141
142interface_status_t interface_detect_beat_ethtool(int fd, char *iface) {
143
144    struct ifreq ifr;
145    struct ethtool_value edata;
146
147    if (interface_auto_up)
148        interface_up(fd, iface);
149   
150    memset(&ifr, 0, sizeof(ifr));
151    strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)-1);
152
153    edata.cmd = ETHTOOL_GLINK;
154    ifr.ifr_data = (caddr_t) &edata;
155
156    if (ioctl(fd, SIOCETHTOOL, &ifr) == -1) {
157        if (interface_do_message)
158            daemon_log(LOG_ERR, "ETHTOOL_GLINK failed: %s", strerror(errno));
159       
160        return IFSTATUS_ERR;
161    }
162
163    return edata.data ? IFSTATUS_UP : IFSTATUS_DOWN;
164}
165
166
167static int get_wlan_qual_old(char *iface) {
168    FILE *f;
169    char buf[256];
170    char *bp;
171    int l, q = -1;
172   
173    l = strlen(iface);
174   
175    if (!(f = fopen("/proc/net/wireless", "r"))) {
176        if (interface_do_message)
177            daemon_log(LOG_WARNING, "Failed to open /proc/net/wireless: %s",strerror(errno));
178       
179        return -1;
180    }
181   
182    while (fgets(buf, sizeof(buf)-1, f)) {
183        bp = buf;
184
185        while (*bp && isspace(*bp))
186            bp++;
187       
188        if(!strncmp(bp, iface, l) && bp[l]==':') {
189
190            /* skip device name */
191            if (!(bp = strchr(bp,' ')))
192                break;
193
194            bp++;
195           
196            /* skip status */
197            if (!(bp = strchr(bp,' ')))
198                break;
199
200            q = atoi(bp);
201            break;
202        };
203    }
204
205    fclose(f);
206
207    if (q < 0) {
208        if (interface_do_message)
209            daemon_log(LOG_ERR, "Failed to find interface in /proc/net/wireless");
210    }
211       
212    return q;
213}
214
215static int get_wlan_qual_new(int fd, char *iface) {
216    struct iwreq req;
217    struct iw_statistics q;
218    static struct iw_range range;
219
220    memset(&req, 0, sizeof(req));
221    strncpy(req.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
222
223    req.u.data.pointer = (caddr_t) &q;
224    req.u.data.length = sizeof(q);
225    req.u.data.flags = 1;
226
227    if (ioctl(fd, SIOCGIWSTATS, &req) < 0) {
228        if (interface_do_message)
229            daemon_log(LOG_ERR, "Failed to get interface quality: %s\n", strerror(errno));
230        return -1;
231    }
232
233    memset(&req, 0, sizeof(req));
234    strncpy(req.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
235
236    memset(&range, 0, sizeof(struct iw_range));
237    req.u.data.pointer = (caddr_t) &range;
238    req.u.data.length = sizeof(struct iw_range);
239    req.u.data.flags = 0;
240     
241    if (ioctl(fd, SIOCGIWRANGE, &req) < 0) {
242        if (interface_do_message)
243            daemon_log(LOG_ERR, "SIOCGIWRANGE failed: %s\n", strerror(errno));
244        return -1;
245    }
246   
247    /* Test if both qual and level are on their lowest level */
248    if (q.qual.qual <= 0 &&
249        (q.qual.level > range.max_qual.level ? q.qual.level <= 156 : q.qual.level <= 0))
250        return 0;
251
252    return 1;
253}
254
255
256static int is_assoc_ap(uint8_t mac[ETH_ALEN]) {
257    int b, j;
258    b = 1;
259   
260    for (j = 1; j < ETH_ALEN; j++)
261        if (mac[j] != mac[0]) {
262            b = 0;
263            break;
264        }
265
266    return !b || (mac[0] != 0xFF && mac[0] != 0x44 && mac[0] != 0x00);
267}
268
269interface_status_t interface_detect_beat_wlan(int fd, char *iface) {
270    uint8_t mac[6];
271    int q;
272    struct iwreq req;
273
274    if (interface_auto_up)
275        interface_up(fd, iface);
276   
277    memset(&req, 0, sizeof(req));
278    strncpy(req.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
279     
280    if (ioctl(fd, SIOCGIWAP, &req) < 0) {
281        if (interface_do_message)
282            daemon_log(LOG_WARNING, "Failed to get AP address: %s",strerror(errno));
283        return IFSTATUS_ERR;
284    }
285
286    memcpy(mac, &(req.u.ap_addr.sa_data), ETH_ALEN);
287           
288    if (!is_assoc_ap(mac))
289        return IFSTATUS_DOWN;
290
291    if ((q = get_wlan_qual_new(fd, iface)) < 0)
292        if ((q = get_wlan_qual_old(iface)) < 0) {
293            if (interface_do_message)
294                daemon_log(LOG_WARNING, "Failed to get wireless link quality.");
295           
296            return IFSTATUS_ERR;
297        }
298   
299    return q > 0 ? IFSTATUS_UP : IFSTATUS_DOWN;
300}
301
Note: See TracBrowser for help on using the repository browser.