4 * Jean II - HPLB 97->99 - HPL 99->09
6 * Common subroutines to all the wireless tools...
8 * This file is released under the GPL license.
9 * Copyright (c) 1997-2009 Jean Tourrilhes <jt@hpl.hp.com>
12 /***************************** INCLUDES *****************************/
15 #include "iwlib-private.h" /* Private header */
17 /************************ CONSTANTS & MACROS ************************/
20 * Constants fof WE-9->15
22 #define IW15_MAX_FREQUENCIES 16
23 #define IW15_MAX_BITRATES 8
24 #define IW15_MAX_TXPOWER 8
25 #define IW15_MAX_ENCODING_SIZES 8
26 #define IW15_MAX_SPY 8
29 /****************************** TYPES ******************************/
32 * Struct iw_range up to WE-15
41 struct iw_freq freq[IW15_MAX_FREQUENCIES];
43 struct iw_quality max_qual;
45 __s32 bitrate[IW15_MAX_BITRATES];
57 __u16 encoding_size[IW15_MAX_ENCODING_SIZES];
58 __u8 num_encoding_sizes;
59 __u8 max_encoding_tokens;
62 __s32 txpower[IW15_MAX_TXPOWER];
63 __u8 we_version_compiled;
64 __u8 we_version_source;
72 struct iw_quality avg_qual;
76 * Union for all the versions of iwrange.
77 * Fortunately, I mostly only add fields at the end, and big-bang
78 * reorganisations are few.
82 struct iw15_range range15; /* WE 9->15 */
83 struct iw_range range; /* WE 16->current */
87 * Offsets in iw_range struct
89 #define iwr15_off(f) ( ((char *) &(((struct iw15_range *) NULL)->f)) - \
91 #define iwr_off(f) ( ((char *) &(((struct iw_range *) NULL)->f)) - \
95 * Union to perform unaligned access when working around alignement issues
100 unsigned char byte[2];
103 /**************************** VARIABLES ****************************/
105 /* Modes as human readable strings */
106 const char * const iw_operation_mode[] = { "Auto",
115 /* Modulations as human readable strings */
116 const struct iw_modul_descr iw_modul_list[] = {
117 /* Start with aggregate types, so that they display first */
118 { IW_MODUL_11AG, "11ag",
119 "IEEE 802.11a + 802.11g (2.4 & 5 GHz, up to 54 Mb/s)" },
120 { IW_MODUL_11AB, "11ab",
121 "IEEE 802.11a + 802.11b (2.4 & 5 GHz, up to 54 Mb/s)" },
122 { IW_MODUL_11G, "11g", "IEEE 802.11g (2.4 GHz, up to 54 Mb/s)" },
123 { IW_MODUL_11A, "11a", "IEEE 802.11a (5 GHz, up to 54 Mb/s)" },
124 { IW_MODUL_11B, "11b", "IEEE 802.11b (2.4 GHz, up to 11 Mb/s)" },
126 /* Proprietary aggregates */
127 { IW_MODUL_TURBO | IW_MODUL_11A, "turboa",
128 "Atheros turbo mode at 5 GHz (up to 108 Mb/s)" },
129 { IW_MODUL_TURBO | IW_MODUL_11G, "turbog",
130 "Atheros turbo mode at 2.4 GHz (up to 108 Mb/s)" },
131 { IW_MODUL_PBCC | IW_MODUL_11B, "11+",
132 "TI 802.11+ (2.4 GHz, up to 22 Mb/s)" },
134 /* Individual modulations */
135 { IW_MODUL_OFDM_G, "OFDMg",
136 "802.11g higher rates, OFDM at 2.4 GHz (up to 54 Mb/s)" },
137 { IW_MODUL_OFDM_A, "OFDMa", "802.11a, OFDM at 5 GHz (up to 54 Mb/s)" },
138 { IW_MODUL_CCK, "CCK", "802.11b higher rates (2.4 GHz, up to 11 Mb/s)" },
139 { IW_MODUL_DS, "DS", "802.11 Direct Sequence (2.4 GHz, up to 2 Mb/s)" },
140 { IW_MODUL_FH, "FH", "802.11 Frequency Hopping (2,4 GHz, up to 2 Mb/s)" },
142 /* Proprietary modulations */
143 { IW_MODUL_TURBO, "turbo",
144 "Atheros turbo mode, channel bonding (up to 108 Mb/s)" },
145 { IW_MODUL_PBCC, "PBCC",
146 "TI 802.11+ higher rates (2.4 GHz, up to 22 Mb/s)" },
147 { IW_MODUL_CUSTOM, "custom",
148 "Driver specific modulation (check driver documentation)" },
151 /* Disable runtime version warning in iw_get_range_info() */
152 int iw_ignore_version = 0;
154 /************************ SOCKET SUBROUTINES *************************/
156 /*------------------------------------------------------------------*/
159 * Depending on the protocol present, open the right socket. The socket
160 * will allow us to talk to the driver.
163 iw_sockets_open(void)
165 static const int families[] = {
166 AF_INET, AF_IPX, AF_AX25, AF_APPLETALK
172 * Now pick any (exisiting) useful socket family for generic queries
173 * Note : don't open all the socket, only returns when one matches,
174 * all protocols might not be valid.
175 * Workaround by Jim Kaba <jkaba@sarnoff.com>
176 * Note : in 99% of the case, we will just open the inet_sock.
177 * The remaining 1% case are not fully correct...
180 /* Try all families we support */
181 for(i = 0; i < sizeof(families)/sizeof(int); ++i)
183 /* Try to open the socket, if success returns it */
184 sock = socket(families[i], SOCK_DGRAM, 0);
192 /*------------------------------------------------------------------*/
194 * Extract the interface name out of /proc/net/wireless or /proc/net/dev.
197 iw_get_ifname(char * name, /* Where to store the name */
198 int nsize, /* Size of name buffer */
199 char * buf) /* Current position in buffer */
203 /* Skip leading spaces */
207 #ifndef IW_RESTRIC_ENUM
208 /* Get name up to the last ':'. Aliases may contain ':' in them,
209 * but the last one should be the separator */
210 end = strrchr(buf, ':');
212 /* Get name up to ": "
213 * Note : we compare to ": " to make sure to process aliased interfaces
214 * properly. Doesn't work on /proc/net/dev, because it doesn't guarantee
215 * a ' ' after the ':'*/
216 end = strstr(buf, ": ");
219 /* Not found ??? To big ??? */
220 if((end == NULL) || (((end - buf) + 1) > nsize))
224 memcpy(name, buf, (end - buf));
225 name[end - buf] = '\0';
227 /* Return value currently unused, just make sure it's non-NULL */
231 /*------------------------------------------------------------------*/
233 * Enumerate devices and call specified routine
234 * The new way just use /proc/net/wireless, so get all wireless interfaces,
235 * whether configured or not. This is the default if available.
236 * The old way use SIOCGIFCONF, so get only configured interfaces (wireless
240 iw_enum_devices(int skfd,
251 #ifndef IW_RESTRIC_ENUM
252 /* Check if /proc/net/dev is available */
253 fh = fopen(PROC_NET_DEV, "r");
255 /* Check if /proc/net/wireless is available */
256 fh = fopen(PROC_NET_WIRELESS, "r");
261 /* Success : use data from /proc/net/wireless */
263 /* Eat 2 lines of header */
264 fgets(buff, sizeof(buff), fh);
265 fgets(buff, sizeof(buff), fh);
267 /* Read each device line */
268 while(fgets(buff, sizeof(buff), fh))
270 char name[IFNAMSIZ + 1];
273 /* Skip empty or almost empty lines. It seems that in some
274 * cases fgets return a line with only a newline. */
275 if((buff[0] == '\0') || (buff[1] == '\0'))
278 /* Extract interface name */
279 s = iw_get_ifname(name, sizeof(name), buff);
283 /* Failed to parse, complain and continue */
284 #ifndef IW_RESTRIC_ENUM
285 fprintf(stderr, "Cannot parse " PROC_NET_DEV "\n");
287 fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
291 /* Got it, print info about this interface */
292 (*fn)(skfd, name, args, count);
299 /* Get list of configured devices using "traditional" way */
300 ifc.ifc_len = sizeof(buff);
302 if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
304 fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
310 for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
311 (*fn)(skfd, ifr->ifr_name, args, count);
315 /*********************** WIRELESS SUBROUTINES ************************/
317 /*------------------------------------------------------------------*/
319 * Extract WE version number from /proc/net/wireless
320 * In most cases, you really want to get version information from
321 * the range info (range->we_version_compiled), see below...
323 * If we have WE-16 and later, the WE version is available at the
324 * end of the header line of the file.
325 * For version prior to that, we can only detect the change from
326 * v11 to v12, so we do an approximate job. Fortunately, v12 to v15
327 * are highly binary compatible (on the struct level).
330 iw_get_kernel_we_version(void)
337 /* Check if /proc/net/wireless is available */
338 fh = fopen(PROC_NET_WIRELESS, "r");
342 fprintf(stderr, "Cannot read " PROC_NET_WIRELESS "\n");
346 /* Read the first line of buffer */
347 fgets(buff, sizeof(buff), fh);
349 if(strstr(buff, "| WE") == NULL)
351 /* Prior to WE16, so explicit version not present */
354 if(strstr(buff, "| Missed") == NULL)
362 /* Read the second line of buffer */
363 fgets(buff, sizeof(buff), fh);
365 /* Get to the last separator, to get the version */
366 p = strrchr(buff, '|');
367 if((p == NULL) || (sscanf(p + 1, "%d", &v) != 1))
369 fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
378 /*------------------------------------------------------------------*/
380 * Print the WE versions of the interface.
383 print_iface_version_info(int skfd,
385 char * args[], /* Command line args */
386 int count) /* Args count */
389 char buffer[sizeof(iwrange) * 2]; /* Large enough */
390 struct iw_range * range;
392 /* Avoid "Unused parameter" warning */
393 args = args; count = count;
395 /* If no wireless name : no wireless extensions.
396 * This enable us to treat the SIOCGIWRANGE failure below properly. */
397 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
401 memset(buffer, 0, sizeof(buffer));
403 wrq.u.data.pointer = (caddr_t) buffer;
404 wrq.u.data.length = sizeof(buffer);
405 wrq.u.data.flags = 0;
406 if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
408 /* Interface support WE (see above), but not IWRANGE */
409 fprintf(stderr, "%-8.16s Driver has no Wireless Extension version information.\n\n", ifname);
413 /* Copy stuff at the right place, ignore extra */
414 range = (struct iw_range *) buffer;
416 /* For new versions, we can check the version directly, for old versions
417 * we use magic. 300 bytes is a also magic number, don't touch... */
418 if(wrq.u.data.length >= 300)
420 /* Version is always at the same offset, so it's ok */
421 printf("%-8.16s Recommend Wireless Extension v%d or later,\n",
422 ifname, range->we_version_source);
423 printf(" Currently compiled with Wireless Extension v%d.\n\n",
424 range->we_version_compiled);
428 fprintf(stderr, "%-8.16s Wireless Extension version too old.\n\n",
436 /*------------------------------------------------------------------*/
438 * Print the WE versions of the tools.
441 iw_print_version_info(const char * toolname)
443 int skfd; /* generic raw socket desc. */
444 int we_kernel_version;
446 /* Create a channel to the NET kernel. */
447 if((skfd = iw_sockets_open()) < 0)
453 /* Information about the tools themselves */
455 printf("%-8.16s Wireless-Tools version %d\n", toolname, WT_VERSION);
456 printf(" Compatible with Wireless Extension v11 to v%d.\n\n",
459 /* Get version from kernel */
460 we_kernel_version = iw_get_kernel_we_version();
461 /* Only version >= 16 can be verified, other are guessed */
462 if(we_kernel_version > 15)
463 printf("Kernel Currently compiled with Wireless Extension v%d.\n\n",
466 /* Version for each device */
467 iw_enum_devices(skfd, &print_iface_version_info, NULL, 0);
469 iw_sockets_close(skfd);
474 /*------------------------------------------------------------------*/
476 * Get the range information out of the driver
479 iw_get_range_info(int skfd,
484 char buffer[sizeof(iwrange) * 2]; /* Large enough */
485 union iw_range_raw * range_raw;
488 bzero(buffer, sizeof(buffer));
490 wrq.u.data.pointer = (caddr_t) buffer;
491 wrq.u.data.length = sizeof(buffer);
492 wrq.u.data.flags = 0;
493 if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
496 /* Point to the buffer */
497 range_raw = (union iw_range_raw *) buffer;
499 /* For new versions, we can check the version directly, for old versions
500 * we use magic. 300 bytes is a also magic number, don't touch... */
501 if(wrq.u.data.length < 300)
503 /* That's v10 or earlier. Ouch ! Let's make a guess...*/
504 range_raw->range.we_version_compiled = 9;
507 /* Check how it needs to be processed */
508 if(range_raw->range.we_version_compiled > 15)
510 /* This is our native format, that's easy... */
511 /* Copy stuff at the right place, ignore extra */
512 memcpy((char *) range, buffer, sizeof(iwrange));
516 /* Zero unknown fields */
517 bzero((char *) range, sizeof(struct iw_range));
519 /* Initial part unmoved */
520 memcpy((char *) range,
522 iwr15_off(num_channels));
523 /* Frequencies pushed futher down towards the end */
524 memcpy((char *) range + iwr_off(num_channels),
525 buffer + iwr15_off(num_channels),
526 iwr15_off(sensitivity) - iwr15_off(num_channels));
527 /* This one moved up */
528 memcpy((char *) range + iwr_off(sensitivity),
529 buffer + iwr15_off(sensitivity),
530 iwr15_off(num_bitrates) - iwr15_off(sensitivity));
531 /* This one goes after avg_qual */
532 memcpy((char *) range + iwr_off(num_bitrates),
533 buffer + iwr15_off(num_bitrates),
534 iwr15_off(min_rts) - iwr15_off(num_bitrates));
535 /* Number of bitrates has changed, put it after */
536 memcpy((char *) range + iwr_off(min_rts),
537 buffer + iwr15_off(min_rts),
538 iwr15_off(txpower_capa) - iwr15_off(min_rts));
539 /* Added encoding_login_index, put it after */
540 memcpy((char *) range + iwr_off(txpower_capa),
541 buffer + iwr15_off(txpower_capa),
542 iwr15_off(txpower) - iwr15_off(txpower_capa));
543 /* Hum... That's an unexpected glitch. Bummer. */
544 memcpy((char *) range + iwr_off(txpower),
545 buffer + iwr15_off(txpower),
546 iwr15_off(avg_qual) - iwr15_off(txpower));
547 /* Avg qual moved up next to max_qual */
548 memcpy((char *) range + iwr_off(avg_qual),
549 buffer + iwr15_off(avg_qual),
550 sizeof(struct iw_quality));
553 /* We are now checking much less than we used to do, because we can
554 * accomodate more WE version. But, there are still cases where things
556 if(!iw_ignore_version)
558 /* We don't like very old version (unfortunately kernel 2.2.X) */
559 if(range->we_version_compiled <= 10)
561 fprintf(stderr, "Warning: Driver for device %s has been compiled with an ancient version\n", ifname);
562 fprintf(stderr, "of Wireless Extension, while this program support version 11 and later.\n");
563 fprintf(stderr, "Some things may be broken...\n\n");
566 /* We don't like future versions of WE, because we can't cope with
568 if(range->we_version_compiled > WE_MAX_VERSION)
570 fprintf(stderr, "Warning: Driver for device %s has been compiled with version %d\n", ifname, range->we_version_compiled);
571 fprintf(stderr, "of Wireless Extension, while this program supports up to version %d.\n", WE_MAX_VERSION);
572 fprintf(stderr, "Some things may be broken...\n\n");
575 /* Driver version verification */
576 if((range->we_version_compiled > 10) &&
577 (range->we_version_compiled < range->we_version_source))
579 fprintf(stderr, "Warning: Driver for device %s recommend version %d of Wireless Extension,\n", ifname, range->we_version_source);
580 fprintf(stderr, "but has been compiled with version %d, therefore some driver features\n", range->we_version_compiled);
581 fprintf(stderr, "may not be available...\n\n");
583 /* Note : we are only trying to catch compile difference, not source.
584 * If the driver source has not been updated to the latest, it doesn't
585 * matter because the new fields are set to zero */
588 /* Don't complain twice.
589 * In theory, the test apply to each individual driver, but usually
590 * all drivers are compiled from the same kernel. */
591 iw_ignore_version = 1;
596 /*------------------------------------------------------------------*/
598 * Get information about what private ioctls are supported by the driver
600 * Note : there is one danger using this function. If it return 0, you
601 * still need to free() the buffer. Beware.
604 iw_get_priv_info(int skfd,
609 iwprivargs * priv = NULL; /* Not allocated yet */
610 int maxpriv = 16; /* Minimum for compatibility WE<13 */
611 iwprivargs * newpriv;
613 /* Some driver may return a very large number of ioctls. Some
614 * others a very small number. We now use a dynamic allocation
615 * of the array to satisfy everybody. Of course, as we don't know
616 * in advance the size of the array, we try various increasing
620 /* (Re)allocate the buffer */
621 newpriv = realloc(priv, maxpriv * sizeof(priv[0]));
624 fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
629 /* Ask the driver if it's large enough */
630 wrq.u.data.pointer = (caddr_t) priv;
631 wrq.u.data.length = maxpriv;
632 wrq.u.data.flags = 0;
633 if(iw_get_ext(skfd, ifname, SIOCGIWPRIV, &wrq) >= 0)
635 /* Success. Pass the buffer by pointer */
637 /* Return the number of ioctls */
638 return(wrq.u.data.length);
641 /* Only E2BIG means the buffer was too small, abort on other errors */
644 /* Most likely "not supported". Don't barf. */
648 /* Failed. We probably need a bigger buffer. Check if the kernel
649 * gave us any hints. */
650 if(wrq.u.data.length > maxpriv)
651 maxpriv = wrq.u.data.length;
655 while(maxpriv < 1000);
665 /*------------------------------------------------------------------*/
667 * Get essential wireless config from the device driver
668 * We will call all the classical wireless ioctl on the driver through
669 * the socket to know what is supported and to get the settings...
670 * Note : compare to the version in iwconfig, we extract only
671 * what's *really* needed to configure a device...
674 iw_get_basic_config(int skfd,
676 wireless_config * info)
680 memset((char *) info, 0, sizeof(struct wireless_config));
682 /* Get wireless name */
683 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
684 /* If no wireless name : no wireless extensions */
688 strncpy(info->name, wrq.u.name, IFNAMSIZ);
689 info->name[IFNAMSIZ] = '\0';
693 if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) >= 0)
696 memcpy(&(info->nwid), &(wrq.u.nwid), sizeof(iwparam));
699 /* Get frequency / channel */
700 if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
703 info->freq = iw_freq2float(&(wrq.u.freq));
704 info->freq_flags = wrq.u.freq.flags;
707 /* Get encryption information */
708 wrq.u.data.pointer = (caddr_t) info->key;
709 wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
710 wrq.u.data.flags = 0;
711 if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
714 info->key_size = wrq.u.data.length;
715 info->key_flags = wrq.u.data.flags;
719 wrq.u.essid.pointer = (caddr_t) info->essid;
720 wrq.u.essid.length = IW_ESSID_MAX_SIZE + 2;
721 wrq.u.essid.flags = 0;
722 if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) >= 0)
725 info->essid_on = wrq.u.data.flags;
726 info->essid_len = wrq.u.essid.length;
729 /* Get operation mode */
730 if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) >= 0)
733 /* Note : event->u.mode is unsigned, no need to check <= 0 */
734 if(wrq.u.mode < IW_NUM_OPER_MODE)
735 info->mode = wrq.u.mode;
737 info->mode = IW_NUM_OPER_MODE; /* Unknown/bug */
743 /*------------------------------------------------------------------*/
745 * Set essential wireless config in the device driver
746 * We will call all the classical wireless ioctl on the driver through
747 * the socket to know what is supported and to set the settings...
748 * We support only the restricted set as above...
751 iw_set_basic_config(int skfd,
753 wireless_config * info)
758 /* Get wireless name (check if interface is valid) */
759 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
760 /* If no wireless name : no wireless extensions */
763 /* Set the current mode of operation
764 * Mode need to be first : some settings apply only in a specific mode
765 * (such as frequency).
769 strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
770 wrq.u.mode = info->mode;
772 if(iw_get_ext(skfd, ifname, SIOCSIWMODE, &wrq) < 0)
774 fprintf(stderr, "SIOCSIWMODE: %s\n", strerror(errno));
779 /* Set frequency / channel */
782 iw_float2freq(info->freq, &(wrq.u.freq));
784 if(iw_set_ext(skfd, ifname, SIOCSIWFREQ, &wrq) < 0)
786 fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
791 /* Set encryption information */
794 int flags = info->key_flags;
796 /* Check if there is a key index */
797 if((flags & IW_ENCODE_INDEX) > 0)
800 wrq.u.data.pointer = (caddr_t) NULL;
801 wrq.u.data.flags = (flags & (IW_ENCODE_INDEX)) | IW_ENCODE_NOKEY;
802 wrq.u.data.length = 0;
804 if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
806 fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
807 errno, strerror(errno));
812 /* Mask out index to minimise probability of reject when setting key */
813 flags = flags & (~IW_ENCODE_INDEX);
815 /* Set the key itself (set current key in this case) */
816 wrq.u.data.pointer = (caddr_t) info->key;
817 wrq.u.data.length = info->key_size;
818 wrq.u.data.flags = flags;
820 /* Compatibility with WE<13 */
821 if(flags & IW_ENCODE_NOKEY)
822 wrq.u.data.pointer = NULL;
824 if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
826 fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
827 errno, strerror(errno));
832 /* Set Network ID, if available (this is for non-802.11 cards) */
835 memcpy(&(wrq.u.nwid), &(info->nwid), sizeof(iwparam));
836 wrq.u.nwid.fixed = 1; /* Hum... When in Rome... */
838 if(iw_set_ext(skfd, ifname, SIOCSIWNWID, &wrq) < 0)
840 fprintf(stderr, "SIOCSIWNWID: %s\n", strerror(errno));
845 /* Set ESSID (extended network), if available.
846 * ESSID need to be last : most device re-perform the scanning/discovery
847 * when this is set, and things like encryption keys are better be
848 * defined if we want to discover the right set of APs/nodes.
852 int we_kernel_version;
853 we_kernel_version = iw_get_kernel_we_version();
855 wrq.u.essid.pointer = (caddr_t) info->essid;
856 wrq.u.essid.length = strlen(info->essid);
857 wrq.u.data.flags = info->essid_on;
858 if(we_kernel_version < 21)
859 wrq.u.essid.length++;
861 if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0)
863 fprintf(stderr, "SIOCSIWESSID: %s\n", strerror(errno));
871 /*********************** PROTOCOL SUBROUTINES ***********************/
873 * Fun stuff with protocol identifiers (SIOCGIWNAME).
874 * We assume that drivers are returning sensible values in there,
875 * which is not always the case :-(
878 /*------------------------------------------------------------------*/
880 * Compare protocol identifiers.
881 * We don't want to know if the two protocols are the exactly same,
882 * but if they interoperate at some level, and also if they accept the
883 * same type of config (ESSID vs NWID, freq...).
884 * This is supposed to work around the alphabet soup.
885 * Return 1 if protocols are compatible, 0 otherwise
888 iw_protocol_compare(const char * protocol1,
889 const char * protocol2)
891 const char * dot11 = "IEEE 802.11";
892 const char * dot11_ds = "Dbg";
893 const char * dot11_5g = "a";
895 /* If the strings are the same -> easy */
896 if(!strncmp(protocol1, protocol2, IFNAMSIZ))
899 /* Are we dealing with one of the 802.11 variant ? */
900 if( (!strncmp(protocol1, dot11, strlen(dot11))) &&
901 (!strncmp(protocol2, dot11, strlen(dot11))) )
903 const char * sub1 = protocol1 + strlen(dot11);
904 const char * sub2 = protocol2 + strlen(dot11);
911 /* Check if we find the magic letters telling it's DS compatible */
912 for(i = 0; i < strlen(dot11_ds); i++)
914 if(strchr(sub1, dot11_ds[i]) != NULL)
916 if(strchr(sub2, dot11_ds[i]) != NULL)
922 /* Check if we find the magic letters telling it's 5GHz compatible */
923 for(i = 0; i < strlen(dot11_5g); i++)
925 if(strchr(sub1, dot11_5g[i]) != NULL)
927 if(strchr(sub2, dot11_5g[i]) != NULL)
937 /************************ ESSID SUBROUTINES ************************/
939 * The ESSID identify 802.11 networks, and is an array if 32 bytes.
940 * Most people use it as an ASCII string, and are happy with it.
941 * However, any byte is valid, including the NUL character. Characters
942 * beyond the ASCII range are interpreted according to the locale and
943 * the OS, which is somethign we don't control (network of other
945 * Routines in here try to deal with that in asafe way.
948 /*------------------------------------------------------------------*/
950 * Escape non-ASCII characters from ESSID.
951 * This allow us to display those weirds characters to the user.
953 * Source is 32 bytes max.
954 * Destination buffer needs to be at least 129 bytes, will be NUL
958 iw_essid_escape(char * dest,
962 const unsigned char * s = (const unsigned char *) src;
963 const unsigned char * e = s + slen;
966 /* Look every character of the string */
971 /* Escape the escape to avoid ambiguity.
972 * We do a fast path test for performance reason. Compiler will
973 * optimise all that ;-) */
976 /* Check if we would confuse it with an escape sequence */
977 if((e-s) > 4 && (s[1] == 'x')
978 && (isxdigit(s[2])) && (isxdigit(s[3])))
989 /* Is it a non-ASCII character ??? */
990 if(isescape || !isascii(*s) || iscntrl(*s))
993 sprintf(d, "\\x%02X", *s);
998 /* Plain ASCII, just copy */
1005 /* NUL terminate destination */
1009 /* ---------------------------------------------------------------- */
1011 * Un-Escape non-ASCII characters from ESSID
1012 * This allow the user to specify weird characters in ESSID.
1014 * The source is a NUL terminated string.
1015 * Destination buffer is at least the size of source (ESSID will shrink)
1016 * Destination may contains NUL, therefore we return the length.
1017 * This function still works is src and dest are the same ;-)
1020 iw_essid_unescape(char * dest,
1023 const char * s = src;
1028 /* Look-up the next '\' sequence, stop when no more */
1029 while((p = strchr(s, '\\')) != NULL)
1031 /* Copy block of unescaped chars before the '\' */
1035 s += len; /* Identical to 's = p' */
1037 /* Check if it is really an escape sequence. We do also check for NUL */
1038 if((s[1] == 'x') && (isxdigit(s[2])) && (isxdigit(s[3])))
1041 /* Valid Escape sequence, un-escape it */
1042 sscanf(s + 2, "%2X", &temp);
1049 /* Not valid, don't un-escape it */
1056 /* Copy remaining of the string */
1058 memcpy(d, s, len + 1);
1060 return((d - dest) + len);
1063 /********************** FREQUENCY SUBROUTINES ***********************/
1065 * Note : the two functions below are the cause of troubles on
1066 * various embeeded platforms, as they are the reason we require
1067 * libm (math library).
1068 * In this case, please use enable BUILD_NOLIBM in the makefile
1070 * FIXME : check negative mantissa and exponent
1073 /*------------------------------------------------------------------*/
1075 * Convert a floating point the our internal representation of
1077 * The kernel doesn't want to hear about floating point, so we use
1078 * this custom format instead.
1081 iw_float2freq(double in,
1085 /* Version without libm : slower */
1093 #else /* WE_NOLIBM */
1094 /* Version with libm : faster */
1095 out->e = (short) (floor(log10(in)));
1098 out->m = ((long) (floor(in / pow(10,out->e - 6)))) * 100;
1106 #endif /* WE_NOLIBM */
1109 /*------------------------------------------------------------------*/
1111 * Convert our internal representation of frequencies to a floating point.
1114 iw_freq2float(const iwfreq * in)
1117 /* Version without libm : slower */
1119 double res = (double) in->m;
1120 for(i = 0; i < in->e; i++)
1123 #else /* WE_NOLIBM */
1124 /* Version with libm : faster */
1125 return ((double) in->m) * pow(10,in->e);
1126 #endif /* WE_NOLIBM */
1129 /*------------------------------------------------------------------*/
1131 * Output a frequency with proper scaling
1134 iw_print_freq_value(char * buffer,
1139 snprintf(buffer, buflen, "%g", freq);
1163 snprintf(buffer, buflen, "%g %cHz", freq / divisor, scale);
1167 /*------------------------------------------------------------------*/
1169 * Output a frequency with proper scaling
1172 iw_print_freq(char * buffer,
1178 char sep = ((freq_flags & IW_FREQ_FIXED) ? '=' : ':');
1181 /* Print the frequency/channel value */
1182 iw_print_freq_value(vbuf, sizeof(vbuf), freq);
1184 /* Check if channel only */
1186 snprintf(buffer, buflen, "Channel%c%s", sep, vbuf);
1189 /* Frequency. Check if we have a channel as well */
1191 snprintf(buffer, buflen, "Frequency%c%s (Channel %d)",
1192 sep, vbuf, channel);
1194 snprintf(buffer, buflen, "Frequency%c%s", sep, vbuf);
1198 /*------------------------------------------------------------------*/
1200 * Convert a frequency to a channel (negative -> error)
1203 iw_freq_to_channel(double freq,
1204 const struct iw_range * range)
1209 /* Check if it's a frequency or not already a channel */
1213 /* We compare the frequencies as double to ignore differences
1214 * in encoding. Slower, but safer... */
1215 for(k = 0; k < range->num_frequency; k++)
1217 ref_freq = iw_freq2float(&(range->freq[k]));
1218 if(freq == ref_freq)
1219 return(range->freq[k].i);
1225 /*------------------------------------------------------------------*/
1227 * Convert a channel to a frequency (negative -> error)
1228 * Return the channel on success
1231 iw_channel_to_freq(int channel,
1233 const struct iw_range * range)
1238 /* Check if the driver support only channels or if it has frequencies */
1239 for(k = 0; k < range->num_frequency; k++)
1241 if((range->freq[k].e != 0) || (range->freq[k].m > (int) KILO))
1247 /* Find the correct frequency in the list */
1248 for(k = 0; k < range->num_frequency; k++)
1250 if(range->freq[k].i == channel)
1252 *pfreq = iw_freq2float(&(range->freq[k]));
1260 /*********************** BITRATE SUBROUTINES ***********************/
1262 /*------------------------------------------------------------------*/
1264 * Output a bitrate with proper scaling
1267 iw_print_bitrate(char * buffer,
1271 double rate = bitrate;
1293 snprintf(buffer, buflen, "%g %cb/s", rate / divisor, scale);
1296 /************************ POWER SUBROUTINES *************************/
1298 /*------------------------------------------------------------------*/
1300 * Convert a value in dBm to a value in milliWatt.
1303 iw_dbm2mwatt(int in)
1306 /* Version without libm : slower */
1312 /* Split integral and floating part to avoid accumulating rounding errors */
1313 for(k = 0; k < ip; k++)
1315 for(k = 0; k < fp; k++)
1318 #else /* WE_NOLIBM */
1319 /* Version with libm : faster */
1320 return((int) (floor(pow(10.0, (((double) in) / 10.0)))));
1321 #endif /* WE_NOLIBM */
1324 /*------------------------------------------------------------------*/
1326 * Convert a value in milliWatt to a value in dBm.
1329 iw_mwatt2dbm(int in)
1332 /* Version without libm : slower */
1333 double fin = (double) in;
1336 /* Split integral and floating part to avoid accumulating rounding errors */
1342 while(fin > 1.000001) /* Eliminate rounding errors, take ceil */
1348 #else /* WE_NOLIBM */
1349 /* Version with libm : faster */
1350 return((int) (ceil(10.0 * log10((double) in))));
1351 #endif /* WE_NOLIBM */
1354 /*------------------------------------------------------------------*/
1356 * Output a txpower with proper conversion
1359 iw_print_txpower(char * buffer,
1361 struct iw_param * txpower)
1365 /* Check if disabled */
1366 if(txpower->disabled)
1368 snprintf(buffer, buflen, "off");
1372 /* Check for relative values */
1373 if(txpower->flags & IW_TXPOW_RELATIVE)
1375 snprintf(buffer, buflen, "%d", txpower->value);
1379 /* Convert everything to dBm */
1380 if(txpower->flags & IW_TXPOW_MWATT)
1381 dbm = iw_mwatt2dbm(txpower->value);
1383 dbm = txpower->value;
1386 snprintf(buffer, buflen, "%d dBm", dbm);
1391 /********************** STATISTICS SUBROUTINES **********************/
1393 /*------------------------------------------------------------------*/
1395 * Read /proc/net/wireless to get the latest statistics
1396 * Note : strtok not thread safe, not used in WE-12 and later.
1399 iw_get_stats(int skfd,
1400 const char * ifname,
1402 const iwrange * range,
1405 /* Fortunately, we can always detect this condition properly */
1406 if((has_range) && (range->we_version_compiled > 11))
1409 wrq.u.data.pointer = (caddr_t) stats;
1410 wrq.u.data.length = sizeof(struct iw_statistics);
1411 wrq.u.data.flags = 1; /* Clear updated flag */
1412 strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
1413 if(iw_get_ext(skfd, ifname, SIOCGIWSTATS, &wrq) < 0)
1416 /* Format has not changed since WE-12, no conversion */
1421 FILE * f = fopen(PROC_NET_WIRELESS, "r");
1428 /* Loop on all devices */
1429 while(fgets(buf,255,f))
1432 while(*bp&&isspace(*bp))
1434 /* Is it the good device ? */
1435 if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':')
1441 bp = strtok(bp, " ");
1442 sscanf(bp, "%X", &t);
1443 stats->status = (unsigned short) t;
1444 /* -- link quality -- */
1445 bp = strtok(NULL, " ");
1446 if(strchr(bp,'.') != NULL)
1447 stats->qual.updated |= 1;
1448 sscanf(bp, "%d", &t);
1449 stats->qual.qual = (unsigned char) t;
1450 /* -- signal level -- */
1451 bp = strtok(NULL, " ");
1452 if(strchr(bp,'.') != NULL)
1453 stats->qual.updated |= 2;
1454 sscanf(bp, "%d", &t);
1455 stats->qual.level = (unsigned char) t;
1456 /* -- noise level -- */
1457 bp = strtok(NULL, " ");
1458 if(strchr(bp,'.') != NULL)
1459 stats->qual.updated += 4;
1460 sscanf(bp, "%d", &t);
1461 stats->qual.noise = (unsigned char) t;
1462 /* -- discarded packets -- */
1463 bp = strtok(NULL, " ");
1464 sscanf(bp, "%d", &stats->discard.nwid);
1465 bp = strtok(NULL, " ");
1466 sscanf(bp, "%d", &stats->discard.code);
1467 bp = strtok(NULL, " ");
1468 sscanf(bp, "%d", &stats->discard.misc);
1470 /* No conversion needed */
1479 /*------------------------------------------------------------------*/
1481 * Output the link statistics, taking care of formating
1484 iw_print_stats(char * buffer,
1486 const iwqual * qual,
1487 const iwrange * range,
1492 /* People are very often confused by the 8 bit arithmetic happening
1494 * All the values here are encoded in a 8 bit integer. 8 bit integers
1495 * are either unsigned [0 ; 255], signed [-128 ; +127] or
1496 * negative [-255 ; 0].
1497 * Further, on 8 bits, 0x100 == 256 == 0.
1499 * Relative/percent values are always encoded unsigned, between 0 and 255.
1500 * Absolute/dBm values are always encoded between -192 and 63.
1501 * (Note that up to version 28 of Wireless Tools, dBm used to be
1502 * encoded always negative, between -256 and -1).
1504 * How do we separate relative from absolute values ?
1505 * The old way is to use the range to do that. As of WE-19, we have
1506 * an explicit IW_QUAL_DBM flag in updated...
1507 * The range allow to specify the real min/max of the value. As the
1508 * range struct only specify one bound of the value, we assume that
1509 * the other bound is 0 (zero).
1510 * For relative values, range is [0 ; range->max].
1511 * For absolute values, range is [range->max ; 63].
1513 * Let's take two example :
1514 * 1) value is 75%. qual->value = 75 ; range->max_qual.value = 100
1515 * 2) value is -54dBm. noise floor of the radio is -104dBm.
1516 * qual->value = -54 = 202 ; range->max_qual.value = -104 = 152
1522 * The old way to detect dBm require both the range and a non-null
1523 * level (which confuse the test). The new way can deal with level of 0
1524 * because it does an explicit test on the flag. */
1525 if(has_range && ((qual->level != 0)
1526 || (qual->updated & (IW_QUAL_DBM | IW_QUAL_RCPI))))
1528 /* Deal with quality : always a relative value */
1529 if(!(qual->updated & IW_QUAL_QUAL_INVALID))
1531 len = snprintf(buffer, buflen, "Quality%c%d/%d ",
1532 qual->updated & IW_QUAL_QUAL_UPDATED ? '=' : ':',
1533 qual->qual, range->max_qual.qual);
1538 /* Check if the statistics are in RCPI (IEEE 802.11k) */
1539 if(qual->updated & IW_QUAL_RCPI)
1541 /* Deal with signal level in RCPI */
1542 /* RCPI = int{(Power in dBm +110)*2} for 0dbm > Power > -110dBm */
1543 if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1545 double rcpilevel = (qual->level / 2.0) - 110.0;
1546 len = snprintf(buffer, buflen, "Signal level%c%g dBm ",
1547 qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1553 /* Deal with noise level in dBm (absolute power measurement) */
1554 if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1556 double rcpinoise = (qual->noise / 2.0) - 110.0;
1557 len = snprintf(buffer, buflen, "Noise level%c%g dBm",
1558 qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1564 /* Check if the statistics are in dBm */
1565 if((qual->updated & IW_QUAL_DBM)
1566 || (qual->level > range->max_qual.level))
1568 /* Deal with signal level in dBm (absolute power measurement) */
1569 if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1571 int dblevel = qual->level;
1572 /* Implement a range for dBm [-192; 63] */
1573 if(qual->level >= 64)
1575 len = snprintf(buffer, buflen, "Signal level%c%d dBm ",
1576 qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1582 /* Deal with noise level in dBm (absolute power measurement) */
1583 if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1585 int dbnoise = qual->noise;
1586 /* Implement a range for dBm [-192; 63] */
1587 if(qual->noise >= 64)
1589 len = snprintf(buffer, buflen, "Noise level%c%d dBm",
1590 qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1596 /* Deal with signal level as relative value (0 -> max) */
1597 if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1599 len = snprintf(buffer, buflen, "Signal level%c%d/%d ",
1600 qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1601 qual->level, range->max_qual.level);
1606 /* Deal with noise level as relative value (0 -> max) */
1607 if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1609 len = snprintf(buffer, buflen, "Noise level%c%d/%d",
1610 qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1611 qual->noise, range->max_qual.noise);
1618 /* We can't read the range, so we don't know... */
1619 snprintf(buffer, buflen,
1620 "Quality:%d Signal level:%d Noise level:%d",
1621 qual->qual, qual->level, qual->noise);
1625 /*********************** ENCODING SUBROUTINES ***********************/
1627 /*------------------------------------------------------------------*/
1629 * Output the encoding key, with a nice formating
1632 iw_print_key(char * buffer,
1634 const unsigned char * key, /* Must be unsigned */
1640 /* Check buffer size -> 1 bytes => 2 digits + 1/2 separator */
1641 if((key_size * 3) > buflen)
1643 snprintf(buffer, buflen, "<too big>");
1647 /* Is the key present ??? */
1648 if(key_flags & IW_ENCODE_NOKEY)
1650 /* Nope : print on or dummy */
1652 strcpy(buffer, "on"); /* Size checked */
1655 strcpy(buffer, "**"); /* Size checked */
1657 for(i = 1; i < key_size; i++)
1660 strcpy(buffer++, "-"); /* Size checked */
1661 strcpy(buffer, "**"); /* Size checked */
1668 /* Yes : print the key */
1669 sprintf(buffer, "%.2X", key[0]); /* Size checked */
1671 for(i = 1; i < key_size; i++)
1674 strcpy(buffer++, "-"); /* Size checked */
1675 sprintf(buffer, "%.2X", key[i]); /* Size checked */
1681 /*------------------------------------------------------------------*/
1683 * Convert a passphrase into a key
1684 * ### NOT IMPLEMENTED ###
1685 * Return size of the key, or 0 (no key) or -1 (error)
1688 iw_pass_key(const char * input,
1689 unsigned char * key)
1691 input = input; key = key;
1692 fprintf(stderr, "Error: Passphrase not implemented\n");
1696 /*------------------------------------------------------------------*/
1698 * Parse a key from the command line.
1699 * Return size of the key, or 0 (no key) or -1 (error)
1700 * If the key is too long, it's simply truncated...
1703 iw_in_key(const char * input,
1704 unsigned char * key)
1708 /* Check the type of key */
1709 if(!strncmp(input, "s:", 2))
1711 /* First case : as an ASCII string (Lucent/Agere cards) */
1712 keylen = strlen(input + 2); /* skip "s:" */
1713 if(keylen > IW_ENCODING_TOKEN_MAX)
1714 keylen = IW_ENCODING_TOKEN_MAX;
1715 memcpy(key, input + 2, keylen);
1718 if(!strncmp(input, "p:", 2))
1720 /* Second case : as a passphrase (PrismII cards) */
1721 return(iw_pass_key(input + 2, key)); /* skip "p:" */
1726 int dlen; /* Digits sequence length */
1727 unsigned char out[IW_ENCODING_TOKEN_MAX];
1729 /* Third case : as hexadecimal digits */
1733 /* Loop until we run out of chars in input or overflow the output */
1739 /* No more chars in this sequence */
1742 /* Skip separator */
1745 /* Calculate num of char to next separator */
1746 dlen = strcspn(p, "-:;.,");
1748 /* Get each char separatly (and not by two) so that we don't
1749 * get confused by 'enc' (=> '0E'+'0C') and similar */
1750 count = sscanf(p, "%1X%1X", &temph, &templ);
1752 return(-1); /* Error -> non-hex char */
1753 /* Fixup odd strings such as '123' is '01'+'23' and not '12'+'03'*/
1756 /* Put back two chars as one byte and output */
1758 templ |= temph << 4;
1761 out[keylen++] = (unsigned char) (templ & 0xFF);
1762 /* Check overflow in output */
1763 if(keylen >= IW_ENCODING_TOKEN_MAX)
1765 /* Move on to next chars */
1769 /* We use a temporary output buffer 'out' so that if there is
1770 * an error, we don't overwrite the original key buffer.
1771 * Because of the way iwconfig loop on multiple key/enc arguments
1772 * until it finds an error in here, this is necessary to avoid
1773 * silently corrupting the encryption key... */
1774 memcpy(key, out, keylen);
1779 char buf[IW_ENCODING_TOKEN_MAX * 3];
1780 iw_print_key(buf, sizeof(buf), key, keylen, 0);
1781 printf("Got key : %d [%s]\n", keylen, buf);
1788 /*------------------------------------------------------------------*/
1790 * Parse a key from the command line.
1791 * Return size of the key, or 0 (no key) or -1 (error)
1794 iw_in_key_full(int skfd,
1795 const char * ifname,
1797 unsigned char * key,
1803 if(!strncmp(input, "l:", 2))
1805 struct iw_range range;
1807 /* Extra case : as a login (user:passwd - Cisco LEAP) */
1808 keylen = strlen(input + 2) + 1; /* skip "l:", add '\0' */
1809 /* Most user/password is 8 char, so 18 char total, < 32 */
1810 if(keylen > IW_ENCODING_TOKEN_MAX)
1811 keylen = IW_ENCODING_TOKEN_MAX;
1812 memcpy(key, input + 2, keylen);
1814 /* Separate the two strings */
1815 p = strchr((char *) key, ':');
1818 fprintf(stderr, "Error: Invalid login format\n");
1823 /* Extract range info */
1824 if(iw_get_range_info(skfd, ifname, &range) < 0)
1825 /* Hum... Maybe we should return an error ??? */
1826 memset(&range, 0, sizeof(range));
1828 if(range.we_version_compiled > 15)
1831 printf("flags = %X, index = %X\n",
1832 *flags, range.encoding_login_index);
1833 if((*flags & IW_ENCODE_INDEX) == 0)
1835 /* Extract range info */
1836 if(iw_get_range_info(skfd, ifname, &range) < 0)
1837 memset(&range, 0, sizeof(range));
1838 printf("flags = %X, index = %X\n", *flags, range.encoding_login_index);
1839 /* Set the index the driver expects */
1840 *flags |= range.encoding_login_index & IW_ENCODE_INDEX;
1842 printf("flags = %X, index = %X\n", *flags, range.encoding_login_index);
1846 /* Simpler routine above */
1847 keylen = iw_in_key(input, key);
1852 /******************* POWER MANAGEMENT SUBROUTINES *******************/
1854 /*------------------------------------------------------------------*/
1856 * Output a power management value with all attributes...
1859 iw_print_pm_value(char * buffer,
1868 snprintf(buffer, buflen, "<too big>");
1874 if(flags & IW_POWER_MIN)
1876 strcpy(buffer, " min"); /* Size checked */
1879 if(flags & IW_POWER_MAX)
1881 strcpy(buffer, " max"); /* Size checked */
1886 if(flags & IW_POWER_TIMEOUT)
1888 strcpy(buffer, " timeout:"); /* Size checked */
1893 if(flags & IW_POWER_SAVING)
1895 strcpy(buffer, " saving:"); /* Size checked */
1900 strcpy(buffer, " period:"); /* Size checked */
1905 /* Display value without units */
1906 if(flags & IW_POWER_RELATIVE)
1910 snprintf(buffer, buflen, "%d", value);
1914 /* Display value with units */
1915 if(value >= (int) MEGA)
1916 snprintf(buffer, buflen, "%gs", ((double) value) / MEGA);
1918 if(value >= (int) KILO)
1919 snprintf(buffer, buflen, "%gms", ((double) value) / KILO);
1921 snprintf(buffer, buflen, "%dus", value);
1925 /*------------------------------------------------------------------*/
1927 * Output a power management mode
1930 iw_print_pm_mode(char * buffer,
1937 snprintf(buffer, buflen, "<too big>");
1941 /* Print the proper mode... */
1942 switch(flags & IW_POWER_MODE)
1944 case IW_POWER_UNICAST_R:
1945 strcpy(buffer, "mode:Unicast only received"); /* Size checked */
1947 case IW_POWER_MULTICAST_R:
1948 strcpy(buffer, "mode:Multicast only received"); /* Size checked */
1950 case IW_POWER_ALL_R:
1951 strcpy(buffer, "mode:All packets received"); /* Size checked */
1953 case IW_POWER_FORCE_S:
1954 strcpy(buffer, "mode:Force sending"); /* Size checked */
1956 case IW_POWER_REPEATER:
1957 strcpy(buffer, "mode:Repeat multicasts"); /* Size checked */
1960 strcpy(buffer, ""); /* Size checked */
1965 /***************** RETRY LIMIT/LIFETIME SUBROUTINES *****************/
1967 /*------------------------------------------------------------------*/
1969 * Output a retry value with all attributes...
1972 iw_print_retry_value(char * buffer,
1978 /* Check buffer size */
1981 snprintf(buffer, buflen, "<too big>");
1987 if(flags & IW_RETRY_MIN)
1989 strcpy(buffer, " min"); /* Size checked */
1992 if(flags & IW_RETRY_MAX)
1994 strcpy(buffer, " max"); /* Size checked */
1997 if(flags & IW_RETRY_SHORT)
1999 strcpy(buffer, " short"); /* Size checked */
2002 if(flags & IW_RETRY_LONG)
2004 strcpy(buffer, " long"); /* Size checked */
2008 /* Type lifetime of limit */
2009 if(flags & IW_RETRY_LIFETIME)
2011 strcpy(buffer, " lifetime:"); /* Size checked */
2014 /* Display value without units */
2015 if(flags & IW_RETRY_RELATIVE)
2019 snprintf(buffer, buflen, "%d", value);
2023 /* Display value with units */
2024 if(value >= (int) MEGA)
2025 snprintf(buffer, buflen, "%gs", ((double) value) / MEGA);
2027 if(value >= (int) KILO)
2028 snprintf(buffer, buflen, "%gms", ((double) value) / KILO);
2030 snprintf(buffer, buflen, "%dus", value);
2034 snprintf(buffer, buflen, " limit:%d", value);
2037 /************************* TIME SUBROUTINES *************************/
2039 /*------------------------------------------------------------------*/
2042 * Inspired from irdadump...
2045 iw_print_timeval(char * buffer,
2047 const struct timeval * timev,
2048 const struct timezone * tz)
2052 s = (timev->tv_sec - tz->tz_minuteswest * 60) % 86400;
2053 snprintf(buffer, buflen, "%02d:%02d:%02d.%06u",
2054 s / 3600, (s % 3600) / 60,
2055 s % 60, (u_int32_t) timev->tv_usec);
2058 /*********************** ADDRESS SUBROUTINES ************************/
2060 * This section is mostly a cut & past from net-tools-1.2.0
2061 * (Well... This has evolved over the years)
2062 * manage address display and input...
2065 /*------------------------------------------------------------------*/
2067 * Check if interface support the right MAC address type...
2070 iw_check_mac_addr_type(int skfd,
2071 const char * ifname)
2075 /* Get the type of hardware address */
2076 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
2077 if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) ||
2078 ((ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
2079 && (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211)))
2081 /* Deep trouble... */
2082 fprintf(stderr, "Interface %s doesn't support MAC addresses\n",
2090 printf("Hardware : %d - %s\n", ifr.ifr_hwaddr.sa_family,
2091 iw_saether_ntop(&ifr.ifr_hwaddr, buf));
2099 /*------------------------------------------------------------------*/
2101 * Check if interface support the right interface address type...
2104 iw_check_if_addr_type(int skfd,
2105 const char * ifname)
2109 /* Get the type of interface address */
2110 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
2111 if((ioctl(skfd, SIOCGIFADDR, &ifr) < 0) ||
2112 (ifr.ifr_addr.sa_family != AF_INET))
2114 /* Deep trouble... */
2115 fprintf(stderr, "Interface %s doesn't support IP addresses\n", ifname);
2120 printf("Interface : %d - 0x%lX\n", ifr.ifr_addr.sa_family,
2121 *((unsigned long *) ifr.ifr_addr.sa_data));
2127 /*------------------------------------------------------------------*/
2129 * Display an arbitrary length MAC address in readable format.
2132 iw_mac_ntop(const unsigned char * mac,
2139 /* Overflow check (don't forget '\0') */
2140 if(buflen < (maclen * 3 - 1 + 1))
2144 sprintf(buf, "%02X", mac[0]);
2147 for(i = 1; i < maclen; i++)
2148 sprintf(buf + (i * 3) - 1, ":%02X", mac[i]);
2152 /*------------------------------------------------------------------*/
2154 * Display an Ethernet address in readable format.
2157 iw_ether_ntop(const struct ether_addr * eth,
2160 sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
2161 eth->ether_addr_octet[0], eth->ether_addr_octet[1],
2162 eth->ether_addr_octet[2], eth->ether_addr_octet[3],
2163 eth->ether_addr_octet[4], eth->ether_addr_octet[5]);
2166 /*------------------------------------------------------------------*/
2168 * Display an Wireless Access Point Socket Address in readable format.
2169 * Note : 0x44 is an accident of history, that's what the Orinoco/PrismII
2170 * chipset report, and the driver doesn't filter it.
2173 iw_sawap_ntop(const struct sockaddr * sap,
2176 const struct ether_addr ether_zero = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }};
2177 const struct ether_addr ether_bcast = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
2178 const struct ether_addr ether_hack = {{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }};
2179 const struct ether_addr * ether_wap = (const struct ether_addr *) sap->sa_data;
2181 if(!iw_ether_cmp(ether_wap, ðer_zero))
2182 sprintf(buf, "Not-Associated");
2184 if(!iw_ether_cmp(ether_wap, ðer_bcast))
2185 sprintf(buf, "Invalid");
2187 if(!iw_ether_cmp(ether_wap, ðer_hack))
2188 sprintf(buf, "None");
2190 iw_ether_ntop(ether_wap, buf);
2194 /*------------------------------------------------------------------*/
2196 * Input an arbitrary length MAC address and convert to binary.
2197 * Return address size.
2200 iw_mac_aton(const char * orig,
2201 unsigned char * mac,
2204 const char * p = orig;
2207 /* Loop on all bytes of the string */
2213 /* Extract one byte as two chars */
2214 count = sscanf(p, "%1X%1X", &temph, &templ);
2216 break; /* Error -> non-hex chars */
2217 /* Output two chars as one byte */
2218 templ |= temph << 4;
2219 mac[maclen++] = (unsigned char) (templ & 0xFF);
2221 /* Check end of string */
2227 iw_ether_ntop((const struct ether_addr *) mac, buf);
2228 fprintf(stderr, "iw_mac_aton(%s): %s\n", orig, buf);
2230 return(maclen); /* Normal exit */
2233 /* Check overflow */
2234 if(maclen >= macmax)
2237 fprintf(stderr, "iw_mac_aton(%s): trailing junk!\n", orig);
2240 return(0); /* Error -> overflow */
2243 /* Check separator */
2251 fprintf(stderr, "iw_mac_aton(%s): invalid ether address!\n", orig);
2257 /*------------------------------------------------------------------*/
2259 * Input an Ethernet address and convert to binary.
2262 iw_ether_aton(const char *orig, struct ether_addr *eth)
2265 maclen = iw_mac_aton(orig, (unsigned char *) eth, ETH_ALEN);
2266 if((maclen > 0) && (maclen < ETH_ALEN))
2274 /*------------------------------------------------------------------*/
2276 * Input an Internet address and convert to binary.
2279 iw_in_inet(char *name, struct sockaddr *sap)
2283 struct sockaddr_in *sain = (struct sockaddr_in *) sap;
2286 sain->sin_family = AF_INET;
2289 /* Default is special, meaning 0.0.0.0. */
2290 if (!strcmp(name, "default")) {
2291 sain->sin_addr.s_addr = INADDR_ANY;
2295 /* Try the NETWORKS database to see if this is a known network. */
2296 if ((np = getnetbyname(name)) != (struct netent *)NULL) {
2297 sain->sin_addr.s_addr = htonl(np->n_net);
2298 strcpy(name, np->n_name);
2302 /* Always use the resolver (DNS name + IP addresses) */
2303 if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
2307 memcpy((char *) &sain->sin_addr, (char *) hp->h_addr_list[0], hp->h_length);
2308 strcpy(name, hp->h_name);
2312 /*------------------------------------------------------------------*/
2314 * Input an address and convert to binary.
2317 iw_in_addr(int skfd,
2318 const char * ifname,
2320 struct sockaddr *sap)
2322 /* Check if it is a hardware or IP address */
2323 if(strchr(bufp, ':') == NULL)
2325 struct sockaddr if_address;
2326 struct arpreq arp_query;
2328 /* Check if we have valid interface address type */
2329 if(iw_check_if_addr_type(skfd, ifname) < 0)
2331 fprintf(stderr, "%-8.16s Interface doesn't support IP addresses\n", ifname);
2335 /* Read interface address */
2336 if(iw_in_inet(bufp, &if_address) < 0)
2338 fprintf(stderr, "Invalid interface address %s\n", bufp);
2342 /* Translate IP addresses to MAC addresses */
2343 memcpy((char *) &(arp_query.arp_pa),
2344 (char *) &if_address,
2345 sizeof(struct sockaddr));
2346 arp_query.arp_ha.sa_family = 0;
2347 arp_query.arp_flags = 0;
2348 /* The following restrict the search to the interface only */
2349 /* For old kernels which complain, just comment it... */
2350 strncpy(arp_query.arp_dev, ifname, IFNAMSIZ);
2351 if((ioctl(skfd, SIOCGARP, &arp_query) < 0) ||
2352 !(arp_query.arp_flags & ATF_COM))
2354 fprintf(stderr, "Arp failed for %s on %s... (%d)\nTry to ping the address before setting it.\n",
2355 bufp, ifname, errno);
2359 /* Store new MAC address */
2360 memcpy((char *) sap,
2361 (char *) &(arp_query.arp_ha),
2362 sizeof(struct sockaddr));
2367 printf("IP Address %s => Hw Address = %s\n",
2368 bufp, iw_saether_ntop(sap, buf));
2372 else /* If it's an hardware address */
2374 /* Check if we have valid mac address type */
2375 if(iw_check_mac_addr_type(skfd, ifname) < 0)
2377 fprintf(stderr, "%-8.16s Interface doesn't support MAC addresses\n", ifname);
2381 /* Get the hardware address */
2382 if(iw_saether_aton(bufp, sap) == 0)
2384 fprintf(stderr, "Invalid hardware address %s\n", bufp);
2392 printf("Hw Address = %s\n", iw_saether_ntop(sap, buf));
2399 /************************* MISC SUBROUTINES **************************/
2401 /* Size (in bytes) of various events */
2402 static const int priv_type_size[] = {
2403 0, /* IW_PRIV_TYPE_NONE */
2404 1, /* IW_PRIV_TYPE_BYTE */
2405 1, /* IW_PRIV_TYPE_CHAR */
2406 0, /* Not defined */
2407 sizeof(__u32), /* IW_PRIV_TYPE_INT */
2408 sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
2409 sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
2410 0, /* Not defined */
2413 /*------------------------------------------------------------------*/
2415 * Max size in bytes of an private argument.
2418 iw_get_priv_size(int args)
2420 int num = args & IW_PRIV_SIZE_MASK;
2421 int type = (args & IW_PRIV_TYPE_MASK) >> 12;
2423 return(num * priv_type_size[type]);
2426 /************************ EVENT SUBROUTINES ************************/
2428 * The Wireless Extension API 14 and greater define Wireless Events,
2429 * that are used for various events and scanning.
2430 * Those functions help the decoding of events, so are needed only in
2434 /* -------------------------- CONSTANTS -------------------------- */
2436 /* Type of headers we know about (basically union iwreq_data) */
2437 #define IW_HEADER_TYPE_NULL 0 /* Not available */
2438 #define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */
2439 #define IW_HEADER_TYPE_UINT 4 /* __u32 */
2440 #define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */
2441 #define IW_HEADER_TYPE_ADDR 6 /* struct sockaddr */
2442 #define IW_HEADER_TYPE_POINT 8 /* struct iw_point */
2443 #define IW_HEADER_TYPE_PARAM 9 /* struct iw_param */
2444 #define IW_HEADER_TYPE_QUAL 10 /* struct iw_quality */
2446 /* Handling flags */
2447 /* Most are not implemented. I just use them as a reminder of some
2448 * cool features we might need one day ;-) */
2449 #define IW_DESCR_FLAG_NONE 0x0000 /* Obvious */
2450 /* Wrapper level flags */
2451 #define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */
2452 #define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */
2453 #define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */
2454 /* SET : Omit payload from generated iwevent */
2455 #define IW_DESCR_FLAG_NOMAX 0x0008 /* GET : no limit on request size */
2456 /* Driver level flags */
2457 #define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */
2459 /* ---------------------------- TYPES ---------------------------- */
2462 * Describe how a standard IOCTL looks like.
2464 struct iw_ioctl_description
2466 __u8 header_type; /* NULL, iw_point or other */
2467 __u8 token_type; /* Future */
2468 __u16 token_size; /* Granularity of payload */
2469 __u16 min_tokens; /* Min acceptable token number */
2470 __u16 max_tokens; /* Max acceptable token number */
2471 __u32 flags; /* Special handling of the request */
2474 /* -------------------------- VARIABLES -------------------------- */
2477 * Meta-data about all the standard Wireless Extension request we
2480 static const struct iw_ioctl_description standard_ioctl_descr[] = {
2481 [SIOCSIWCOMMIT - SIOCIWFIRST] = {
2482 .header_type = IW_HEADER_TYPE_NULL,
2484 [SIOCGIWNAME - SIOCIWFIRST] = {
2485 .header_type = IW_HEADER_TYPE_CHAR,
2486 .flags = IW_DESCR_FLAG_DUMP,
2488 [SIOCSIWNWID - SIOCIWFIRST] = {
2489 .header_type = IW_HEADER_TYPE_PARAM,
2490 .flags = IW_DESCR_FLAG_EVENT,
2492 [SIOCGIWNWID - SIOCIWFIRST] = {
2493 .header_type = IW_HEADER_TYPE_PARAM,
2494 .flags = IW_DESCR_FLAG_DUMP,
2496 [SIOCSIWFREQ - SIOCIWFIRST] = {
2497 .header_type = IW_HEADER_TYPE_FREQ,
2498 .flags = IW_DESCR_FLAG_EVENT,
2500 [SIOCGIWFREQ - SIOCIWFIRST] = {
2501 .header_type = IW_HEADER_TYPE_FREQ,
2502 .flags = IW_DESCR_FLAG_DUMP,
2504 [SIOCSIWMODE - SIOCIWFIRST] = {
2505 .header_type = IW_HEADER_TYPE_UINT,
2506 .flags = IW_DESCR_FLAG_EVENT,
2508 [SIOCGIWMODE - SIOCIWFIRST] = {
2509 .header_type = IW_HEADER_TYPE_UINT,
2510 .flags = IW_DESCR_FLAG_DUMP,
2512 [SIOCSIWSENS - SIOCIWFIRST] = {
2513 .header_type = IW_HEADER_TYPE_PARAM,
2515 [SIOCGIWSENS - SIOCIWFIRST] = {
2516 .header_type = IW_HEADER_TYPE_PARAM,
2518 [SIOCSIWRANGE - SIOCIWFIRST] = {
2519 .header_type = IW_HEADER_TYPE_NULL,
2521 [SIOCGIWRANGE - SIOCIWFIRST] = {
2522 .header_type = IW_HEADER_TYPE_POINT,
2524 .max_tokens = sizeof(struct iw_range),
2525 .flags = IW_DESCR_FLAG_DUMP,
2527 [SIOCSIWPRIV - SIOCIWFIRST] = {
2528 .header_type = IW_HEADER_TYPE_NULL,
2530 [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */
2531 .header_type = IW_HEADER_TYPE_NULL,
2533 [SIOCSIWSTATS - SIOCIWFIRST] = {
2534 .header_type = IW_HEADER_TYPE_NULL,
2536 [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */
2537 .header_type = IW_HEADER_TYPE_NULL,
2538 .flags = IW_DESCR_FLAG_DUMP,
2540 [SIOCSIWSPY - SIOCIWFIRST] = {
2541 .header_type = IW_HEADER_TYPE_POINT,
2542 .token_size = sizeof(struct sockaddr),
2543 .max_tokens = IW_MAX_SPY,
2545 [SIOCGIWSPY - SIOCIWFIRST] = {
2546 .header_type = IW_HEADER_TYPE_POINT,
2547 .token_size = sizeof(struct sockaddr) +
2548 sizeof(struct iw_quality),
2549 .max_tokens = IW_MAX_SPY,
2551 [SIOCSIWTHRSPY - SIOCIWFIRST] = {
2552 .header_type = IW_HEADER_TYPE_POINT,
2553 .token_size = sizeof(struct iw_thrspy),
2557 [SIOCGIWTHRSPY - SIOCIWFIRST] = {
2558 .header_type = IW_HEADER_TYPE_POINT,
2559 .token_size = sizeof(struct iw_thrspy),
2563 [SIOCSIWAP - SIOCIWFIRST] = {
2564 .header_type = IW_HEADER_TYPE_ADDR,
2566 [SIOCGIWAP - SIOCIWFIRST] = {
2567 .header_type = IW_HEADER_TYPE_ADDR,
2568 .flags = IW_DESCR_FLAG_DUMP,
2570 [SIOCSIWMLME - SIOCIWFIRST] = {
2571 .header_type = IW_HEADER_TYPE_POINT,
2573 .min_tokens = sizeof(struct iw_mlme),
2574 .max_tokens = sizeof(struct iw_mlme),
2576 [SIOCGIWAPLIST - SIOCIWFIRST] = {
2577 .header_type = IW_HEADER_TYPE_POINT,
2578 .token_size = sizeof(struct sockaddr) +
2579 sizeof(struct iw_quality),
2580 .max_tokens = IW_MAX_AP,
2581 .flags = IW_DESCR_FLAG_NOMAX,
2583 [SIOCSIWSCAN - SIOCIWFIRST] = {
2584 .header_type = IW_HEADER_TYPE_POINT,
2587 .max_tokens = sizeof(struct iw_scan_req),
2589 [SIOCGIWSCAN - SIOCIWFIRST] = {
2590 .header_type = IW_HEADER_TYPE_POINT,
2592 .max_tokens = IW_SCAN_MAX_DATA,
2593 .flags = IW_DESCR_FLAG_NOMAX,
2595 [SIOCSIWESSID - SIOCIWFIRST] = {
2596 .header_type = IW_HEADER_TYPE_POINT,
2598 .max_tokens = IW_ESSID_MAX_SIZE + 1,
2599 .flags = IW_DESCR_FLAG_EVENT,
2601 [SIOCGIWESSID - SIOCIWFIRST] = {
2602 .header_type = IW_HEADER_TYPE_POINT,
2604 .max_tokens = IW_ESSID_MAX_SIZE + 1,
2605 .flags = IW_DESCR_FLAG_DUMP,
2607 [SIOCSIWNICKN - SIOCIWFIRST] = {
2608 .header_type = IW_HEADER_TYPE_POINT,
2610 .max_tokens = IW_ESSID_MAX_SIZE + 1,
2612 [SIOCGIWNICKN - SIOCIWFIRST] = {
2613 .header_type = IW_HEADER_TYPE_POINT,
2615 .max_tokens = IW_ESSID_MAX_SIZE + 1,
2617 [SIOCSIWRATE - SIOCIWFIRST] = {
2618 .header_type = IW_HEADER_TYPE_PARAM,
2620 [SIOCGIWRATE - SIOCIWFIRST] = {
2621 .header_type = IW_HEADER_TYPE_PARAM,
2623 [SIOCSIWRTS - SIOCIWFIRST] = {
2624 .header_type = IW_HEADER_TYPE_PARAM,
2626 [SIOCGIWRTS - SIOCIWFIRST] = {
2627 .header_type = IW_HEADER_TYPE_PARAM,
2629 [SIOCSIWFRAG - SIOCIWFIRST] = {
2630 .header_type = IW_HEADER_TYPE_PARAM,
2632 [SIOCGIWFRAG - SIOCIWFIRST] = {
2633 .header_type = IW_HEADER_TYPE_PARAM,
2635 [SIOCSIWTXPOW - SIOCIWFIRST] = {
2636 .header_type = IW_HEADER_TYPE_PARAM,
2638 [SIOCGIWTXPOW - SIOCIWFIRST] = {
2639 .header_type = IW_HEADER_TYPE_PARAM,
2641 [SIOCSIWRETRY - SIOCIWFIRST] = {
2642 .header_type = IW_HEADER_TYPE_PARAM,
2644 [SIOCGIWRETRY - SIOCIWFIRST] = {
2645 .header_type = IW_HEADER_TYPE_PARAM,
2647 [SIOCSIWENCODE - SIOCIWFIRST] = {
2648 .header_type = IW_HEADER_TYPE_POINT,
2649 /* Hack : this never returns any payload in event.
2650 * Fix the 64->32 bit hack... */
2652 .max_tokens = IW_ENCODING_TOKEN_MAX,
2653 .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
2655 [SIOCGIWENCODE - SIOCIWFIRST] = {
2656 .header_type = IW_HEADER_TYPE_POINT,
2657 /* Hack : this never returns any payload in event.
2658 * Fix the 64->32 bit hack... */
2660 .max_tokens = IW_ENCODING_TOKEN_MAX,
2661 .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
2663 [SIOCSIWPOWER - SIOCIWFIRST] = {
2664 .header_type = IW_HEADER_TYPE_PARAM,
2666 [SIOCGIWPOWER - SIOCIWFIRST] = {
2667 .header_type = IW_HEADER_TYPE_PARAM,
2669 [SIOCSIWMODUL - SIOCIWFIRST] = {
2670 .header_type = IW_HEADER_TYPE_PARAM,
2672 [SIOCGIWMODUL - SIOCIWFIRST] = {
2673 .header_type = IW_HEADER_TYPE_PARAM,
2675 [SIOCSIWGENIE - SIOCIWFIRST] = {
2676 .header_type = IW_HEADER_TYPE_POINT,
2678 .max_tokens = IW_GENERIC_IE_MAX,
2680 [SIOCGIWGENIE - SIOCIWFIRST] = {
2681 .header_type = IW_HEADER_TYPE_POINT,
2683 .max_tokens = IW_GENERIC_IE_MAX,
2685 [SIOCSIWAUTH - SIOCIWFIRST] = {
2686 .header_type = IW_HEADER_TYPE_PARAM,
2688 [SIOCGIWAUTH - SIOCIWFIRST] = {
2689 .header_type = IW_HEADER_TYPE_PARAM,
2691 [SIOCSIWENCODEEXT - SIOCIWFIRST] = {
2692 .header_type = IW_HEADER_TYPE_POINT,
2694 .min_tokens = sizeof(struct iw_encode_ext),
2695 .max_tokens = sizeof(struct iw_encode_ext) +
2696 IW_ENCODING_TOKEN_MAX,
2698 [SIOCGIWENCODEEXT - SIOCIWFIRST] = {
2699 .header_type = IW_HEADER_TYPE_POINT,
2701 .min_tokens = sizeof(struct iw_encode_ext),
2702 .max_tokens = sizeof(struct iw_encode_ext) +
2703 IW_ENCODING_TOKEN_MAX,
2705 [SIOCSIWPMKSA - SIOCIWFIRST] = {
2706 .header_type = IW_HEADER_TYPE_POINT,
2708 .min_tokens = sizeof(struct iw_pmksa),
2709 .max_tokens = sizeof(struct iw_pmksa),
2712 static const unsigned int standard_ioctl_num = (sizeof(standard_ioctl_descr) /
2713 sizeof(struct iw_ioctl_description));
2716 * Meta-data about all the additional standard Wireless Extension events
2719 static const struct iw_ioctl_description standard_event_descr[] = {
2720 [IWEVTXDROP - IWEVFIRST] = {
2721 .header_type = IW_HEADER_TYPE_ADDR,
2723 [IWEVQUAL - IWEVFIRST] = {
2724 .header_type = IW_HEADER_TYPE_QUAL,
2726 [IWEVCUSTOM - IWEVFIRST] = {
2727 .header_type = IW_HEADER_TYPE_POINT,
2729 .max_tokens = IW_CUSTOM_MAX,
2731 [IWEVREGISTERED - IWEVFIRST] = {
2732 .header_type = IW_HEADER_TYPE_ADDR,
2734 [IWEVEXPIRED - IWEVFIRST] = {
2735 .header_type = IW_HEADER_TYPE_ADDR,
2737 [IWEVGENIE - IWEVFIRST] = {
2738 .header_type = IW_HEADER_TYPE_POINT,
2740 .max_tokens = IW_GENERIC_IE_MAX,
2742 [IWEVMICHAELMICFAILURE - IWEVFIRST] = {
2743 .header_type = IW_HEADER_TYPE_POINT,
2745 .max_tokens = sizeof(struct iw_michaelmicfailure),
2747 [IWEVASSOCREQIE - IWEVFIRST] = {
2748 .header_type = IW_HEADER_TYPE_POINT,
2750 .max_tokens = IW_GENERIC_IE_MAX,
2752 [IWEVASSOCRESPIE - IWEVFIRST] = {
2753 .header_type = IW_HEADER_TYPE_POINT,
2755 .max_tokens = IW_GENERIC_IE_MAX,
2757 [IWEVPMKIDCAND - IWEVFIRST] = {
2758 .header_type = IW_HEADER_TYPE_POINT,
2760 .max_tokens = sizeof(struct iw_pmkid_cand),
2763 static const unsigned int standard_event_num = (sizeof(standard_event_descr) /
2764 sizeof(struct iw_ioctl_description));
2766 /* Size (in bytes) of various events */
2767 static const int event_type_size[] = {
2768 IW_EV_LCP_PK_LEN, /* IW_HEADER_TYPE_NULL */
2770 IW_EV_CHAR_PK_LEN, /* IW_HEADER_TYPE_CHAR */
2772 IW_EV_UINT_PK_LEN, /* IW_HEADER_TYPE_UINT */
2773 IW_EV_FREQ_PK_LEN, /* IW_HEADER_TYPE_FREQ */
2774 IW_EV_ADDR_PK_LEN, /* IW_HEADER_TYPE_ADDR */
2776 IW_EV_POINT_PK_LEN, /* Without variable payload */
2777 IW_EV_PARAM_PK_LEN, /* IW_HEADER_TYPE_PARAM */
2778 IW_EV_QUAL_PK_LEN, /* IW_HEADER_TYPE_QUAL */
2781 /*------------------------------------------------------------------*/
2783 * Initialise the struct stream_descr so that we can extract
2784 * individual events from the event stream.
2787 iw_init_event_stream(struct stream_descr * stream, /* Stream of events */
2792 memset((char *) stream, '\0', sizeof(struct stream_descr));
2795 stream->current = data;
2796 stream->end = data + len;
2799 /*------------------------------------------------------------------*/
2801 * Extract the next event from the event stream.
2804 iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */
2805 struct iw_event * iwe, /* Extracted event */
2808 const struct iw_ioctl_description * descr = NULL;
2810 unsigned int event_len = 1; /* Invalid */
2812 /* Don't "optimise" the following variable, it will crash */
2813 unsigned cmd_index; /* *MUST* be unsigned */
2815 /* Check for end of stream */
2816 if((stream->current + IW_EV_LCP_PK_LEN) > stream->end)
2820 printf("DBG - stream->current = %p, stream->value = %p, stream->end = %p\n",
2821 stream->current, stream->value, stream->end);
2824 /* Extract the event header (to get the event id).
2825 * Note : the event may be unaligned, therefore copy... */
2826 memcpy((char *) iwe, stream->current, IW_EV_LCP_PK_LEN);
2829 printf("DBG - iwe->cmd = 0x%X, iwe->len = %d\n",
2830 iwe->cmd, iwe->len);
2833 /* Check invalid events */
2834 if(iwe->len <= IW_EV_LCP_PK_LEN)
2837 /* Get the type and length of that event */
2838 if(iwe->cmd <= SIOCIWLAST)
2840 cmd_index = iwe->cmd - SIOCIWFIRST;
2841 if(cmd_index < standard_ioctl_num)
2842 descr = &(standard_ioctl_descr[cmd_index]);
2846 cmd_index = iwe->cmd - IWEVFIRST;
2847 if(cmd_index < standard_event_num)
2848 descr = &(standard_event_descr[cmd_index]);
2851 event_type = descr->header_type;
2852 /* Unknown events -> event_type=0 => IW_EV_LCP_PK_LEN */
2853 event_len = event_type_size[event_type];
2854 /* Fixup for earlier version of WE */
2855 if((we_version <= 18) && (event_type == IW_HEADER_TYPE_POINT))
2856 event_len += IW_EV_POINT_OFF;
2858 /* Check if we know about this event */
2859 if(event_len <= IW_EV_LCP_PK_LEN)
2861 /* Skip to next event */
2862 stream->current += iwe->len;
2865 event_len -= IW_EV_LCP_PK_LEN;
2867 /* Set pointer on data */
2868 if(stream->value != NULL)
2869 pointer = stream->value; /* Next value in event */
2871 pointer = stream->current + IW_EV_LCP_PK_LEN; /* First value in event */
2874 printf("DBG - event_type = %d, event_len = %d, pointer = %p\n",
2875 event_type, event_len, pointer);
2878 /* Copy the rest of the event (at least, fixed part) */
2879 if((pointer + event_len) > stream->end)
2881 /* Go to next event */
2882 stream->current += iwe->len;
2885 /* Fixup for WE-19 and later : pointer no longer in the stream */
2886 /* Beware of alignement. Dest has local alignement, not packed */
2887 if((we_version > 18) && (event_type == IW_HEADER_TYPE_POINT))
2888 memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
2889 pointer, event_len);
2891 memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
2893 /* Skip event in the stream */
2894 pointer += event_len;
2896 /* Special processing for iw_point events */
2897 if(event_type == IW_HEADER_TYPE_POINT)
2899 /* Check the length of the payload */
2900 unsigned int extra_len = iwe->len - (event_len + IW_EV_LCP_PK_LEN);
2903 /* Set pointer on variable part (warning : non aligned) */
2904 iwe->u.data.pointer = pointer;
2906 /* Check that we have a descriptor for the command */
2908 /* Can't check payload -> unsafe... */
2909 iwe->u.data.pointer = NULL; /* Discard paylod */
2912 /* Those checks are actually pretty hard to trigger,
2913 * because of the checks done in the kernel... */
2915 unsigned int token_len = iwe->u.data.length * descr->token_size;
2917 /* Ugly fixup for alignement issues.
2918 * If the kernel is 64 bits and userspace 32 bits,
2919 * we have an extra 4+4 bytes.
2920 * Fixing that in the kernel would break 64 bits userspace. */
2921 if((token_len != extra_len) && (extra_len >= 4))
2923 union iw_align_u16 alt_dlen;
2924 unsigned int alt_token_len;
2925 /* Usespace seems to not always like unaligned access,
2926 * so be careful and make sure to align value.
2927 * I hope gcc won't play any of its aliasing tricks... */
2928 alt_dlen.byte[0] = *(pointer);
2929 alt_dlen.byte[1] = *(pointer + 1);
2930 alt_token_len = alt_dlen.value * descr->token_size;
2932 printf("DBG - alt_token_len = %d\n", alt_token_len);
2934 /* Verify that data is consistent if assuming 64 bit
2936 if((alt_token_len + 8) == extra_len)
2938 /* Ok, let's redo everything */
2939 pointer -= event_len;
2941 /* Dest has local alignement, not packed */
2942 memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
2943 pointer, event_len);
2944 pointer += event_len + 4;
2945 token_len = alt_token_len;
2946 /* We may have no payload */
2948 iwe->u.data.pointer = pointer;
2950 iwe->u.data.pointer = NULL;
2954 /* Discard bogus events which advertise more tokens than
2955 * what they carry... */
2956 if(token_len > extra_len)
2957 iwe->u.data.pointer = NULL; /* Discard paylod */
2958 /* Check that the advertised token size is not going to
2959 * produce buffer overflow to our caller... */
2960 if((iwe->u.data.length > descr->max_tokens)
2961 && !(descr->flags & IW_DESCR_FLAG_NOMAX))
2962 iwe->u.data.pointer = NULL; /* Discard paylod */
2963 /* Same for underflows... */
2964 if(iwe->u.data.length < descr->min_tokens)
2965 iwe->u.data.pointer = NULL; /* Discard paylod */
2967 printf("DBG - extra_len = %d, token_len = %d, token = %d, max = %d, min = %d\n",
2968 extra_len, token_len, iwe->u.data.length, descr->max_tokens, descr->min_tokens);
2974 iwe->u.data.pointer = NULL;
2976 /* Go to next event */
2977 stream->current += iwe->len;
2981 /* Ugly fixup for alignement issues.
2982 * If the kernel is 64 bits and userspace 32 bits,
2983 * we have an extra 4 bytes.
2984 * Fixing that in the kernel would break 64 bits userspace. */
2985 if((stream->value == NULL)
2986 && ((((iwe->len - IW_EV_LCP_PK_LEN) % event_len) == 4)
2987 || ((iwe->len == 12) && ((event_type == IW_HEADER_TYPE_UINT) ||
2988 (event_type == IW_HEADER_TYPE_QUAL))) ))
2991 printf("DBG - alt iwe->len = %d\n", iwe->len - 4);
2993 pointer -= event_len;
2995 /* Beware of alignement. Dest has local alignement, not packed */
2996 memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
2997 pointer += event_len;
3000 /* Is there more value in the event ? */
3001 if((pointer + event_len) <= (stream->current + iwe->len))
3002 /* Go to next value */
3003 stream->value = pointer;
3006 /* Go to next event */
3007 stream->value = NULL;
3008 stream->current += iwe->len;
3014 /*********************** SCANNING SUBROUTINES ***********************/
3016 * The Wireless Extension API 14 and greater define Wireless Scanning.
3017 * The normal API is complex, this is an easy API that return
3018 * a subset of the scanning results. This should be enough for most
3019 * applications that want to use Scanning.
3020 * If you want to have use the full/normal API, check iwlist.c...
3022 * Precaution when using scanning :
3023 * The scanning operation disable normal network traffic, and therefore
3024 * you should not abuse of scan.
3025 * The scan need to check the presence of network on other frequencies.
3026 * While you are checking those other frequencies, you can *NOT* be on
3027 * your normal frequency to listen to normal traffic in the cell.
3028 * You need typically in the order of one second to actively probe all
3029 * 802.11b channels (do the maths). Some cards may do that in background,
3030 * to reply to scan commands faster, but they still have to do it.
3031 * Leaving the cell for such an extended period of time is pretty bad.
3032 * Any kind of streaming/low latency traffic will be impacted, and the
3033 * user will perceive it (easily checked with telnet). People trying to
3034 * send traffic to you will retry packets and waste bandwidth. Some
3035 * applications may be sensitive to those packet losses in weird ways,
3036 * and tracing those weird behavior back to scanning may take time.
3037 * If you are in ad-hoc mode, if two nodes scan approx at the same
3038 * time, they won't see each other, which may create associations issues.
3039 * For those reasons, the scanning activity should be limited to
3040 * what's really needed, and continuous scanning is a bad idea.
3044 /*------------------------------------------------------------------*/
3046 * Process/store one element from the scanning results in wireless_scan
3048 static inline struct wireless_scan *
3049 iw_process_scanning_token(struct iw_event * event,
3050 struct wireless_scan * wscan)
3052 struct wireless_scan * oldwscan;
3054 /* Now, let's decode the event */
3058 /* New cell description. Allocate new cell descriptor, zero it. */
3060 wscan = (struct wireless_scan *) malloc(sizeof(struct wireless_scan));
3063 /* Link at the end of the list */
3064 if(oldwscan != NULL)
3065 oldwscan->next = wscan;
3068 bzero(wscan, sizeof(struct wireless_scan));
3070 /* Save cell identifier */
3071 wscan->has_ap_addr = 1;
3072 memcpy(&(wscan->ap_addr), &(event->u.ap_addr), sizeof (sockaddr));
3075 wscan->b.has_nwid = 1;
3076 memcpy(&(wscan->b.nwid), &(event->u.nwid), sizeof(iwparam));
3079 wscan->b.has_freq = 1;
3080 wscan->b.freq = iw_freq2float(&(event->u.freq));
3081 wscan->b.freq_flags = event->u.freq.flags;
3084 wscan->b.mode = event->u.mode;
3085 if((wscan->b.mode < IW_NUM_OPER_MODE) && (wscan->b.mode >= 0))
3086 wscan->b.has_mode = 1;
3089 wscan->b.has_essid = 1;
3090 wscan->b.essid_on = event->u.data.flags;
3091 memset(wscan->b.essid, '\0', IW_ESSID_MAX_SIZE + 1);
3092 if((event->u.essid.pointer) && (event->u.essid.length))
3093 memcpy(wscan->b.essid, event->u.essid.pointer, event->u.essid.length);
3096 wscan->b.has_key = 1;
3097 wscan->b.key_size = event->u.data.length;
3098 wscan->b.key_flags = event->u.data.flags;
3099 if(event->u.data.pointer)
3100 memcpy(wscan->b.key, event->u.essid.pointer, event->u.data.length);
3102 wscan->b.key_flags |= IW_ENCODE_NOKEY;
3105 /* We don't get complete stats, only qual */
3106 wscan->has_stats = 1;
3107 memcpy(&wscan->stats.qual, &event->u.qual, sizeof(struct iw_quality));
3110 /* Scan may return a list of bitrates. As we have space for only
3111 * a single bitrate, we only keep the largest one. */
3112 if((!wscan->has_maxbitrate) ||
3113 (event->u.bitrate.value > wscan->maxbitrate.value))
3115 wscan->has_maxbitrate = 1;
3116 memcpy(&(wscan->maxbitrate), &(event->u.bitrate), sizeof(iwparam));
3119 /* How can we deal with those sanely ? Jean II */
3122 } /* switch(event->cmd) */
3127 /*------------------------------------------------------------------*/
3129 * Initiate the scan procedure, and process results.
3130 * This is a non-blocking procedure and it will return each time
3131 * it would block, returning the amount of time the caller should wait
3132 * before calling again.
3133 * Return -1 for error, delay to wait for (in ms), or 0 for success.
3134 * Error code is in errno
3137 iw_process_scan(int skfd,
3140 wireless_scan_head * context)
3143 unsigned char * buffer = NULL; /* Results */
3144 int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
3145 unsigned char * newbuf;
3147 /* Don't waste too much time on interfaces (150 * 100 = 15s) */
3149 if(context->retry > 150)
3155 /* If we have not yet initiated scanning on the interface */
3156 if(context->retry == 1)
3159 wrq.u.data.pointer = NULL; /* Later */
3160 wrq.u.data.flags = 0;
3161 wrq.u.data.length = 0;
3162 /* Remember that as non-root, we will get an EPERM here */
3163 if((iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0)
3164 && (errno != EPERM))
3166 /* Success : now, just wait for event or results */
3167 return(250); /* Wait 250 ms */
3171 /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
3172 newbuf = realloc(buffer, buflen);
3175 /* man says : If realloc() fails the original block is left untouched */
3183 /* Try to read the results */
3184 wrq.u.data.pointer = buffer;
3185 wrq.u.data.flags = 0;
3186 wrq.u.data.length = buflen;
3187 if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0)
3189 /* Check if buffer was too small (WE-17 only) */
3190 if((errno == E2BIG) && (we_version > 16) && (buflen < 0xFFFF))
3192 /* Some driver may return very large scan results, either
3193 * because there are many cells, or because they have many
3194 * large elements in cells (like IWEVCUSTOM). Most will
3195 * only need the regular sized buffer. We now use a dynamic
3196 * allocation of the buffer to satisfy everybody. Of course,
3197 * as we don't know in advance the size of the array, we try
3198 * various increasing sizes. Jean II */
3200 /* Check if the driver gave us any hints. */
3201 if(wrq.u.data.length > buflen)
3202 buflen = wrq.u.data.length;
3206 /* wrq.u.data.length is 16 bits so max size is 65535 */
3214 /* Check if results not available yet */
3218 /* Wait for only 100ms from now on */
3219 return(100); /* Wait 100 ms */
3223 /* Bad error, please don't come back... */
3227 /* We have the results, process them */
3228 if(wrq.u.data.length)
3230 struct iw_event iwe;
3231 struct stream_descr stream;
3232 struct wireless_scan * wscan = NULL;
3235 /* Debugging code. In theory useless, because it's debugged ;-) */
3237 printf("Scan result [%02X", buffer[0]);
3238 for(i = 1; i < wrq.u.data.length; i++)
3239 printf(":%02X", buffer[i]);
3244 iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
3245 /* This is dangerous, we may leak user data... */
3246 context->result = NULL;
3248 /* Look every token */
3251 /* Extract an event and print it */
3252 ret = iw_extract_event_stream(&stream, &iwe, we_version);
3255 /* Convert to wireless_scan struct */
3256 wscan = iw_process_scanning_token(&iwe, wscan);
3257 /* Check problems */
3264 /* Save head of list */
3265 if(context->result == NULL)
3266 context->result = wscan;
3272 /* Done with this interface - return success */
3277 /*------------------------------------------------------------------*/
3279 * Perform a wireless scan on the specified interface.
3280 * This is a blocking procedure and it will when the scan is completed
3281 * or when an error occur.
3283 * The scan results are given in a linked list of wireless_scan objects.
3284 * The caller *must* free the result himself (by walking the list).
3285 * If there is an error, -1 is returned and the error code is available
3288 * The parameter we_version can be extracted from the range structure
3289 * (range.we_version_compiled - see iw_get_range_info()), or using
3290 * iw_get_kernel_we_version(). For performance reason, you should
3291 * cache this parameter when possible rather than querying it every time.
3293 * Return -1 for error and 0 for success.
3299 wireless_scan_head * context)
3301 int delay; /* in ms */
3303 /* Clean up context. Potential memory leak if(context.result != NULL) */
3304 context->result = NULL;
3307 /* Wait until we get results or error */
3310 /* Try to get scan results */
3311 delay = iw_process_scan(skfd, ifname, we_version, context);
3313 /* Check termination */
3318 usleep(delay * 1000);
3321 /* End - return -1 or 0 */