libiwinfo: major changes
[project/luci.git] / contrib / package / 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 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 void wext_close(void)
69 {
70         /* Nop */
71 }
72
73 int wext_get_mode(const char *ifname, char *buf)
74 {
75         struct iwreq wrq;
76
77         if(wext_ioctl(ifname, SIOCGIWMODE, &wrq) >= 0)
78         {
79                 switch(wrq.u.mode)
80                 {
81                         case 0:
82                                 sprintf(buf, "Auto");
83                                 break;
84
85                         case 1:
86                                 sprintf(buf, "Ad-Hoc");
87                                 break;
88
89                         case 2:
90                                 sprintf(buf, "Client");
91                                 break;
92
93                         case 3:
94                                 sprintf(buf, "Master");
95                                 break;
96
97                         case 4:
98                                 sprintf(buf, "Repeater");
99                                 break;
100
101                         case 5:
102                                 sprintf(buf, "Secondary");
103                                 break;
104
105                         case 6:
106                                 sprintf(buf, "Monitor");
107                                 break;
108
109                         default:
110                                 sprintf(buf, "Unknown");
111                 }
112
113                 return 0;
114         }
115
116         return -1;
117 }
118
119 int wext_get_ssid(const char *ifname, char *buf)
120 {
121         struct iwreq wrq;
122
123         wrq.u.essid.pointer = (caddr_t) buf;
124         wrq.u.essid.length  = IW_ESSID_MAX_SIZE + 1;
125         wrq.u.essid.flags   = 0;
126
127         if(wext_ioctl(ifname, SIOCGIWESSID, &wrq) >= 0)
128                 return 0;
129
130         return -1;
131 }
132
133 int wext_get_bssid(const char *ifname, char *buf)
134 {
135         struct iwreq wrq;
136
137         if(wext_ioctl(ifname, SIOCGIWAP, &wrq) >= 0)
138         {
139                 sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
140                         (uint8_t)wrq.u.ap_addr.sa_data[0], (uint8_t)wrq.u.ap_addr.sa_data[1],
141                         (uint8_t)wrq.u.ap_addr.sa_data[2], (uint8_t)wrq.u.ap_addr.sa_data[3],
142                         (uint8_t)wrq.u.ap_addr.sa_data[4], (uint8_t)wrq.u.ap_addr.sa_data[5]);
143
144                 return 0;
145         }
146
147         return -1;
148 }
149
150 int wext_get_bitrate(const char *ifname, int *buf)
151 {
152         struct iwreq wrq;
153
154         if(wext_ioctl(ifname, SIOCGIWRATE, &wrq) >= 0)
155         {
156                 *buf = (wrq.u.bitrate.value / 1000);
157                 return 0;
158         }
159
160         return -1;
161 }
162
163 int wext_get_channel(const char *ifname, int *buf)
164 {
165         struct iwreq wrq;
166         struct iw_range range;
167         double freq;
168         int i;
169
170         if(wext_ioctl(ifname, SIOCGIWFREQ, &wrq) >= 0)
171         {
172                 if( wrq.u.freq.m >= 1000 )
173                 {
174                         freq = wext_freq2float(&wrq.u.freq);
175                         wrq.u.data.pointer = (caddr_t) &range;
176                         wrq.u.data.length  = sizeof(struct iw_range);
177                         wrq.u.data.flags   = 0;
178
179                         if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
180                         {
181                                 for(i = 0; i < range.num_frequency; i++)
182                                 {
183                                         if( wext_freq2float(&range.freq[i]) == freq )
184                                         {
185                                                 *buf = range.freq[i].i;
186                                                 return 0;
187                                         }
188                                 }
189                         }
190                 }
191                 else
192                 {
193                         *buf = wrq.u.freq.m;
194                         return 0;
195                 }
196         }
197
198         return -1;
199 }
200
201 int wext_get_frequency(const char *ifname, int *buf)
202 {
203         struct iwreq wrq;
204         struct iw_range range;
205         int i, channel;
206
207         if(wext_ioctl(ifname, SIOCGIWFREQ, &wrq) >= 0)
208         {
209                 /* We got a channel number instead ... */
210                 if( wrq.u.freq.m < 1000 )
211                 {
212                         channel = wrq.u.freq.m;
213                         wrq.u.data.pointer = (caddr_t) &range;
214                         wrq.u.data.length  = sizeof(struct iw_range);
215                         wrq.u.data.flags   = 0;
216
217                         if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
218                         {
219                                 for(i = 0; i < range.num_frequency; i++)
220                                 {
221                                         if( range.freq[i].i == channel )
222                                         {
223                                                 *buf = wext_freq2mhz(&range.freq[i]);
224                                                 return 0;
225                                         }
226                                 }
227                         }
228                 }
229                 else
230                 {
231                         *buf = wext_freq2mhz(&wrq.u.freq);
232                         return 0;
233                 }
234         }
235
236         return -1;
237 }
238
239 int wext_get_txpower(const char *ifname, int *buf)
240 {
241         struct iwreq wrq;
242
243         wrq.u.txpower.flags = 0;
244
245         if(wext_ioctl(ifname, SIOCGIWTXPOW, &wrq) >= 0)
246         {
247                 if(wrq.u.txpower.flags & IW_TXPOW_MWATT)
248                         *buf = iwinfo_mw2dbm(wrq.u.txpower.value);
249                 else
250                         *buf = wrq.u.txpower.value;
251
252                 return 0;
253         }
254
255         return -1;
256 }
257
258 int wext_get_signal(const char *ifname, int *buf)
259 {
260         struct iwreq wrq;
261         struct iw_statistics stats;
262
263         wrq.u.data.pointer = (caddr_t) &stats;
264         wrq.u.data.length  = sizeof(struct iw_statistics);
265         wrq.u.data.flags   = 1;
266
267         if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0)
268         {
269                 *buf = (stats.qual.updated & IW_QUAL_DBM)
270                         ? (stats.qual.level - 0x100) : stats.qual.level;
271
272                 return 0;
273         }
274
275         return -1;
276 }
277
278 int wext_get_noise(const char *ifname, int *buf)
279 {
280         struct iwreq wrq;
281         struct iw_statistics stats;
282
283         wrq.u.data.pointer = (caddr_t) &stats;
284         wrq.u.data.length  = sizeof(struct iw_statistics);
285         wrq.u.data.flags   = 1;
286
287         if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0)
288         {
289                 *buf = (stats.qual.updated & IW_QUAL_DBM)
290                         ? (stats.qual.noise - 0x100) : stats.qual.noise;
291
292                 return 0;
293         }
294
295         return -1;
296 }
297
298 int wext_get_quality(const char *ifname, int *buf)
299 {
300         struct iwreq wrq;
301         struct iw_statistics stats;
302
303         wrq.u.data.pointer = (caddr_t) &stats;
304         wrq.u.data.length  = sizeof(struct iw_statistics);
305         wrq.u.data.flags   = 1;
306
307         if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0)
308         {
309                 *buf = stats.qual.qual;
310                 return 0;
311         }
312
313         return -1;
314 }
315
316 int wext_get_quality_max(const char *ifname, int *buf)
317 {
318         struct iwreq wrq;
319         struct iw_range range;
320
321         wrq.u.data.pointer = (caddr_t) &range;
322         wrq.u.data.length  = sizeof(struct iw_range);
323         wrq.u.data.flags   = 0;
324
325         if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
326         {
327                 *buf = range.max_qual.qual;
328                 return 0;
329         }
330
331         return -1;
332 }
333
334 int wext_get_assoclist(const char *ifname, char *buf, int *len)
335 {
336         /* Stub */
337         return -1;
338 }
339
340 int wext_get_txpwrlist(const char *ifname, char *buf, int *len)
341 {
342         struct iwreq wrq;
343         struct iw_range range;
344         struct iwinfo_txpwrlist_entry entry;
345         int i;
346
347         wrq.u.data.pointer = (caddr_t) &range;
348         wrq.u.data.length  = sizeof(struct iw_range);
349         wrq.u.data.flags   = 0;
350
351         if( (wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0) &&
352             (range.num_txpower > 0) && (range.num_txpower <= IW_MAX_TXPOWER) &&
353             !(range.txpower_capa & IW_TXPOW_RELATIVE)
354         ) {
355                 for( i = 0; i < range.num_txpower; i++ )
356                 {
357                         if( range.txpower_capa & IW_TXPOW_MWATT )
358                         {
359                                 entry.dbm = iwinfo_mw2dbm(range.txpower[i]);
360                                 entry.mw  = range.txpower[i];
361                         }
362
363                         /* Madwifi does neither set mW not dBm caps, also iwlist assumes
364                          * dBm if mW is not set, so don't check here... */
365                         else /* if( range.txpower_capa & IW_TXPOW_DBM ) */
366                         {
367                                 entry.dbm = range.txpower[i];
368                                 entry.mw  = iwinfo_dbm2mw(range.txpower[i]);
369                         }
370
371                         memcpy(&buf[i*sizeof(entry)], &entry, sizeof(entry));
372                 }
373
374                 *len = i * sizeof(entry);
375                 return 0;
376         }
377
378         return -1;
379 }
380
381 int wext_get_freqlist(const char *ifname, char *buf, int *len)
382 {
383         struct iwreq wrq;
384         struct iw_range range;
385         struct iwinfo_freqlist_entry entry;
386         int i, bl;
387
388         wrq.u.data.pointer = (caddr_t) &range;
389         wrq.u.data.length  = sizeof(struct iw_range);
390         wrq.u.data.flags   = 0;
391
392         if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
393         {
394                 bl = 0;
395
396                 for(i = 0; i < range.num_frequency; i++)
397                 {
398                         entry.mhz        = wext_freq2mhz(&range.freq[i]);
399                         entry.channel    = range.freq[i].i;
400                         entry.restricted = 0;
401
402                         memcpy(&buf[bl], &entry, sizeof(struct iwinfo_freqlist_entry));
403                         bl += sizeof(struct iwinfo_freqlist_entry);
404                 }
405
406                 *len = bl;
407                 return 0;
408         }
409
410         return -1;
411 }
412
413 int wext_get_country(const char *ifname, char *buf)
414 {
415         sprintf(buf, "00");
416         return 0;
417 }
418
419 int wext_get_countrylist(const char *ifname, char *buf, int *len)
420 {
421         /* Stub */
422         return -1;
423 }
424
425 int wext_get_hwmodelist(const char *ifname, int *buf)
426 {
427         char chans[IWINFO_BUFSIZE] = { 0 };
428         struct iwinfo_freqlist_entry *e = NULL;
429         int len = 0;
430
431         if( !wext_get_freqlist(ifname, chans, &len) )
432         {
433                 for( e = (struct iwinfo_freqlist_entry *)chans; e->channel; e++ )
434                 {
435                         if( e->channel <= 14 )
436                         {
437                                 *buf |= IWINFO_80211_B;
438                                 *buf |= IWINFO_80211_G;
439                         }
440                         else
441                         {
442                                 *buf |= IWINFO_80211_A;
443                         }
444                 }
445
446                 return 0;
447         }
448
449         return -1;
450 }
451
452 int wext_get_encryption(const char *ifname, char *buf)
453 {
454         /* No reliable crypto info in wext */
455         return -1;
456 }
457
458 int wext_get_mbssid_support(const char *ifname, int *buf)
459 {
460         /* No multi bssid support atm */
461         return -1;
462 }