cli: add command to translate uci section to phy name
[project/iwinfo.git] / 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 };