[libiwinfo] introduce country() and countrylist() (ISO3166 to driver code mapping)
[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 #define LOG10_MAGIC     1.25892541179
26
27 static int ioctl_socket = -1;
28
29 static double wext_freq2float(const struct iw_freq *in)
30 {
31         int             i;
32         double  res = (double) in->m;
33         for(i = 0; i < in->e; i++) res *= 10;
34         return res;
35 }
36
37 static int wext_freq2mhz(const struct iw_freq *in)
38 {
39         int i, mhz;
40
41         if( in->e == 6 )
42         {
43                 return in->m;
44         }
45         else
46         {
47                 mhz = in->m;
48                 for(i = 0; i < in->e; i++)
49                         mhz *= 10;
50
51                 return (int)(mhz / 100000);
52         }
53 }
54
55 int wext_dbm2mw(int in)
56 {
57         double res = 1.0;
58         int ip = in / 10;
59         int fp = in % 10;
60         int k;
61
62         for(k = 0; k < ip; k++) res *= 10;
63         for(k = 0; k < fp; k++) res *= LOG10_MAGIC;
64
65         return (int)res;
66 }
67
68 int wext_mw2dbm(int in)
69 {
70         double fin = (double) in;
71         int res = 0;
72
73         while(fin > 10.0)
74         {
75                 res += 10;
76                 fin /= 10.0;
77         }
78
79         while(fin > 1.000001)
80         {
81                 res += 1;
82                 fin /= LOG10_MAGIC;
83         }
84
85         return (int)res;
86 }
87
88 static int wext_ioctl(const char *ifname, int cmd, struct iwreq *wrq)
89 {
90         /* prepare socket */
91         if( ioctl_socket == -1 )
92                 ioctl_socket = socket(AF_INET, SOCK_DGRAM, 0);
93
94         if( !strncmp(ifname, "mon.", 4) )
95                 strncpy(wrq->ifr_name, &ifname[4], IFNAMSIZ);
96         else
97                 strncpy(wrq->ifr_name, ifname, IFNAMSIZ);
98
99         return ioctl(ioctl_socket, cmd, wrq);
100 }
101
102
103 int wext_probe(const char *ifname)
104 {
105         struct iwreq wrq;
106
107         if(wext_ioctl(ifname, SIOCGIWNAME, &wrq) >= 0)
108                 return 1;
109
110         return 0;
111 }
112
113 int wext_get_mode(const char *ifname, char *buf)
114 {
115         struct iwreq wrq;
116
117         if(wext_ioctl(ifname, SIOCGIWMODE, &wrq) >= 0)
118         {
119                 switch(wrq.u.mode)
120                 {
121                         case 0:
122                                 sprintf(buf, "Auto");
123                                 break;
124
125                         case 1:
126                                 sprintf(buf, "Ad-Hoc");
127                                 break;
128
129                         case 2:
130                                 sprintf(buf, "Client");
131                                 break;
132
133                         case 3:
134                                 sprintf(buf, "Master");
135                                 break;
136
137                         case 4:
138                                 sprintf(buf, "Repeater");
139                                 break;
140
141                         case 5:
142                                 sprintf(buf, "Secondary");
143                                 break;
144
145                         case 6:
146                                 sprintf(buf, "Monitor");
147                                 break;
148
149                         default:
150                                 sprintf(buf, "Unknown");
151                 }
152
153                 return 0;
154         }
155
156         return -1;
157 }
158
159 int wext_get_ssid(const char *ifname, char *buf)
160 {
161         struct iwreq wrq;
162
163         wrq.u.essid.pointer = (caddr_t) buf;
164         wrq.u.essid.length  = IW_ESSID_MAX_SIZE + 1;
165         wrq.u.essid.flags   = 0;
166
167         if(wext_ioctl(ifname, SIOCGIWESSID, &wrq) >= 0)
168                 return 0;
169
170         return -1;
171 }
172
173 int wext_get_bssid(const char *ifname, char *buf)
174 {
175         struct iwreq wrq;
176
177         if(wext_ioctl(ifname, SIOCGIWAP, &wrq) >= 0)
178         {
179                 sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
180                         (uint8_t)wrq.u.ap_addr.sa_data[0], (uint8_t)wrq.u.ap_addr.sa_data[1],
181                         (uint8_t)wrq.u.ap_addr.sa_data[2], (uint8_t)wrq.u.ap_addr.sa_data[3],
182                         (uint8_t)wrq.u.ap_addr.sa_data[4], (uint8_t)wrq.u.ap_addr.sa_data[5]);
183
184                 return 0;
185         }
186
187         return -1;
188 }
189
190 int wext_get_bitrate(const char *ifname, int *buf)
191 {
192         struct iwreq wrq;
193
194         if(wext_ioctl(ifname, SIOCGIWRATE, &wrq) >= 0)
195         {
196                 *buf = (wrq.u.bitrate.value / 1000);
197                 return 0;
198         }
199
200         return -1;
201 }
202
203 int wext_get_channel(const char *ifname, int *buf)
204 {
205         struct iwreq wrq;
206         struct iw_range range;
207         double freq;
208         int i;
209
210         if(wext_ioctl(ifname, SIOCGIWFREQ, &wrq) >= 0)
211         {
212                 if( wrq.u.freq.m >= 1000 )
213                 {
214                         freq = wext_freq2float(&wrq.u.freq);
215                         wrq.u.data.pointer = (caddr_t) &range;
216                         wrq.u.data.length  = sizeof(struct iw_range);
217                         wrq.u.data.flags   = 0;
218
219                         if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
220                         {
221                                 for(i = 0; i < range.num_frequency; i++)
222                                 {
223                                         if( wext_freq2float(&range.freq[i]) == freq )
224                                         {
225                                                 *buf = range.freq[i].i;
226                                                 return 0;
227                                         }
228                                 }
229                         }
230                 }
231                 else
232                 {
233                         *buf = wrq.u.freq.m;
234                         return 0;
235                 }
236         }
237
238         return -1;
239 }
240
241 int wext_get_frequency(const char *ifname, int *buf)
242 {
243         struct iwreq wrq;
244         struct iw_range range;
245         int i, channel;
246
247         if(wext_ioctl(ifname, SIOCGIWFREQ, &wrq) >= 0)
248         {
249                 /* We got a channel number instead ... */
250                 if( wrq.u.freq.m < 1000 )
251                 {
252                         channel = wrq.u.freq.m;
253                         wrq.u.data.pointer = (caddr_t) &range;
254                         wrq.u.data.length  = sizeof(struct iw_range);
255                         wrq.u.data.flags   = 0;
256
257                         if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
258                         {
259                                 for(i = 0; i < range.num_frequency; i++)
260                                 {
261                                         if( range.freq[i].i == channel )
262                                         {
263                                                 *buf = wext_freq2mhz(&range.freq[i]);
264                                                 return 0;
265                                         }
266                                 }
267                         }
268                 }
269                 else
270                 {
271                         *buf = wext_freq2mhz(&wrq.u.freq);
272                         return 0;
273                 }
274         }
275
276         return -1;
277 }
278
279 int wext_get_txpower(const char *ifname, int *buf)
280 {
281         struct iwreq wrq;
282
283         wrq.u.txpower.flags = 0;
284
285         if(wext_ioctl(ifname, SIOCGIWTXPOW, &wrq) >= 0)
286         {
287                 if(wrq.u.txpower.flags & IW_TXPOW_MWATT)
288                         *buf = wext_mw2dbm(wrq.u.txpower.value);
289                 else
290                         *buf = wrq.u.txpower.value;
291
292                 return 0;
293         }
294
295         return -1;
296 }
297
298 int wext_get_signal(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.updated & IW_QUAL_DBM)
310                         ? (stats.qual.level - 0x100) : stats.qual.level;
311
312                 return 0;
313         }
314
315         return -1;
316 }
317
318 int wext_get_noise(const char *ifname, int *buf)
319 {
320         struct iwreq wrq;
321         struct iw_statistics stats;
322
323         wrq.u.data.pointer = (caddr_t) &stats;
324         wrq.u.data.length  = sizeof(struct iw_statistics);
325         wrq.u.data.flags   = 1;
326
327         if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0)
328         {
329                 *buf = (stats.qual.updated & IW_QUAL_DBM)
330                         ? (stats.qual.noise - 0x100) : stats.qual.noise;
331
332                 return 0;
333         }
334
335         return -1;
336 }
337
338 int wext_get_quality(const char *ifname, int *buf)
339 {
340         struct iwreq wrq;
341         struct iw_statistics stats;
342
343         wrq.u.data.pointer = (caddr_t) &stats;
344         wrq.u.data.length  = sizeof(struct iw_statistics);
345         wrq.u.data.flags   = 1;
346
347         if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0)
348         {
349                 *buf = stats.qual.qual;
350                 return 0;
351         }
352
353         return -1;
354 }
355
356 int wext_get_quality_max(const char *ifname, int *buf)
357 {
358         struct iwreq wrq;
359         struct iw_range range;
360
361         wrq.u.data.pointer = (caddr_t) &range;
362         wrq.u.data.length  = sizeof(struct iw_range);
363         wrq.u.data.flags   = 0;
364
365         if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
366         {
367                 *buf = range.max_qual.qual;
368                 return 0;
369         }
370
371         return -1;
372 }
373
374 int wext_get_assoclist(const char *ifname, char *buf, int *len)
375 {
376         /* Stub */
377         return -1;
378 }
379
380 int wext_get_txpwrlist(const char *ifname, char *buf, int *len)
381 {
382         struct iwreq wrq;
383         struct iw_range range;
384         struct iwinfo_txpwrlist_entry entry;
385         int i;
386
387         wrq.u.data.pointer = (caddr_t) &range;
388         wrq.u.data.length  = sizeof(struct iw_range);
389         wrq.u.data.flags   = 0;
390
391         if( (wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0) &&
392             (range.num_txpower > 0) && (range.num_txpower <= IW_MAX_TXPOWER) &&
393             !(range.txpower_capa & IW_TXPOW_RELATIVE)
394         ) {
395                 for( i = 0; i < range.num_txpower; i++ )
396                 {
397                         if( range.txpower_capa & IW_TXPOW_DBM )
398                         {
399                                 entry.dbm = range.txpower[i];
400                                 entry.mw  = wext_dbm2mw(range.txpower[i]);
401                         }
402
403                         else if( range.txpower_capa & IW_TXPOW_MWATT )
404                         {
405                                 entry.dbm = wext_mw2dbm(range.txpower[i]);
406                                 entry.mw  = range.txpower[i];
407                         }
408
409                         memcpy(&buf[i*sizeof(entry)], &entry, sizeof(entry));
410                 }
411
412                 *len = i * sizeof(entry);
413                 return 0;
414         }
415
416         return -1;
417 }
418
419 int wext_get_freqlist(const char *ifname, char *buf, int *len)
420 {
421         struct iwreq wrq;
422         struct iw_range range;
423         struct iwinfo_freqlist_entry entry;
424         int i, bl;
425
426         wrq.u.data.pointer = (caddr_t) &range;
427         wrq.u.data.length  = sizeof(struct iw_range);
428         wrq.u.data.flags   = 0;
429
430         if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
431         {
432                 bl = 0;
433
434                 for(i = 0; i < range.num_frequency; i++)
435                 {
436                         entry.mhz     = wext_freq2mhz(&range.freq[i]);
437                         entry.channel = range.freq[i].i;
438
439                         memcpy(&buf[bl], &entry, sizeof(struct iwinfo_freqlist_entry));
440                         bl += sizeof(struct iwinfo_freqlist_entry);
441                 }
442
443                 *len = bl;
444                 return 0;
445         }
446
447         return -1;
448 }
449
450 int wext_get_country(const char *ifname, char *buf)
451 {
452         sprintf(buf, "00");
453         return 0;
454 }
455
456 int wext_get_countrylist(const char *ifname, char *buf, int *len)
457 {
458         /* Stub */
459         return -1;
460 }
461
462 int wext_get_encryption(const char *ifname, char *buf)
463 {
464         /* No reliable crypto info in wext */
465         return -1;
466 }
467
468 int wext_get_mbssid_support(const char *ifname, int *buf)
469 {
470         /* No multi bssid support atm */
471         return -1;
472 }