iwinfo: improve center channel handling
[project/iwinfo.git] / iwinfo_cli.c
1 /*
2 * iwinfo - Wireless Information Library - Command line frontend
3 *
4 * Copyright (C) 2011 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
19 #include <stdio.h>
20 #include <glob.h>
21
22 #include "iwinfo.h"
23
24
25 static char * format_bssid(unsigned char *mac)
26 {
27 static char buf[18];
28
29 snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X",
30 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
31
32 return buf;
33 }
34
35 static char * format_ssid(char *ssid)
36 {
37 static char buf[IWINFO_ESSID_MAX_SIZE+3];
38
39 if (ssid && ssid[0])
40 snprintf(buf, sizeof(buf), "\"%s\"", ssid);
41 else
42 snprintf(buf, sizeof(buf), "unknown");
43
44 return buf;
45 }
46
47 static char * format_channel(int ch)
48 {
49 static char buf[8];
50
51 if (ch <= 0)
52 snprintf(buf, sizeof(buf), "unknown");
53 else
54 snprintf(buf, sizeof(buf), "%d", ch);
55
56 return buf;
57 }
58
59 static char * format_frequency(int freq)
60 {
61 static char buf[11];
62
63 if (freq <= 0)
64 snprintf(buf, sizeof(buf), "unknown");
65 else
66 snprintf(buf, sizeof(buf), "%.3f GHz", ((float)freq / 1000.0));
67
68 return buf;
69 }
70
71 static char * format_txpower(int pwr)
72 {
73 static char buf[10];
74
75 if (pwr < 0)
76 snprintf(buf, sizeof(buf), "unknown");
77 else
78 snprintf(buf, sizeof(buf), "%d dBm", pwr);
79
80 return buf;
81 }
82
83 static char * format_quality(int qual)
84 {
85 static char buf[8];
86
87 if (qual < 0)
88 snprintf(buf, sizeof(buf), "unknown");
89 else
90 snprintf(buf, sizeof(buf), "%d", qual);
91
92 return buf;
93 }
94
95 static char * format_quality_max(int qmax)
96 {
97 static char buf[8];
98
99 if (qmax < 0)
100 snprintf(buf, sizeof(buf), "unknown");
101 else
102 snprintf(buf, sizeof(buf), "%d", qmax);
103
104 return buf;
105 }
106
107 static char * format_signal(int sig)
108 {
109 static char buf[10];
110
111 if (!sig)
112 snprintf(buf, sizeof(buf), "unknown");
113 else
114 snprintf(buf, sizeof(buf), "%d dBm", sig);
115
116 return buf;
117 }
118
119 static char * format_noise(int noise)
120 {
121 static char buf[10];
122
123 if (!noise)
124 snprintf(buf, sizeof(buf), "unknown");
125 else
126 snprintf(buf, sizeof(buf), "%d dBm", noise);
127
128 return buf;
129 }
130
131 static char * format_rate(int rate)
132 {
133 static char buf[18];
134
135 if (rate <= 0)
136 snprintf(buf, sizeof(buf), "unknown");
137 else
138 snprintf(buf, sizeof(buf), "%d.%d MBit/s",
139 rate / 1000, (rate % 1000) / 100);
140
141 return buf;
142 }
143
144 static char * format_enc_ciphers(int ciphers)
145 {
146 static char str[128] = { 0 };
147 char *pos = str;
148
149 if (ciphers & IWINFO_CIPHER_WEP40)
150 pos += sprintf(pos, "WEP-40, ");
151
152 if (ciphers & IWINFO_CIPHER_WEP104)
153 pos += sprintf(pos, "WEP-104, ");
154
155 if (ciphers & IWINFO_CIPHER_TKIP)
156 pos += sprintf(pos, "TKIP, ");
157
158 if (ciphers & IWINFO_CIPHER_CCMP)
159 pos += sprintf(pos, "CCMP, ");
160
161 if (ciphers & IWINFO_CIPHER_GCMP)
162 pos += sprintf(pos, "GCMP, ");
163
164 if (ciphers & IWINFO_CIPHER_WRAP)
165 pos += sprintf(pos, "WRAP, ");
166
167 if (ciphers & IWINFO_CIPHER_AESOCB)
168 pos += sprintf(pos, "AES-OCB, ");
169
170 if (ciphers & IWINFO_CIPHER_CKIP)
171 pos += sprintf(pos, "CKIP, ");
172
173 if (!ciphers || (ciphers & IWINFO_CIPHER_NONE))
174 pos += sprintf(pos, "NONE, ");
175
176 *(pos - 2) = 0;
177
178 return str;
179 }
180
181 static char * format_enc_suites(int suites)
182 {
183 static char str[64] = { 0 };
184 char *pos = str;
185
186 if (suites & IWINFO_KMGMT_PSK)
187 pos += sprintf(pos, "PSK/");
188
189 if (suites & IWINFO_KMGMT_8021x)
190 pos += sprintf(pos, "802.1X/");
191
192 if (suites & IWINFO_KMGMT_SAE)
193 pos += sprintf(pos, "SAE/");
194
195 if (suites & IWINFO_KMGMT_OWE)
196 pos += sprintf(pos, "OWE/");
197
198 if (!suites || (suites & IWINFO_KMGMT_NONE))
199 pos += sprintf(pos, "NONE/");
200
201 *(pos - 1) = 0;
202
203 return str;
204 }
205
206 static char * format_encryption(struct iwinfo_crypto_entry *c)
207 {
208 static char buf[512];
209 char *pos = buf;
210 int i, n;
211
212 if (!c)
213 {
214 snprintf(buf, sizeof(buf), "unknown");
215 }
216 else if (c->enabled)
217 {
218 /* WEP */
219 if (c->auth_algs && !c->wpa_version)
220 {
221 if ((c->auth_algs & IWINFO_AUTH_OPEN) &&
222 (c->auth_algs & IWINFO_AUTH_SHARED))
223 {
224 snprintf(buf, sizeof(buf), "WEP Open/Shared (%s)",
225 format_enc_ciphers(c->pair_ciphers));
226 }
227 else if (c->auth_algs & IWINFO_AUTH_OPEN)
228 {
229 snprintf(buf, sizeof(buf), "WEP Open System (%s)",
230 format_enc_ciphers(c->pair_ciphers));
231 }
232 else if (c->auth_algs & IWINFO_AUTH_SHARED)
233 {
234 snprintf(buf, sizeof(buf), "WEP Shared Auth (%s)",
235 format_enc_ciphers(c->pair_ciphers));
236 }
237 }
238
239 /* WPA */
240 else if (c->wpa_version)
241 {
242 for (i = 0, n = 0; i < 3; i++)
243 if (c->wpa_version & (1 << i))
244 n++;
245
246 if (n > 1)
247 pos += sprintf(pos, "mixed ");
248
249 for (i = 0; i < 3; i++)
250 if (c->wpa_version & (1 << i))
251 if (i)
252 pos += sprintf(pos, "WPA%d/", i + 1);
253 else
254 pos += sprintf(pos, "WPA/");
255
256 pos--;
257
258 sprintf(pos, " %s (%s)",
259 format_enc_suites(c->auth_suites),
260 format_enc_ciphers(c->pair_ciphers | c->group_ciphers));
261 }
262 else
263 {
264 snprintf(buf, sizeof(buf), "none");
265 }
266 }
267 else
268 {
269 snprintf(buf, sizeof(buf), "none");
270 }
271
272 return buf;
273 }
274
275 static char * format_hwmodes(int modes)
276 {
277 static char buf[15];
278
279 if (modes <= 0)
280 snprintf(buf, sizeof(buf), "unknown");
281 else
282 snprintf(buf, sizeof(buf), "802.11%s%s%s%s%s%s",
283 (modes & IWINFO_80211_A) ? "a" : "",
284 (modes & IWINFO_80211_B) ? "b" : "",
285 (modes & IWINFO_80211_G) ? "g" : "",
286 (modes & IWINFO_80211_N) ? "n" : "",
287 (modes & IWINFO_80211_AC) ? "ac" : "",
288 (modes & IWINFO_80211_AD) ? "ad" : "");
289
290 return buf;
291 }
292
293 static char * format_assocrate(struct iwinfo_rate_entry *r)
294 {
295 static char buf[80];
296 char *p = buf;
297 int l = sizeof(buf);
298
299 if (r->rate <= 0)
300 {
301 snprintf(buf, sizeof(buf), "unknown");
302 }
303 else
304 {
305 p += snprintf(p, l, "%s", format_rate(r->rate));
306 l = sizeof(buf) - (p - buf);
307
308 if (r->is_ht)
309 {
310 p += snprintf(p, l, ", MCS %d, %dMHz", r->mcs, r->mhz);
311 l = sizeof(buf) - (p - buf);
312 }
313 else if (r->is_vht)
314 {
315 p += snprintf(p, l, ", VHT-MCS %d, %dMHz", r->mcs, r->mhz);
316 l = sizeof(buf) - (p - buf);
317
318 if (r->nss)
319 {
320 p += snprintf(p, l, ", VHT-NSS %d", r->nss);
321 l = sizeof(buf) - (p - buf);
322 }
323 }
324 }
325
326 return buf;
327 }
328
329 static const char* format_chan_width(uint16_t width)
330 {
331 switch (width) {
332 case 20: return "20 MHz";
333 case 2040: return "40 MHz and upper or 20 MHz with intolerant bit";
334 case 40: return "40 MHz or lower";
335 case 80: return "80 MHz";
336 case 8080: return "80+80 MHz";
337 case 160: return "160 MHz";
338 }
339
340 return "unknown";
341 }
342
343
344 static const char * print_type(const struct iwinfo_ops *iw, const char *ifname)
345 {
346 const char *type = iwinfo_type(ifname);
347 return type ? type : "unknown";
348 }
349
350 static char * print_hardware_id(const struct iwinfo_ops *iw, const char *ifname)
351 {
352 static char buf[20];
353 struct iwinfo_hardware_id ids;
354
355 if (!iw->hardware_id(ifname, (char *)&ids))
356 {
357 snprintf(buf, sizeof(buf), "%04X:%04X %04X:%04X",
358 ids.vendor_id, ids.device_id,
359 ids.subsystem_vendor_id, ids.subsystem_device_id);
360 }
361 else
362 {
363 snprintf(buf, sizeof(buf), "unknown");
364 }
365
366 return buf;
367 }
368
369 static char * print_hardware_name(const struct iwinfo_ops *iw, const char *ifname)
370 {
371 static char buf[128];
372
373 if (iw->hardware_name(ifname, buf))
374 snprintf(buf, sizeof(buf), "unknown");
375
376 return buf;
377 }
378
379 static char * print_txpower_offset(const struct iwinfo_ops *iw, const char *ifname)
380 {
381 int off;
382 static char buf[12];
383
384 if (iw->txpower_offset(ifname, &off))
385 snprintf(buf, sizeof(buf), "unknown");
386 else if (off != 0)
387 snprintf(buf, sizeof(buf), "%d dB", off);
388 else
389 snprintf(buf, sizeof(buf), "none");
390
391 return buf;
392 }
393
394 static char * print_frequency_offset(const struct iwinfo_ops *iw, const char *ifname)
395 {
396 int off;
397 static char buf[12];
398
399 if (iw->frequency_offset(ifname, &off))
400 snprintf(buf, sizeof(buf), "unknown");
401 else if (off != 0)
402 snprintf(buf, sizeof(buf), "%.3f GHz", ((float)off / 1000.0));
403 else
404 snprintf(buf, sizeof(buf), "none");
405
406 return buf;
407 }
408
409 static char * print_ssid(const struct iwinfo_ops *iw, const char *ifname)
410 {
411 char buf[IWINFO_ESSID_MAX_SIZE+1] = { 0 };
412
413 if (iw->ssid(ifname, buf))
414 memset(buf, 0, sizeof(buf));
415
416 return format_ssid(buf);
417 }
418
419 static char * print_bssid(const struct iwinfo_ops *iw, const char *ifname)
420 {
421 static char buf[18] = { 0 };
422
423 if (iw->bssid(ifname, buf))
424 snprintf(buf, sizeof(buf), "00:00:00:00:00:00");
425
426 return buf;
427 }
428
429 static char * print_mode(const struct iwinfo_ops *iw, const char *ifname)
430 {
431 int mode;
432 static char buf[128];
433
434 if (iw->mode(ifname, &mode))
435 mode = IWINFO_OPMODE_UNKNOWN;
436
437 snprintf(buf, sizeof(buf), "%s", IWINFO_OPMODE_NAMES[mode]);
438
439 return buf;
440 }
441
442 static char * print_channel(const struct iwinfo_ops *iw, const char *ifname)
443 {
444 int ch;
445 if (iw->channel(ifname, &ch))
446 ch = -1;
447
448 return format_channel(ch);
449 }
450
451 static char * print_center_chan1(const struct iwinfo_ops *iw, const char *ifname)
452 {
453 int ch;
454 if (iw->center_chan1(ifname, &ch))
455 ch = -1;
456
457 return format_channel(ch);
458 }
459
460 static char * print_center_chan2(const struct iwinfo_ops *iw, const char *ifname)
461 {
462 int ch;
463 if (iw->center_chan2(ifname, &ch))
464 ch = -1;
465
466 return format_channel(ch);
467 }
468
469 static char * print_frequency(const struct iwinfo_ops *iw, const char *ifname)
470 {
471 int freq;
472 if (iw->frequency(ifname, &freq))
473 freq = -1;
474
475 return format_frequency(freq);
476 }
477
478 static char * print_txpower(const struct iwinfo_ops *iw, const char *ifname)
479 {
480 int pwr, off;
481 if (iw->txpower_offset(ifname, &off))
482 off = 0;
483
484 if (iw->txpower(ifname, &pwr))
485 pwr = -1;
486 else
487 pwr += off;
488
489 return format_txpower(pwr);
490 }
491
492 static char * print_quality(const struct iwinfo_ops *iw, const char *ifname)
493 {
494 int qual;
495 if (iw->quality(ifname, &qual))
496 qual = -1;
497
498 return format_quality(qual);
499 }
500
501 static char * print_quality_max(const struct iwinfo_ops *iw, const char *ifname)
502 {
503 int qmax;
504 if (iw->quality_max(ifname, &qmax))
505 qmax = -1;
506
507 return format_quality_max(qmax);
508 }
509
510 static char * print_signal(const struct iwinfo_ops *iw, const char *ifname)
511 {
512 int sig;
513 if (iw->signal(ifname, &sig))
514 sig = 0;
515
516 return format_signal(sig);
517 }
518
519 static char * print_noise(const struct iwinfo_ops *iw, const char *ifname)
520 {
521 int noise;
522 if (iw->noise(ifname, &noise))
523 noise = 0;
524
525 return format_noise(noise);
526 }
527
528 static char * print_rate(const struct iwinfo_ops *iw, const char *ifname)
529 {
530 int rate;
531 if (iw->bitrate(ifname, &rate))
532 rate = -1;
533
534 return format_rate(rate);
535 }
536
537 static char * print_encryption(const struct iwinfo_ops *iw, const char *ifname)
538 {
539 struct iwinfo_crypto_entry c = { 0 };
540 if (iw->encryption(ifname, (char *)&c))
541 return format_encryption(NULL);
542
543 return format_encryption(&c);
544 }
545
546 static char * print_hwmodes(const struct iwinfo_ops *iw, const char *ifname)
547 {
548 int modes;
549 if (iw->hwmodelist(ifname, &modes))
550 modes = -1;
551
552 return format_hwmodes(modes);
553 }
554
555 static char * print_mbssid_supp(const struct iwinfo_ops *iw, const char *ifname)
556 {
557 int supp;
558 static char buf[4];
559
560 if (iw->mbssid_support(ifname, &supp))
561 snprintf(buf, sizeof(buf), "no");
562 else
563 snprintf(buf, sizeof(buf), "%s", supp ? "yes" : "no");
564
565 return buf;
566 }
567
568 static char * print_phyname(const struct iwinfo_ops *iw, const char *ifname)
569 {
570 static char buf[32];
571
572 if (!iw->phyname(ifname, buf))
573 return buf;
574
575 return "?";
576 }
577
578
579 static void print_info(const struct iwinfo_ops *iw, const char *ifname)
580 {
581 printf("%-9s ESSID: %s\n",
582 ifname,
583 print_ssid(iw, ifname));
584 printf(" Access Point: %s\n",
585 print_bssid(iw, ifname));
586 printf(" Mode: %s Channel: %s (%s)\n",
587 print_mode(iw, ifname),
588 print_channel(iw, ifname),
589 print_frequency(iw, ifname));
590 if (iw->center_chan1 != NULL) {
591 printf(" Center Channel 1: %s",
592 print_center_chan1(iw, ifname));
593 printf(" 2: %s\n", print_center_chan2(iw, ifname));
594 }
595 printf(" Tx-Power: %s Link Quality: %s/%s\n",
596 print_txpower(iw, ifname),
597 print_quality(iw, ifname),
598 print_quality_max(iw, ifname));
599 printf(" Signal: %s Noise: %s\n",
600 print_signal(iw, ifname),
601 print_noise(iw, ifname));
602 printf(" Bit Rate: %s\n",
603 print_rate(iw, ifname));
604 printf(" Encryption: %s\n",
605 print_encryption(iw, ifname));
606 printf(" Type: %s HW Mode(s): %s\n",
607 print_type(iw, ifname),
608 print_hwmodes(iw, ifname));
609 printf(" Hardware: %s [%s]\n",
610 print_hardware_id(iw, ifname),
611 print_hardware_name(iw, ifname));
612 printf(" TX power offset: %s\n",
613 print_txpower_offset(iw, ifname));
614 printf(" Frequency offset: %s\n",
615 print_frequency_offset(iw, ifname));
616 printf(" Supports VAPs: %s PHY name: %s\n",
617 print_mbssid_supp(iw, ifname),
618 print_phyname(iw, ifname));
619 }
620
621
622 static void print_scanlist(const struct iwinfo_ops *iw, const char *ifname)
623 {
624 int i, x, len;
625 char buf[IWINFO_BUFSIZE];
626 struct iwinfo_scanlist_entry *e;
627
628 if (iw->scanlist(ifname, buf, &len))
629 {
630 printf("Scanning not possible\n\n");
631 return;
632 }
633 else if (len <= 0)
634 {
635 printf("No scan results\n\n");
636 return;
637 }
638
639 for (i = 0, x = 1; i < len; i += sizeof(struct iwinfo_scanlist_entry), x++)
640 {
641 e = (struct iwinfo_scanlist_entry *) &buf[i];
642
643 printf("Cell %02d - Address: %s\n",
644 x,
645 format_bssid(e->mac));
646 printf(" ESSID: %s\n",
647 format_ssid(e->ssid));
648 printf(" Mode: %s Channel: %s\n",
649 IWINFO_OPMODE_NAMES[e->mode],
650 format_channel(e->channel));
651 printf(" Signal: %s Quality: %s/%s\n",
652 format_signal(e->signal - 0x100),
653 format_quality(e->quality),
654 format_quality_max(e->quality_max));
655 printf(" Encryption: %s\n",
656 format_encryption(&e->crypto));
657 printf(" HT Operation:\n");
658 printf(" Primary Channel: %d\n",
659 e->ht_chan_info.primary_chan);
660 printf(" Secondary Channel Offset: %s\n",
661 ht_secondary_offset[e->ht_chan_info.secondary_chan_off]);
662 printf(" Channel Width: %s\n",
663 format_chan_width(e->ht_chan_info.chan_width));
664
665 if (e->vht_chan_info.center_chan_1) {
666 printf(" VHT Operation:\n");
667 printf(" Channel Width: %s\n",
668 format_chan_width(e->vht_chan_info.chan_width));
669 printf(" Center Frequency 1: %d\n",
670 e->vht_chan_info.center_chan_1);
671 printf(" Center Frequency 2: %d\n",
672 e->vht_chan_info.center_chan_2);
673 }
674
675 printf("\n");
676 }
677 }
678
679
680 static void print_txpwrlist(const struct iwinfo_ops *iw, const char *ifname)
681 {
682 int len, pwr, off, i;
683 char buf[IWINFO_BUFSIZE];
684 struct iwinfo_txpwrlist_entry *e;
685
686 if (iw->txpwrlist(ifname, buf, &len) || len <= 0)
687 {
688 printf("No TX power information available\n");
689 return;
690 }
691
692 if (iw->txpower(ifname, &pwr))
693 pwr = -1;
694
695 if (iw->txpower_offset(ifname, &off))
696 off = 0;
697
698 for (i = 0; i < len; i += sizeof(struct iwinfo_txpwrlist_entry))
699 {
700 e = (struct iwinfo_txpwrlist_entry *) &buf[i];
701
702 printf("%s%3d dBm (%4d mW)\n",
703 (pwr == e->dbm) ? "*" : " ",
704 e->dbm + off,
705 iwinfo_dbm2mw(e->dbm + off));
706 }
707 }
708
709
710 static void print_freqlist(const struct iwinfo_ops *iw, const char *ifname)
711 {
712 int i, len, ch;
713 char buf[IWINFO_BUFSIZE];
714 struct iwinfo_freqlist_entry *e;
715
716 if (iw->freqlist(ifname, buf, &len) || len <= 0)
717 {
718 printf("No frequency information available\n");
719 return;
720 }
721
722 if (iw->channel(ifname, &ch))
723 ch = -1;
724
725 for (i = 0; i < len; i += sizeof(struct iwinfo_freqlist_entry))
726 {
727 e = (struct iwinfo_freqlist_entry *) &buf[i];
728
729 printf("%s %s (Channel %s)%s\n",
730 (ch == e->channel) ? "*" : " ",
731 format_frequency(e->mhz),
732 format_channel(e->channel),
733 e->restricted ? " [restricted]" : "");
734 }
735 }
736
737
738 static void print_assoclist(const struct iwinfo_ops *iw, const char *ifname)
739 {
740 int i, len;
741 char buf[IWINFO_BUFSIZE];
742 struct iwinfo_assoclist_entry *e;
743
744 if (iw->assoclist(ifname, buf, &len))
745 {
746 printf("No information available\n");
747 return;
748 }
749 else if (len <= 0)
750 {
751 printf("No station connected\n");
752 return;
753 }
754
755 for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry))
756 {
757 e = (struct iwinfo_assoclist_entry *) &buf[i];
758
759 printf("%s %s / %s (SNR %d) %d ms ago\n",
760 format_bssid(e->mac),
761 format_signal(e->signal),
762 format_noise(e->noise),
763 (e->signal - e->noise),
764 e->inactive);
765
766 printf(" RX: %-38s %8d Pkts.\n",
767 format_assocrate(&e->rx_rate),
768 e->rx_packets
769 );
770
771 printf(" TX: %-38s %8d Pkts.\n",
772 format_assocrate(&e->tx_rate),
773 e->tx_packets
774 );
775
776 printf(" expected throughput: %s\n\n",
777 format_rate(e->thr));
778 }
779 }
780
781
782 static char * lookup_country(char *buf, int len, int iso3166)
783 {
784 int i;
785 struct iwinfo_country_entry *c;
786
787 for (i = 0; i < len; i += sizeof(struct iwinfo_country_entry))
788 {
789 c = (struct iwinfo_country_entry *) &buf[i];
790
791 if (c->iso3166 == iso3166)
792 return c->ccode;
793 }
794
795 return NULL;
796 }
797
798 static void print_countrylist(const struct iwinfo_ops *iw, const char *ifname)
799 {
800 int len;
801 char buf[IWINFO_BUFSIZE];
802 char *ccode;
803 char curcode[3];
804 const struct iwinfo_iso3166_label *l;
805
806 if (iw->countrylist(ifname, buf, &len))
807 {
808 printf("No country code information available\n");
809 return;
810 }
811
812 if (iw->country(ifname, curcode))
813 memset(curcode, 0, sizeof(curcode));
814
815 for (l = IWINFO_ISO3166_NAMES; l->iso3166; l++)
816 {
817 if ((ccode = lookup_country(buf, len, l->iso3166)) != NULL)
818 {
819 printf("%s %4s %c%c\n",
820 strncmp(ccode, curcode, 2) ? " " : "*",
821 ccode, (l->iso3166 / 256), (l->iso3166 % 256));
822 }
823 }
824 }
825
826 static void print_htmodelist(const struct iwinfo_ops *iw, const char *ifname)
827 {
828 int i, htmodes = 0;
829
830 if (iw->htmodelist(ifname, &htmodes))
831 {
832 printf("No HT mode information available\n");
833 return;
834 }
835
836 for (i = 0; i < ARRAY_SIZE(IWINFO_HTMODE_NAMES); i++)
837 if (htmodes & (1 << i))
838 printf("%s ", IWINFO_HTMODE_NAMES[i]);
839
840 printf("\n");
841 }
842
843 static void lookup_phy(const struct iwinfo_ops *iw, const char *section)
844 {
845 char buf[IWINFO_BUFSIZE];
846
847 if (!iw->lookup_phy)
848 {
849 fprintf(stderr, "Not supported\n");
850 return;
851 }
852
853 if (iw->lookup_phy(section, buf))
854 {
855 fprintf(stderr, "Phy not found\n");
856 return;
857 }
858
859 printf("%s\n", buf);
860 }
861
862
863 int main(int argc, char **argv)
864 {
865 int i, rv = 0;
866 char *p;
867 const struct iwinfo_ops *iw;
868 glob_t globbuf;
869
870 if (argc > 1 && argc < 3)
871 {
872 fprintf(stderr,
873 "Usage:\n"
874 " iwinfo <device> info\n"
875 " iwinfo <device> scan\n"
876 " iwinfo <device> txpowerlist\n"
877 " iwinfo <device> freqlist\n"
878 " iwinfo <device> assoclist\n"
879 " iwinfo <device> countrylist\n"
880 " iwinfo <device> htmodelist\n"
881 " iwinfo <backend> phyname <section>\n"
882 );
883
884 return 1;
885 }
886
887 if (argc == 1)
888 {
889 glob("/sys/class/net/*", 0, NULL, &globbuf);
890
891 for (i = 0; i < globbuf.gl_pathc; i++)
892 {
893 p = strrchr(globbuf.gl_pathv[i], '/');
894
895 if (!p)
896 continue;
897
898 iw = iwinfo_backend(++p);
899
900 if (!iw)
901 continue;
902
903 print_info(iw, p);
904 printf("\n");
905 }
906
907 globfree(&globbuf);
908 return 0;
909 }
910
911 if (argc > 3)
912 {
913 iw = iwinfo_backend_by_name(argv[1]);
914
915 if (!iw)
916 {
917 fprintf(stderr, "No such wireless backend: %s\n", argv[1]);
918 rv = 1;
919 }
920 else
921 {
922 switch (argv[2][0])
923 {
924 case 'p':
925 lookup_phy(iw, argv[3]);
926 break;
927
928 default:
929 fprintf(stderr, "Unknown command: %s\n", argv[2]);
930 rv = 1;
931 }
932 }
933 }
934 else
935 {
936 iw = iwinfo_backend(argv[1]);
937
938 if (!iw)
939 {
940 fprintf(stderr, "No such wireless device: %s\n", argv[1]);
941 rv = 1;
942 }
943 else
944 {
945 for (i = 2; i < argc; i++)
946 {
947 switch(argv[i][0])
948 {
949 case 'i':
950 print_info(iw, argv[1]);
951 break;
952
953 case 's':
954 print_scanlist(iw, argv[1]);
955 break;
956
957 case 't':
958 print_txpwrlist(iw, argv[1]);
959 break;
960
961 case 'f':
962 print_freqlist(iw, argv[1]);
963 break;
964
965 case 'a':
966 print_assoclist(iw, argv[1]);
967 break;
968
969 case 'c':
970 print_countrylist(iw, argv[1]);
971 break;
972
973 case 'h':
974 print_htmodelist(iw, argv[1]);
975 break;
976
977 default:
978 fprintf(stderr, "Unknown command: %s\n", argv[i]);
979 rv = 1;
980 }
981 }
982 }
983 }
984
985 iwinfo_finish();
986
987 return rv;
988 }