4 * Jean II - HPLB '99 - HPL 99->04
6 * This tool can access various piece of information on the card
7 * not part of iwconfig...
8 * You need to link this code against "iwlist.c" and "-lm".
10 * This file is released under the GPL license.
11 * Copyright (c) 1997-2004 Jean Tourrilhes <jt@hpl.hp.com>
14 #include "iwlib.h" /* Header */
17 /****************************** TYPES ******************************/
20 * Scan state and meta-information, used to decode events...
22 typedef struct iwscan_state
25 int ap_num; /* Access Point number 1->N */
26 int val_index; /* Value in table 0->(N-1) */
30 /*********************** FREQUENCIES/CHANNELS ***********************/
32 /*------------------------------------------------------------------*/
34 * Print the number of channels and available frequency for the device
37 print_freq_info(int skfd,
39 char * args[], /* Command line args */
40 int count) /* Args count */
43 struct iw_range range;
47 char buffer[128]; /* Temporary buffer */
49 /* Avoid "Unused parameter" warning */
50 args = args; count = count;
52 /* Get list of frequencies / channels */
53 if(iw_get_range_info(skfd, ifname, &range) < 0)
54 fprintf(stderr, "%-8.16s no frequency information.\n\n",
58 if(range.num_frequency > 0)
60 printf("%-8.16s %d channels in total; available frequencies :\n",
61 ifname, range.num_channels);
63 for(k = 0; k < range.num_frequency; k++)
65 freq = iw_freq2float(&(range.freq[k]));
66 iw_print_freq_value(buffer, sizeof(buffer), freq);
67 printf(" Channel %.2d : %s\n",
68 range.freq[k].i, buffer);
72 printf("%-8.16s %d channels\n",
73 ifname, range.num_channels);
75 /* Get current frequency / channel and display it */
76 if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
78 freq = iw_freq2float(&(wrq.u.freq));
79 channel = iw_freq_to_channel(freq, &range);
80 iw_print_freq(buffer, sizeof(buffer),
81 freq, channel, wrq.u.freq.flags);
82 printf(" Current %s\n\n", buffer);
88 /************************ ACCESS POINT LIST ************************/
90 * Note : now that we have scanning support, this is depracted and
91 * won't survive long. Actually, next version it's out !
94 /*------------------------------------------------------------------*/
96 * Display the list of ap addresses and the associated stats
97 * Exacly the same as the spy list, only with different IOCTL and messages
100 print_ap_info(int skfd,
102 char * args[], /* Command line args */
103 int count) /* Args count */
106 char buffer[(sizeof(struct iw_quality) +
107 sizeof(struct sockaddr)) * IW_MAX_AP];
109 struct sockaddr * hwa;
110 struct iw_quality * qual;
117 /* Avoid "Unused parameter" warning */
118 args = args; count = count;
121 wrq.u.data.pointer = (caddr_t) buffer;
122 wrq.u.data.length = IW_MAX_AP;
123 wrq.u.data.flags = 0;
124 if(iw_get_ext(skfd, ifname, SIOCGIWAPLIST, &wrq) < 0)
126 fprintf(stderr, "%-8.16s Interface doesn't have a list of Peers/Access-Points\n\n", ifname);
130 /* Number of addresses */
131 n = wrq.u.data.length;
132 has_qual = wrq.u.data.flags;
135 hwa = (struct sockaddr *) buffer;
136 qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n));
138 /* Check if we have valid mac address type */
139 if(iw_check_mac_addr_type(skfd, ifname) < 0)
141 fprintf(stderr, "%-8.16s Interface doesn't support MAC addresses\n\n", ifname);
145 /* Get range info if we can */
146 if(iw_get_range_info(skfd, ifname, &(range)) >= 0)
151 printf("%-8.16s No Peers/Access-Point in range\n", ifname);
153 printf("%-8.16s Peers/Access-Points in range:\n", ifname);
154 for(i = 0; i < n; i++)
158 /* Print stats for this address */
159 printf(" %s : ", iw_saether_ntop(&hwa[i], temp));
160 iw_print_stats(temp, sizeof(buffer), &qual[i], &range, has_range);
161 printf("%s\n", temp);
164 /* Only print the address */
165 printf(" %s\n", iw_saether_ntop(&hwa[i], temp));
171 /***************************** BITRATES *****************************/
173 /*------------------------------------------------------------------*/
175 * Print the number of available bitrates for the device
178 print_bitrate_info(int skfd,
180 char * args[], /* Command line args */
181 int count) /* Args count */
184 struct iw_range range;
188 /* Avoid "Unused parameter" warning */
189 args = args; count = count;
191 /* Extract range info */
192 if(iw_get_range_info(skfd, ifname, &range) < 0)
193 fprintf(stderr, "%-8.16s no bit-rate information.\n\n",
197 if((range.num_bitrates > 0) && (range.num_bitrates <= IW_MAX_BITRATES))
199 printf("%-8.16s %d available bit-rates :\n",
200 ifname, range.num_bitrates);
202 for(k = 0; k < range.num_bitrates; k++)
204 iw_print_bitrate(buffer, sizeof(buffer), range.bitrate[k]);
205 /* Maybe this should be %10s */
206 printf("\t %s\n", buffer);
210 printf("%-8.16s unknown bit-rate information.\n", ifname);
212 /* Get current bit rate */
213 if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
215 iw_print_bitrate(buffer, sizeof(buffer), wrq.u.bitrate.value);
216 printf(" Current Bit Rate%c%s\n\n",
217 (wrq.u.bitrate.fixed ? '=' : ':'), buffer);
223 /************************* ENCRYPTION KEYS *************************/
225 /*------------------------------------------------------------------*/
227 * Print the number of available encryption key for the device
230 print_keys_info(int skfd,
232 char * args[], /* Command line args */
233 int count) /* Args count */
236 struct iw_range range;
237 unsigned char key[IW_ENCODING_TOKEN_MAX];
241 /* Avoid "Unused parameter" warning */
242 args = args; count = count;
244 /* Extract range info */
245 if(iw_get_range_info(skfd, ifname, &range) < 0)
246 fprintf(stderr, "%-8.16s no encryption keys information.\n\n",
250 printf("%-8.16s ", ifname);
251 /* Print key sizes */
252 if((range.num_encoding_sizes > 0) &&
253 (range.num_encoding_sizes < IW_MAX_ENCODING_SIZES))
255 printf("%d key sizes : %d", range.num_encoding_sizes,
256 range.encoding_size[0] * 8);
258 for(k = 1; k < range.num_encoding_sizes; k++)
259 printf(", %d", range.encoding_size[k] * 8);
262 /* Print the keys and associate mode */
263 printf("%d keys available :\n", range.max_encoding_tokens);
264 for(k = 1; k <= range.max_encoding_tokens; k++)
266 wrq.u.data.pointer = (caddr_t) key;
267 wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
268 wrq.u.data.flags = k;
269 if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) < 0)
271 fprintf(stderr, "Error reading wireless keys (SIOCGIWENCODE): %s\n", strerror(errno));
274 if((wrq.u.data.flags & IW_ENCODE_DISABLED) ||
275 (wrq.u.data.length == 0))
276 printf("\t\t[%d]: off\n", k);
279 /* Display the key */
280 iw_print_key(buffer, sizeof(buffer),
281 key, wrq.u.data.length, wrq.u.data.flags);
282 printf("\t\t[%d]: %s", k, buffer);
285 printf(" (%d bits)", wrq.u.data.length * 8);
289 /* Print current key and mode */
290 wrq.u.data.pointer = (caddr_t) key;
291 wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
292 wrq.u.data.flags = 0; /* Set index to zero to get current */
293 if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
295 /* Note : if above fails, we have already printed an error
296 * message int the loop above */
297 printf(" Current Transmit Key: [%d]\n",
298 wrq.u.data.flags & IW_ENCODE_INDEX);
299 if(wrq.u.data.flags & IW_ENCODE_RESTRICTED)
300 printf(" Security mode:restricted\n");
301 if(wrq.u.data.flags & IW_ENCODE_OPEN)
302 printf(" Security mode:open\n");
305 /* Print WPA/802.1x/802.11i security parameters */
306 if(range.we_version_compiled > 17)
308 /* Display advance encryption capabilities */
311 const char * auth_string[] = { "WPA",
315 const int auth_num = (sizeof(auth_string) /
316 sizeof(auth_string[1]));
320 printf(" Authentication capabilities :\n");
321 for(i = 0; i < auth_num; i++)
323 if(range.enc_capa & mask)
324 printf("\t\t%s\n", auth_string[i]);
329 /* Current values for authentication */
330 wrq.u.param.flags = IW_AUTH_KEY_MGMT;
331 if(iw_get_ext(skfd, ifname, SIOCGIWAUTH, &wrq) >= 0)
332 printf(" Current key_mgmt:0x%X\n",
335 wrq.u.param.flags = IW_AUTH_CIPHER_PAIRWISE;
336 if(iw_get_ext(skfd, ifname, SIOCGIWAUTH, &wrq) >= 0)
337 printf(" Current cipher_pairwise:0x%X\n",
340 wrq.u.param.flags = IW_AUTH_CIPHER_GROUP;
341 if(iw_get_ext(skfd, ifname, SIOCGIWAUTH, &wrq) >= 0)
342 printf(" Current cipher_group:0x%X\n",
351 /************************* POWER MANAGEMENT *************************/
353 /*------------------------------------------------------------------*/
355 * Print Power Management info for each device
358 get_pm_value(int skfd,
365 /* Get Another Power Management value */
366 pwrq->u.power.flags = flags;
367 if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, pwrq) >= 0)
369 /* Let's check the value and its type */
370 if(pwrq->u.power.flags & IW_POWER_TYPE)
372 iw_print_pm_value(buffer, buflen,
373 pwrq->u.power.value, pwrq->u.power.flags);
374 printf("\n %s", buffer);
377 return(pwrq->u.power.flags);
380 /*------------------------------------------------------------------*/
382 * Print Power Management info for each device
385 print_pm_info(int skfd,
387 char * args[], /* Command line args */
388 int count) /* Args count */
391 struct iw_range range;
394 /* Avoid "Unused parameter" warning */
395 args = args; count = count;
397 /* Extract range info */
398 if((iw_get_range_info(skfd, ifname, &range) < 0) ||
399 (range.we_version_compiled < 10))
400 fprintf(stderr, "%-8.16s no power management information.\n\n",
404 printf("%-8.16s ", ifname);
406 /* Display modes availables */
407 if(range.pm_capa & IW_POWER_MODE)
409 printf("Supported modes :\n ");
410 if(range.pm_capa & (IW_POWER_UNICAST_R | IW_POWER_MULTICAST_R))
411 printf("\t\to Receive all packets (unicast & multicast)\n ");
412 if(range.pm_capa & IW_POWER_UNICAST_R)
413 printf("\t\to Receive Unicast only (discard multicast)\n ");
414 if(range.pm_capa & IW_POWER_MULTICAST_R)
415 printf("\t\to Receive Multicast only (discard unicast)\n ");
416 if(range.pm_capa & IW_POWER_FORCE_S)
417 printf("\t\to Force sending using Power Management\n ");
418 if(range.pm_capa & IW_POWER_REPEATER)
419 printf("\t\to Repeat multicast\n ");
421 /* Display min/max period availables */
422 if(range.pmp_flags & IW_POWER_PERIOD)
424 int flags = (range.pmp_flags & ~(IW_POWER_MIN | IW_POWER_MAX));
425 /* Display if auto or fixed */
426 if(range.pmp_flags & IW_POWER_MIN)
427 printf("Auto period ; ");
429 printf("Fixed period ; ");
430 /* Print the range */
431 iw_print_pm_value(buffer, sizeof(buffer),
432 range.min_pmp, flags | IW_POWER_MIN);
433 printf("%s\n ", buffer);
434 iw_print_pm_value(buffer, sizeof(buffer),
435 range.max_pmp, flags | IW_POWER_MAX);
436 printf("%s\n ", buffer);
438 /* Display min/max timeout availables */
439 if(range.pmt_flags & IW_POWER_TIMEOUT)
441 int flags = (range.pmt_flags & ~(IW_POWER_MIN | IW_POWER_MAX));
442 /* Display if auto or fixed */
443 if(range.pmt_flags & IW_POWER_MIN)
444 printf("Auto timeout ; ");
446 printf("Fixed timeout ; ");
447 /* Print the range */
448 iw_print_pm_value(buffer, sizeof(buffer),
449 range.min_pmt, flags | IW_POWER_MIN);
450 printf("%s\n ", buffer);
451 iw_print_pm_value(buffer, sizeof(buffer),
452 range.max_pmt, flags | IW_POWER_MAX);
453 printf("%s\n ", buffer);
456 /* Get current Power Management settings */
457 wrq.u.power.flags = 0;
458 if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, &wrq) >= 0)
460 int flags = wrq.u.power.flags;
462 /* Is it disabled ? */
463 if(wrq.u.power.disabled)
464 printf("Current mode:off\n ");
469 /* Let's check the mode */
470 iw_print_pm_mode(buffer, sizeof(buffer), flags);
471 printf("Current %s", buffer);
473 /* Let's check if nothing (simply on) */
474 if((flags & IW_POWER_MODE) == IW_POWER_ON)
478 /* Let's check the value and its type */
479 if(wrq.u.power.flags & IW_POWER_TYPE)
481 iw_print_pm_value(buffer, sizeof(buffer),
482 wrq.u.power.value, wrq.u.power.flags);
483 printf("%s", buffer);
486 /* If we have been returned a MIN value, ask for the MAX */
487 if(flags & IW_POWER_MIN)
488 pm_mask = IW_POWER_MAX;
489 /* If we have been returned a MAX value, ask for the MIN */
490 if(flags & IW_POWER_MAX)
491 pm_mask = IW_POWER_MIN;
492 /* If we have something to ask for... */
494 get_pm_value(skfd, ifname, &wrq, pm_mask,
495 buffer, sizeof(buffer));
497 /* And if we have both a period and a timeout, ask the other */
498 pm_mask = (range.pm_capa & (~(wrq.u.power.flags) &
502 int base_mask = pm_mask;
503 flags = get_pm_value(skfd, ifname, &wrq, pm_mask,
504 buffer, sizeof(buffer));
507 /* If we have been returned a MIN value, ask for the MAX */
508 if(flags & IW_POWER_MIN)
509 pm_mask = IW_POWER_MAX | base_mask;
510 /* If we have been returned a MAX value, ask for the MIN */
511 if(flags & IW_POWER_MAX)
512 pm_mask = IW_POWER_MIN | base_mask;
513 /* If we have something to ask for... */
515 get_pm_value(skfd, ifname, &wrq, pm_mask,
516 buffer, sizeof(buffer));
525 /************************** TRANSMIT POWER **************************/
527 /*------------------------------------------------------------------*/
529 * Print the number of available transmit powers for the device
532 print_txpower_info(int skfd,
534 char * args[], /* Command line args */
535 int count) /* Args count */
538 struct iw_range range;
543 /* Avoid "Unused parameter" warning */
544 args = args; count = count;
546 /* Extract range info */
547 if((iw_get_range_info(skfd, ifname, &range) < 0) ||
548 (range.we_version_compiled < 10))
549 fprintf(stderr, "%-8.16s no transmit-power information.\n\n",
553 if((range.num_txpower <= 0) || (range.num_txpower > IW_MAX_TXPOWER))
554 printf("%-8.16s unknown transmit-power information.\n\n", ifname);
557 printf("%-8.16s %d available transmit-powers :\n",
558 ifname, range.num_txpower);
560 for(k = 0; k < range.num_txpower; k++)
562 /* Check for relative values */
563 if(range.txpower_capa & IW_TXPOW_RELATIVE)
565 printf("\t %d (no units)\n", range.txpower[k]);
569 if(range.txpower_capa & IW_TXPOW_MWATT)
571 dbm = iw_mwatt2dbm(range.txpower[k]);
572 mwatt = range.txpower[k];
576 dbm = range.txpower[k];
577 mwatt = iw_dbm2mwatt(range.txpower[k]);
579 printf("\t %d dBm \t(%d mW)\n", dbm, mwatt);
584 /* Get current Transmit Power */
585 if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) >= 0)
587 printf(" Current Tx-Power");
589 if(wrq.u.txpower.disabled)
594 if(wrq.u.txpower.fixed)
598 /* Check for relative values */
599 if(wrq.u.txpower.flags & IW_TXPOW_RELATIVE)
601 /* I just hate relative value, because they are
602 * driver specific, so not very meaningfull to apps.
603 * But, we have to support that, because
604 * this is the way hardware is... */
605 printf("\t %d (no units)\n", wrq.u.txpower.value);
609 if(wrq.u.txpower.flags & IW_TXPOW_MWATT)
611 dbm = iw_mwatt2dbm(wrq.u.txpower.value);
612 mwatt = wrq.u.txpower.value;
616 dbm = wrq.u.txpower.value;
617 mwatt = iw_dbm2mwatt(wrq.u.txpower.value);
619 printf("%d dBm \t(%d mW)\n\n", dbm, mwatt);
627 /*********************** RETRY LIMIT/LIFETIME ***********************/
629 /*------------------------------------------------------------------*/
631 * Print one retry value
634 get_retry_value(int skfd,
641 /* Get Another retry value */
642 pwrq->u.retry.flags = flags;
643 if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, pwrq) >= 0)
645 /* Let's check the value and its type */
646 if(pwrq->u.retry.flags & IW_RETRY_TYPE)
648 iw_print_retry_value(buffer, buflen,
649 pwrq->u.retry.value, pwrq->u.retry.flags);
650 printf("%s\n ", buffer);
653 return(pwrq->u.retry.flags);
656 /*------------------------------------------------------------------*/
658 * Print Retry info for each device
661 print_retry_info(int skfd,
663 char * args[], /* Command line args */
664 int count) /* Args count */
667 struct iw_range range;
670 /* Avoid "Unused parameter" warning */
671 args = args; count = count;
673 /* Extract range info */
674 if((iw_get_range_info(skfd, ifname, &range) < 0) ||
675 (range.we_version_compiled < 11))
676 fprintf(stderr, "%-8.16s no retry limit/lifetime information.\n\n",
680 printf("%-8.16s ", ifname);
682 /* Display min/max limit availables */
683 if(range.retry_flags & IW_RETRY_LIMIT)
685 int flags = (range.retry_flags & ~(IW_RETRY_MIN | IW_RETRY_MAX));
686 /* Display if auto or fixed */
687 if(range.retry_flags & IW_RETRY_MIN)
688 printf("Auto limit ; ");
690 printf("Fixed limit ; ");
691 /* Print the range */
692 iw_print_retry_value(buffer, sizeof(buffer),
693 range.min_retry, flags | IW_RETRY_MIN);
694 printf("%s\n ", buffer);
695 iw_print_retry_value(buffer, sizeof(buffer),
696 range.max_retry, flags | IW_RETRY_MAX);
697 printf("%s\n ", buffer);
700 /* Display min/max lifetime availables */
701 if(range.r_time_flags & IW_RETRY_LIFETIME)
703 int flags = (range.r_time_flags & ~(IW_RETRY_MIN | IW_RETRY_MAX));
704 /* Display if auto or fixed */
705 if(range.r_time_flags & IW_RETRY_MIN)
706 printf("Auto lifetime ; ");
708 printf("Fixed lifetime ; ");
709 /* Print the range */
710 iw_print_retry_value(buffer, sizeof(buffer),
711 range.min_r_time, flags | IW_RETRY_MIN);
712 printf("%s\n ", buffer);
713 iw_print_retry_value(buffer, sizeof(buffer),
714 range.max_r_time, flags | IW_RETRY_MAX);
715 printf("%s\n ", buffer);
719 /* Get current retry settings */
720 wrq.u.retry.flags = 0;
721 if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, &wrq) >= 0)
723 int flags = wrq.u.retry.flags;
725 /* Is it disabled ? */
726 if(wrq.u.retry.disabled)
727 printf("Current mode:off\n ");
732 /* Let's check the mode */
733 printf("Current mode:on\n ");
735 /* Let's check the value and its type */
736 if(wrq.u.retry.flags & IW_RETRY_TYPE)
738 iw_print_retry_value(buffer, sizeof(buffer),
739 wrq.u.retry.value, wrq.u.retry.flags);
740 printf("%s\n ", buffer);
743 /* If we have been returned a MIN value, ask for the MAX */
744 if(flags & IW_RETRY_MIN)
745 retry_mask = IW_RETRY_MAX;
746 /* If we have been returned a MAX value, ask for the MIN */
747 if(flags & IW_RETRY_MAX)
748 retry_mask = IW_RETRY_MIN;
749 /* If we have something to ask for... */
751 get_retry_value(skfd, ifname, &wrq, retry_mask,
752 buffer, sizeof(buffer));
754 /* And if we have both a period and a timeout, ask the other */
755 retry_mask = (range.retry_capa & (~(wrq.u.retry.flags) &
759 int base_mask = retry_mask;
760 flags = get_retry_value(skfd, ifname, &wrq, retry_mask,
761 buffer, sizeof(buffer));
764 /* If we have been returned a MIN value, ask for the MAX */
765 if(flags & IW_RETRY_MIN)
766 retry_mask = IW_RETRY_MAX | base_mask;
767 /* If we have been returned a MAX value, ask for the MIN */
768 if(flags & IW_RETRY_MAX)
769 retry_mask = IW_RETRY_MIN | base_mask;
770 /* If we have something to ask for... */
772 get_retry_value(skfd, ifname, &wrq, retry_mask,
773 buffer, sizeof(buffer));
782 /***************************** SCANNING *****************************/
784 * This one behave quite differently from the others
786 * Note that we don't use the scanning capability of iwlib (functions
787 * iw_process_scan() and iw_scan()). The main reason is that
788 * iw_process_scan() return only a subset of the scan data to the caller,
789 * for example custom elements and bitrates are ommited. Here, we
790 * do the complete job...
793 /*------------------------------------------------------------------*/
795 * Parse, and display the results of a WPA or WPA2 IE.
799 iw_print_ie_unknown(unsigned char * iebuf,
802 int ielen = iebuf[1] + 2;
809 for(i = 0; i < ielen; i++)
810 printf("%02X", iebuf[i]);
814 /*-----------------------------------------------------------------*/
816 * Display the cipher type for the value passed in.
820 iw_print_ie_cipher(unsigned char csuite)
825 printf("None or same as Group ");
854 /*------------------------------------------------------------------*/
856 * Parse, and display the results of a WPA or WPA2 IE.
860 iw_print_ie_wpa(unsigned char * iebuf,
863 int ielen = iebuf[1] + 2;
864 int offset = 2; /* Skip the IE id, and the length. */
865 unsigned char wpa1_oui[3] = {0x00, 0x50, 0xf2};
866 unsigned char wpa2_oui[3] = {0x00, 0x0f, 0xac};
867 unsigned char * wpa_oui;
877 case 0x30: /* WPA2 */
878 /* Check if we have enough data */
881 iw_print_ie_unknown(iebuf, buflen);
888 case 0xdd: /* WPA or else */
891 /* Not all IEs that start with 0xdd are WPA.
892 * So check that the OUI is valid. */
894 || ((memcmp(&iebuf[offset], wpa_oui, 3) != 0)
895 && (iebuf[offset+3] == 0x01)))
897 iw_print_ie_unknown(iebuf, buflen);
908 /* Pick version number (little endian) */
909 ver = iebuf[offset] | (iebuf[offset + 1] << 8);
913 printf("WPA Version %d\n", ver);
915 printf("IEEE 802.11i/WPA2 Version %d\n", ver);
917 /* From here, everything is technically optional. */
919 /* Check if we are done */
920 if(ielen < (offset + 4))
922 /* We have a short IE. So we should assume TKIP/TKIP. */
923 printf(" Group Cipher : TKIP\n");
924 printf(" Pairwise Cipher : TKIP\n");
928 /* Next we have our group cipher. */
929 if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
931 printf(" Group Cipher : Proprietary\n");
935 printf(" Group Cipher : ");
936 iw_print_ie_cipher(iebuf[offset+3]);
941 /* Check if we are done */
942 if(ielen < (offset + 2))
944 /* We don't have a pairwise cipher, or auth method. Assume TKIP. */
945 printf(" Pairwise Ciphers (1) : TKIP\n");
949 /* Otherwise, we have some number of pairwise ciphers. */
950 cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
952 printf(" Pairwise Ciphers (%d) : ", cnt);
954 if(ielen < (offset + 4*cnt))
957 for(i = 0; i < cnt; i++)
959 if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
961 printf("Proprietary ");
965 iw_print_ie_cipher(iebuf[offset+3]);
971 /* Check if we are done */
972 if(ielen < (offset + 2))
975 /* Now, we have authentication suites. */
976 cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
978 printf(" Authentication Suites (%d) : ", cnt);
980 if(ielen < (offset + 4*cnt))
983 for(i = 0; i < cnt; i++)
985 if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
987 printf("Proprietary ");
991 switch(iebuf[offset+3])
1014 /* Check if we are done */
1015 if(ielen < (offset + 1))
1018 /* Otherwise, we have capabilities bytes.
1019 * For now, we only care about preauth which is in bit position 1 of the
1020 * first byte. (But, preauth with WPA version 1 isn't supposed to be
1022 if(iebuf[offset] & 0x01)
1024 printf(" Preauthentication Supported\n");
1028 /*------------------------------------------------------------------*/
1030 * Process a generic IE and display the info in human readable form
1031 * for some of the most interesting ones.
1032 * For now, we only decode the WPA IEs.
1035 iw_print_gen_ie(unsigned char * buffer,
1040 /* Loop on each IE, each IE is minimum 2 bytes */
1041 while(offset <= (buflen - 2))
1046 switch(buffer[offset])
1048 case 0xdd: /* WPA1 (and other) */
1049 case 0x30: /* WPA2 */
1050 iw_print_ie_wpa(buffer + offset, buflen);
1053 iw_print_ie_unknown(buffer + offset, buflen);
1055 /* Skip over this IE to the next one in the list. */
1056 offset += buffer[offset+1] + 2;
1060 /*------------------------------------------------------------------*/
1062 * Print one element from the scanning results
1065 print_scanning_token(struct stream_descr * stream, /* Stream of events */
1066 struct iw_event * event, /* Extracted token */
1067 struct iwscan_state * state,
1068 struct iw_range * iw_range, /* Range info */
1071 char buffer[128]; /* Temporary buffer */
1073 /* Now, let's decode the event */
1077 printf(" Cell %02d - Address: %s\n", state->ap_num,
1078 iw_saether_ntop(&event->u.ap_addr, buffer));
1082 if(event->u.nwid.disabled)
1083 printf(" NWID:off/any\n");
1085 printf(" NWID:%X\n", event->u.nwid.value);
1089 double freq; /* Frequency/channel */
1090 int channel = -1; /* Converted to channel */
1091 freq = iw_freq2float(&(event->u.freq));
1092 /* Convert to channel if possible */
1094 channel = iw_freq_to_channel(freq, iw_range);
1095 iw_print_freq(buffer, sizeof(buffer),
1096 freq, channel, event->u.freq.flags);
1097 printf(" %s\n", buffer);
1101 printf(" Mode:%s\n",
1102 iw_operation_mode[event->u.mode]);
1105 printf(" Protocol:%-1.16s\n", event->u.name);
1109 char essid[IW_ESSID_MAX_SIZE+1];
1110 memset(essid, '\0', sizeof(essid));
1111 if((event->u.essid.pointer) && (event->u.essid.length))
1112 memcpy(essid, event->u.essid.pointer, event->u.essid.length);
1113 if(event->u.essid.flags)
1115 /* Does it have an ESSID index ? */
1116 if((event->u.essid.flags & IW_ENCODE_INDEX) > 1)
1117 printf(" ESSID:\"%s\" [%d]\n", essid,
1118 (event->u.essid.flags & IW_ENCODE_INDEX));
1120 printf(" ESSID:\"%s\"\n", essid);
1123 printf(" ESSID:off/any/hidden\n");
1128 unsigned char key[IW_ENCODING_TOKEN_MAX];
1129 if(event->u.data.pointer)
1130 memcpy(key, event->u.data.pointer, event->u.data.length);
1132 event->u.data.flags |= IW_ENCODE_NOKEY;
1133 printf(" Encryption key:");
1134 if(event->u.data.flags & IW_ENCODE_DISABLED)
1138 /* Display the key */
1139 iw_print_key(buffer, sizeof(buffer), key, event->u.data.length,
1140 event->u.data.flags);
1141 printf("%s", buffer);
1144 if((event->u.data.flags & IW_ENCODE_INDEX) > 1)
1145 printf(" [%d]", event->u.data.flags & IW_ENCODE_INDEX);
1146 if(event->u.data.flags & IW_ENCODE_RESTRICTED)
1147 printf(" Security mode:restricted");
1148 if(event->u.data.flags & IW_ENCODE_OPEN)
1149 printf(" Security mode:open");
1155 if(state->val_index == 0)
1156 printf(" Bit Rates:");
1158 if((state->val_index % 5) == 0)
1162 iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
1163 printf("%s", buffer);
1164 /* Check for termination */
1165 if(stream->value == NULL)
1168 state->val_index = 0;
1175 iw_print_stats(buffer, sizeof(buffer),
1176 &event->u.qual, iw_range, has_range);
1177 printf(" %s\n", buffer);
1181 /* Informations Elements are complex, let's do only some of them */
1182 iw_print_gen_ie(event->u.data.pointer, event->u.data.length);
1186 char custom[IW_CUSTOM_MAX+1];
1187 if((event->u.data.pointer) && (event->u.data.length))
1188 memcpy(custom, event->u.data.pointer, event->u.data.length);
1189 custom[event->u.data.length] = '\0';
1190 printf(" Extra:%s\n", custom);
1194 printf(" (Unknown Wireless Token 0x%04X)\n",
1196 } /* switch(event->cmd) */
1199 /*------------------------------------------------------------------*/
1201 * Perform a scanning on one device
1204 print_scanning_info(int skfd,
1206 char * args[], /* Command line args */
1207 int count) /* Args count */
1210 unsigned char * buffer = NULL; /* Results */
1211 int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
1212 struct iw_range range;
1214 struct timeval tv; /* Select timeout */
1215 int timeout = 15000000; /* 15s */
1217 /* Avoid "Unused parameter" warning */
1218 args = args; count = count;
1220 /* Get range stuff */
1221 has_range = (iw_get_range_info(skfd, ifname, &range) >= 0);
1223 /* Check if the interface could support scanning. */
1224 if((!has_range) || (range.we_version_compiled < 14))
1226 fprintf(stderr, "%-8.16s Interface doesn't support scanning.\n\n",
1231 /* Init timeout value -> 250ms*/
1233 tv.tv_usec = 250000;
1236 * Here we should look at the command line args and set the IW_SCAN_ flags
1239 wrq.u.data.pointer = NULL; /* Later */
1240 wrq.u.data.flags = 0;
1241 wrq.u.data.length = 0;
1243 /* Initiate Scanning */
1244 if(iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0)
1248 fprintf(stderr, "%-8.16s Interface doesn't support scanning : %s\n\n",
1249 ifname, strerror(errno));
1252 /* If we don't have the permission to initiate the scan, we may
1253 * still have permission to read left-over results.
1254 * But, don't wait !!! */
1256 /* Not cool, it display for non wireless interfaces... */
1257 fprintf(stderr, "%-8.16s (Could not trigger scanning, just reading left-over results)\n", ifname);
1261 timeout -= tv.tv_usec;
1266 fd_set rfds; /* File descriptors for select */
1267 int last_fd; /* Last fd */
1270 /* Guess what ? We must re-generate rfds each time */
1274 /* In here, add the rtnetlink fd in the list */
1276 /* Wait until something happens */
1277 ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
1279 /* Check if there was an error */
1282 if(errno == EAGAIN || errno == EINTR)
1284 fprintf(stderr, "Unhandled signal - exiting...\n");
1288 /* Check if there was a timeout */
1291 unsigned char * newbuf;
1294 /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
1295 newbuf = realloc(buffer, buflen);
1300 fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
1305 /* Try to read the results */
1306 wrq.u.data.pointer = buffer;
1307 wrq.u.data.flags = 0;
1308 wrq.u.data.length = buflen;
1309 if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0)
1311 /* Check if buffer was too small (WE-17 only) */
1312 if((errno == E2BIG) && (range.we_version_compiled > 16))
1314 /* Some driver may return very large scan results, either
1315 * because there are many cells, or because they have many
1316 * large elements in cells (like IWEVCUSTOM). Most will
1317 * only need the regular sized buffer. We now use a dynamic
1318 * allocation of the buffer to satisfy everybody. Of course,
1319 * as we don't know in advance the size of the array, we try
1320 * various increasing sizes. Jean II */
1322 /* Check if the driver gave us any hints. */
1323 if(wrq.u.data.length > buflen)
1324 buflen = wrq.u.data.length;
1332 /* Check if results not available yet */
1335 /* Restart timer for only 100ms*/
1337 tv.tv_usec = 100000;
1338 timeout -= tv.tv_usec;
1340 continue; /* Try again later */
1345 fprintf(stderr, "%-8.16s Failed to read scan data : %s\n\n",
1346 ifname, strerror(errno));
1350 /* We have the results, go to process them */
1354 /* In here, check if event and event type
1355 * if scan event, read results. All errors bad & no reset timeout */
1358 if(wrq.u.data.length)
1360 struct iw_event iwe;
1361 struct stream_descr stream;
1362 struct iwscan_state state = { .ap_num = 1, .val_index = 0 };
1366 /* Debugging code. In theory useless, because it's debugged ;-) */
1368 printf("Scan result %d [%02X", wrq.u.data.length, buffer[0]);
1369 for(i = 1; i < wrq.u.data.length; i++)
1370 printf(":%02X", buffer[i]);
1373 printf("%-8.16s Scan completed :\n", ifname);
1374 iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
1377 /* Extract an event and print it */
1378 ret = iw_extract_event_stream(&stream, &iwe,
1379 range.we_version_compiled);
1381 print_scanning_token(&stream, &iwe, &state,
1388 printf("%-8.16s No scan results\n", ifname);
1394 /******************** WIRELESS EVENT CAPABILITY ********************/
1396 static const char * event_capa_req[] =
1398 [SIOCSIWNWID - SIOCIWFIRST] = "Set NWID (kernel generated)",
1399 [SIOCSIWFREQ - SIOCIWFIRST] = "Set Frequency/Channel (kernel generated)",
1400 [SIOCGIWFREQ - SIOCIWFIRST] = "New Frequency/Channel",
1401 [SIOCSIWMODE - SIOCIWFIRST] = "Set Mode (kernel generated)",
1402 [SIOCGIWTHRSPY - SIOCIWFIRST] = "Spy threshold crossed",
1403 [SIOCGIWAP - SIOCIWFIRST] = "New Access Point/Cell address - roaming",
1404 [SIOCGIWSCAN - SIOCIWFIRST] = "Scan request completed",
1405 [SIOCSIWESSID - SIOCIWFIRST] = "Set ESSID (kernel generated)",
1406 [SIOCGIWESSID - SIOCIWFIRST] = "New ESSID",
1407 [SIOCGIWRATE - SIOCIWFIRST] = "New bit-rate",
1408 [SIOCSIWENCODE - SIOCIWFIRST] = "Set Encoding (kernel generated)",
1409 [SIOCGIWPOWER - SIOCIWFIRST] = NULL,
1412 static const char * event_capa_evt[] =
1414 [IWEVTXDROP - IWEVFIRST] = "Tx packet dropped - retry exceeded",
1415 [IWEVCUSTOM - IWEVFIRST] = "Custom driver event",
1416 [IWEVREGISTERED - IWEVFIRST] = "Registered node",
1417 [IWEVEXPIRED - IWEVFIRST] = "Expired node",
1420 /*------------------------------------------------------------------*/
1422 * Print the number of available transmit powers for the device
1425 print_event_capa_info(int skfd,
1427 char * args[], /* Command line args */
1428 int count) /* Args count */
1430 struct iw_range range;
1433 /* Avoid "Unused parameter" warning */
1434 args = args; count = count;
1436 /* Extract range info */
1437 if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1438 (range.we_version_compiled < 10))
1439 fprintf(stderr, "%-8.16s no wireless event capability information.\n\n",
1445 for(cmd = 0x8B00; cmd < 0x8C0F; cmd++)
1447 int idx = IW_EVENT_CAPA_INDEX(cmd);
1448 int mask = IW_EVENT_CAPA_MASK(cmd);
1449 printf("0x%X - %d - %X\n", cmd, idx, mask);
1453 printf("%-8.16s Wireless Events supported :\n", ifname);
1455 for(cmd = SIOCIWFIRST; cmd <= SIOCGIWPOWER; cmd++)
1457 int idx = IW_EVENT_CAPA_INDEX(cmd);
1458 int mask = IW_EVENT_CAPA_MASK(cmd);
1459 if(range.event_capa[idx] & mask)
1460 printf(" 0x%04X : %s\n",
1461 cmd, event_capa_req[cmd - SIOCIWFIRST]);
1463 for(cmd = IWEVFIRST; cmd <= IWEVEXPIRED; cmd++)
1465 int idx = IW_EVENT_CAPA_INDEX(cmd);
1466 int mask = IW_EVENT_CAPA_MASK(cmd);
1467 if(range.event_capa[idx] & mask)
1468 printf(" 0x%04X : %s\n",
1469 cmd, event_capa_evt[cmd - IWEVFIRST]);
1476 /************************* COMMON UTILITIES *************************/
1478 * This section was initially written by Michael Tokarev <mjt@tls.msk.ru>
1479 * but heavily modified by me ;-)
1482 /*------------------------------------------------------------------*/
1484 * Map command line arguments to the proper procedure...
1486 typedef struct iwlist_entry {
1493 static const struct iwlist_entry iwlist_cmds[] = {
1494 { "scanning", print_scanning_info, 0, 5 },
1495 { "frequency", print_freq_info, 0, 0 },
1496 { "channel", print_freq_info, 0, 0 },
1497 { "bitrate", print_bitrate_info, 0, 0 },
1498 { "rate", print_bitrate_info, 0, 0 },
1499 { "encryption", print_keys_info, 0, 0 },
1500 { "key", print_keys_info, 0, 0 },
1501 { "power", print_pm_info, 0, 0 },
1502 { "txpower", print_txpower_info, 0, 0 },
1503 { "retry", print_retry_info, 0, 0 },
1504 { "ap", print_ap_info, 0, 0 },
1505 { "accesspoints", print_ap_info, 0, 0 },
1506 { "peers", print_ap_info, 0, 0 },
1507 { "event", print_event_capa_info, 0, 0 },
1508 { NULL, NULL, 0, 0 },
1511 /*------------------------------------------------------------------*/
1513 * Find the most appropriate command matching the command line
1515 static inline const iwlist_cmd *
1516 find_command(const char * cmd)
1518 const iwlist_cmd * found = NULL;
1520 unsigned int len = strlen(cmd);
1523 /* Go through all commands */
1524 for(i = 0; iwlist_cmds[i].cmd != NULL; ++i)
1526 /* No match -> next one */
1527 if(strncasecmp(iwlist_cmds[i].cmd, cmd, len) != 0)
1530 /* Exact match -> perfect */
1531 if(len == strlen(iwlist_cmds[i].cmd))
1532 return &iwlist_cmds[i];
1537 found = &iwlist_cmds[i];
1540 if (iwlist_cmds[i].fn != found->fn)
1546 fprintf(stderr, "iwlist: unknown command `%s'\n", cmd);
1552 fprintf(stderr, "iwlist: command `%s' is ambiguous\n", cmd);
1559 /*------------------------------------------------------------------*/
1563 static void iw_usage(int status)
1565 FILE* f = status ? stderr : stdout;
1568 fprintf(f, "Usage: iwlist [interface] %s\n", iwlist_cmds[0].cmd);
1569 for(i = 1; iwlist_cmds[i].cmd != NULL; ++i)
1570 fprintf(f, " [interface] %s\n", iwlist_cmds[i].cmd);
1574 /******************************* MAIN ********************************/
1576 /*------------------------------------------------------------------*/
1584 int skfd; /* generic raw socket desc. */
1585 char *dev; /* device name */
1586 char *cmd; /* command */
1587 char **args; /* Command arguments */
1588 int count; /* Number of arguments */
1589 const iwlist_cmd *iwcmd;
1591 if(argc == 1 || argc > 3)
1594 /* Those don't apply to all interfaces */
1595 if((argc == 2) && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))
1597 if((argc == 2) && (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")))
1598 return(iw_print_version_info("iwlist"));
1615 /* find a command */
1616 iwcmd = find_command(cmd);
1620 /* Check arg numbers */
1621 if(count < iwcmd->min_count)
1623 fprintf(stderr, "iwlist: command `%s' needs more arguments\n", cmd);
1626 if(count > iwcmd->max_count)
1628 fprintf(stderr, "iwlist: command `%s' needs fewer arguments\n", cmd);
1632 /* Create a channel to the NET kernel. */
1633 if((skfd = iw_sockets_open()) < 0)
1639 /* do the actual work */
1641 (*iwcmd->fn)(skfd, dev, args, count);
1643 iw_enum_devices(skfd, iwcmd->fn, args, count);
1645 /* Close the socket. */
1646 iw_sockets_close(skfd);