iwinfo: move wext_ops to iwinfo_wext.c, make functions static
[openwrt/openwrt.git] / package / network / utils / iwinfo / src / iwinfo_wext.c
1 /*
2 * iwinfo - Wireless Information Library - Linux Wireless Extension 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 * Parts of this code are derived from the Linux wireless tools, iwlib.c,
19 * iwlist.c and iwconfig.c in particular.
20 */
21
22 #include "iwinfo.h"
23 #include "iwinfo_wext.h"
24
25 static double wext_freq2float(const struct iw_freq *in)
26 {
27 int i;
28 double res = (double) in->m;
29 for(i = 0; i < in->e; i++) res *= 10;
30 return res;
31 }
32
33 static inline int wext_freq2mhz(const struct iw_freq *in)
34 {
35 int i;
36
37 if( in->e == 6 )
38 {
39 return in->m;
40 }
41 else
42 {
43 return (int)(wext_freq2float(in) / 1000000);
44 }
45 }
46
47 static inline int wext_ioctl(const char *ifname, int cmd, struct iwreq *wrq)
48 {
49 if( !strncmp(ifname, "mon.", 4) )
50 strncpy(wrq->ifr_name, &ifname[4], IFNAMSIZ);
51 else
52 strncpy(wrq->ifr_name, ifname, IFNAMSIZ);
53
54 return iwinfo_ioctl(cmd, wrq);
55 }
56
57
58 static int wext_probe(const char *ifname)
59 {
60 struct iwreq wrq;
61
62 if(wext_ioctl(ifname, SIOCGIWNAME, &wrq) >= 0)
63 return 1;
64
65 return 0;
66 }
67
68 static void wext_close(void)
69 {
70 /* Nop */
71 }
72
73 static int wext_get_mode(const char *ifname, int *buf)
74 {
75 struct iwreq wrq;
76
77 if(wext_ioctl(ifname, SIOCGIWMODE, &wrq) >= 0)
78 {
79 switch(wrq.u.mode)
80 {
81 case 1:
82 *buf = IWINFO_OPMODE_ADHOC;
83 break;
84
85 case 2:
86 *buf = IWINFO_OPMODE_CLIENT;
87 break;
88
89 case 3:
90 *buf = IWINFO_OPMODE_MASTER;
91 break;
92
93 case 6:
94 *buf = IWINFO_OPMODE_MONITOR;
95 break;
96
97 default:
98 *buf = IWINFO_OPMODE_UNKNOWN;
99 break;
100 }
101
102 return 0;
103 }
104
105 return -1;
106 }
107
108 static int wext_get_ssid(const char *ifname, char *buf)
109 {
110 struct iwreq wrq;
111
112 wrq.u.essid.pointer = (caddr_t) buf;
113 wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
114 wrq.u.essid.flags = 0;
115
116 if(wext_ioctl(ifname, SIOCGIWESSID, &wrq) >= 0)
117 return 0;
118
119 return -1;
120 }
121
122 static int wext_get_bssid(const char *ifname, char *buf)
123 {
124 struct iwreq wrq;
125
126 if(wext_ioctl(ifname, SIOCGIWAP, &wrq) >= 0)
127 {
128 sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
129 (uint8_t)wrq.u.ap_addr.sa_data[0], (uint8_t)wrq.u.ap_addr.sa_data[1],
130 (uint8_t)wrq.u.ap_addr.sa_data[2], (uint8_t)wrq.u.ap_addr.sa_data[3],
131 (uint8_t)wrq.u.ap_addr.sa_data[4], (uint8_t)wrq.u.ap_addr.sa_data[5]);
132
133 return 0;
134 }
135
136 return -1;
137 }
138
139 static int wext_get_bitrate(const char *ifname, int *buf)
140 {
141 struct iwreq wrq;
142
143 if(wext_ioctl(ifname, SIOCGIWRATE, &wrq) >= 0)
144 {
145 *buf = (wrq.u.bitrate.value / 1000);
146 return 0;
147 }
148
149 return -1;
150 }
151
152 static int wext_get_channel(const char *ifname, int *buf)
153 {
154 struct iwreq wrq;
155 struct iw_range range;
156 double freq;
157 int i;
158
159 if(wext_ioctl(ifname, SIOCGIWFREQ, &wrq) >= 0)
160 {
161 if( wrq.u.freq.m >= 1000 )
162 {
163 freq = wext_freq2float(&wrq.u.freq);
164 wrq.u.data.pointer = (caddr_t) &range;
165 wrq.u.data.length = sizeof(struct iw_range);
166 wrq.u.data.flags = 0;
167
168 if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
169 {
170 for(i = 0; i < range.num_frequency; i++)
171 {
172 if( wext_freq2float(&range.freq[i]) == freq )
173 {
174 *buf = range.freq[i].i;
175 return 0;
176 }
177 }
178 }
179 }
180 else
181 {
182 *buf = wrq.u.freq.m;
183 return 0;
184 }
185 }
186
187 return -1;
188 }
189
190 static int wext_get_frequency(const char *ifname, int *buf)
191 {
192 struct iwreq wrq;
193 struct iw_range range;
194 int i, channel;
195
196 if(wext_ioctl(ifname, SIOCGIWFREQ, &wrq) >= 0)
197 {
198 /* We got a channel number instead ... */
199 if( wrq.u.freq.m < 1000 )
200 {
201 channel = wrq.u.freq.m;
202 wrq.u.data.pointer = (caddr_t) &range;
203 wrq.u.data.length = sizeof(struct iw_range);
204 wrq.u.data.flags = 0;
205
206 if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
207 {
208 for(i = 0; i < range.num_frequency; i++)
209 {
210 if( range.freq[i].i == channel )
211 {
212 *buf = wext_freq2mhz(&range.freq[i]);
213 return 0;
214 }
215 }
216 }
217 }
218 else
219 {
220 *buf = wext_freq2mhz(&wrq.u.freq);
221 return 0;
222 }
223 }
224
225 return -1;
226 }
227
228 static int wext_get_txpower(const char *ifname, int *buf)
229 {
230 struct iwreq wrq;
231
232 wrq.u.txpower.flags = 0;
233
234 if(wext_ioctl(ifname, SIOCGIWTXPOW, &wrq) >= 0)
235 {
236 if(wrq.u.txpower.flags & IW_TXPOW_MWATT)
237 *buf = iwinfo_mw2dbm(wrq.u.txpower.value);
238 else
239 *buf = wrq.u.txpower.value;
240
241 return 0;
242 }
243
244 return -1;
245 }
246
247 static int wext_get_signal(const char *ifname, int *buf)
248 {
249 struct iwreq wrq;
250 struct iw_statistics stats;
251
252 wrq.u.data.pointer = (caddr_t) &stats;
253 wrq.u.data.length = sizeof(struct iw_statistics);
254 wrq.u.data.flags = 1;
255
256 if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0)
257 {
258 *buf = (stats.qual.updated & IW_QUAL_DBM)
259 ? (stats.qual.level - 0x100) : stats.qual.level;
260
261 return 0;
262 }
263
264 return -1;
265 }
266
267 static int wext_get_noise(const char *ifname, int *buf)
268 {
269 struct iwreq wrq;
270 struct iw_statistics stats;
271
272 wrq.u.data.pointer = (caddr_t) &stats;
273 wrq.u.data.length = sizeof(struct iw_statistics);
274 wrq.u.data.flags = 1;
275
276 if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0)
277 {
278 *buf = (stats.qual.updated & IW_QUAL_DBM)
279 ? (stats.qual.noise - 0x100) : stats.qual.noise;
280
281 return 0;
282 }
283
284 return -1;
285 }
286
287 static int wext_get_quality(const char *ifname, int *buf)
288 {
289 struct iwreq wrq;
290 struct iw_statistics stats;
291
292 wrq.u.data.pointer = (caddr_t) &stats;
293 wrq.u.data.length = sizeof(struct iw_statistics);
294 wrq.u.data.flags = 1;
295
296 if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0)
297 {
298 *buf = stats.qual.qual;
299 return 0;
300 }
301
302 return -1;
303 }
304
305 static int wext_get_quality_max(const char *ifname, int *buf)
306 {
307 struct iwreq wrq;
308 struct iw_range range;
309
310 wrq.u.data.pointer = (caddr_t) &range;
311 wrq.u.data.length = sizeof(struct iw_range);
312 wrq.u.data.flags = 0;
313
314 if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
315 {
316 *buf = range.max_qual.qual;
317 return 0;
318 }
319
320 return -1;
321 }
322
323 static int wext_get_assoclist(const char *ifname, char *buf, int *len)
324 {
325 /* Stub */
326 return -1;
327 }
328
329 static int wext_get_txpwrlist(const char *ifname, char *buf, int *len)
330 {
331 struct iwreq wrq;
332 struct iw_range range;
333 struct iwinfo_txpwrlist_entry entry;
334 int i;
335
336 wrq.u.data.pointer = (caddr_t) &range;
337 wrq.u.data.length = sizeof(struct iw_range);
338 wrq.u.data.flags = 0;
339
340 if( (wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0) &&
341 (range.num_txpower > 0) && (range.num_txpower <= IW_MAX_TXPOWER) &&
342 !(range.txpower_capa & IW_TXPOW_RELATIVE)
343 ) {
344 for( i = 0; i < range.num_txpower; i++ )
345 {
346 if( range.txpower_capa & IW_TXPOW_MWATT )
347 {
348 entry.dbm = iwinfo_mw2dbm(range.txpower[i]);
349 entry.mw = range.txpower[i];
350 }
351
352 /* Madwifi does neither set mW not dBm caps, also iwlist assumes
353 * dBm if mW is not set, so don't check here... */
354 else /* if( range.txpower_capa & IW_TXPOW_DBM ) */
355 {
356 entry.dbm = range.txpower[i];
357 entry.mw = iwinfo_dbm2mw(range.txpower[i]);
358 }
359
360 memcpy(&buf[i*sizeof(entry)], &entry, sizeof(entry));
361 }
362
363 *len = i * sizeof(entry);
364 return 0;
365 }
366
367 return -1;
368 }
369
370 static int wext_get_freqlist(const char *ifname, char *buf, int *len)
371 {
372 struct iwreq wrq;
373 struct iw_range range;
374 struct iwinfo_freqlist_entry entry;
375 int i, bl;
376
377 wrq.u.data.pointer = (caddr_t) &range;
378 wrq.u.data.length = sizeof(struct iw_range);
379 wrq.u.data.flags = 0;
380
381 if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
382 {
383 bl = 0;
384
385 for(i = 0; i < range.num_frequency; i++)
386 {
387 entry.mhz = wext_freq2mhz(&range.freq[i]);
388 entry.channel = range.freq[i].i;
389 entry.restricted = 0;
390
391 memcpy(&buf[bl], &entry, sizeof(struct iwinfo_freqlist_entry));
392 bl += sizeof(struct iwinfo_freqlist_entry);
393 }
394
395 *len = bl;
396 return 0;
397 }
398
399 return -1;
400 }
401
402 static int wext_get_country(const char *ifname, char *buf)
403 {
404 sprintf(buf, "00");
405 return 0;
406 }
407
408 static int wext_get_countrylist(const char *ifname, char *buf, int *len)
409 {
410 /* Stub */
411 return -1;
412 }
413
414 static int wext_get_hwmodelist(const char *ifname, int *buf)
415 {
416 char chans[IWINFO_BUFSIZE] = { 0 };
417 struct iwinfo_freqlist_entry *e = NULL;
418 int len = 0;
419
420 *buf = 0;
421
422 if( !wext_get_freqlist(ifname, chans, &len) )
423 {
424 for( e = (struct iwinfo_freqlist_entry *)chans; e->channel; e++ )
425 {
426 if( e->channel <= 14 )
427 {
428 *buf |= IWINFO_80211_B;
429 *buf |= IWINFO_80211_G;
430 }
431 else
432 {
433 *buf |= IWINFO_80211_A;
434 }
435 }
436
437 return 0;
438 }
439
440 return -1;
441 }
442
443 static int wext_get_encryption(const char *ifname, char *buf)
444 {
445 /* No reliable crypto info in wext */
446 return -1;
447 }
448
449 static int wext_get_phyname(const char *ifname, char *buf)
450 {
451 /* No suitable api in wext */
452 strcpy(buf, ifname);
453 return 0;
454 }
455
456 static int wext_get_mbssid_support(const char *ifname, int *buf)
457 {
458 /* No multi bssid support atm */
459 return -1;
460 }
461
462 static char * wext_sysfs_ifname_file(const char *ifname, const char *path)
463 {
464 FILE *f;
465 static char buf[128];
466 char *rv = NULL;
467
468 snprintf(buf, sizeof(buf), "/sys/class/net/%s/%s", ifname, path);
469
470 if ((f = fopen(buf, "r")) != NULL)
471 {
472 memset(buf, 0, sizeof(buf));
473
474 if (fread(buf, 1, sizeof(buf), f))
475 rv = buf;
476
477 fclose(f);
478 }
479
480 return rv;
481 }
482
483 static int wext_get_hardware_id(const char *ifname, char *buf)
484 {
485 char *data;
486 struct iwinfo_hardware_id *id = (struct iwinfo_hardware_id *)buf;
487
488 memset(id, 0, sizeof(struct iwinfo_hardware_id));
489
490 data = wext_sysfs_ifname_file(ifname, "device/vendor");
491 if (data)
492 id->vendor_id = strtoul(data, NULL, 16);
493
494 data = wext_sysfs_ifname_file(ifname, "device/device");
495 if (data)
496 id->device_id = strtoul(data, NULL, 16);
497
498 data = wext_sysfs_ifname_file(ifname, "device/subsystem_device");
499 if (data)
500 id->subsystem_device_id = strtoul(data, NULL, 16);
501
502 data = wext_sysfs_ifname_file(ifname, "device/subsystem_vendor");
503 if (data)
504 id->subsystem_vendor_id = strtoul(data, NULL, 16);
505
506 return (id->vendor_id > 0 && id->device_id > 0) ? 0 : -1;
507 }
508
509 static int wext_get_hardware_name(const char *ifname, char *buf)
510 {
511 sprintf(buf, "Generic WEXT");
512 return 0;
513 }
514
515 static int wext_get_txpower_offset(const char *ifname, int *buf)
516 {
517 /* Stub */
518 *buf = 0;
519 return -1;
520 }
521
522 static int wext_get_frequency_offset(const char *ifname, int *buf)
523 {
524 /* Stub */
525 *buf = 0;
526 return -1;
527 }
528
529 const struct iwinfo_ops wext_ops = {
530 .name = "wext",
531 .probe = wext_probe,
532 .channel = wext_get_channel,
533 .frequency = wext_get_frequency,
534 .frequency_offset = wext_get_frequency_offset,
535 .txpower = wext_get_txpower,
536 .txpower_offset = wext_get_txpower_offset,
537 .bitrate = wext_get_bitrate,
538 .signal = wext_get_signal,
539 .noise = wext_get_noise,
540 .quality = wext_get_quality,
541 .quality_max = wext_get_quality_max,
542 .mbssid_support = wext_get_mbssid_support,
543 .hwmodelist = wext_get_hwmodelist,
544 .mode = wext_get_mode,
545 .ssid = wext_get_ssid,
546 .bssid = wext_get_bssid,
547 .country = wext_get_country,
548 .hardware_id = wext_get_hardware_id,
549 .hardware_name = wext_get_hardware_name,
550 .encryption = wext_get_encryption,
551 .phyname = wext_get_phyname,
552 .assoclist = wext_get_assoclist,
553 .txpwrlist = wext_get_txpwrlist,
554 .scanlist = wext_get_scanlist,
555 .freqlist = wext_get_freqlist,
556 .countrylist = wext_get_countrylist,
557 .close = wext_close
558 };