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 *****************************/
14 #include "iwlib-private.h" /* Private header */
16 /************************ CONSTANTS & MACROS ************************/
19 * Constants fof WE-9->15
21 #define IW15_MAX_FREQUENCIES 16
22 #define IW15_MAX_BITRATES 8
23 #define IW15_MAX_TXPOWER 8
24 #define IW15_MAX_ENCODING_SIZES 8
25 #define IW15_MAX_SPY 8
28 /****************************** TYPES ******************************/
31 * Struct iw_range up to WE-15
40 struct iw_freq freq[IW15_MAX_FREQUENCIES];
42 struct iw_quality max_qual;
44 __s32 bitrate[IW15_MAX_BITRATES];
56 __u16 encoding_size[IW15_MAX_ENCODING_SIZES];
57 __u8 num_encoding_sizes;
58 __u8 max_encoding_tokens;
61 __s32 txpower[IW15_MAX_TXPOWER];
62 __u8 we_version_compiled;
63 __u8 we_version_source;
71 struct iw_quality avg_qual;
75 * Union for all the versions of iwrange.
76 * Fortunately, I mostly only add fields at the end, and big-bang
77 * reorganisations are few.
81 struct iw15_range range15; /* WE 9->15 */
82 struct iw_range range; /* WE 16->current */
86 * Offsets in iw_range struct
88 #define iwr15_off(f) ( ((char *) &(((struct iw15_range *) NULL)->f)) - \
90 #define iwr_off(f) ( ((char *) &(((struct iw_range *) NULL)->f)) - \
94 * Union to perform unaligned access when working around alignement issues
99 unsigned char byte[2];
102 /**************************** VARIABLES ****************************/
104 /* Modes as human readable strings */
105 const char * const iw_operation_mode[] = { "Auto",
114 /* Modulations as human readable strings */
115 const struct iw_modul_descr iw_modul_list[] = {
116 /* Start with aggregate types, so that they display first */
117 { IW_MODUL_11AG, "11ag",
118 "IEEE 802.11a + 802.11g (2.4 & 5 GHz, up to 54 Mb/s)" },
119 { IW_MODUL_11AB, "11ab",
120 "IEEE 802.11a + 802.11b (2.4 & 5 GHz, up to 54 Mb/s)" },
121 { IW_MODUL_11G, "11g", "IEEE 802.11g (2.4 GHz, up to 54 Mb/s)" },
122 { IW_MODUL_11A, "11a", "IEEE 802.11a (5 GHz, up to 54 Mb/s)" },
123 { IW_MODUL_11B, "11b", "IEEE 802.11b (2.4 GHz, up to 11 Mb/s)" },
125 /* Proprietary aggregates */
126 { IW_MODUL_TURBO | IW_MODUL_11A, "turboa",
127 "Atheros turbo mode at 5 GHz (up to 108 Mb/s)" },
128 { IW_MODUL_TURBO | IW_MODUL_11G, "turbog",
129 "Atheros turbo mode at 2.4 GHz (up to 108 Mb/s)" },
130 { IW_MODUL_PBCC | IW_MODUL_11B, "11+",
131 "TI 802.11+ (2.4 GHz, up to 22 Mb/s)" },
133 /* Individual modulations */
134 { IW_MODUL_OFDM_G, "OFDMg",
135 "802.11g higher rates, OFDM at 2.4 GHz (up to 54 Mb/s)" },
136 { IW_MODUL_OFDM_A, "OFDMa", "802.11a, OFDM at 5 GHz (up to 54 Mb/s)" },
137 { IW_MODUL_CCK, "CCK", "802.11b higher rates (2.4 GHz, up to 11 Mb/s)" },
138 { IW_MODUL_DS, "DS", "802.11 Direct Sequence (2.4 GHz, up to 2 Mb/s)" },
139 { IW_MODUL_FH, "FH", "802.11 Frequency Hopping (2,4 GHz, up to 2 Mb/s)" },
141 /* Proprietary modulations */
142 { IW_MODUL_TURBO, "turbo",
143 "Atheros turbo mode, channel bonding (up to 108 Mb/s)" },
144 { IW_MODUL_PBCC, "PBCC",
145 "TI 802.11+ higher rates (2.4 GHz, up to 22 Mb/s)" },
146 { IW_MODUL_CUSTOM, "custom",
147 "Driver specific modulation (check driver documentation)" },
150 /* Disable runtime version warning in iw_get_range_info() */
151 int iw_ignore_version = 0;
153 /************************ SOCKET SUBROUTINES *************************/
155 /*------------------------------------------------------------------*/
158 * Depending on the protocol present, open the right socket. The socket
159 * will allow us to talk to the driver.
162 iw_sockets_open(void)
164 static const int families[] = {
165 AF_INET, AF_IPX, AF_AX25, AF_APPLETALK
171 * Now pick any (exisiting) useful socket family for generic queries
172 * Note : don't open all the socket, only returns when one matches,
173 * all protocols might not be valid.
174 * Workaround by Jim Kaba <jkaba@sarnoff.com>
175 * Note : in 99% of the case, we will just open the inet_sock.
176 * The remaining 1% case are not fully correct...
179 /* Try all families we support */
180 for(i = 0; i < sizeof(families)/sizeof(int); ++i)
182 /* Try to open the socket, if success returns it */
183 sock = socket(families[i], SOCK_DGRAM, 0);
191 /*------------------------------------------------------------------*/
193 * Extract the interface name out of /proc/net/wireless or /proc/net/dev.
196 iw_get_ifname(char * name, /* Where to store the name */
197 int nsize, /* Size of name buffer */
198 char * buf) /* Current position in buffer */
202 /* Skip leading spaces */
206 #ifndef IW_RESTRIC_ENUM
207 /* Get name up to the last ':'. Aliases may contain ':' in them,
208 * but the last one should be the separator */
209 end = strrchr(buf, ':');
211 /* Get name up to ": "
212 * Note : we compare to ": " to make sure to process aliased interfaces
213 * properly. Doesn't work on /proc/net/dev, because it doesn't guarantee
214 * a ' ' after the ':'*/
215 end = strstr(buf, ": ");
218 /* Not found ??? To big ??? */
219 if((end == NULL) || (((end - buf) + 1) > nsize))
223 memcpy(name, buf, (end - buf));
224 name[end - buf] = '\0';
226 /* Return value currently unused, just make sure it's non-NULL */
230 /*------------------------------------------------------------------*/
232 * Enumerate devices and call specified routine
233 * The new way just use /proc/net/wireless, so get all wireless interfaces,
234 * whether configured or not. This is the default if available.
235 * The old way use SIOCGIFCONF, so get only configured interfaces (wireless
239 iw_enum_devices(int skfd,
250 #ifndef IW_RESTRIC_ENUM
251 /* Check if /proc/net/dev is available */
252 fh = fopen(PROC_NET_DEV, "r");
254 /* Check if /proc/net/wireless is available */
255 fh = fopen(PROC_NET_WIRELESS, "r");
260 /* Success : use data from /proc/net/wireless */
262 /* Eat 2 lines of header */
263 fgets(buff, sizeof(buff), fh);
264 fgets(buff, sizeof(buff), fh);
266 /* Read each device line */
267 while(fgets(buff, sizeof(buff), fh))
269 char name[IFNAMSIZ + 1];
272 /* Skip empty or almost empty lines. It seems that in some
273 * cases fgets return a line with only a newline. */
274 if((buff[0] == '\0') || (buff[1] == '\0'))
277 /* Extract interface name */
278 s = iw_get_ifname(name, sizeof(name), buff);
282 /* Failed to parse, complain and continue */
283 #ifndef IW_RESTRIC_ENUM
284 fprintf(stderr, "Cannot parse " PROC_NET_DEV "\n");
286 fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
290 /* Got it, print info about this interface */
291 (*fn)(skfd, name, args, count);
298 /* Get list of configured devices using "traditional" way */
299 ifc.ifc_len = sizeof(buff);
301 if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
303 fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
309 for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
310 (*fn)(skfd, ifr->ifr_name, args, count);
314 /*********************** WIRELESS SUBROUTINES ************************/
316 /*------------------------------------------------------------------*/
318 * Extract WE version number from /proc/net/wireless
319 * In most cases, you really want to get version information from
320 * the range info (range->we_version_compiled), see below...
322 * If we have WE-16 and later, the WE version is available at the
323 * end of the header line of the file.
324 * For version prior to that, we can only detect the change from
325 * v11 to v12, so we do an approximate job. Fortunately, v12 to v15
326 * are highly binary compatible (on the struct level).
329 iw_get_kernel_we_version(void)
336 /* Check if /proc/net/wireless is available */
337 fh = fopen(PROC_NET_WIRELESS, "r");
341 fprintf(stderr, "Cannot read " PROC_NET_WIRELESS "\n");
345 /* Read the first line of buffer */
346 fgets(buff, sizeof(buff), fh);
348 if(strstr(buff, "| WE") == NULL)
350 /* Prior to WE16, so explicit version not present */
353 if(strstr(buff, "| Missed") == NULL)
361 /* Read the second line of buffer */
362 fgets(buff, sizeof(buff), fh);
364 /* Get to the last separator, to get the version */
365 p = strrchr(buff, '|');
366 if((p == NULL) || (sscanf(p + 1, "%d", &v) != 1))
368 fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
377 /*------------------------------------------------------------------*/
379 * Print the WE versions of the interface.
382 print_iface_version_info(int skfd,
384 char * args[], /* Command line args */
385 int count) /* Args count */
388 char buffer[sizeof(iwrange) * 2]; /* Large enough */
389 struct iw_range * range;
391 /* Avoid "Unused parameter" warning */
392 args = args; count = count;
394 /* If no wireless name : no wireless extensions.
395 * This enable us to treat the SIOCGIWRANGE failure below properly. */
396 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
400 memset(buffer, 0, sizeof(buffer));
402 wrq.u.data.pointer = (caddr_t) buffer;
403 wrq.u.data.length = sizeof(buffer);
404 wrq.u.data.flags = 0;
405 if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
407 /* Interface support WE (see above), but not IWRANGE */
408 fprintf(stderr, "%-8.16s Driver has no Wireless Extension version information.\n\n", ifname);
412 /* Copy stuff at the right place, ignore extra */
413 range = (struct iw_range *) buffer;
415 /* For new versions, we can check the version directly, for old versions
416 * we use magic. 300 bytes is a also magic number, don't touch... */
417 if(wrq.u.data.length >= 300)
419 /* Version is always at the same offset, so it's ok */
420 printf("%-8.16s Recommend Wireless Extension v%d or later,\n",
421 ifname, range->we_version_source);
422 printf(" Currently compiled with Wireless Extension v%d.\n\n",
423 range->we_version_compiled);
427 fprintf(stderr, "%-8.16s Wireless Extension version too old.\n\n",
435 /*------------------------------------------------------------------*/
437 * Print the WE versions of the tools.
440 iw_print_version_info(const char * toolname)
442 int skfd; /* generic raw socket desc. */
443 int we_kernel_version;
445 /* Create a channel to the NET kernel. */
446 if((skfd = iw_sockets_open()) < 0)
452 /* Information about the tools themselves */
454 printf("%-8.16s Wireless-Tools version %d\n", toolname, WT_VERSION);
455 printf(" Compatible with Wireless Extension v11 to v%d.\n\n",
458 /* Get version from kernel */
459 we_kernel_version = iw_get_kernel_we_version();
460 /* Only version >= 16 can be verified, other are guessed */
461 if(we_kernel_version > 15)
462 printf("Kernel Currently compiled with Wireless Extension v%d.\n\n",
465 /* Version for each device */
466 iw_enum_devices(skfd, &print_iface_version_info, NULL, 0);
468 iw_sockets_close(skfd);
473 /*------------------------------------------------------------------*/
475 * Get the range information out of the driver
478 iw_get_range_info(int skfd,
483 char buffer[sizeof(iwrange) * 2]; /* Large enough */
484 union iw_range_raw * range_raw;
487 bzero(buffer, sizeof(buffer));
489 wrq.u.data.pointer = (caddr_t) buffer;
490 wrq.u.data.length = sizeof(buffer);
491 wrq.u.data.flags = 0;
492 if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
495 /* Point to the buffer */
496 range_raw = (union iw_range_raw *) buffer;
498 /* For new versions, we can check the version directly, for old versions
499 * we use magic. 300 bytes is a also magic number, don't touch... */
500 if(wrq.u.data.length < 300)
502 /* That's v10 or earlier. Ouch ! Let's make a guess...*/
503 range_raw->range.we_version_compiled = 9;
506 /* Check how it needs to be processed */
507 if(range_raw->range.we_version_compiled > 15)
509 /* This is our native format, that's easy... */
510 /* Copy stuff at the right place, ignore extra */
511 memcpy((char *) range, buffer, sizeof(iwrange));
515 /* Zero unknown fields */
516 bzero((char *) range, sizeof(struct iw_range));
518 /* Initial part unmoved */
519 memcpy((char *) range,
521 iwr15_off(num_channels));
522 /* Frequencies pushed futher down towards the end */
523 memcpy((char *) range + iwr_off(num_channels),
524 buffer + iwr15_off(num_channels),
525 iwr15_off(sensitivity) - iwr15_off(num_channels));
526 /* This one moved up */
527 memcpy((char *) range + iwr_off(sensitivity),
528 buffer + iwr15_off(sensitivity),
529 iwr15_off(num_bitrates) - iwr15_off(sensitivity));
530 /* This one goes after avg_qual */
531 memcpy((char *) range + iwr_off(num_bitrates),
532 buffer + iwr15_off(num_bitrates),
533 iwr15_off(min_rts) - iwr15_off(num_bitrates));
534 /* Number of bitrates has changed, put it after */
535 memcpy((char *) range + iwr_off(min_rts),
536 buffer + iwr15_off(min_rts),
537 iwr15_off(txpower_capa) - iwr15_off(min_rts));
538 /* Added encoding_login_index, put it after */
539 memcpy((char *) range + iwr_off(txpower_capa),
540 buffer + iwr15_off(txpower_capa),
541 iwr15_off(txpower) - iwr15_off(txpower_capa));
542 /* Hum... That's an unexpected glitch. Bummer. */
543 memcpy((char *) range + iwr_off(txpower),
544 buffer + iwr15_off(txpower),
545 iwr15_off(avg_qual) - iwr15_off(txpower));
546 /* Avg qual moved up next to max_qual */
547 memcpy((char *) range + iwr_off(avg_qual),
548 buffer + iwr15_off(avg_qual),
549 sizeof(struct iw_quality));
552 /* We are now checking much less than we used to do, because we can
553 * accomodate more WE version. But, there are still cases where things
555 if(!iw_ignore_version)
557 /* We don't like very old version (unfortunately kernel 2.2.X) */
558 if(range->we_version_compiled <= 10)
560 fprintf(stderr, "Warning: Driver for device %s has been compiled with an ancient version\n", ifname);
561 fprintf(stderr, "of Wireless Extension, while this program support version 11 and later.\n");
562 fprintf(stderr, "Some things may be broken...\n\n");
565 /* We don't like future versions of WE, because we can't cope with
567 if(range->we_version_compiled > WE_MAX_VERSION)
569 fprintf(stderr, "Warning: Driver for device %s has been compiled with version %d\n", ifname, range->we_version_compiled);
570 fprintf(stderr, "of Wireless Extension, while this program supports up to version %d.\n", WE_MAX_VERSION);
571 fprintf(stderr, "Some things may be broken...\n\n");
574 /* Driver version verification */
575 if((range->we_version_compiled > 10) &&
576 (range->we_version_compiled < range->we_version_source))
578 fprintf(stderr, "Warning: Driver for device %s recommend version %d of Wireless Extension,\n", ifname, range->we_version_source);
579 fprintf(stderr, "but has been compiled with version %d, therefore some driver features\n", range->we_version_compiled);
580 fprintf(stderr, "may not be available...\n\n");
582 /* Note : we are only trying to catch compile difference, not source.
583 * If the driver source has not been updated to the latest, it doesn't
584 * matter because the new fields are set to zero */
587 /* Don't complain twice.
588 * In theory, the test apply to each individual driver, but usually
589 * all drivers are compiled from the same kernel. */
590 iw_ignore_version = 1;
595 /*------------------------------------------------------------------*/
597 * Get information about what private ioctls are supported by the driver
599 * Note : there is one danger using this function. If it return 0, you
600 * still need to free() the buffer. Beware.
603 iw_get_priv_info(int skfd,
608 iwprivargs * priv = NULL; /* Not allocated yet */
609 int maxpriv = 16; /* Minimum for compatibility WE<13 */
610 iwprivargs * newpriv;
612 /* Some driver may return a very large number of ioctls. Some
613 * others a very small number. We now use a dynamic allocation
614 * of the array to satisfy everybody. Of course, as we don't know
615 * in advance the size of the array, we try various increasing
619 /* (Re)allocate the buffer */
620 newpriv = realloc(priv, maxpriv * sizeof(priv[0]));
623 fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
628 /* Ask the driver if it's large enough */
629 wrq.u.data.pointer = (caddr_t) priv;
630 wrq.u.data.length = maxpriv;
631 wrq.u.data.flags = 0;
632 if(iw_get_ext(skfd, ifname, SIOCGIWPRIV, &wrq) >= 0)
634 /* Success. Pass the buffer by pointer */
636 /* Return the number of ioctls */
637 return(wrq.u.data.length);
640 /* Only E2BIG means the buffer was too small, abort on other errors */
643 /* Most likely "not supported". Don't barf. */
647 /* Failed. We probably need a bigger buffer. Check if the kernel
648 * gave us any hints. */
649 if(wrq.u.data.length > maxpriv)
650 maxpriv = wrq.u.data.length;
654 while(maxpriv < 1000);
664 /*------------------------------------------------------------------*/
666 * Get essential wireless config from the device driver
667 * We will call all the classical wireless ioctl on the driver through
668 * the socket to know what is supported and to get the settings...
669 * Note : compare to the version in iwconfig, we extract only
670 * what's *really* needed to configure a device...
673 iw_get_basic_config(int skfd,
675 wireless_config * info)
679 memset((char *) info, 0, sizeof(struct wireless_config));
681 /* Get wireless name */
682 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
683 /* If no wireless name : no wireless extensions */
687 strncpy(info->name, wrq.u.name, IFNAMSIZ);
688 info->name[IFNAMSIZ] = '\0';
692 if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) >= 0)
695 memcpy(&(info->nwid), &(wrq.u.nwid), sizeof(iwparam));
698 /* Get frequency / channel */
699 if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
702 info->freq = iw_freq2float(&(wrq.u.freq));
703 info->freq_flags = wrq.u.freq.flags;
706 /* Get encryption information */
707 wrq.u.data.pointer = (caddr_t) info->key;
708 wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
709 wrq.u.data.flags = 0;
710 if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
713 info->key_size = wrq.u.data.length;
714 info->key_flags = wrq.u.data.flags;
718 wrq.u.essid.pointer = (caddr_t) info->essid;
719 wrq.u.essid.length = IW_ESSID_MAX_SIZE + 2;
720 wrq.u.essid.flags = 0;
721 if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) >= 0)
724 info->essid_on = wrq.u.data.flags;
725 info->essid_len = wrq.u.essid.length;
728 /* Get operation mode */
729 if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) >= 0)
732 /* Note : event->u.mode is unsigned, no need to check <= 0 */
733 if(wrq.u.mode < IW_NUM_OPER_MODE)
734 info->mode = wrq.u.mode;
736 info->mode = IW_NUM_OPER_MODE; /* Unknown/bug */
742 /*------------------------------------------------------------------*/
744 * Set essential wireless config in the device driver
745 * We will call all the classical wireless ioctl on the driver through
746 * the socket to know what is supported and to set the settings...
747 * We support only the restricted set as above...
750 iw_set_basic_config(int skfd,
752 wireless_config * info)
757 /* Get wireless name (check if interface is valid) */
758 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
759 /* If no wireless name : no wireless extensions */
762 /* Set the current mode of operation
763 * Mode need to be first : some settings apply only in a specific mode
764 * (such as frequency).
768 strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
769 wrq.u.mode = info->mode;
771 if(iw_get_ext(skfd, ifname, SIOCSIWMODE, &wrq) < 0)
773 fprintf(stderr, "SIOCSIWMODE: %s\n", strerror(errno));
778 /* Set frequency / channel */
781 iw_float2freq(info->freq, &(wrq.u.freq));
783 if(iw_set_ext(skfd, ifname, SIOCSIWFREQ, &wrq) < 0)
785 fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
790 /* Set encryption information */
793 int flags = info->key_flags;
795 /* Check if there is a key index */
796 if((flags & IW_ENCODE_INDEX) > 0)
799 wrq.u.data.pointer = (caddr_t) NULL;
800 wrq.u.data.flags = (flags & (IW_ENCODE_INDEX)) | IW_ENCODE_NOKEY;
801 wrq.u.data.length = 0;
803 if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
805 fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
806 errno, strerror(errno));
811 /* Mask out index to minimise probability of reject when setting key */
812 flags = flags & (~IW_ENCODE_INDEX);
814 /* Set the key itself (set current key in this case) */
815 wrq.u.data.pointer = (caddr_t) info->key;
816 wrq.u.data.length = info->key_size;
817 wrq.u.data.flags = flags;
819 /* Compatibility with WE<13 */
820 if(flags & IW_ENCODE_NOKEY)
821 wrq.u.data.pointer = NULL;
823 if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
825 fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
826 errno, strerror(errno));
831 /* Set Network ID, if available (this is for non-802.11 cards) */
834 memcpy(&(wrq.u.nwid), &(info->nwid), sizeof(iwparam));
835 wrq.u.nwid.fixed = 1; /* Hum... When in Rome... */
837 if(iw_set_ext(skfd, ifname, SIOCSIWNWID, &wrq) < 0)
839 fprintf(stderr, "SIOCSIWNWID: %s\n", strerror(errno));
844 /* Set ESSID (extended network), if available.
845 * ESSID need to be last : most device re-perform the scanning/discovery
846 * when this is set, and things like encryption keys are better be
847 * defined if we want to discover the right set of APs/nodes.
851 int we_kernel_version;
852 we_kernel_version = iw_get_kernel_we_version();
854 wrq.u.essid.pointer = (caddr_t) info->essid;
855 wrq.u.essid.length = strlen(info->essid);
856 wrq.u.data.flags = info->essid_on;
857 if(we_kernel_version < 21)
858 wrq.u.essid.length++;
860 if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0)
862 fprintf(stderr, "SIOCSIWESSID: %s\n", strerror(errno));
870 /*********************** PROTOCOL SUBROUTINES ***********************/
872 * Fun stuff with protocol identifiers (SIOCGIWNAME).
873 * We assume that drivers are returning sensible values in there,
874 * which is not always the case :-(
877 /*------------------------------------------------------------------*/
879 * Compare protocol identifiers.
880 * We don't want to know if the two protocols are the exactly same,
881 * but if they interoperate at some level, and also if they accept the
882 * same type of config (ESSID vs NWID, freq...).
883 * This is supposed to work around the alphabet soup.
884 * Return 1 if protocols are compatible, 0 otherwise
887 iw_protocol_compare(const char * protocol1,
888 const char * protocol2)
890 const char * dot11 = "IEEE 802.11";
891 const char * dot11_ds = "Dbg";
892 const char * dot11_5g = "a";
894 /* If the strings are the same -> easy */
895 if(!strncmp(protocol1, protocol2, IFNAMSIZ))
898 /* Are we dealing with one of the 802.11 variant ? */
899 if( (!strncmp(protocol1, dot11, strlen(dot11))) &&
900 (!strncmp(protocol2, dot11, strlen(dot11))) )
902 const char * sub1 = protocol1 + strlen(dot11);
903 const char * sub2 = protocol2 + strlen(dot11);
910 /* Check if we find the magic letters telling it's DS compatible */
911 for(i = 0; i < strlen(dot11_ds); i++)
913 if(strchr(sub1, dot11_ds[i]) != NULL)
915 if(strchr(sub2, dot11_ds[i]) != NULL)
921 /* Check if we find the magic letters telling it's 5GHz compatible */
922 for(i = 0; i < strlen(dot11_5g); i++)
924 if(strchr(sub1, dot11_5g[i]) != NULL)
926 if(strchr(sub2, dot11_5g[i]) != NULL)
936 /************************ ESSID SUBROUTINES ************************/
938 * The ESSID identify 802.11 networks, and is an array if 32 bytes.
939 * Most people use it as an ASCII string, and are happy with it.
940 * However, any byte is valid, including the NUL character. Characters
941 * beyond the ASCII range are interpreted according to the locale and
942 * the OS, which is somethign we don't control (network of other
944 * Routines in here try to deal with that in asafe way.
947 /*------------------------------------------------------------------*/
949 * Escape non-ASCII characters from ESSID.
950 * This allow us to display those weirds characters to the user.
952 * Source is 32 bytes max.
953 * Destination buffer needs to be at least 129 bytes, will be NUL
957 iw_essid_escape(char * dest,
961 const unsigned char * s = (const unsigned char *) src;
962 const unsigned char * e = s + slen;
965 /* Look every character of the string */
970 /* Escape the escape to avoid ambiguity.
971 * We do a fast path test for performance reason. Compiler will
972 * optimise all that ;-) */
975 /* Check if we would confuse it with an escape sequence */
976 if((e-s) > 4 && (s[1] == 'x')
977 && (isxdigit(s[2])) && (isxdigit(s[3])))
988 /* Is it a non-ASCII character ??? */
989 if(isescape || !isascii(*s) || iscntrl(*s))
992 sprintf(d, "\\x%02X", *s);
997 /* Plain ASCII, just copy */
1004 /* NUL terminate destination */
1008 /* ---------------------------------------------------------------- */
1010 * Un-Escape non-ASCII characters from ESSID
1011 * This allow the user to specify weird characters in ESSID.
1013 * The source is a NUL terminated string.
1014 * Destination buffer is at least the size of source (ESSID will shrink)
1015 * Destination may contains NUL, therefore we return the length.
1016 * This function still works is src and dest are the same ;-)
1019 iw_essid_unescape(char * dest,
1022 const char * s = src;
1027 /* Look-up the next '\' sequence, stop when no more */
1028 while((p = strchr(s, '\\')) != NULL)
1030 /* Copy block of unescaped chars before the '\' */
1034 s += len; /* Identical to 's = p' */
1036 /* Check if it is really an escape sequence. We do also check for NUL */
1037 if((s[1] == 'x') && (isxdigit(s[2])) && (isxdigit(s[3])))
1040 /* Valid Escape sequence, un-escape it */
1041 sscanf(s + 2, "%2X", &temp);
1048 /* Not valid, don't un-escape it */
1055 /* Copy remaining of the string */
1057 memcpy(d, s, len + 1);
1059 return((d - dest) + len);
1062 /********************** FREQUENCY SUBROUTINES ***********************/
1064 * Note : the two functions below are the cause of troubles on
1065 * various embeeded platforms, as they are the reason we require
1066 * libm (math library).
1067 * In this case, please use enable BUILD_NOLIBM in the makefile
1069 * FIXME : check negative mantissa and exponent
1072 /*------------------------------------------------------------------*/
1074 * Convert a floating point the our internal representation of
1076 * The kernel doesn't want to hear about floating point, so we use
1077 * this custom format instead.
1080 iw_float2freq(double in,
1084 /* Version without libm : slower */
1092 #else /* WE_NOLIBM */
1093 /* Version with libm : faster */
1094 out->e = (short) (floor(log10(in)));
1097 out->m = ((long) (floor(in / pow(10,out->e - 6)))) * 100;
1105 #endif /* WE_NOLIBM */
1108 /*------------------------------------------------------------------*/
1110 * Convert our internal representation of frequencies to a floating point.
1113 iw_freq2float(const iwfreq * in)
1116 /* Version without libm : slower */
1118 double res = (double) in->m;
1119 for(i = 0; i < in->e; i++)
1122 #else /* WE_NOLIBM */
1123 /* Version with libm : faster */
1124 return ((double) in->m) * pow(10,in->e);
1125 #endif /* WE_NOLIBM */
1128 /*------------------------------------------------------------------*/
1130 * Output a frequency with proper scaling
1133 iw_print_freq_value(char * buffer,
1138 snprintf(buffer, buflen, "%g", freq);
1162 snprintf(buffer, buflen, "%g %cHz", freq / divisor, scale);
1166 /*------------------------------------------------------------------*/
1168 * Output a frequency with proper scaling
1171 iw_print_freq(char * buffer,
1177 char sep = ((freq_flags & IW_FREQ_FIXED) ? '=' : ':');
1180 /* Print the frequency/channel value */
1181 iw_print_freq_value(vbuf, sizeof(vbuf), freq);
1183 /* Check if channel only */
1185 snprintf(buffer, buflen, "Channel%c%s", sep, vbuf);
1188 /* Frequency. Check if we have a channel as well */
1190 snprintf(buffer, buflen, "Frequency%c%s (Channel %d)",
1191 sep, vbuf, channel);
1193 snprintf(buffer, buflen, "Frequency%c%s", sep, vbuf);
1197 /*------------------------------------------------------------------*/
1199 * Convert a frequency to a channel (negative -> error)
1202 iw_freq_to_channel(double freq,
1203 const struct iw_range * range)
1208 /* Check if it's a frequency or not already a channel */
1212 /* We compare the frequencies as double to ignore differences
1213 * in encoding. Slower, but safer... */
1214 for(k = 0; k < range->num_frequency; k++)
1216 ref_freq = iw_freq2float(&(range->freq[k]));
1217 if(freq == ref_freq)
1218 return(range->freq[k].i);
1224 /*------------------------------------------------------------------*/
1226 * Convert a channel to a frequency (negative -> error)
1227 * Return the channel on success
1230 iw_channel_to_freq(int channel,
1232 const struct iw_range * range)
1237 /* Check if the driver support only channels or if it has frequencies */
1238 for(k = 0; k < range->num_frequency; k++)
1240 if((range->freq[k].e != 0) || (range->freq[k].m > (int) KILO))
1246 /* Find the correct frequency in the list */
1247 for(k = 0; k < range->num_frequency; k++)
1249 if(range->freq[k].i == channel)
1251 *pfreq = iw_freq2float(&(range->freq[k]));
1259 /*********************** BITRATE SUBROUTINES ***********************/
1261 /*------------------------------------------------------------------*/
1263 * Output a bitrate with proper scaling
1266 iw_print_bitrate(char * buffer,
1270 double rate = bitrate;
1292 snprintf(buffer, buflen, "%g %cb/s", rate / divisor, scale);
1295 /************************ POWER SUBROUTINES *************************/
1297 /*------------------------------------------------------------------*/
1299 * Convert a value in dBm to a value in milliWatt.
1302 iw_dbm2mwatt(int in)
1305 /* Version without libm : slower */
1311 /* Split integral and floating part to avoid accumulating rounding errors */
1312 for(k = 0; k < ip; k++)
1314 for(k = 0; k < fp; k++)
1317 #else /* WE_NOLIBM */
1318 /* Version with libm : faster */
1319 return((int) (floor(pow(10.0, (((double) in) / 10.0)))));
1320 #endif /* WE_NOLIBM */
1323 /*------------------------------------------------------------------*/
1325 * Convert a value in milliWatt to a value in dBm.
1328 iw_mwatt2dbm(int in)
1331 /* Version without libm : slower */
1332 double fin = (double) in;
1335 /* Split integral and floating part to avoid accumulating rounding errors */
1341 while(fin > 1.000001) /* Eliminate rounding errors, take ceil */
1347 #else /* WE_NOLIBM */
1348 /* Version with libm : faster */
1349 return((int) (ceil(10.0 * log10((double) in))));
1350 #endif /* WE_NOLIBM */
1353 /*------------------------------------------------------------------*/
1355 * Output a txpower with proper conversion
1358 iw_print_txpower(char * buffer,
1360 struct iw_param * txpower)
1364 /* Check if disabled */
1365 if(txpower->disabled)
1367 snprintf(buffer, buflen, "off");
1371 /* Check for relative values */
1372 if(txpower->flags & IW_TXPOW_RELATIVE)
1374 snprintf(buffer, buflen, "%d", txpower->value);
1378 /* Convert everything to dBm */
1379 if(txpower->flags & IW_TXPOW_MWATT)
1380 dbm = iw_mwatt2dbm(txpower->value);
1382 dbm = txpower->value;
1385 snprintf(buffer, buflen, "%d dBm", dbm);
1390 /********************** STATISTICS SUBROUTINES **********************/
1392 /*------------------------------------------------------------------*/
1394 * Read /proc/net/wireless to get the latest statistics
1395 * Note : strtok not thread safe, not used in WE-12 and later.
1398 iw_get_stats(int skfd,
1399 const char * ifname,
1401 const iwrange * range,
1404 /* Fortunately, we can always detect this condition properly */
1405 if((has_range) && (range->we_version_compiled > 11))
1408 wrq.u.data.pointer = (caddr_t) stats;
1409 wrq.u.data.length = sizeof(struct iw_statistics);
1410 wrq.u.data.flags = 1; /* Clear updated flag */
1411 strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
1412 if(iw_get_ext(skfd, ifname, SIOCGIWSTATS, &wrq) < 0)
1415 /* Format has not changed since WE-12, no conversion */
1420 FILE * f = fopen(PROC_NET_WIRELESS, "r");
1427 /* Loop on all devices */
1428 while(fgets(buf,255,f))
1431 while(*bp&&isspace(*bp))
1433 /* Is it the good device ? */
1434 if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':')
1440 bp = strtok(bp, " ");
1441 sscanf(bp, "%X", &t);
1442 stats->status = (unsigned short) t;
1443 /* -- link quality -- */
1444 bp = strtok(NULL, " ");
1445 if(strchr(bp,'.') != NULL)
1446 stats->qual.updated |= 1;
1447 sscanf(bp, "%d", &t);
1448 stats->qual.qual = (unsigned char) t;
1449 /* -- signal level -- */
1450 bp = strtok(NULL, " ");
1451 if(strchr(bp,'.') != NULL)
1452 stats->qual.updated |= 2;
1453 sscanf(bp, "%d", &t);
1454 stats->qual.level = (unsigned char) t;
1455 /* -- noise level -- */
1456 bp = strtok(NULL, " ");
1457 if(strchr(bp,'.') != NULL)
1458 stats->qual.updated += 4;
1459 sscanf(bp, "%d", &t);
1460 stats->qual.noise = (unsigned char) t;
1461 /* -- discarded packets -- */
1462 bp = strtok(NULL, " ");
1463 sscanf(bp, "%d", &stats->discard.nwid);
1464 bp = strtok(NULL, " ");
1465 sscanf(bp, "%d", &stats->discard.code);
1466 bp = strtok(NULL, " ");
1467 sscanf(bp, "%d", &stats->discard.misc);
1469 /* No conversion needed */
1478 /*------------------------------------------------------------------*/
1480 * Output the link statistics, taking care of formating
1483 iw_print_stats(char * buffer,
1485 const iwqual * qual,
1486 const iwrange * range,
1491 /* People are very often confused by the 8 bit arithmetic happening
1493 * All the values here are encoded in a 8 bit integer. 8 bit integers
1494 * are either unsigned [0 ; 255], signed [-128 ; +127] or
1495 * negative [-255 ; 0].
1496 * Further, on 8 bits, 0x100 == 256 == 0.
1498 * Relative/percent values are always encoded unsigned, between 0 and 255.
1499 * Absolute/dBm values are always encoded between -192 and 63.
1500 * (Note that up to version 28 of Wireless Tools, dBm used to be
1501 * encoded always negative, between -256 and -1).
1503 * How do we separate relative from absolute values ?
1504 * The old way is to use the range to do that. As of WE-19, we have
1505 * an explicit IW_QUAL_DBM flag in updated...
1506 * The range allow to specify the real min/max of the value. As the
1507 * range struct only specify one bound of the value, we assume that
1508 * the other bound is 0 (zero).
1509 * For relative values, range is [0 ; range->max].
1510 * For absolute values, range is [range->max ; 63].
1512 * Let's take two example :
1513 * 1) value is 75%. qual->value = 75 ; range->max_qual.value = 100
1514 * 2) value is -54dBm. noise floor of the radio is -104dBm.
1515 * qual->value = -54 = 202 ; range->max_qual.value = -104 = 152
1521 * The old way to detect dBm require both the range and a non-null
1522 * level (which confuse the test). The new way can deal with level of 0
1523 * because it does an explicit test on the flag. */
1524 if(has_range && ((qual->level != 0)
1525 || (qual->updated & (IW_QUAL_DBM | IW_QUAL_RCPI))))
1527 /* Deal with quality : always a relative value */
1528 if(!(qual->updated & IW_QUAL_QUAL_INVALID))
1530 len = snprintf(buffer, buflen, "Quality%c%d/%d ",
1531 qual->updated & IW_QUAL_QUAL_UPDATED ? '=' : ':',
1532 qual->qual, range->max_qual.qual);
1537 /* Check if the statistics are in RCPI (IEEE 802.11k) */
1538 if(qual->updated & IW_QUAL_RCPI)
1540 /* Deal with signal level in RCPI */
1541 /* RCPI = int{(Power in dBm +110)*2} for 0dbm > Power > -110dBm */
1542 if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1544 double rcpilevel = (qual->level / 2.0) - 110.0;
1545 len = snprintf(buffer, buflen, "Signal level%c%g dBm ",
1546 qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1552 /* Deal with noise level in dBm (absolute power measurement) */
1553 if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1555 double rcpinoise = (qual->noise / 2.0) - 110.0;
1556 len = snprintf(buffer, buflen, "Noise level%c%g dBm",
1557 qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1563 /* Check if the statistics are in dBm */
1564 if((qual->updated & IW_QUAL_DBM)
1565 || (qual->level > range->max_qual.level))
1567 /* Deal with signal level in dBm (absolute power measurement) */
1568 if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1570 int dblevel = qual->level;
1571 /* Implement a range for dBm [-192; 63] */
1572 if(qual->level >= 64)
1574 len = snprintf(buffer, buflen, "Signal level%c%d dBm ",
1575 qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1581 /* Deal with noise level in dBm (absolute power measurement) */
1582 if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1584 int dbnoise = qual->noise;
1585 /* Implement a range for dBm [-192; 63] */
1586 if(qual->noise >= 64)
1588 len = snprintf(buffer, buflen, "Noise level%c%d dBm",
1589 qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1595 /* Deal with signal level as relative value (0 -> max) */
1596 if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1598 len = snprintf(buffer, buflen, "Signal level%c%d/%d ",
1599 qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1600 qual->level, range->max_qual.level);
1605 /* Deal with noise level as relative value (0 -> max) */
1606 if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1608 len = snprintf(buffer, buflen, "Noise level%c%d/%d",
1609 qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1610 qual->noise, range->max_qual.noise);
1617 /* We can't read the range, so we don't know... */
1618 snprintf(buffer, buflen,
1619 "Quality:%d Signal level:%d Noise level:%d",
1620 qual->qual, qual->level, qual->noise);
1624 /*********************** ENCODING SUBROUTINES ***********************/
1626 /*------------------------------------------------------------------*/
1628 * Output the encoding key, with a nice formating
1631 iw_print_key(char * buffer,
1633 const unsigned char * key, /* Must be unsigned */
1639 /* Check buffer size -> 1 bytes => 2 digits + 1/2 separator */
1640 if((key_size * 3) > buflen)
1642 snprintf(buffer, buflen, "<too big>");
1646 /* Is the key present ??? */
1647 if(key_flags & IW_ENCODE_NOKEY)
1649 /* Nope : print on or dummy */
1651 strcpy(buffer, "on"); /* Size checked */
1654 strcpy(buffer, "**"); /* Size checked */
1656 for(i = 1; i < key_size; i++)
1659 strcpy(buffer++, "-"); /* Size checked */
1660 strcpy(buffer, "**"); /* Size checked */
1667 /* Yes : print the key */
1668 sprintf(buffer, "%.2X", key[0]); /* Size checked */
1670 for(i = 1; i < key_size; i++)
1673 strcpy(buffer++, "-"); /* Size checked */
1674 sprintf(buffer, "%.2X", key[i]); /* Size checked */
1680 /*------------------------------------------------------------------*/
1682 * Convert a passphrase into a key
1683 * ### NOT IMPLEMENTED ###
1684 * Return size of the key, or 0 (no key) or -1 (error)
1687 iw_pass_key(const char * input,
1688 unsigned char * key)
1690 input = input; key = key;
1691 fprintf(stderr, "Error: Passphrase not implemented\n");
1695 /*------------------------------------------------------------------*/
1697 * Parse a key from the command line.
1698 * Return size of the key, or 0 (no key) or -1 (error)
1699 * If the key is too long, it's simply truncated...
1702 iw_in_key(const char * input,
1703 unsigned char * key)
1707 /* Check the type of key */
1708 if(!strncmp(input, "s:", 2))
1710 /* First case : as an ASCII string (Lucent/Agere cards) */
1711 keylen = strlen(input + 2); /* skip "s:" */
1712 if(keylen > IW_ENCODING_TOKEN_MAX)
1713 keylen = IW_ENCODING_TOKEN_MAX;
1714 memcpy(key, input + 2, keylen);
1717 if(!strncmp(input, "p:", 2))
1719 /* Second case : as a passphrase (PrismII cards) */
1720 return(iw_pass_key(input + 2, key)); /* skip "p:" */
1725 int dlen; /* Digits sequence length */
1726 unsigned char out[IW_ENCODING_TOKEN_MAX];
1728 /* Third case : as hexadecimal digits */
1732 /* Loop until we run out of chars in input or overflow the output */
1738 /* No more chars in this sequence */
1741 /* Skip separator */
1744 /* Calculate num of char to next separator */
1745 dlen = strcspn(p, "-:;.,");
1747 /* Get each char separatly (and not by two) so that we don't
1748 * get confused by 'enc' (=> '0E'+'0C') and similar */
1749 count = sscanf(p, "%1X%1X", &temph, &templ);
1751 return(-1); /* Error -> non-hex char */
1752 /* Fixup odd strings such as '123' is '01'+'23' and not '12'+'03'*/
1755 /* Put back two chars as one byte and output */
1757 templ |= temph << 4;
1760 out[keylen++] = (unsigned char) (templ & 0xFF);
1761 /* Check overflow in output */
1762 if(keylen >= IW_ENCODING_TOKEN_MAX)
1764 /* Move on to next chars */
1768 /* We use a temporary output buffer 'out' so that if there is
1769 * an error, we don't overwrite the original key buffer.
1770 * Because of the way iwconfig loop on multiple key/enc arguments
1771 * until it finds an error in here, this is necessary to avoid
1772 * silently corrupting the encryption key... */
1773 memcpy(key, out, keylen);
1778 char buf[IW_ENCODING_TOKEN_MAX * 3];
1779 iw_print_key(buf, sizeof(buf), key, keylen, 0);
1780 printf("Got key : %d [%s]\n", keylen, buf);
1787 /*------------------------------------------------------------------*/
1789 * Parse a key from the command line.
1790 * Return size of the key, or 0 (no key) or -1 (error)
1793 iw_in_key_full(int skfd,
1794 const char * ifname,
1796 unsigned char * key,
1802 if(!strncmp(input, "l:", 2))
1804 struct iw_range range;
1806 /* Extra case : as a login (user:passwd - Cisco LEAP) */
1807 keylen = strlen(input + 2) + 1; /* skip "l:", add '\0' */
1808 /* Most user/password is 8 char, so 18 char total, < 32 */
1809 if(keylen > IW_ENCODING_TOKEN_MAX)
1810 keylen = IW_ENCODING_TOKEN_MAX;
1811 memcpy(key, input + 2, keylen);
1813 /* Separate the two strings */
1814 p = strchr((char *) key, ':');
1817 fprintf(stderr, "Error: Invalid login format\n");
1822 /* Extract range info */
1823 if(iw_get_range_info(skfd, ifname, &range) < 0)
1824 /* Hum... Maybe we should return an error ??? */
1825 memset(&range, 0, sizeof(range));
1827 if(range.we_version_compiled > 15)
1830 printf("flags = %X, index = %X\n",
1831 *flags, range.encoding_login_index);
1832 if((*flags & IW_ENCODE_INDEX) == 0)
1834 /* Extract range info */
1835 if(iw_get_range_info(skfd, ifname, &range) < 0)
1836 memset(&range, 0, sizeof(range));
1837 printf("flags = %X, index = %X\n", *flags, range.encoding_login_index);
1838 /* Set the index the driver expects */
1839 *flags |= range.encoding_login_index & IW_ENCODE_INDEX;
1841 printf("flags = %X, index = %X\n", *flags, range.encoding_login_index);
1845 /* Simpler routine above */
1846 keylen = iw_in_key(input, key);
1851 /******************* POWER MANAGEMENT SUBROUTINES *******************/
1853 /*------------------------------------------------------------------*/
1855 * Output a power management value with all attributes...
1858 iw_print_pm_value(char * buffer,
1867 snprintf(buffer, buflen, "<too big>");
1873 if(flags & IW_POWER_MIN)
1875 strcpy(buffer, " min"); /* Size checked */
1878 if(flags & IW_POWER_MAX)
1880 strcpy(buffer, " max"); /* Size checked */
1885 if(flags & IW_POWER_TIMEOUT)
1887 strcpy(buffer, " timeout:"); /* Size checked */
1892 if(flags & IW_POWER_SAVING)
1894 strcpy(buffer, " saving:"); /* Size checked */
1899 strcpy(buffer, " period:"); /* Size checked */
1904 /* Display value without units */
1905 if(flags & IW_POWER_RELATIVE)
1909 snprintf(buffer, buflen, "%d", value);
1913 /* Display value with units */
1914 if(value >= (int) MEGA)
1915 snprintf(buffer, buflen, "%gs", ((double) value) / MEGA);
1917 if(value >= (int) KILO)
1918 snprintf(buffer, buflen, "%gms", ((double) value) / KILO);
1920 snprintf(buffer, buflen, "%dus", value);
1924 /*------------------------------------------------------------------*/
1926 * Output a power management mode
1929 iw_print_pm_mode(char * buffer,
1936 snprintf(buffer, buflen, "<too big>");
1940 /* Print the proper mode... */
1941 switch(flags & IW_POWER_MODE)
1943 case IW_POWER_UNICAST_R:
1944 strcpy(buffer, "mode:Unicast only received"); /* Size checked */
1946 case IW_POWER_MULTICAST_R:
1947 strcpy(buffer, "mode:Multicast only received"); /* Size checked */
1949 case IW_POWER_ALL_R:
1950 strcpy(buffer, "mode:All packets received"); /* Size checked */
1952 case IW_POWER_FORCE_S:
1953 strcpy(buffer, "mode:Force sending"); /* Size checked */
1955 case IW_POWER_REPEATER:
1956 strcpy(buffer, "mode:Repeat multicasts"); /* Size checked */
1959 strcpy(buffer, ""); /* Size checked */
1964 /***************** RETRY LIMIT/LIFETIME SUBROUTINES *****************/
1966 /*------------------------------------------------------------------*/
1968 * Output a retry value with all attributes...
1971 iw_print_retry_value(char * buffer,
1977 /* Check buffer size */
1980 snprintf(buffer, buflen, "<too big>");
1986 if(flags & IW_RETRY_MIN)
1988 strcpy(buffer, " min"); /* Size checked */
1991 if(flags & IW_RETRY_MAX)
1993 strcpy(buffer, " max"); /* Size checked */
1996 if(flags & IW_RETRY_SHORT)
1998 strcpy(buffer, " short"); /* Size checked */
2001 if(flags & IW_RETRY_LONG)
2003 strcpy(buffer, " long"); /* Size checked */
2007 /* Type lifetime of limit */
2008 if(flags & IW_RETRY_LIFETIME)
2010 strcpy(buffer, " lifetime:"); /* Size checked */
2013 /* Display value without units */
2014 if(flags & IW_RETRY_RELATIVE)
2018 snprintf(buffer, buflen, "%d", value);
2022 /* Display value with units */
2023 if(value >= (int) MEGA)
2024 snprintf(buffer, buflen, "%gs", ((double) value) / MEGA);
2026 if(value >= (int) KILO)
2027 snprintf(buffer, buflen, "%gms", ((double) value) / KILO);
2029 snprintf(buffer, buflen, "%dus", value);
2033 snprintf(buffer, buflen, " limit:%d", value);
2036 /************************* TIME SUBROUTINES *************************/
2038 /*------------------------------------------------------------------*/
2041 * Inspired from irdadump...
2044 iw_print_timeval(char * buffer,
2046 const struct timeval * timev,
2047 const struct timezone * tz)
2051 s = (timev->tv_sec - tz->tz_minuteswest * 60) % 86400;
2052 snprintf(buffer, buflen, "%02d:%02d:%02d.%06u",
2053 s / 3600, (s % 3600) / 60,
2054 s % 60, (u_int32_t) timev->tv_usec);
2057 /*********************** ADDRESS SUBROUTINES ************************/
2059 * This section is mostly a cut & past from net-tools-1.2.0
2060 * (Well... This has evolved over the years)
2061 * manage address display and input...
2064 /*------------------------------------------------------------------*/
2066 * Check if interface support the right MAC address type...
2069 iw_check_mac_addr_type(int skfd,
2070 const char * ifname)
2074 /* Get the type of hardware address */
2075 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
2076 if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) ||
2077 ((ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
2078 && (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211)))
2080 /* Deep trouble... */
2081 fprintf(stderr, "Interface %s doesn't support MAC addresses\n",
2089 printf("Hardware : %d - %s\n", ifr.ifr_hwaddr.sa_family,
2090 iw_saether_ntop(&ifr.ifr_hwaddr, buf));
2098 /*------------------------------------------------------------------*/
2100 * Check if interface support the right interface address type...
2103 iw_check_if_addr_type(int skfd,
2104 const char * ifname)
2108 /* Get the type of interface address */
2109 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
2110 if((ioctl(skfd, SIOCGIFADDR, &ifr) < 0) ||
2111 (ifr.ifr_addr.sa_family != AF_INET))
2113 /* Deep trouble... */
2114 fprintf(stderr, "Interface %s doesn't support IP addresses\n", ifname);
2119 printf("Interface : %d - 0x%lX\n", ifr.ifr_addr.sa_family,
2120 *((unsigned long *) ifr.ifr_addr.sa_data));
2126 /*------------------------------------------------------------------*/
2128 * Display an arbitrary length MAC address in readable format.
2131 iw_mac_ntop(const unsigned char * mac,
2138 /* Overflow check (don't forget '\0') */
2139 if(buflen < (maclen * 3 - 1 + 1))
2143 sprintf(buf, "%02X", mac[0]);
2146 for(i = 1; i < maclen; i++)
2147 sprintf(buf + (i * 3) - 1, ":%02X", mac[i]);
2151 /*------------------------------------------------------------------*/
2153 * Display an Ethernet address in readable format.
2156 iw_ether_ntop(const struct ether_addr * eth,
2159 sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
2160 eth->ether_addr_octet[0], eth->ether_addr_octet[1],
2161 eth->ether_addr_octet[2], eth->ether_addr_octet[3],
2162 eth->ether_addr_octet[4], eth->ether_addr_octet[5]);
2165 /*------------------------------------------------------------------*/
2167 * Display an Wireless Access Point Socket Address in readable format.
2168 * Note : 0x44 is an accident of history, that's what the Orinoco/PrismII
2169 * chipset report, and the driver doesn't filter it.
2172 iw_sawap_ntop(const struct sockaddr * sap,
2175 const struct ether_addr ether_zero = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }};
2176 const struct ether_addr ether_bcast = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
2177 const struct ether_addr ether_hack = {{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }};
2178 const struct ether_addr * ether_wap = (const struct ether_addr *) sap->sa_data;
2180 if(!iw_ether_cmp(ether_wap, ðer_zero))
2181 sprintf(buf, "Not-Associated");
2183 if(!iw_ether_cmp(ether_wap, ðer_bcast))
2184 sprintf(buf, "Invalid");
2186 if(!iw_ether_cmp(ether_wap, ðer_hack))
2187 sprintf(buf, "None");
2189 iw_ether_ntop(ether_wap, buf);
2193 /*------------------------------------------------------------------*/
2195 * Input an arbitrary length MAC address and convert to binary.
2196 * Return address size.
2199 iw_mac_aton(const char * orig,
2200 unsigned char * mac,
2203 const char * p = orig;
2206 /* Loop on all bytes of the string */
2212 /* Extract one byte as two chars */
2213 count = sscanf(p, "%1X%1X", &temph, &templ);
2215 break; /* Error -> non-hex chars */
2216 /* Output two chars as one byte */
2217 templ |= temph << 4;
2218 mac[maclen++] = (unsigned char) (templ & 0xFF);
2220 /* Check end of string */
2226 iw_ether_ntop((const struct ether_addr *) mac, buf);
2227 fprintf(stderr, "iw_mac_aton(%s): %s\n", orig, buf);
2229 return(maclen); /* Normal exit */
2232 /* Check overflow */
2233 if(maclen >= macmax)
2236 fprintf(stderr, "iw_mac_aton(%s): trailing junk!\n", orig);
2239 return(0); /* Error -> overflow */
2242 /* Check separator */
2250 fprintf(stderr, "iw_mac_aton(%s): invalid ether address!\n", orig);
2256 /*------------------------------------------------------------------*/
2258 * Input an Ethernet address and convert to binary.
2261 iw_ether_aton(const char *orig, struct ether_addr *eth)
2264 maclen = iw_mac_aton(orig, (unsigned char *) eth, ETH_ALEN);
2265 if((maclen > 0) && (maclen < ETH_ALEN))
2273 /*------------------------------------------------------------------*/
2275 * Input an Internet address and convert to binary.
2278 iw_in_inet(char *name, struct sockaddr *sap)
2282 struct sockaddr_in *sain = (struct sockaddr_in *) sap;
2285 sain->sin_family = AF_INET;
2288 /* Default is special, meaning 0.0.0.0. */
2289 if (!strcmp(name, "default")) {
2290 sain->sin_addr.s_addr = INADDR_ANY;
2294 /* Try the NETWORKS database to see if this is a known network. */
2295 if ((np = getnetbyname(name)) != (struct netent *)NULL) {
2296 sain->sin_addr.s_addr = htonl(np->n_net);
2297 strcpy(name, np->n_name);
2301 /* Always use the resolver (DNS name + IP addresses) */
2302 if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
2306 memcpy((char *) &sain->sin_addr, (char *) hp->h_addr_list[0], hp->h_length);
2307 strcpy(name, hp->h_name);
2311 /*------------------------------------------------------------------*/
2313 * Input an address and convert to binary.
2316 iw_in_addr(int skfd,
2317 const char * ifname,
2319 struct sockaddr *sap)
2321 /* Check if it is a hardware or IP address */
2322 if(strchr(bufp, ':') == NULL)
2324 struct sockaddr if_address;
2325 struct arpreq arp_query;
2327 /* Check if we have valid interface address type */
2328 if(iw_check_if_addr_type(skfd, ifname) < 0)
2330 fprintf(stderr, "%-8.16s Interface doesn't support IP addresses\n", ifname);
2334 /* Read interface address */
2335 if(iw_in_inet(bufp, &if_address) < 0)
2337 fprintf(stderr, "Invalid interface address %s\n", bufp);
2341 /* Translate IP addresses to MAC addresses */
2342 memcpy((char *) &(arp_query.arp_pa),
2343 (char *) &if_address,
2344 sizeof(struct sockaddr));
2345 arp_query.arp_ha.sa_family = 0;
2346 arp_query.arp_flags = 0;
2347 /* The following restrict the search to the interface only */
2348 /* For old kernels which complain, just comment it... */
2349 strncpy(arp_query.arp_dev, ifname, IFNAMSIZ);
2350 if((ioctl(skfd, SIOCGARP, &arp_query) < 0) ||
2351 !(arp_query.arp_flags & ATF_COM))
2353 fprintf(stderr, "Arp failed for %s on %s... (%d)\nTry to ping the address before setting it.\n",
2354 bufp, ifname, errno);
2358 /* Store new MAC address */
2359 memcpy((char *) sap,
2360 (char *) &(arp_query.arp_ha),
2361 sizeof(struct sockaddr));
2366 printf("IP Address %s => Hw Address = %s\n",
2367 bufp, iw_saether_ntop(sap, buf));
2371 else /* If it's an hardware address */
2373 /* Check if we have valid mac address type */
2374 if(iw_check_mac_addr_type(skfd, ifname) < 0)
2376 fprintf(stderr, "%-8.16s Interface doesn't support MAC addresses\n", ifname);
2380 /* Get the hardware address */
2381 if(iw_saether_aton(bufp, sap) == 0)
2383 fprintf(stderr, "Invalid hardware address %s\n", bufp);
2391 printf("Hw Address = %s\n", iw_saether_ntop(sap, buf));
2398 /************************* MISC SUBROUTINES **************************/
2400 /* Size (in bytes) of various events */
2401 static const int priv_type_size[] = {
2402 0, /* IW_PRIV_TYPE_NONE */
2403 1, /* IW_PRIV_TYPE_BYTE */
2404 1, /* IW_PRIV_TYPE_CHAR */
2405 0, /* Not defined */
2406 sizeof(__u32), /* IW_PRIV_TYPE_INT */
2407 sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
2408 sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
2409 0, /* Not defined */
2412 /*------------------------------------------------------------------*/
2414 * Max size in bytes of an private argument.
2417 iw_get_priv_size(int args)
2419 int num = args & IW_PRIV_SIZE_MASK;
2420 int type = (args & IW_PRIV_TYPE_MASK) >> 12;
2422 return(num * priv_type_size[type]);
2425 /************************ EVENT SUBROUTINES ************************/
2427 * The Wireless Extension API 14 and greater define Wireless Events,
2428 * that are used for various events and scanning.
2429 * Those functions help the decoding of events, so are needed only in
2433 /* -------------------------- CONSTANTS -------------------------- */
2435 /* Type of headers we know about (basically union iwreq_data) */
2436 #define IW_HEADER_TYPE_NULL 0 /* Not available */
2437 #define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */
2438 #define IW_HEADER_TYPE_UINT 4 /* __u32 */
2439 #define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */
2440 #define IW_HEADER_TYPE_ADDR 6 /* struct sockaddr */
2441 #define IW_HEADER_TYPE_POINT 8 /* struct iw_point */
2442 #define IW_HEADER_TYPE_PARAM 9 /* struct iw_param */
2443 #define IW_HEADER_TYPE_QUAL 10 /* struct iw_quality */
2445 /* Handling flags */
2446 /* Most are not implemented. I just use them as a reminder of some
2447 * cool features we might need one day ;-) */
2448 #define IW_DESCR_FLAG_NONE 0x0000 /* Obvious */
2449 /* Wrapper level flags */
2450 #define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */
2451 #define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */
2452 #define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */
2453 /* SET : Omit payload from generated iwevent */
2454 #define IW_DESCR_FLAG_NOMAX 0x0008 /* GET : no limit on request size */
2455 /* Driver level flags */
2456 #define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */
2458 /* ---------------------------- TYPES ---------------------------- */
2461 * Describe how a standard IOCTL looks like.
2463 struct iw_ioctl_description
2465 __u8 header_type; /* NULL, iw_point or other */
2466 __u8 token_type; /* Future */
2467 __u16 token_size; /* Granularity of payload */
2468 __u16 min_tokens; /* Min acceptable token number */
2469 __u16 max_tokens; /* Max acceptable token number */
2470 __u32 flags; /* Special handling of the request */
2473 /* -------------------------- VARIABLES -------------------------- */
2476 * Meta-data about all the standard Wireless Extension request we
2479 static const struct iw_ioctl_description standard_ioctl_descr[] = {
2480 [SIOCSIWCOMMIT - SIOCIWFIRST] = {
2481 .header_type = IW_HEADER_TYPE_NULL,
2483 [SIOCGIWNAME - SIOCIWFIRST] = {
2484 .header_type = IW_HEADER_TYPE_CHAR,
2485 .flags = IW_DESCR_FLAG_DUMP,
2487 [SIOCSIWNWID - SIOCIWFIRST] = {
2488 .header_type = IW_HEADER_TYPE_PARAM,
2489 .flags = IW_DESCR_FLAG_EVENT,
2491 [SIOCGIWNWID - SIOCIWFIRST] = {
2492 .header_type = IW_HEADER_TYPE_PARAM,
2493 .flags = IW_DESCR_FLAG_DUMP,
2495 [SIOCSIWFREQ - SIOCIWFIRST] = {
2496 .header_type = IW_HEADER_TYPE_FREQ,
2497 .flags = IW_DESCR_FLAG_EVENT,
2499 [SIOCGIWFREQ - SIOCIWFIRST] = {
2500 .header_type = IW_HEADER_TYPE_FREQ,
2501 .flags = IW_DESCR_FLAG_DUMP,
2503 [SIOCSIWMODE - SIOCIWFIRST] = {
2504 .header_type = IW_HEADER_TYPE_UINT,
2505 .flags = IW_DESCR_FLAG_EVENT,
2507 [SIOCGIWMODE - SIOCIWFIRST] = {
2508 .header_type = IW_HEADER_TYPE_UINT,
2509 .flags = IW_DESCR_FLAG_DUMP,
2511 [SIOCSIWSENS - SIOCIWFIRST] = {
2512 .header_type = IW_HEADER_TYPE_PARAM,
2514 [SIOCGIWSENS - SIOCIWFIRST] = {
2515 .header_type = IW_HEADER_TYPE_PARAM,
2517 [SIOCSIWRANGE - SIOCIWFIRST] = {
2518 .header_type = IW_HEADER_TYPE_NULL,
2520 [SIOCGIWRANGE - SIOCIWFIRST] = {
2521 .header_type = IW_HEADER_TYPE_POINT,
2523 .max_tokens = sizeof(struct iw_range),
2524 .flags = IW_DESCR_FLAG_DUMP,
2526 [SIOCSIWPRIV - SIOCIWFIRST] = {
2527 .header_type = IW_HEADER_TYPE_NULL,
2529 [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */
2530 .header_type = IW_HEADER_TYPE_NULL,
2532 [SIOCSIWSTATS - SIOCIWFIRST] = {
2533 .header_type = IW_HEADER_TYPE_NULL,
2535 [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */
2536 .header_type = IW_HEADER_TYPE_NULL,
2537 .flags = IW_DESCR_FLAG_DUMP,
2539 [SIOCSIWSPY - SIOCIWFIRST] = {
2540 .header_type = IW_HEADER_TYPE_POINT,
2541 .token_size = sizeof(struct sockaddr),
2542 .max_tokens = IW_MAX_SPY,
2544 [SIOCGIWSPY - SIOCIWFIRST] = {
2545 .header_type = IW_HEADER_TYPE_POINT,
2546 .token_size = sizeof(struct sockaddr) +
2547 sizeof(struct iw_quality),
2548 .max_tokens = IW_MAX_SPY,
2550 [SIOCSIWTHRSPY - SIOCIWFIRST] = {
2551 .header_type = IW_HEADER_TYPE_POINT,
2552 .token_size = sizeof(struct iw_thrspy),
2556 [SIOCGIWTHRSPY - SIOCIWFIRST] = {
2557 .header_type = IW_HEADER_TYPE_POINT,
2558 .token_size = sizeof(struct iw_thrspy),
2562 [SIOCSIWAP - SIOCIWFIRST] = {
2563 .header_type = IW_HEADER_TYPE_ADDR,
2565 [SIOCGIWAP - SIOCIWFIRST] = {
2566 .header_type = IW_HEADER_TYPE_ADDR,
2567 .flags = IW_DESCR_FLAG_DUMP,
2569 [SIOCSIWMLME - SIOCIWFIRST] = {
2570 .header_type = IW_HEADER_TYPE_POINT,
2572 .min_tokens = sizeof(struct iw_mlme),
2573 .max_tokens = sizeof(struct iw_mlme),
2575 [SIOCGIWAPLIST - SIOCIWFIRST] = {
2576 .header_type = IW_HEADER_TYPE_POINT,
2577 .token_size = sizeof(struct sockaddr) +
2578 sizeof(struct iw_quality),
2579 .max_tokens = IW_MAX_AP,
2580 .flags = IW_DESCR_FLAG_NOMAX,
2582 [SIOCSIWSCAN - SIOCIWFIRST] = {
2583 .header_type = IW_HEADER_TYPE_POINT,
2586 .max_tokens = sizeof(struct iw_scan_req),
2588 [SIOCGIWSCAN - SIOCIWFIRST] = {
2589 .header_type = IW_HEADER_TYPE_POINT,
2591 .max_tokens = IW_SCAN_MAX_DATA,
2592 .flags = IW_DESCR_FLAG_NOMAX,
2594 [SIOCSIWESSID - SIOCIWFIRST] = {
2595 .header_type = IW_HEADER_TYPE_POINT,
2597 .max_tokens = IW_ESSID_MAX_SIZE + 1,
2598 .flags = IW_DESCR_FLAG_EVENT,
2600 [SIOCGIWESSID - SIOCIWFIRST] = {
2601 .header_type = IW_HEADER_TYPE_POINT,
2603 .max_tokens = IW_ESSID_MAX_SIZE + 1,
2604 .flags = IW_DESCR_FLAG_DUMP,
2606 [SIOCSIWNICKN - SIOCIWFIRST] = {
2607 .header_type = IW_HEADER_TYPE_POINT,
2609 .max_tokens = IW_ESSID_MAX_SIZE + 1,
2611 [SIOCGIWNICKN - SIOCIWFIRST] = {
2612 .header_type = IW_HEADER_TYPE_POINT,
2614 .max_tokens = IW_ESSID_MAX_SIZE + 1,
2616 [SIOCSIWRATE - SIOCIWFIRST] = {
2617 .header_type = IW_HEADER_TYPE_PARAM,
2619 [SIOCGIWRATE - SIOCIWFIRST] = {
2620 .header_type = IW_HEADER_TYPE_PARAM,
2622 [SIOCSIWRTS - SIOCIWFIRST] = {
2623 .header_type = IW_HEADER_TYPE_PARAM,
2625 [SIOCGIWRTS - SIOCIWFIRST] = {
2626 .header_type = IW_HEADER_TYPE_PARAM,
2628 [SIOCSIWFRAG - SIOCIWFIRST] = {
2629 .header_type = IW_HEADER_TYPE_PARAM,
2631 [SIOCGIWFRAG - SIOCIWFIRST] = {
2632 .header_type = IW_HEADER_TYPE_PARAM,
2634 [SIOCSIWTXPOW - SIOCIWFIRST] = {
2635 .header_type = IW_HEADER_TYPE_PARAM,
2637 [SIOCGIWTXPOW - SIOCIWFIRST] = {
2638 .header_type = IW_HEADER_TYPE_PARAM,
2640 [SIOCSIWRETRY - SIOCIWFIRST] = {
2641 .header_type = IW_HEADER_TYPE_PARAM,
2643 [SIOCGIWRETRY - SIOCIWFIRST] = {
2644 .header_type = IW_HEADER_TYPE_PARAM,
2646 [SIOCSIWENCODE - SIOCIWFIRST] = {
2647 .header_type = IW_HEADER_TYPE_POINT,
2648 /* Hack : this never returns any payload in event.
2649 * Fix the 64->32 bit hack... */
2651 .max_tokens = IW_ENCODING_TOKEN_MAX,
2652 .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
2654 [SIOCGIWENCODE - SIOCIWFIRST] = {
2655 .header_type = IW_HEADER_TYPE_POINT,
2656 /* Hack : this never returns any payload in event.
2657 * Fix the 64->32 bit hack... */
2659 .max_tokens = IW_ENCODING_TOKEN_MAX,
2660 .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
2662 [SIOCSIWPOWER - SIOCIWFIRST] = {
2663 .header_type = IW_HEADER_TYPE_PARAM,
2665 [SIOCGIWPOWER - SIOCIWFIRST] = {
2666 .header_type = IW_HEADER_TYPE_PARAM,
2668 [SIOCSIWMODUL - SIOCIWFIRST] = {
2669 .header_type = IW_HEADER_TYPE_PARAM,
2671 [SIOCGIWMODUL - SIOCIWFIRST] = {
2672 .header_type = IW_HEADER_TYPE_PARAM,
2674 [SIOCSIWGENIE - SIOCIWFIRST] = {
2675 .header_type = IW_HEADER_TYPE_POINT,
2677 .max_tokens = IW_GENERIC_IE_MAX,
2679 [SIOCGIWGENIE - SIOCIWFIRST] = {
2680 .header_type = IW_HEADER_TYPE_POINT,
2682 .max_tokens = IW_GENERIC_IE_MAX,
2684 [SIOCSIWAUTH - SIOCIWFIRST] = {
2685 .header_type = IW_HEADER_TYPE_PARAM,
2687 [SIOCGIWAUTH - SIOCIWFIRST] = {
2688 .header_type = IW_HEADER_TYPE_PARAM,
2690 [SIOCSIWENCODEEXT - SIOCIWFIRST] = {
2691 .header_type = IW_HEADER_TYPE_POINT,
2693 .min_tokens = sizeof(struct iw_encode_ext),
2694 .max_tokens = sizeof(struct iw_encode_ext) +
2695 IW_ENCODING_TOKEN_MAX,
2697 [SIOCGIWENCODEEXT - SIOCIWFIRST] = {
2698 .header_type = IW_HEADER_TYPE_POINT,
2700 .min_tokens = sizeof(struct iw_encode_ext),
2701 .max_tokens = sizeof(struct iw_encode_ext) +
2702 IW_ENCODING_TOKEN_MAX,
2704 [SIOCSIWPMKSA - SIOCIWFIRST] = {
2705 .header_type = IW_HEADER_TYPE_POINT,
2707 .min_tokens = sizeof(struct iw_pmksa),
2708 .max_tokens = sizeof(struct iw_pmksa),
2711 static const unsigned int standard_ioctl_num = (sizeof(standard_ioctl_descr) /
2712 sizeof(struct iw_ioctl_description));
2715 * Meta-data about all the additional standard Wireless Extension events
2718 static const struct iw_ioctl_description standard_event_descr[] = {
2719 [IWEVTXDROP - IWEVFIRST] = {
2720 .header_type = IW_HEADER_TYPE_ADDR,
2722 [IWEVQUAL - IWEVFIRST] = {
2723 .header_type = IW_HEADER_TYPE_QUAL,
2725 [IWEVCUSTOM - IWEVFIRST] = {
2726 .header_type = IW_HEADER_TYPE_POINT,
2728 .max_tokens = IW_CUSTOM_MAX,
2730 [IWEVREGISTERED - IWEVFIRST] = {
2731 .header_type = IW_HEADER_TYPE_ADDR,
2733 [IWEVEXPIRED - IWEVFIRST] = {
2734 .header_type = IW_HEADER_TYPE_ADDR,
2736 [IWEVGENIE - IWEVFIRST] = {
2737 .header_type = IW_HEADER_TYPE_POINT,
2739 .max_tokens = IW_GENERIC_IE_MAX,
2741 [IWEVMICHAELMICFAILURE - IWEVFIRST] = {
2742 .header_type = IW_HEADER_TYPE_POINT,
2744 .max_tokens = sizeof(struct iw_michaelmicfailure),
2746 [IWEVASSOCREQIE - IWEVFIRST] = {
2747 .header_type = IW_HEADER_TYPE_POINT,
2749 .max_tokens = IW_GENERIC_IE_MAX,
2751 [IWEVASSOCRESPIE - IWEVFIRST] = {
2752 .header_type = IW_HEADER_TYPE_POINT,
2754 .max_tokens = IW_GENERIC_IE_MAX,
2756 [IWEVPMKIDCAND - IWEVFIRST] = {
2757 .header_type = IW_HEADER_TYPE_POINT,
2759 .max_tokens = sizeof(struct iw_pmkid_cand),
2762 static const unsigned int standard_event_num = (sizeof(standard_event_descr) /
2763 sizeof(struct iw_ioctl_description));
2765 /* Size (in bytes) of various events */
2766 static const int event_type_size[] = {
2767 IW_EV_LCP_PK_LEN, /* IW_HEADER_TYPE_NULL */
2769 IW_EV_CHAR_PK_LEN, /* IW_HEADER_TYPE_CHAR */
2771 IW_EV_UINT_PK_LEN, /* IW_HEADER_TYPE_UINT */
2772 IW_EV_FREQ_PK_LEN, /* IW_HEADER_TYPE_FREQ */
2773 IW_EV_ADDR_PK_LEN, /* IW_HEADER_TYPE_ADDR */
2775 IW_EV_POINT_PK_LEN, /* Without variable payload */
2776 IW_EV_PARAM_PK_LEN, /* IW_HEADER_TYPE_PARAM */
2777 IW_EV_QUAL_PK_LEN, /* IW_HEADER_TYPE_QUAL */
2780 /*------------------------------------------------------------------*/
2782 * Initialise the struct stream_descr so that we can extract
2783 * individual events from the event stream.
2786 iw_init_event_stream(struct stream_descr * stream, /* Stream of events */
2791 memset((char *) stream, '\0', sizeof(struct stream_descr));
2794 stream->current = data;
2795 stream->end = data + len;
2798 /*------------------------------------------------------------------*/
2800 * Extract the next event from the event stream.
2803 iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */
2804 struct iw_event * iwe, /* Extracted event */
2807 const struct iw_ioctl_description * descr = NULL;
2809 unsigned int event_len = 1; /* Invalid */
2811 /* Don't "optimise" the following variable, it will crash */
2812 unsigned cmd_index; /* *MUST* be unsigned */
2814 /* Check for end of stream */
2815 if((stream->current + IW_EV_LCP_PK_LEN) > stream->end)
2819 printf("DBG - stream->current = %p, stream->value = %p, stream->end = %p\n",
2820 stream->current, stream->value, stream->end);
2823 /* Extract the event header (to get the event id).
2824 * Note : the event may be unaligned, therefore copy... */
2825 memcpy((char *) iwe, stream->current, IW_EV_LCP_PK_LEN);
2828 printf("DBG - iwe->cmd = 0x%X, iwe->len = %d\n",
2829 iwe->cmd, iwe->len);
2832 /* Check invalid events */
2833 if(iwe->len <= IW_EV_LCP_PK_LEN)
2836 /* Get the type and length of that event */
2837 if(iwe->cmd <= SIOCIWLAST)
2839 cmd_index = iwe->cmd - SIOCIWFIRST;
2840 if(cmd_index < standard_ioctl_num)
2841 descr = &(standard_ioctl_descr[cmd_index]);
2845 cmd_index = iwe->cmd - IWEVFIRST;
2846 if(cmd_index < standard_event_num)
2847 descr = &(standard_event_descr[cmd_index]);
2850 event_type = descr->header_type;
2851 /* Unknown events -> event_type=0 => IW_EV_LCP_PK_LEN */
2852 event_len = event_type_size[event_type];
2853 /* Fixup for earlier version of WE */
2854 if((we_version <= 18) && (event_type == IW_HEADER_TYPE_POINT))
2855 event_len += IW_EV_POINT_OFF;
2857 /* Check if we know about this event */
2858 if(event_len <= IW_EV_LCP_PK_LEN)
2860 /* Skip to next event */
2861 stream->current += iwe->len;
2864 event_len -= IW_EV_LCP_PK_LEN;
2866 /* Set pointer on data */
2867 if(stream->value != NULL)
2868 pointer = stream->value; /* Next value in event */
2870 pointer = stream->current + IW_EV_LCP_PK_LEN; /* First value in event */
2873 printf("DBG - event_type = %d, event_len = %d, pointer = %p\n",
2874 event_type, event_len, pointer);
2877 /* Copy the rest of the event (at least, fixed part) */
2878 if((pointer + event_len) > stream->end)
2880 /* Go to next event */
2881 stream->current += iwe->len;
2884 /* Fixup for WE-19 and later : pointer no longer in the stream */
2885 /* Beware of alignement. Dest has local alignement, not packed */
2886 if((we_version > 18) && (event_type == IW_HEADER_TYPE_POINT))
2887 memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
2888 pointer, event_len);
2890 memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
2892 /* Skip event in the stream */
2893 pointer += event_len;
2895 /* Special processing for iw_point events */
2896 if(event_type == IW_HEADER_TYPE_POINT)
2898 /* Check the length of the payload */
2899 unsigned int extra_len = iwe->len - (event_len + IW_EV_LCP_PK_LEN);
2902 /* Set pointer on variable part (warning : non aligned) */
2903 iwe->u.data.pointer = pointer;
2905 /* Check that we have a descriptor for the command */
2907 /* Can't check payload -> unsafe... */
2908 iwe->u.data.pointer = NULL; /* Discard paylod */
2911 /* Those checks are actually pretty hard to trigger,
2912 * because of the checks done in the kernel... */
2914 unsigned int token_len = iwe->u.data.length * descr->token_size;
2916 /* Ugly fixup for alignement issues.
2917 * If the kernel is 64 bits and userspace 32 bits,
2918 * we have an extra 4+4 bytes.
2919 * Fixing that in the kernel would break 64 bits userspace. */
2920 if((token_len != extra_len) && (extra_len >= 4))
2922 union iw_align_u16 alt_dlen;
2923 unsigned int alt_token_len;
2924 /* Usespace seems to not always like unaligned access,
2925 * so be careful and make sure to align value.
2926 * I hope gcc won't play any of its aliasing tricks... */
2927 alt_dlen.byte[0] = *(pointer);
2928 alt_dlen.byte[1] = *(pointer + 1);
2929 alt_token_len = alt_dlen.value * descr->token_size;
2931 printf("DBG - alt_token_len = %d\n", alt_token_len);
2933 /* Verify that data is consistent if assuming 64 bit
2935 if((alt_token_len + 8) == extra_len)
2937 /* Ok, let's redo everything */
2938 pointer -= event_len;
2940 /* Dest has local alignement, not packed */
2941 memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
2942 pointer, event_len);
2943 pointer += event_len + 4;
2944 token_len = alt_token_len;
2945 /* We may have no payload */
2947 iwe->u.data.pointer = pointer;
2949 iwe->u.data.pointer = NULL;
2953 /* Discard bogus events which advertise more tokens than
2954 * what they carry... */
2955 if(token_len > extra_len)
2956 iwe->u.data.pointer = NULL; /* Discard paylod */
2957 /* Check that the advertised token size is not going to
2958 * produce buffer overflow to our caller... */
2959 if((iwe->u.data.length > descr->max_tokens)
2960 && !(descr->flags & IW_DESCR_FLAG_NOMAX))
2961 iwe->u.data.pointer = NULL; /* Discard paylod */
2962 /* Same for underflows... */
2963 if(iwe->u.data.length < descr->min_tokens)
2964 iwe->u.data.pointer = NULL; /* Discard paylod */
2966 printf("DBG - extra_len = %d, token_len = %d, token = %d, max = %d, min = %d\n",
2967 extra_len, token_len, iwe->u.data.length, descr->max_tokens, descr->min_tokens);
2973 iwe->u.data.pointer = NULL;
2975 /* Go to next event */
2976 stream->current += iwe->len;
2980 /* Ugly fixup for alignement issues.
2981 * If the kernel is 64 bits and userspace 32 bits,
2982 * we have an extra 4 bytes.
2983 * Fixing that in the kernel would break 64 bits userspace. */
2984 if((stream->value == NULL)
2985 && ((((iwe->len - IW_EV_LCP_PK_LEN) % event_len) == 4)
2986 || ((iwe->len == 12) && ((event_type == IW_HEADER_TYPE_UINT) ||
2987 (event_type == IW_HEADER_TYPE_QUAL))) ))
2990 printf("DBG - alt iwe->len = %d\n", iwe->len - 4);
2992 pointer -= event_len;
2994 /* Beware of alignement. Dest has local alignement, not packed */
2995 memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
2996 pointer += event_len;
2999 /* Is there more value in the event ? */
3000 if((pointer + event_len) <= (stream->current + iwe->len))
3001 /* Go to next value */
3002 stream->value = pointer;
3005 /* Go to next event */
3006 stream->value = NULL;
3007 stream->current += iwe->len;
3013 /*********************** SCANNING SUBROUTINES ***********************/
3015 * The Wireless Extension API 14 and greater define Wireless Scanning.
3016 * The normal API is complex, this is an easy API that return
3017 * a subset of the scanning results. This should be enough for most
3018 * applications that want to use Scanning.
3019 * If you want to have use the full/normal API, check iwlist.c...
3021 * Precaution when using scanning :
3022 * The scanning operation disable normal network traffic, and therefore
3023 * you should not abuse of scan.
3024 * The scan need to check the presence of network on other frequencies.
3025 * While you are checking those other frequencies, you can *NOT* be on
3026 * your normal frequency to listen to normal traffic in the cell.
3027 * You need typically in the order of one second to actively probe all
3028 * 802.11b channels (do the maths). Some cards may do that in background,
3029 * to reply to scan commands faster, but they still have to do it.
3030 * Leaving the cell for such an extended period of time is pretty bad.
3031 * Any kind of streaming/low latency traffic will be impacted, and the
3032 * user will perceive it (easily checked with telnet). People trying to
3033 * send traffic to you will retry packets and waste bandwidth. Some
3034 * applications may be sensitive to those packet losses in weird ways,
3035 * and tracing those weird behavior back to scanning may take time.
3036 * If you are in ad-hoc mode, if two nodes scan approx at the same
3037 * time, they won't see each other, which may create associations issues.
3038 * For those reasons, the scanning activity should be limited to
3039 * what's really needed, and continuous scanning is a bad idea.
3043 /*------------------------------------------------------------------*/
3045 * Process/store one element from the scanning results in wireless_scan
3047 static inline struct wireless_scan *
3048 iw_process_scanning_token(struct iw_event * event,
3049 struct wireless_scan * wscan)
3051 struct wireless_scan * oldwscan;
3053 /* Now, let's decode the event */
3057 /* New cell description. Allocate new cell descriptor, zero it. */
3059 wscan = (struct wireless_scan *) malloc(sizeof(struct wireless_scan));
3062 /* Link at the end of the list */
3063 if(oldwscan != NULL)
3064 oldwscan->next = wscan;
3067 bzero(wscan, sizeof(struct wireless_scan));
3069 /* Save cell identifier */
3070 wscan->has_ap_addr = 1;
3071 memcpy(&(wscan->ap_addr), &(event->u.ap_addr), sizeof (sockaddr));
3074 wscan->b.has_nwid = 1;
3075 memcpy(&(wscan->b.nwid), &(event->u.nwid), sizeof(iwparam));
3078 wscan->b.has_freq = 1;
3079 wscan->b.freq = iw_freq2float(&(event->u.freq));
3080 wscan->b.freq_flags = event->u.freq.flags;
3083 wscan->b.mode = event->u.mode;
3084 if((wscan->b.mode < IW_NUM_OPER_MODE) && (wscan->b.mode >= 0))
3085 wscan->b.has_mode = 1;
3088 wscan->b.has_essid = 1;
3089 wscan->b.essid_on = event->u.data.flags;
3090 memset(wscan->b.essid, '\0', IW_ESSID_MAX_SIZE + 1);
3091 if((event->u.essid.pointer) && (event->u.essid.length))
3092 memcpy(wscan->b.essid, event->u.essid.pointer, event->u.essid.length);
3095 wscan->b.has_key = 1;
3096 wscan->b.key_size = event->u.data.length;
3097 wscan->b.key_flags = event->u.data.flags;
3098 if(event->u.data.pointer)
3099 memcpy(wscan->b.key, event->u.essid.pointer, event->u.data.length);
3101 wscan->b.key_flags |= IW_ENCODE_NOKEY;
3104 /* We don't get complete stats, only qual */
3105 wscan->has_stats = 1;
3106 memcpy(&wscan->stats.qual, &event->u.qual, sizeof(struct iw_quality));
3109 /* Scan may return a list of bitrates. As we have space for only
3110 * a single bitrate, we only keep the largest one. */
3111 if((!wscan->has_maxbitrate) ||
3112 (event->u.bitrate.value > wscan->maxbitrate.value))
3114 wscan->has_maxbitrate = 1;
3115 memcpy(&(wscan->maxbitrate), &(event->u.bitrate), sizeof(iwparam));
3118 /* How can we deal with those sanely ? Jean II */
3121 } /* switch(event->cmd) */
3126 /*------------------------------------------------------------------*/
3128 * Initiate the scan procedure, and process results.
3129 * This is a non-blocking procedure and it will return each time
3130 * it would block, returning the amount of time the caller should wait
3131 * before calling again.
3132 * Return -1 for error, delay to wait for (in ms), or 0 for success.
3133 * Error code is in errno
3136 iw_process_scan(int skfd,
3139 wireless_scan_head * context)
3142 unsigned char * buffer = NULL; /* Results */
3143 int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
3144 unsigned char * newbuf;
3146 /* Don't waste too much time on interfaces (150 * 100 = 15s) */
3148 if(context->retry > 150)
3154 /* If we have not yet initiated scanning on the interface */
3155 if(context->retry == 1)
3158 wrq.u.data.pointer = NULL; /* Later */
3159 wrq.u.data.flags = 0;
3160 wrq.u.data.length = 0;
3161 /* Remember that as non-root, we will get an EPERM here */
3162 if((iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0)
3163 && (errno != EPERM))
3165 /* Success : now, just wait for event or results */
3166 return(250); /* Wait 250 ms */
3170 /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
3171 newbuf = realloc(buffer, buflen);
3174 /* man says : If realloc() fails the original block is left untouched */
3182 /* Try to read the results */
3183 wrq.u.data.pointer = buffer;
3184 wrq.u.data.flags = 0;
3185 wrq.u.data.length = buflen;
3186 if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0)
3188 /* Check if buffer was too small (WE-17 only) */
3189 if((errno == E2BIG) && (we_version > 16) && (buflen < 0xFFFF))
3191 /* Some driver may return very large scan results, either
3192 * because there are many cells, or because they have many
3193 * large elements in cells (like IWEVCUSTOM). Most will
3194 * only need the regular sized buffer. We now use a dynamic
3195 * allocation of the buffer to satisfy everybody. Of course,
3196 * as we don't know in advance the size of the array, we try
3197 * various increasing sizes. Jean II */
3199 /* Check if the driver gave us any hints. */
3200 if(wrq.u.data.length > buflen)
3201 buflen = wrq.u.data.length;
3205 /* wrq.u.data.length is 16 bits so max size is 65535 */
3213 /* Check if results not available yet */
3217 /* Wait for only 100ms from now on */
3218 return(100); /* Wait 100 ms */
3222 /* Bad error, please don't come back... */
3226 /* We have the results, process them */
3227 if(wrq.u.data.length)
3229 struct iw_event iwe;
3230 struct stream_descr stream;
3231 struct wireless_scan * wscan = NULL;
3234 /* Debugging code. In theory useless, because it's debugged ;-) */
3236 printf("Scan result [%02X", buffer[0]);
3237 for(i = 1; i < wrq.u.data.length; i++)
3238 printf(":%02X", buffer[i]);
3243 iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
3244 /* This is dangerous, we may leak user data... */
3245 context->result = NULL;
3247 /* Look every token */
3250 /* Extract an event and print it */
3251 ret = iw_extract_event_stream(&stream, &iwe, we_version);
3254 /* Convert to wireless_scan struct */
3255 wscan = iw_process_scanning_token(&iwe, wscan);
3256 /* Check problems */
3263 /* Save head of list */
3264 if(context->result == NULL)
3265 context->result = wscan;
3271 /* Done with this interface - return success */
3276 /*------------------------------------------------------------------*/
3278 * Perform a wireless scan on the specified interface.
3279 * This is a blocking procedure and it will when the scan is completed
3280 * or when an error occur.
3282 * The scan results are given in a linked list of wireless_scan objects.
3283 * The caller *must* free the result himself (by walking the list).
3284 * If there is an error, -1 is returned and the error code is available
3287 * The parameter we_version can be extracted from the range structure
3288 * (range.we_version_compiled - see iw_get_range_info()), or using
3289 * iw_get_kernel_we_version(). For performance reason, you should
3290 * cache this parameter when possible rather than querying it every time.
3292 * Return -1 for error and 0 for success.
3298 wireless_scan_head * context)
3300 int delay; /* in ms */
3302 /* Clean up context. Potential memory leak if(context.result != NULL) */
3303 context->result = NULL;
3306 /* Wait until we get results or error */
3309 /* Try to get scan results */
3310 delay = iw_process_scan(skfd, ifname, we_version, context);
3312 /* Check termination */
3317 usleep(delay * 1000);
3320 /* End - return -1 or 0 */