e2bde1c14e4766f5549842546e098393c634bfc3
[project/luci.git] / libs / iwinfo / src / iwinfo_madwifi.c
1 /*
2 * iwinfo - Wireless Information Library - Madwifi Backend
3 *
4 * Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
5 *
6 * The iwinfo library is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * The iwinfo library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with the iwinfo library. If not, see http://www.gnu.org/licenses/.
17 *
18 * The signal handling code is derived from the official madwifi tools,
19 * wlanconfig.c in particular. The encryption property handling was
20 * inspired by the hostapd madwifi driver.
21 */
22
23 #include "iwinfo_madwifi.h"
24 #include "iwinfo_wext.h"
25
26 static int ioctl_socket = -1;
27
28 static int madwifi_ioctl(struct iwreq *wrq, const char *ifname, int cmd, void *data, size_t len)
29 {
30 /* prepare socket */
31 if( ioctl_socket == -1 )
32 ioctl_socket = socket(AF_INET, SOCK_DGRAM, 0);
33
34 strncpy(wrq->ifr_name, ifname, IFNAMSIZ);
35
36 if( data != NULL )
37 {
38 if( len < IFNAMSIZ )
39 {
40 memcpy(wrq->u.name, data, len);
41 }
42 else
43 {
44 wrq->u.data.pointer = data;
45 wrq->u.data.length = len;
46 }
47 }
48
49 return ioctl(ioctl_socket, cmd, wrq);
50 }
51
52 static int get80211priv(const char *ifname, int op, void *data, size_t len)
53 {
54 struct iwreq iwr;
55
56 if( madwifi_ioctl(&iwr, ifname, op, data, len) < 0 )
57 return -1;
58
59 return iwr.u.data.length;
60 }
61
62
63 int madwifi_probe(const char *ifname)
64 {
65 int fd, ret;
66 char path[32];
67 char name[5];
68
69 sprintf(path, "/proc/sys/net/%s/%%parent", ifname);
70 ret = 0;
71
72 if( (fd = open(path, O_RDONLY)) > -1 )
73 {
74 if( read(fd, name, 4) == 4 )
75 ret = strncmp(name, "wifi", 4) ? 0 : 1;
76
77 (void) close(fd);
78 }
79
80 return ret;
81 }
82
83 int madwifi_get_mode(const char *ifname, char *buf)
84 {
85 return wext_get_mode(ifname, buf);
86 }
87
88 int madwifi_get_ssid(const char *ifname, char *buf)
89 {
90 return wext_get_ssid(ifname, buf);
91 }
92
93 int madwifi_get_bssid(const char *ifname, char *buf)
94 {
95 return wext_get_bssid(ifname, buf);
96 }
97
98 int madwifi_get_channel(const char *ifname, int *buf)
99 {
100 int i;
101 uint16_t freq;
102 struct iwreq wrq;
103 struct ieee80211req_chaninfo chans;
104
105 if( madwifi_ioctl(&wrq, ifname, SIOCGIWFREQ, NULL, 0) >= 0 )
106 {
107 /* Madwifi returns a Hz frequency, get it's freq list to find channel index */
108 freq = (uint16_t)(wrq.u.freq.m / 100000);
109
110 if( get80211priv(ifname, IEEE80211_IOCTL_GETCHANINFO, &chans, sizeof(chans)) >= 0 )
111 {
112 *buf = 0;
113
114 for( i = 0; i < chans.ic_nchans; i++ )
115 {
116 if( freq == chans.ic_chans[i].ic_freq )
117 {
118 *buf = chans.ic_chans[i].ic_ieee;
119 break;
120 }
121 }
122
123 return 0;
124 }
125 }
126
127 return -1;
128 }
129
130 int madwifi_get_frequency(const char *ifname, int *buf)
131 {
132 struct iwreq wrq;
133
134 if( madwifi_ioctl(&wrq, ifname, SIOCGIWFREQ, NULL, 0) >= 0 )
135 {
136 *buf = (uint16_t)(wrq.u.freq.m / 100000);
137 return 0;
138 }
139
140 return -1;
141 }
142
143 int madwifi_get_bitrate(const char *ifname, int *buf)
144 {
145 unsigned int mode, len, rate, rate_count;
146 uint8_t tmp[24*1024];
147 uint8_t *cp;
148 struct iwreq wrq;
149 struct ieee80211req_sta_info *si;
150
151 if( madwifi_ioctl(&wrq, ifname, SIOCGIWMODE, NULL, 0) >= 0 )
152 {
153 mode = wrq.u.mode;
154
155 /* Calculate bitrate average from associated stations in ad-hoc mode */
156 if( mode == 1 )
157 {
158 rate = rate_count = 0;
159
160 if( (len = get80211priv(ifname, IEEE80211_IOCTL_STA_INFO, tmp, 24*1024)) > 0 )
161 {
162 cp = tmp;
163
164 do {
165 si = (struct ieee80211req_sta_info *) cp;
166
167 if( si->isi_rssi > 0 )
168 {
169 rate_count++;
170 rate += ((si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL) / 2);
171 }
172
173 cp += si->isi_len;
174 len -= si->isi_len;
175 } while (len >= sizeof(struct ieee80211req_sta_info));
176 }
177
178 *buf = (rate == 0 || rate_count == 0) ? 0 : (rate / rate_count) * 1000;
179 return 0;
180 }
181
182 /* Return whatever wext tells us ... */
183 return wext_get_bitrate(ifname, buf);
184 }
185
186 return -1;
187 }
188
189 int madwifi_get_signal(const char *ifname, int *buf)
190 {
191 unsigned int mode, len, rssi, rssi_count;
192 uint8_t tmp[24*1024];
193 uint8_t *cp;
194 struct iwreq wrq;
195 struct ieee80211req_sta_info *si;
196
197 if( madwifi_ioctl(&wrq, ifname, SIOCGIWMODE, NULL, 0) >= 0 )
198 {
199 mode = wrq.u.mode;
200
201 /* Calculate signal average from associated stations in ap or ad-hoc mode */
202 if( mode == 1 )
203 {
204 rssi = rssi_count = 0;
205
206 if( (len = get80211priv(ifname, IEEE80211_IOCTL_STA_INFO, tmp, 24*1024)) > 0 )
207 {
208 cp = tmp;
209
210 do {
211 si = (struct ieee80211req_sta_info *) cp;
212
213 if( si->isi_rssi > 0 )
214 {
215 rssi_count++;
216 rssi -= (si->isi_rssi - 95);
217 }
218
219 cp += si->isi_len;
220 len -= si->isi_len;
221 } while (len >= sizeof(struct ieee80211req_sta_info));
222 }
223
224 *buf = (rssi == 0 || rssi_count == 0) ? 1 : -(rssi / rssi_count);
225 return 0;
226 }
227
228 /* Return whatever wext tells us ... */
229 return wext_get_signal(ifname, buf);
230 }
231
232 return -1;
233 }
234
235 int madwifi_get_noise(const char *ifname, int *buf)
236 {
237 return wext_get_noise(ifname, buf);
238 }
239
240 int madwifi_get_quality(const char *ifname, int *buf)
241 {
242 unsigned int mode, len, quality, quality_count;
243 uint8_t tmp[24*1024];
244 uint8_t *cp;
245 struct iwreq wrq;
246 struct ieee80211req_sta_info *si;
247
248 if( madwifi_ioctl(&wrq, ifname, SIOCGIWMODE, NULL, 0) >= 0 )
249 {
250 mode = wrq.u.mode;
251
252 /* Calculate signal average from associated stations in ad-hoc mode */
253 if( mode == 1 )
254 {
255 quality = quality_count = 0;
256
257 if( (len = get80211priv(ifname, IEEE80211_IOCTL_STA_INFO, tmp, 24*1024)) > 0 )
258 {
259 cp = tmp;
260
261 do {
262 si = (struct ieee80211req_sta_info *) cp;
263
264 if( si->isi_rssi > 0 )
265 {
266 quality_count++;
267 quality += si->isi_rssi;
268 }
269
270 cp += si->isi_len;
271 len -= si->isi_len;
272 } while (len >= sizeof(struct ieee80211req_sta_info));
273 }
274
275 *buf = (quality == 0 || quality_count == 0) ? 0 : (quality / quality_count);
276 return 0;
277 }
278
279 /* Return whatever wext tells us ... */
280 return wext_get_quality(ifname, buf);
281 }
282
283 return -1;
284 }
285
286 int madwifi_get_quality_max(const char *ifname, int *buf)
287 {
288 return wext_get_quality_max(ifname, buf);
289 }
290
291 int madwifi_get_enctype(const char *ifname, char *buf)
292 {
293 struct iwreq wrq;
294 struct ieee80211req_key wk;
295 int wpa_version = 0, ciphers = 0, key_type = 0;
296 char cipher_string[32];
297
298 sprintf(buf, "Unknown");
299
300 memset(&wrq, 0, sizeof(wrq));
301 memset(&wk, 0, sizeof(wk));
302 memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
303
304 /* Get key information */
305 if( get80211priv(ifname, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk)) >= 0 )
306 key_type = wk.ik_type;
307
308 /* Get wpa protocol version */
309 wrq.u.mode = IEEE80211_PARAM_WPA;
310 if( madwifi_ioctl(&wrq, ifname, IEEE80211_IOCTL_GETPARAM, NULL, 0) >= 0 )
311 wpa_version = wrq.u.mode;
312
313 /* Get used pairwise ciphers */
314 wrq.u.mode = IEEE80211_PARAM_UCASTCIPHERS;
315 if( madwifi_ioctl(&wrq, ifname, IEEE80211_IOCTL_GETPARAM, NULL, 0) >= 0 )
316 {
317 ciphers = wrq.u.mode;
318
319 if( wpa_version > 0 )
320 {
321 memset(cipher_string, 0, sizeof(cipher_string));
322
323 /* Looks like mixed wpa/wpa2 ? */
324 if( (ciphers & (1<<IEEE80211_CIPHER_TKIP)) && (ciphers & (1<<IEEE80211_CIPHER_AES_CCM)) )
325 wpa_version = 3;
326
327
328 if( (ciphers & (1<<IEEE80211_CIPHER_TKIP)) )
329 strcat(cipher_string, "TKIP, ");
330
331 if( (ciphers & (1<<IEEE80211_CIPHER_AES_CCM)) )
332 strcat(cipher_string, "CCMP, ");
333
334 if( (ciphers & (1<<IEEE80211_CIPHER_AES_OCB)) )
335 strcat(cipher_string, "AES-OCB, ");
336
337 if( (ciphers & (1<<IEEE80211_CIPHER_CKIP)) )
338 strcat(cipher_string, "CKIP, ");
339
340 cipher_string[strlen(cipher_string)-2] = 0;
341 }
342
343 switch(wpa_version)
344 {
345 case 3:
346 sprintf(buf, "mixed WPA/WPA2 (%s)", cipher_string);
347 break;
348
349 case 2:
350 sprintf(buf, "WPA2 (%s)", cipher_string);
351 break;
352
353 case 1:
354 sprintf(buf, "WPA (%s)", cipher_string);
355 break;
356
357 default:
358 sprintf(buf, "%s", (key_type == 0) ? "WEP" : "None");
359 }
360 }
361
362 return 0;
363 }
364
365 int madwifi_get_assoclist(const char *ifname, char *buf, int *len)
366 {
367 int bl, tl, noise;
368 uint8_t *cp;
369 uint8_t tmp[24*1024];
370 struct ieee80211req_sta_info *si;
371 struct iwinfo_assoclist_entry entry;
372
373 if( (tl = get80211priv(ifname, IEEE80211_IOCTL_STA_INFO, tmp, 24*1024)) > 0 )
374 {
375 cp = tmp;
376 bl = 0;
377
378 if( madwifi_get_noise(ifname, &noise) )
379 noise = 0;
380
381 do {
382 si = (struct ieee80211req_sta_info *) cp;
383
384 entry.signal = (si->isi_rssi - 95);
385 entry.noise = noise;
386 memcpy(entry.mac, &si->isi_macaddr, 6);
387 memcpy(&buf[bl], &entry, sizeof(struct iwinfo_assoclist_entry));
388
389 bl += sizeof(struct iwinfo_assoclist_entry);
390 cp += si->isi_len;
391 tl -= si->isi_len;
392 } while (tl >= sizeof(struct ieee80211req_sta_info));
393
394 *len = bl;
395 return 0;
396 }
397
398 return -1;
399 }
400
401 int madwifi_get_txpwrlist(const char *ifname, char *buf, int *len)
402 {
403 return wext_get_txpwrlist(ifname, buf, len);
404 }
405
406 int madwifi_get_scanlist(const char *ifname, char *buf, int *len)
407 {
408 return wext_get_scanlist(ifname, buf, len);
409 }
410
411 int madwifi_get_mbssid_support(const char *ifname, int *buf)
412 {
413 /* We assume that multi bssid is always possible */
414 *buf = 1;
415 return 0;
416 }
417