4 * Jean II - HPLB 97->99 - HPL 99->07
6 * Common subroutines to all the wireless tools...
8 * This file is released under the GPL license.
9 * Copyright (c) 1997-2007 Jean Tourrilhes <jt@hpl.hp.com>
12 /***************************** INCLUDES *****************************/
14 #include "iwlib.h" /* 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)) - \
93 /**************************** VARIABLES ****************************/
95 /* Modes as human readable strings */
96 const char * const iw_operation_mode[] = { "Auto",
105 /* Modulations as human readable strings */
106 const struct iw_modul_descr iw_modul_list[] = {
107 /* Start with aggregate types, so that they display first */
108 { IW_MODUL_11AG, "11ag",
109 "IEEE 802.11a + 802.11g (2.4 & 5 GHz, up to 54 Mb/s)" },
110 { IW_MODUL_11AB, "11ab",
111 "IEEE 802.11a + 802.11b (2.4 & 5 GHz, up to 54 Mb/s)" },
112 { IW_MODUL_11G, "11g", "IEEE 802.11g (2.4 GHz, up to 54 Mb/s)" },
113 { IW_MODUL_11A, "11a", "IEEE 802.11a (5 GHz, up to 54 Mb/s)" },
114 { IW_MODUL_11B, "11b", "IEEE 802.11b (2.4 GHz, up to 11 Mb/s)" },
116 /* Proprietary aggregates */
117 { IW_MODUL_TURBO | IW_MODUL_11A, "turboa",
118 "Atheros turbo mode at 5 GHz (up to 108 Mb/s)" },
119 { IW_MODUL_TURBO | IW_MODUL_11G, "turbog",
120 "Atheros turbo mode at 2.4 GHz (up to 108 Mb/s)" },
121 { IW_MODUL_PBCC | IW_MODUL_11B, "11+",
122 "TI 802.11+ (2.4 GHz, up to 22 Mb/s)" },
124 /* Individual modulations */
125 { IW_MODUL_OFDM_G, "OFDMg",
126 "802.11g higher rates, OFDM at 2.4 GHz (up to 54 Mb/s)" },
127 { IW_MODUL_OFDM_A, "OFDMa", "802.11a, OFDM at 5 GHz (up to 54 Mb/s)" },
128 { IW_MODUL_CCK, "CCK", "802.11b higher rates (2.4 GHz, up to 11 Mb/s)" },
129 { IW_MODUL_DS, "DS", "802.11 Direct Sequence (2.4 GHz, up to 2 Mb/s)" },
130 { IW_MODUL_FH, "FH", "802.11 Frequency Hopping (2,4 GHz, up to 2 Mb/s)" },
132 /* Proprietary modulations */
133 { IW_MODUL_TURBO, "turbo",
134 "Atheros turbo mode, channel bonding (up to 108 Mb/s)" },
135 { IW_MODUL_PBCC, "PBCC",
136 "TI 802.11+ higher rates (2.4 GHz, up to 22 Mb/s)" },
137 { IW_MODUL_CUSTOM, "custom",
138 "Driver specific modulation (check driver documentation)" },
141 /* Disable runtime version warning in iw_get_range_info() */
142 int iw_ignore_version = 0;
144 /************************ SOCKET SUBROUTINES *************************/
146 /*------------------------------------------------------------------*/
149 * Depending on the protocol present, open the right socket. The socket
150 * will allow us to talk to the driver.
153 iw_sockets_open(void)
155 static const int families[] = {
156 AF_INET, AF_IPX, AF_AX25, AF_APPLETALK
162 * Now pick any (exisiting) useful socket family for generic queries
163 * Note : don't open all the socket, only returns when one matches,
164 * all protocols might not be valid.
165 * Workaround by Jim Kaba <jkaba@sarnoff.com>
166 * Note : in 99% of the case, we will just open the inet_sock.
167 * The remaining 1% case are not fully correct...
170 /* Try all families we support */
171 for(i = 0; i < sizeof(families)/sizeof(int); ++i)
173 /* Try to open the socket, if success returns it */
174 sock = socket(families[i], SOCK_DGRAM, 0);
182 /*------------------------------------------------------------------*/
184 * Extract the interface name out of /proc/net/wireless or /proc/net/dev.
187 iw_get_ifname(char * name, /* Where to store the name */
188 int nsize, /* Size of name buffer */
189 char * buf) /* Current position in buffer */
193 /* Skip leading spaces */
197 #ifndef IW_RESTRIC_ENUM
198 /* Get name up to the last ':'. Aliases may contain ':' in them,
199 * but the last one should be the separator */
200 end = strrchr(buf, ':');
202 /* Get name up to ": "
203 * Note : we compare to ": " to make sure to process aliased interfaces
204 * properly. Doesn't work on /proc/net/dev, because it doesn't guarantee
205 * a ' ' after the ':'*/
206 end = strstr(buf, ": ");
209 /* Not found ??? To big ??? */
210 if((end == NULL) || (((end - buf) + 1) > nsize))
214 memcpy(name, buf, (end - buf));
215 name[end - buf] = '\0';
217 /* Return value currently unused, just make sure it's non-NULL */
221 /*------------------------------------------------------------------*/
223 * Enumerate devices and call specified routine
224 * The new way just use /proc/net/wireless, so get all wireless interfaces,
225 * whether configured or not. This is the default if available.
226 * The old way use SIOCGIFCONF, so get only configured interfaces (wireless
230 iw_enum_devices(int skfd,
241 #ifndef IW_RESTRIC_ENUM
242 /* Check if /proc/net/dev is available */
243 fh = fopen(PROC_NET_DEV, "r");
245 /* Check if /proc/net/wireless is available */
246 fh = fopen(PROC_NET_WIRELESS, "r");
251 /* Success : use data from /proc/net/wireless */
253 /* Eat 2 lines of header */
254 fgets(buff, sizeof(buff), fh);
255 fgets(buff, sizeof(buff), fh);
257 /* Read each device line */
258 while(fgets(buff, sizeof(buff), fh))
260 char name[IFNAMSIZ + 1];
263 /* Skip empty or almost empty lines. It seems that in some
264 * cases fgets return a line with only a newline. */
265 if((buff[0] == '\0') || (buff[1] == '\0'))
268 /* Extract interface name */
269 s = iw_get_ifname(name, sizeof(name), buff);
273 /* Failed to parse, complain and continue */
274 #ifndef IW_RESTRIC_ENUM
275 fprintf(stderr, "Cannot parse " PROC_NET_DEV "\n");
277 fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
281 /* Got it, print info about this interface */
282 (*fn)(skfd, name, args, count);
289 /* Get list of configured devices using "traditional" way */
290 ifc.ifc_len = sizeof(buff);
292 if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
294 fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
300 for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
301 (*fn)(skfd, ifr->ifr_name, args, count);
305 /*********************** WIRELESS SUBROUTINES ************************/
307 /*------------------------------------------------------------------*/
309 * Extract WE version number from /proc/net/wireless
310 * In most cases, you really want to get version information from
311 * the range info (range->we_version_compiled), see below...
313 * If we have WE-16 and later, the WE version is available at the
314 * end of the header line of the file.
315 * For version prior to that, we can only detect the change from
316 * v11 to v12, so we do an approximate job. Fortunately, v12 to v15
317 * are highly binary compatible (on the struct level).
320 iw_get_kernel_we_version(void)
327 /* Check if /proc/net/wireless is available */
328 fh = fopen(PROC_NET_WIRELESS, "r");
332 fprintf(stderr, "Cannot read " PROC_NET_WIRELESS "\n");
336 /* Read the first line of buffer */
337 fgets(buff, sizeof(buff), fh);
339 if(strstr(buff, "| WE") == NULL)
341 /* Prior to WE16, so explicit version not present */
344 if(strstr(buff, "| Missed") == NULL)
352 /* Read the second line of buffer */
353 fgets(buff, sizeof(buff), fh);
355 /* Get to the last separator, to get the version */
356 p = strrchr(buff, '|');
357 if((p == NULL) || (sscanf(p + 1, "%d", &v) != 1))
359 fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
368 /*------------------------------------------------------------------*/
370 * Print the WE versions of the interface.
373 print_iface_version_info(int skfd,
375 char * args[], /* Command line args */
376 int count) /* Args count */
379 char buffer[sizeof(iwrange) * 2]; /* Large enough */
380 struct iw_range * range;
382 /* Avoid "Unused parameter" warning */
383 args = args; count = count;
385 /* If no wireless name : no wireless extensions.
386 * This enable us to treat the SIOCGIWRANGE failure below properly. */
387 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
391 memset(buffer, 0, sizeof(buffer));
393 wrq.u.data.pointer = (caddr_t) buffer;
394 wrq.u.data.length = sizeof(buffer);
395 wrq.u.data.flags = 0;
396 if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
398 /* Interface support WE (see above), but not IWRANGE */
399 fprintf(stderr, "%-8.16s Driver has no Wireless Extension version information.\n\n", ifname);
403 /* Copy stuff at the right place, ignore extra */
404 range = (struct iw_range *) buffer;
406 /* For new versions, we can check the version directly, for old versions
407 * we use magic. 300 bytes is a also magic number, don't touch... */
408 if(wrq.u.data.length >= 300)
410 /* Version is always at the same offset, so it's ok */
411 printf("%-8.16s Recommend Wireless Extension v%d or later,\n",
412 ifname, range->we_version_source);
413 printf(" Currently compiled with Wireless Extension v%d.\n\n",
414 range->we_version_compiled);
418 fprintf(stderr, "%-8.16s Wireless Extension version too old.\n\n",
426 /*------------------------------------------------------------------*/
428 * Print the WE versions of the tools.
431 iw_print_version_info(const char * toolname)
433 int skfd; /* generic raw socket desc. */
434 int we_kernel_version;
436 /* Create a channel to the NET kernel. */
437 if((skfd = iw_sockets_open()) < 0)
443 /* Information about the tools themselves */
445 printf("%-8.16s Wireless-Tools version %d\n", toolname, WT_VERSION);
446 printf(" Compatible with Wireless Extension v11 to v%d.\n\n",
449 /* Get version from kernel */
450 we_kernel_version = iw_get_kernel_we_version();
451 /* Only version >= 16 can be verified, other are guessed */
452 if(we_kernel_version > 15)
453 printf("Kernel Currently compiled with Wireless Extension v%d.\n\n",
456 /* Version for each device */
457 iw_enum_devices(skfd, &print_iface_version_info, NULL, 0);
459 iw_sockets_close(skfd);
464 /*------------------------------------------------------------------*/
466 * Get the range information out of the driver
469 iw_get_range_info(int skfd,
474 char buffer[sizeof(iwrange) * 2]; /* Large enough */
475 union iw_range_raw * range_raw;
478 bzero(buffer, sizeof(buffer));
480 wrq.u.data.pointer = (caddr_t) buffer;
481 wrq.u.data.length = sizeof(buffer);
482 wrq.u.data.flags = 0;
483 if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
486 /* Point to the buffer */
487 range_raw = (union iw_range_raw *) buffer;
489 /* For new versions, we can check the version directly, for old versions
490 * we use magic. 300 bytes is a also magic number, don't touch... */
491 if(wrq.u.data.length < 300)
493 /* That's v10 or earlier. Ouch ! Let's make a guess...*/
494 range_raw->range.we_version_compiled = 9;
497 /* Check how it needs to be processed */
498 if(range_raw->range.we_version_compiled > 15)
500 /* This is our native format, that's easy... */
501 /* Copy stuff at the right place, ignore extra */
502 memcpy((char *) range, buffer, sizeof(iwrange));
506 /* Zero unknown fields */
507 bzero((char *) range, sizeof(struct iw_range));
509 /* Initial part unmoved */
510 memcpy((char *) range,
512 iwr15_off(num_channels));
513 /* Frequencies pushed futher down towards the end */
514 memcpy((char *) range + iwr_off(num_channels),
515 buffer + iwr15_off(num_channels),
516 iwr15_off(sensitivity) - iwr15_off(num_channels));
517 /* This one moved up */
518 memcpy((char *) range + iwr_off(sensitivity),
519 buffer + iwr15_off(sensitivity),
520 iwr15_off(num_bitrates) - iwr15_off(sensitivity));
521 /* This one goes after avg_qual */
522 memcpy((char *) range + iwr_off(num_bitrates),
523 buffer + iwr15_off(num_bitrates),
524 iwr15_off(min_rts) - iwr15_off(num_bitrates));
525 /* Number of bitrates has changed, put it after */
526 memcpy((char *) range + iwr_off(min_rts),
527 buffer + iwr15_off(min_rts),
528 iwr15_off(txpower_capa) - iwr15_off(min_rts));
529 /* Added encoding_login_index, put it after */
530 memcpy((char *) range + iwr_off(txpower_capa),
531 buffer + iwr15_off(txpower_capa),
532 iwr15_off(txpower) - iwr15_off(txpower_capa));
533 /* Hum... That's an unexpected glitch. Bummer. */
534 memcpy((char *) range + iwr_off(txpower),
535 buffer + iwr15_off(txpower),
536 iwr15_off(avg_qual) - iwr15_off(txpower));
537 /* Avg qual moved up next to max_qual */
538 memcpy((char *) range + iwr_off(avg_qual),
539 buffer + iwr15_off(avg_qual),
540 sizeof(struct iw_quality));
543 /* We are now checking much less than we used to do, because we can
544 * accomodate more WE version. But, there are still cases where things
546 if(!iw_ignore_version)
548 /* We don't like very old version (unfortunately kernel 2.2.X) */
549 if(range->we_version_compiled <= 10)
551 fprintf(stderr, "Warning: Driver for device %s has been compiled with an ancient version\n", ifname);
552 fprintf(stderr, "of Wireless Extension, while this program support version 11 and later.\n");
553 fprintf(stderr, "Some things may be broken...\n\n");
556 /* We don't like future versions of WE, because we can't cope with
558 if(range->we_version_compiled > WE_MAX_VERSION)
560 fprintf(stderr, "Warning: Driver for device %s has been compiled with version %d\n", ifname, range->we_version_compiled);
561 fprintf(stderr, "of Wireless Extension, while this program supports up to version %d.\n", WE_MAX_VERSION);
562 fprintf(stderr, "Some things may be broken...\n\n");
565 /* Driver version verification */
566 if((range->we_version_compiled > 10) &&
567 (range->we_version_compiled < range->we_version_source))
569 fprintf(stderr, "Warning: Driver for device %s recommend version %d of Wireless Extension,\n", ifname, range->we_version_source);
570 fprintf(stderr, "but has been compiled with version %d, therefore some driver features\n", range->we_version_compiled);
571 fprintf(stderr, "may not be available...\n\n");
573 /* Note : we are only trying to catch compile difference, not source.
574 * If the driver source has not been updated to the latest, it doesn't
575 * matter because the new fields are set to zero */
578 /* Don't complain twice.
579 * In theory, the test apply to each individual driver, but usually
580 * all drivers are compiled from the same kernel. */
581 iw_ignore_version = 1;
586 /*------------------------------------------------------------------*/
588 * Get information about what private ioctls are supported by the driver
590 * Note : there is one danger using this function. If it return 0, you
591 * still need to free() the buffer. Beware.
594 iw_get_priv_info(int skfd,
599 iwprivargs * priv = NULL; /* Not allocated yet */
600 int maxpriv = 16; /* Minimum for compatibility WE<13 */
601 iwprivargs * newpriv;
603 /* Some driver may return a very large number of ioctls. Some
604 * others a very small number. We now use a dynamic allocation
605 * of the array to satisfy everybody. Of course, as we don't know
606 * in advance the size of the array, we try various increasing
610 /* (Re)allocate the buffer */
611 newpriv = realloc(priv, maxpriv * sizeof(priv[0]));
614 fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
619 /* Ask the driver if it's large enough */
620 wrq.u.data.pointer = (caddr_t) priv;
621 wrq.u.data.length = maxpriv;
622 wrq.u.data.flags = 0;
623 if(iw_get_ext(skfd, ifname, SIOCGIWPRIV, &wrq) >= 0)
625 /* Success. Pass the buffer by pointer */
627 /* Return the number of ioctls */
628 return(wrq.u.data.length);
631 /* Only E2BIG means the buffer was too small, abort on other errors */
634 /* Most likely "not supported". Don't barf. */
638 /* Failed. We probably need a bigger buffer. Check if the kernel
639 * gave us any hints. */
640 if(wrq.u.data.length > maxpriv)
641 maxpriv = wrq.u.data.length;
645 while(maxpriv < 1000);
655 /*------------------------------------------------------------------*/
657 * Get essential wireless config from the device driver
658 * We will call all the classical wireless ioctl on the driver through
659 * the socket to know what is supported and to get the settings...
660 * Note : compare to the version in iwconfig, we extract only
661 * what's *really* needed to configure a device...
664 iw_get_basic_config(int skfd,
666 wireless_config * info)
670 memset((char *) info, 0, sizeof(struct wireless_config));
672 /* Get wireless name */
673 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
674 /* If no wireless name : no wireless extensions */
678 strncpy(info->name, wrq.u.name, IFNAMSIZ);
679 info->name[IFNAMSIZ] = '\0';
683 if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) >= 0)
686 memcpy(&(info->nwid), &(wrq.u.nwid), sizeof(iwparam));
689 /* Get frequency / channel */
690 if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
693 info->freq = iw_freq2float(&(wrq.u.freq));
694 info->freq_flags = wrq.u.freq.flags;
697 /* Get encryption information */
698 wrq.u.data.pointer = (caddr_t) info->key;
699 wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
700 wrq.u.data.flags = 0;
701 if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
704 info->key_size = wrq.u.data.length;
705 info->key_flags = wrq.u.data.flags;
709 wrq.u.essid.pointer = (caddr_t) info->essid;
710 wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
711 wrq.u.essid.flags = 0;
712 if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) >= 0)
715 info->essid_on = wrq.u.data.flags;
718 /* Get operation mode */
719 if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) >= 0)
722 /* Note : event->u.mode is unsigned, no need to check <= 0 */
723 if(wrq.u.mode < IW_NUM_OPER_MODE)
724 info->mode = wrq.u.mode;
726 info->mode = IW_NUM_OPER_MODE; /* Unknown/bug */
732 /*------------------------------------------------------------------*/
734 * Set essential wireless config in the device driver
735 * We will call all the classical wireless ioctl on the driver through
736 * the socket to know what is supported and to set the settings...
737 * We support only the restricted set as above...
740 iw_set_basic_config(int skfd,
742 wireless_config * info)
747 /* Get wireless name (check if interface is valid) */
748 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
749 /* If no wireless name : no wireless extensions */
752 /* Set the current mode of operation
753 * Mode need to be first : some settings apply only in a specific mode
754 * (such as frequency).
758 strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
759 wrq.u.mode = info->mode;
761 if(iw_get_ext(skfd, ifname, SIOCSIWMODE, &wrq) < 0)
763 fprintf(stderr, "SIOCSIWMODE: %s\n", strerror(errno));
768 /* Set frequency / channel */
771 iw_float2freq(info->freq, &(wrq.u.freq));
773 if(iw_set_ext(skfd, ifname, SIOCSIWFREQ, &wrq) < 0)
775 fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
780 /* Set encryption information */
783 int flags = info->key_flags;
785 /* Check if there is a key index */
786 if((flags & IW_ENCODE_INDEX) > 0)
789 wrq.u.data.pointer = (caddr_t) NULL;
790 wrq.u.data.flags = (flags & (IW_ENCODE_INDEX)) | IW_ENCODE_NOKEY;
791 wrq.u.data.length = 0;
793 if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
795 fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
796 errno, strerror(errno));
801 /* Mask out index to minimise probability of reject when setting key */
802 flags = flags & (~IW_ENCODE_INDEX);
804 /* Set the key itself (set current key in this case) */
805 wrq.u.data.pointer = (caddr_t) info->key;
806 wrq.u.data.length = info->key_size;
807 wrq.u.data.flags = flags;
809 /* Compatibility with WE<13 */
810 if(flags & IW_ENCODE_NOKEY)
811 wrq.u.data.pointer = NULL;
813 if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
815 fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
816 errno, strerror(errno));
821 /* Set Network ID, if available (this is for non-802.11 cards) */
824 memcpy(&(wrq.u.nwid), &(info->nwid), sizeof(iwparam));
825 wrq.u.nwid.fixed = 1; /* Hum... When in Rome... */
827 if(iw_set_ext(skfd, ifname, SIOCSIWNWID, &wrq) < 0)
829 fprintf(stderr, "SIOCSIWNWID: %s\n", strerror(errno));
834 /* Set ESSID (extended network), if available.
835 * ESSID need to be last : most device re-perform the scanning/discovery
836 * when this is set, and things like encryption keys are better be
837 * defined if we want to discover the right set of APs/nodes.
841 int we_kernel_version;
842 we_kernel_version = iw_get_kernel_we_version();
844 wrq.u.essid.pointer = (caddr_t) info->essid;
845 wrq.u.essid.length = strlen(info->essid);
846 wrq.u.data.flags = info->essid_on;
847 if(we_kernel_version < 21)
848 wrq.u.essid.length++;
850 if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0)
852 fprintf(stderr, "SIOCSIWESSID: %s\n", strerror(errno));
860 /*********************** PROTOCOL SUBROUTINES ***********************/
862 * Fun stuff with protocol identifiers (SIOCGIWNAME).
863 * We assume that drivers are returning sensible values in there,
864 * which is not always the case :-(
867 /*------------------------------------------------------------------*/
869 * Compare protocol identifiers.
870 * We don't want to know if the two protocols are the exactly same,
871 * but if they interoperate at some level, and also if they accept the
872 * same type of config (ESSID vs NWID, freq...).
873 * This is supposed to work around the alphabet soup.
874 * Return 1 if protocols are compatible, 0 otherwise
877 iw_protocol_compare(const char * protocol1,
878 const char * protocol2)
880 const char * dot11 = "IEEE 802.11";
881 const char * dot11_ds = "Dbg";
882 const char * dot11_5g = "a";
884 /* If the strings are the same -> easy */
885 if(!strncmp(protocol1, protocol2, IFNAMSIZ))
888 /* Are we dealing with one of the 802.11 variant ? */
889 if( (!strncmp(protocol1, dot11, strlen(dot11))) &&
890 (!strncmp(protocol2, dot11, strlen(dot11))) )
892 const char * sub1 = protocol1 + strlen(dot11);
893 const char * sub2 = protocol2 + strlen(dot11);
900 /* Check if we find the magic letters telling it's DS compatible */
901 for(i = 0; i < strlen(dot11_ds); i++)
903 if(strchr(sub1, dot11_ds[i]) != NULL)
905 if(strchr(sub2, dot11_ds[i]) != NULL)
911 /* Check if we find the magic letters telling it's 5GHz compatible */
912 for(i = 0; i < strlen(dot11_5g); i++)
914 if(strchr(sub1, dot11_5g[i]) != NULL)
916 if(strchr(sub2, dot11_5g[i]) != NULL)
926 /********************** FREQUENCY SUBROUTINES ***********************/
928 * Note : the two functions below are the cause of troubles on
929 * various embeeded platforms, as they are the reason we require
930 * libm (math library).
931 * In this case, please use enable BUILD_NOLIBM in the makefile
933 * FIXME : check negative mantissa and exponent
936 /*------------------------------------------------------------------*/
938 * Convert a floating point the our internal representation of
940 * The kernel doesn't want to hear about floating point, so we use
941 * this custom format instead.
944 iw_float2freq(double in,
948 /* Version without libm : slower */
956 #else /* WE_NOLIBM */
957 /* Version with libm : faster */
958 out->e = (short) (floor(log10(in)));
961 out->m = ((long) (floor(in / pow(10,out->e - 6)))) * 100;
969 #endif /* WE_NOLIBM */
972 /*------------------------------------------------------------------*/
974 * Convert our internal representation of frequencies to a floating point.
977 iw_freq2float(const iwfreq * in)
980 /* Version without libm : slower */
982 double res = (double) in->m;
983 for(i = 0; i < in->e; i++)
986 #else /* WE_NOLIBM */
987 /* Version with libm : faster */
988 return ((double) in->m) * pow(10,in->e);
989 #endif /* WE_NOLIBM */
992 /*------------------------------------------------------------------*/
994 * Output a frequency with proper scaling
997 iw_print_freq_value(char * buffer,
1002 snprintf(buffer, buflen, "%g", freq);
1026 snprintf(buffer, buflen, "%g %cHz", freq / divisor, scale);
1030 /*------------------------------------------------------------------*/
1032 * Output a frequency with proper scaling
1035 iw_print_freq(char * buffer,
1041 char sep = ((freq_flags & IW_FREQ_FIXED) ? '=' : ':');
1044 /* Print the frequency/channel value */
1045 iw_print_freq_value(vbuf, sizeof(vbuf), freq);
1047 /* Check if channel only */
1049 snprintf(buffer, buflen, "Channel%c%s", sep, vbuf);
1052 /* Frequency. Check if we have a channel as well */
1054 snprintf(buffer, buflen, "Frequency%c%s (Channel %d)",
1055 sep, vbuf, channel);
1057 snprintf(buffer, buflen, "Frequency%c%s", sep, vbuf);
1061 /*------------------------------------------------------------------*/
1063 * Convert a frequency to a channel (negative -> error)
1066 iw_freq_to_channel(double freq,
1067 const struct iw_range * range)
1072 /* Check if it's a frequency or not already a channel */
1076 /* We compare the frequencies as double to ignore differences
1077 * in encoding. Slower, but safer... */
1078 for(k = 0; k < range->num_frequency; k++)
1080 ref_freq = iw_freq2float(&(range->freq[k]));
1081 if(freq == ref_freq)
1082 return(range->freq[k].i);
1088 /*------------------------------------------------------------------*/
1090 * Convert a channel to a frequency (negative -> error)
1091 * Return the channel on success
1094 iw_channel_to_freq(int channel,
1096 const struct iw_range * range)
1101 /* Check if the driver support only channels or if it has frequencies */
1102 for(k = 0; k < range->num_frequency; k++)
1104 if((range->freq[k].e != 0) || (range->freq[k].m > (int) KILO))
1110 /* Find the correct frequency in the list */
1111 for(k = 0; k < range->num_frequency; k++)
1113 if(range->freq[k].i == channel)
1115 *pfreq = iw_freq2float(&(range->freq[k]));
1123 /*********************** BITRATE SUBROUTINES ***********************/
1125 /*------------------------------------------------------------------*/
1127 * Output a bitrate with proper scaling
1130 iw_print_bitrate(char * buffer,
1134 double rate = bitrate;
1156 snprintf(buffer, buflen, "%g %cb/s", rate / divisor, scale);
1159 /************************ POWER SUBROUTINES *************************/
1161 /*------------------------------------------------------------------*/
1163 * Convert a value in dBm to a value in milliWatt.
1166 iw_dbm2mwatt(int in)
1169 /* Version without libm : slower */
1175 /* Split integral and floating part to avoid accumulating rounding errors */
1176 for(k = 0; k < ip; k++)
1178 for(k = 0; k < fp; k++)
1181 #else /* WE_NOLIBM */
1182 /* Version with libm : faster */
1183 return((int) (floor(pow(10.0, (((double) in) / 10.0)))));
1184 #endif /* WE_NOLIBM */
1187 /*------------------------------------------------------------------*/
1189 * Convert a value in milliWatt to a value in dBm.
1192 iw_mwatt2dbm(int in)
1195 /* Version without libm : slower */
1196 double fin = (double) in;
1199 /* Split integral and floating part to avoid accumulating rounding errors */
1205 while(fin > 1.000001) /* Eliminate rounding errors, take ceil */
1211 #else /* WE_NOLIBM */
1212 /* Version with libm : faster */
1213 return((int) (ceil(10.0 * log10((double) in))));
1214 #endif /* WE_NOLIBM */
1217 /*------------------------------------------------------------------*/
1219 * Output a txpower with proper conversion
1222 iw_print_txpower(char * buffer,
1224 struct iw_param * txpower)
1228 /* Check if disabled */
1229 if(txpower->disabled)
1231 snprintf(buffer, buflen, "off");
1235 /* Check for relative values */
1236 if(txpower->flags & IW_TXPOW_RELATIVE)
1238 snprintf(buffer, buflen, "%d", txpower->value);
1242 /* Convert everything to dBm */
1243 if(txpower->flags & IW_TXPOW_MWATT)
1244 dbm = iw_mwatt2dbm(txpower->value);
1246 dbm = txpower->value;
1249 snprintf(buffer, buflen, "%d dBm", dbm);
1254 /********************** STATISTICS SUBROUTINES **********************/
1256 /*------------------------------------------------------------------*/
1258 * Read /proc/net/wireless to get the latest statistics
1259 * Note : strtok not thread safe, not used in WE-12 and later.
1262 iw_get_stats(int skfd,
1263 const char * ifname,
1265 const iwrange * range,
1268 /* Fortunately, we can always detect this condition properly */
1269 if((has_range) && (range->we_version_compiled > 11))
1272 wrq.u.data.pointer = (caddr_t) stats;
1273 wrq.u.data.length = sizeof(struct iw_statistics);
1274 wrq.u.data.flags = 1; /* Clear updated flag */
1275 strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
1276 if(iw_get_ext(skfd, ifname, SIOCGIWSTATS, &wrq) < 0)
1279 /* Format has not changed since WE-12, no conversion */
1284 FILE * f = fopen(PROC_NET_WIRELESS, "r");
1291 /* Loop on all devices */
1292 while(fgets(buf,255,f))
1295 while(*bp&&isspace(*bp))
1297 /* Is it the good device ? */
1298 if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':')
1304 bp = strtok(bp, " ");
1305 sscanf(bp, "%X", &t);
1306 stats->status = (unsigned short) t;
1307 /* -- link quality -- */
1308 bp = strtok(NULL, " ");
1309 if(strchr(bp,'.') != NULL)
1310 stats->qual.updated |= 1;
1311 sscanf(bp, "%d", &t);
1312 stats->qual.qual = (unsigned char) t;
1313 /* -- signal level -- */
1314 bp = strtok(NULL, " ");
1315 if(strchr(bp,'.') != NULL)
1316 stats->qual.updated |= 2;
1317 sscanf(bp, "%d", &t);
1318 stats->qual.level = (unsigned char) t;
1319 /* -- noise level -- */
1320 bp = strtok(NULL, " ");
1321 if(strchr(bp,'.') != NULL)
1322 stats->qual.updated += 4;
1323 sscanf(bp, "%d", &t);
1324 stats->qual.noise = (unsigned char) t;
1325 /* -- discarded packets -- */
1326 bp = strtok(NULL, " ");
1327 sscanf(bp, "%d", &stats->discard.nwid);
1328 bp = strtok(NULL, " ");
1329 sscanf(bp, "%d", &stats->discard.code);
1330 bp = strtok(NULL, " ");
1331 sscanf(bp, "%d", &stats->discard.misc);
1333 /* No conversion needed */
1342 /*------------------------------------------------------------------*/
1344 * Output the link statistics, taking care of formating
1347 iw_print_stats(char * buffer,
1349 const iwqual * qual,
1350 const iwrange * range,
1355 /* People are very often confused by the 8 bit arithmetic happening
1357 * All the values here are encoded in a 8 bit integer. 8 bit integers
1358 * are either unsigned [0 ; 255], signed [-128 ; +127] or
1359 * negative [-255 ; 0].
1360 * Further, on 8 bits, 0x100 == 256 == 0.
1362 * Relative/percent values are always encoded unsigned, between 0 and 255.
1363 * Absolute/dBm values are always encoded between -192 and 63.
1364 * (Note that up to version 28 of Wireless Tools, dBm used to be
1365 * encoded always negative, between -256 and -1).
1367 * How do we separate relative from absolute values ?
1368 * The old way is to use the range to do that. As of WE-19, we have
1369 * an explicit IW_QUAL_DBM flag in updated...
1370 * The range allow to specify the real min/max of the value. As the
1371 * range struct only specify one bound of the value, we assume that
1372 * the other bound is 0 (zero).
1373 * For relative values, range is [0 ; range->max].
1374 * For absolute values, range is [range->max ; 63].
1376 * Let's take two example :
1377 * 1) value is 75%. qual->value = 75 ; range->max_qual.value = 100
1378 * 2) value is -54dBm. noise floor of the radio is -104dBm.
1379 * qual->value = -54 = 202 ; range->max_qual.value = -104 = 152
1385 * The old way to detect dBm require both the range and a non-null
1386 * level (which confuse the test). The new way can deal with level of 0
1387 * because it does an explicit test on the flag. */
1388 if(has_range && ((qual->level != 0)
1389 || (qual->updated & (IW_QUAL_DBM | IW_QUAL_RCPI))))
1391 /* Deal with quality : always a relative value */
1392 if(!(qual->updated & IW_QUAL_QUAL_INVALID))
1394 len = snprintf(buffer, buflen, "Quality%c%d/%d ",
1395 qual->updated & IW_QUAL_QUAL_UPDATED ? '=' : ':',
1396 qual->qual, range->max_qual.qual);
1401 /* Check if the statistics are in RCPI (IEEE 802.11k) */
1402 if(qual->updated & IW_QUAL_RCPI)
1404 /* Deal with signal level in RCPI */
1405 /* RCPI = int{(Power in dBm +110)*2} for 0dbm > Power > -110dBm */
1406 if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1408 double rcpilevel = (qual->level / 2.0) - 110.0;
1409 len = snprintf(buffer, buflen, "Signal level%c%g dBm ",
1410 qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1416 /* Deal with noise level in dBm (absolute power measurement) */
1417 if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1419 double rcpinoise = (qual->noise / 2.0) - 110.0;
1420 len = snprintf(buffer, buflen, "Noise level%c%g dBm",
1421 qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1427 /* Check if the statistics are in dBm */
1428 if((qual->updated & IW_QUAL_DBM)
1429 || (qual->level > range->max_qual.level))
1431 /* Deal with signal level in dBm (absolute power measurement) */
1432 if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1434 int dblevel = qual->level;
1435 /* Implement a range for dBm [-192; 63] */
1436 if(qual->level >= 64)
1438 len = snprintf(buffer, buflen, "Signal level%c%d dBm ",
1439 qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1445 /* Deal with noise level in dBm (absolute power measurement) */
1446 if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1448 int dbnoise = qual->noise;
1449 /* Implement a range for dBm [-192; 63] */
1450 if(qual->noise >= 64)
1452 len = snprintf(buffer, buflen, "Noise level%c%d dBm",
1453 qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1459 /* Deal with signal level as relative value (0 -> max) */
1460 if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1462 len = snprintf(buffer, buflen, "Signal level%c%d/%d ",
1463 qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1464 qual->level, range->max_qual.level);
1469 /* Deal with noise level as relative value (0 -> max) */
1470 if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1472 len = snprintf(buffer, buflen, "Noise level%c%d/%d",
1473 qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1474 qual->noise, range->max_qual.noise);
1481 /* We can't read the range, so we don't know... */
1482 snprintf(buffer, buflen,
1483 "Quality:%d Signal level:%d Noise level:%d",
1484 qual->qual, qual->level, qual->noise);
1488 /*********************** ENCODING SUBROUTINES ***********************/
1490 /*------------------------------------------------------------------*/
1492 * Output the encoding key, with a nice formating
1495 iw_print_key(char * buffer,
1497 const unsigned char * key, /* Must be unsigned */
1503 /* Check buffer size -> 1 bytes => 2 digits + 1/2 separator */
1504 if((key_size * 3) > buflen)
1506 snprintf(buffer, buflen, "<too big>");
1510 /* Is the key present ??? */
1511 if(key_flags & IW_ENCODE_NOKEY)
1513 /* Nope : print on or dummy */
1515 strcpy(buffer, "on"); /* Size checked */
1518 strcpy(buffer, "**"); /* Size checked */
1520 for(i = 1; i < key_size; i++)
1523 strcpy(buffer++, "-"); /* Size checked */
1524 strcpy(buffer, "**"); /* Size checked */
1531 /* Yes : print the key */
1532 sprintf(buffer, "%.2X", key[0]); /* Size checked */
1534 for(i = 1; i < key_size; i++)
1537 strcpy(buffer++, "-"); /* Size checked */
1538 sprintf(buffer, "%.2X", key[i]); /* Size checked */
1544 /*------------------------------------------------------------------*/
1546 * Convert a passphrase into a key
1547 * ### NOT IMPLEMENTED ###
1548 * Return size of the key, or 0 (no key) or -1 (error)
1551 iw_pass_key(const char * input,
1552 unsigned char * key)
1554 input = input; key = key;
1555 fprintf(stderr, "Error: Passphrase not implemented\n");
1559 /*------------------------------------------------------------------*/
1561 * Parse a key from the command line.
1562 * Return size of the key, or 0 (no key) or -1 (error)
1563 * If the key is too long, it's simply truncated...
1566 iw_in_key(const char * input,
1567 unsigned char * key)
1571 /* Check the type of key */
1572 if(!strncmp(input, "s:", 2))
1574 /* First case : as an ASCII string (Lucent/Agere cards) */
1575 keylen = strlen(input + 2); /* skip "s:" */
1576 if(keylen > IW_ENCODING_TOKEN_MAX)
1577 keylen = IW_ENCODING_TOKEN_MAX;
1578 memcpy(key, input + 2, keylen);
1581 if(!strncmp(input, "p:", 2))
1583 /* Second case : as a passphrase (PrismII cards) */
1584 return(iw_pass_key(input + 2, key)); /* skip "p:" */
1589 int dlen; /* Digits sequence length */
1590 unsigned char out[IW_ENCODING_TOKEN_MAX];
1592 /* Third case : as hexadecimal digits */
1596 /* Loop until we run out of chars in input or overflow the output */
1602 /* No more chars in this sequence */
1605 /* Skip separator */
1608 /* Calculate num of char to next separator */
1609 dlen = strcspn(p, "-:;.,");
1611 /* Get each char separatly (and not by two) so that we don't
1612 * get confused by 'enc' (=> '0E'+'0C') and similar */
1613 count = sscanf(p, "%1X%1X", &temph, &templ);
1615 return(-1); /* Error -> non-hex char */
1616 /* Fixup odd strings such as '123' is '01'+'23' and not '12'+'03'*/
1619 /* Put back two chars as one byte and output */
1621 templ |= temph << 4;
1624 out[keylen++] = (unsigned char) (templ & 0xFF);
1625 /* Check overflow in output */
1626 if(keylen >= IW_ENCODING_TOKEN_MAX)
1628 /* Move on to next chars */
1632 /* We use a temporary output buffer 'out' so that if there is
1633 * an error, we don't overwrite the original key buffer.
1634 * Because of the way iwconfig loop on multiple key/enc arguments
1635 * until it finds an error in here, this is necessary to avoid
1636 * silently corrupting the encryption key... */
1637 memcpy(key, out, keylen);
1642 char buf[IW_ENCODING_TOKEN_MAX * 3];
1643 iw_print_key(buf, sizeof(buf), key, keylen, 0);
1644 printf("Got key : %d [%s]\n", keylen, buf);
1651 /*------------------------------------------------------------------*/
1653 * Parse a key from the command line.
1654 * Return size of the key, or 0 (no key) or -1 (error)
1657 iw_in_key_full(int skfd,
1658 const char * ifname,
1660 unsigned char * key,
1666 if(!strncmp(input, "l:", 2))
1668 struct iw_range range;
1670 /* Extra case : as a login (user:passwd - Cisco LEAP) */
1671 keylen = strlen(input + 2) + 1; /* skip "l:", add '\0' */
1672 /* Most user/password is 8 char, so 18 char total, < 32 */
1673 if(keylen > IW_ENCODING_TOKEN_MAX)
1674 keylen = IW_ENCODING_TOKEN_MAX;
1675 memcpy(key, input + 2, keylen);
1677 /* Separate the two strings */
1678 p = strchr((char *) key, ':');
1681 fprintf(stderr, "Error: Invalid login format\n");
1686 /* Extract range info */
1687 if(iw_get_range_info(skfd, ifname, &range) < 0)
1688 /* Hum... Maybe we should return an error ??? */
1689 memset(&range, 0, sizeof(range));
1691 if(range.we_version_compiled > 15)
1694 printf("flags = %X, index = %X\n",
1695 *flags, range.encoding_login_index);
1696 if((*flags & IW_ENCODE_INDEX) == 0)
1698 /* Extract range info */
1699 if(iw_get_range_info(skfd, ifname, &range) < 0)
1700 memset(&range, 0, sizeof(range));
1701 printf("flags = %X, index = %X\n", *flags, range.encoding_login_index);
1702 /* Set the index the driver expects */
1703 *flags |= range.encoding_login_index & IW_ENCODE_INDEX;
1705 printf("flags = %X, index = %X\n", *flags, range.encoding_login_index);
1709 /* Simpler routine above */
1710 keylen = iw_in_key(input, key);
1715 /******************* POWER MANAGEMENT SUBROUTINES *******************/
1717 /*------------------------------------------------------------------*/
1719 * Output a power management value with all attributes...
1722 iw_print_pm_value(char * buffer,
1731 snprintf(buffer, buflen, "<too big>");
1737 if(flags & IW_POWER_MIN)
1739 strcpy(buffer, " min"); /* Size checked */
1742 if(flags & IW_POWER_MAX)
1744 strcpy(buffer, " max"); /* Size checked */
1749 if(flags & IW_POWER_TIMEOUT)
1751 strcpy(buffer, " timeout:"); /* Size checked */
1756 if(flags & IW_POWER_SAVING)
1758 strcpy(buffer, " saving:"); /* Size checked */
1763 strcpy(buffer, " period:"); /* Size checked */
1768 /* Display value without units */
1769 if(flags & IW_POWER_RELATIVE)
1773 snprintf(buffer, buflen, "%d", value);
1777 /* Display value with units */
1778 if(value >= (int) MEGA)
1779 snprintf(buffer, buflen, "%gs", ((double) value) / MEGA);
1781 if(value >= (int) KILO)
1782 snprintf(buffer, buflen, "%gms", ((double) value) / KILO);
1784 snprintf(buffer, buflen, "%dus", value);
1788 /*------------------------------------------------------------------*/
1790 * Output a power management mode
1793 iw_print_pm_mode(char * buffer,
1800 snprintf(buffer, buflen, "<too big>");
1804 /* Print the proper mode... */
1805 switch(flags & IW_POWER_MODE)
1807 case IW_POWER_UNICAST_R:
1808 strcpy(buffer, "mode:Unicast only received"); /* Size checked */
1810 case IW_POWER_MULTICAST_R:
1811 strcpy(buffer, "mode:Multicast only received"); /* Size checked */
1813 case IW_POWER_ALL_R:
1814 strcpy(buffer, "mode:All packets received"); /* Size checked */
1816 case IW_POWER_FORCE_S:
1817 strcpy(buffer, "mode:Force sending"); /* Size checked */
1819 case IW_POWER_REPEATER:
1820 strcpy(buffer, "mode:Repeat multicasts"); /* Size checked */
1823 strcpy(buffer, ""); /* Size checked */
1828 /***************** RETRY LIMIT/LIFETIME SUBROUTINES *****************/
1830 /*------------------------------------------------------------------*/
1832 * Output a retry value with all attributes...
1835 iw_print_retry_value(char * buffer,
1841 /* Check buffer size */
1844 snprintf(buffer, buflen, "<too big>");
1850 if(flags & IW_RETRY_MIN)
1852 strcpy(buffer, " min"); /* Size checked */
1855 if(flags & IW_RETRY_MAX)
1857 strcpy(buffer, " max"); /* Size checked */
1860 if(flags & IW_RETRY_SHORT)
1862 strcpy(buffer, " short"); /* Size checked */
1865 if(flags & IW_RETRY_LONG)
1867 strcpy(buffer, " long"); /* Size checked */
1871 /* Type lifetime of limit */
1872 if(flags & IW_RETRY_LIFETIME)
1874 strcpy(buffer, " lifetime:"); /* Size checked */
1877 /* Display value without units */
1878 if(flags & IW_RETRY_RELATIVE)
1882 snprintf(buffer, buflen, "%d", value);
1886 /* Display value with units */
1887 if(value >= (int) MEGA)
1888 snprintf(buffer, buflen, "%gs", ((double) value) / MEGA);
1890 if(value >= (int) KILO)
1891 snprintf(buffer, buflen, "%gms", ((double) value) / KILO);
1893 snprintf(buffer, buflen, "%dus", value);
1897 snprintf(buffer, buflen, " limit:%d", value);
1900 /************************* TIME SUBROUTINES *************************/
1902 /*------------------------------------------------------------------*/
1905 * Inspired from irdadump...
1908 iw_print_timeval(char * buffer,
1910 const struct timeval * timev,
1911 const struct timezone * tz)
1915 s = (timev->tv_sec - tz->tz_minuteswest * 60) % 86400;
1916 snprintf(buffer, buflen, "%02d:%02d:%02d.%06u",
1917 s / 3600, (s % 3600) / 60,
1918 s % 60, (u_int32_t) timev->tv_usec);
1921 /*********************** ADDRESS SUBROUTINES ************************/
1923 * This section is mostly a cut & past from net-tools-1.2.0
1924 * (Well... This has evolved over the years)
1925 * manage address display and input...
1928 /*------------------------------------------------------------------*/
1930 * Check if interface support the right MAC address type...
1933 iw_check_mac_addr_type(int skfd,
1934 const char * ifname)
1938 /* Get the type of hardware address */
1939 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
1940 if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) ||
1941 ((ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
1942 && (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211)))
1944 /* Deep trouble... */
1945 fprintf(stderr, "Interface %s doesn't support MAC addresses\n",
1953 printf("Hardware : %d - %s\n", ifr.ifr_hwaddr.sa_family,
1954 iw_saether_ntop(&ifr.ifr_hwaddr, buf));
1962 /*------------------------------------------------------------------*/
1964 * Check if interface support the right interface address type...
1967 iw_check_if_addr_type(int skfd,
1968 const char * ifname)
1972 /* Get the type of interface address */
1973 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
1974 if((ioctl(skfd, SIOCGIFADDR, &ifr) < 0) ||
1975 (ifr.ifr_addr.sa_family != AF_INET))
1977 /* Deep trouble... */
1978 fprintf(stderr, "Interface %s doesn't support IP addresses\n", ifname);
1983 printf("Interface : %d - 0x%lX\n", ifr.ifr_addr.sa_family,
1984 *((unsigned long *) ifr.ifr_addr.sa_data));
1991 /*------------------------------------------------------------------*/
1993 * Check if interface support the right address types...
1996 iw_check_addr_type(int skfd,
1999 /* Check the interface address type */
2000 if(iw_check_if_addr_type(skfd, ifname) < 0)
2003 /* Check the interface address type */
2004 if(iw_check_mac_addr_type(skfd, ifname) < 0)
2012 /*------------------------------------------------------------------*/
2014 * Ask the kernel for the MAC address of an interface.
2017 iw_get_mac_addr(int skfd,
2018 const char * ifname,
2019 struct ether_addr * eth,
2020 unsigned short * ptype)
2025 /* Prepare request */
2026 bzero(&ifr, sizeof(struct ifreq));
2027 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
2030 ret = ioctl(skfd, SIOCGIFHWADDR, &ifr);
2032 memcpy(eth->ether_addr_octet, ifr.ifr_hwaddr.sa_data, 6);
2033 *ptype = ifr.ifr_hwaddr.sa_family;
2038 /*------------------------------------------------------------------*/
2040 * Display an arbitrary length MAC address in readable format.
2043 iw_mac_ntop(const unsigned char * mac,
2050 /* Overflow check (don't forget '\0') */
2051 if(buflen < (maclen * 3 - 1 + 1))
2055 sprintf(buf, "%02X", mac[0]);
2058 for(i = 1; i < maclen; i++)
2059 sprintf(buf + (i * 3) - 1, ":%02X", mac[i]);
2063 /*------------------------------------------------------------------*/
2065 * Display an Ethernet address in readable format.
2068 iw_ether_ntop(const struct ether_addr * eth,
2071 sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
2072 eth->ether_addr_octet[0], eth->ether_addr_octet[1],
2073 eth->ether_addr_octet[2], eth->ether_addr_octet[3],
2074 eth->ether_addr_octet[4], eth->ether_addr_octet[5]);
2077 /*------------------------------------------------------------------*/
2079 * Display an Wireless Access Point Socket Address in readable format.
2080 * Note : 0x44 is an accident of history, that's what the Orinoco/PrismII
2081 * chipset report, and the driver doesn't filter it.
2084 iw_sawap_ntop(const struct sockaddr * sap,
2087 const struct ether_addr ether_zero = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }};
2088 const struct ether_addr ether_bcast = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
2089 const struct ether_addr ether_hack = {{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }};
2090 const struct ether_addr * ether_wap = (const struct ether_addr *) sap->sa_data;
2092 if(!iw_ether_cmp(ether_wap, ðer_zero))
2093 sprintf(buf, "Not-Associated");
2095 if(!iw_ether_cmp(ether_wap, ðer_bcast))
2096 sprintf(buf, "Invalid");
2098 if(!iw_ether_cmp(ether_wap, ðer_hack))
2099 sprintf(buf, "None");
2101 iw_ether_ntop(ether_wap, buf);
2105 /*------------------------------------------------------------------*/
2107 * Input an arbitrary length MAC address and convert to binary.
2108 * Return address size.
2111 iw_mac_aton(const char * orig,
2112 unsigned char * mac,
2115 const char * p = orig;
2118 /* Loop on all bytes of the string */
2124 /* Extract one byte as two chars */
2125 count = sscanf(p, "%1X%1X", &temph, &templ);
2127 break; /* Error -> non-hex chars */
2128 /* Output two chars as one byte */
2129 templ |= temph << 4;
2130 mac[maclen++] = (unsigned char) (templ & 0xFF);
2132 /* Check end of string */
2138 iw_ether_ntop((const struct ether_addr *) mac, buf);
2139 fprintf(stderr, "iw_mac_aton(%s): %s\n", orig, buf);
2141 return(maclen); /* Normal exit */
2144 /* Check overflow */
2145 if(maclen >= macmax)
2148 fprintf(stderr, "iw_mac_aton(%s): trailing junk!\n", orig);
2151 return(0); /* Error -> overflow */
2154 /* Check separator */
2162 fprintf(stderr, "iw_mac_aton(%s): invalid ether address!\n", orig);
2168 /*------------------------------------------------------------------*/
2170 * Input an Ethernet address and convert to binary.
2173 iw_ether_aton(const char *orig, struct ether_addr *eth)
2176 maclen = iw_mac_aton(orig, (unsigned char *) eth, ETH_ALEN);
2177 if((maclen > 0) && (maclen < ETH_ALEN))
2185 /*------------------------------------------------------------------*/
2187 * Input an Internet address and convert to binary.
2190 iw_in_inet(char *name, struct sockaddr *sap)
2194 struct sockaddr_in *sain = (struct sockaddr_in *) sap;
2197 sain->sin_family = AF_INET;
2200 /* Default is special, meaning 0.0.0.0. */
2201 if (!strcmp(name, "default")) {
2202 sain->sin_addr.s_addr = INADDR_ANY;
2206 /* Try the NETWORKS database to see if this is a known network. */
2207 if ((np = getnetbyname(name)) != (struct netent *)NULL) {
2208 sain->sin_addr.s_addr = htonl(np->n_net);
2209 strcpy(name, np->n_name);
2213 /* Always use the resolver (DNS name + IP addresses) */
2214 if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
2218 memcpy((char *) &sain->sin_addr, (char *) hp->h_addr_list[0], hp->h_length);
2219 strcpy(name, hp->h_name);
2223 /*------------------------------------------------------------------*/
2225 * Input an address and convert to binary.
2228 iw_in_addr(int skfd,
2229 const char * ifname,
2231 struct sockaddr *sap)
2233 /* Check if it is a hardware or IP address */
2234 if(strchr(bufp, ':') == NULL)
2236 struct sockaddr if_address;
2237 struct arpreq arp_query;
2239 /* Check if we have valid interface address type */
2240 if(iw_check_if_addr_type(skfd, ifname) < 0)
2242 fprintf(stderr, "%-8.16s Interface doesn't support IP addresses\n", ifname);
2246 /* Read interface address */
2247 if(iw_in_inet(bufp, &if_address) < 0)
2249 fprintf(stderr, "Invalid interface address %s\n", bufp);
2253 /* Translate IP addresses to MAC addresses */
2254 memcpy((char *) &(arp_query.arp_pa),
2255 (char *) &if_address,
2256 sizeof(struct sockaddr));
2257 arp_query.arp_ha.sa_family = 0;
2258 arp_query.arp_flags = 0;
2259 /* The following restrict the search to the interface only */
2260 /* For old kernels which complain, just comment it... */
2261 strncpy(arp_query.arp_dev, ifname, IFNAMSIZ);
2262 if((ioctl(skfd, SIOCGARP, &arp_query) < 0) ||
2263 !(arp_query.arp_flags & ATF_COM))
2265 fprintf(stderr, "Arp failed for %s on %s... (%d)\nTry to ping the address before setting it.\n",
2266 bufp, ifname, errno);
2270 /* Store new MAC address */
2271 memcpy((char *) sap,
2272 (char *) &(arp_query.arp_ha),
2273 sizeof(struct sockaddr));
2278 printf("IP Address %s => Hw Address = %s\n",
2279 bufp, iw_saether_ntop(sap, buf));
2283 else /* If it's an hardware address */
2285 /* Check if we have valid mac address type */
2286 if(iw_check_mac_addr_type(skfd, ifname) < 0)
2288 fprintf(stderr, "%-8.16s Interface doesn't support MAC addresses\n", ifname);
2292 /* Get the hardware address */
2293 if(iw_saether_aton(bufp, sap) == 0)
2295 fprintf(stderr, "Invalid hardware address %s\n", bufp);
2303 printf("Hw Address = %s\n", iw_saether_ntop(sap, buf));
2310 /************************* MISC SUBROUTINES **************************/
2312 /* Size (in bytes) of various events */
2313 static const int priv_type_size[] = {
2314 0, /* IW_PRIV_TYPE_NONE */
2315 1, /* IW_PRIV_TYPE_BYTE */
2316 1, /* IW_PRIV_TYPE_CHAR */
2317 0, /* Not defined */
2318 sizeof(__u32), /* IW_PRIV_TYPE_INT */
2319 sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
2320 sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
2321 0, /* Not defined */
2324 /*------------------------------------------------------------------*/
2326 * Max size in bytes of an private argument.
2329 iw_get_priv_size(int args)
2331 int num = args & IW_PRIV_SIZE_MASK;
2332 int type = (args & IW_PRIV_TYPE_MASK) >> 12;
2334 return(num * priv_type_size[type]);
2337 /************************ EVENT SUBROUTINES ************************/
2339 * The Wireless Extension API 14 and greater define Wireless Events,
2340 * that are used for various events and scanning.
2341 * Those functions help the decoding of events, so are needed only in
2345 /* -------------------------- CONSTANTS -------------------------- */
2347 /* Type of headers we know about (basically union iwreq_data) */
2348 #define IW_HEADER_TYPE_NULL 0 /* Not available */
2349 #define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */
2350 #define IW_HEADER_TYPE_UINT 4 /* __u32 */
2351 #define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */
2352 #define IW_HEADER_TYPE_ADDR 6 /* struct sockaddr */
2353 #define IW_HEADER_TYPE_POINT 8 /* struct iw_point */
2354 #define IW_HEADER_TYPE_PARAM 9 /* struct iw_param */
2355 #define IW_HEADER_TYPE_QUAL 10 /* struct iw_quality */
2357 /* Handling flags */
2358 /* Most are not implemented. I just use them as a reminder of some
2359 * cool features we might need one day ;-) */
2360 #define IW_DESCR_FLAG_NONE 0x0000 /* Obvious */
2361 /* Wrapper level flags */
2362 #define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */
2363 #define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */
2364 #define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */
2365 /* SET : Omit payload from generated iwevent */
2366 #define IW_DESCR_FLAG_NOMAX 0x0008 /* GET : no limit on request size */
2367 /* Driver level flags */
2368 #define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */
2370 /* ---------------------------- TYPES ---------------------------- */
2373 * Describe how a standard IOCTL looks like.
2375 struct iw_ioctl_description
2377 __u8 header_type; /* NULL, iw_point or other */
2378 __u8 token_type; /* Future */
2379 __u16 token_size; /* Granularity of payload */
2380 __u16 min_tokens; /* Min acceptable token number */
2381 __u16 max_tokens; /* Max acceptable token number */
2382 __u32 flags; /* Special handling of the request */
2385 /* -------------------------- VARIABLES -------------------------- */
2388 * Meta-data about all the standard Wireless Extension request we
2391 static const struct iw_ioctl_description standard_ioctl_descr[] = {
2392 [SIOCSIWCOMMIT - SIOCIWFIRST] = {
2393 .header_type = IW_HEADER_TYPE_NULL,
2395 [SIOCGIWNAME - SIOCIWFIRST] = {
2396 .header_type = IW_HEADER_TYPE_CHAR,
2397 .flags = IW_DESCR_FLAG_DUMP,
2399 [SIOCSIWNWID - SIOCIWFIRST] = {
2400 .header_type = IW_HEADER_TYPE_PARAM,
2401 .flags = IW_DESCR_FLAG_EVENT,
2403 [SIOCGIWNWID - SIOCIWFIRST] = {
2404 .header_type = IW_HEADER_TYPE_PARAM,
2405 .flags = IW_DESCR_FLAG_DUMP,
2407 [SIOCSIWFREQ - SIOCIWFIRST] = {
2408 .header_type = IW_HEADER_TYPE_FREQ,
2409 .flags = IW_DESCR_FLAG_EVENT,
2411 [SIOCGIWFREQ - SIOCIWFIRST] = {
2412 .header_type = IW_HEADER_TYPE_FREQ,
2413 .flags = IW_DESCR_FLAG_DUMP,
2415 [SIOCSIWMODE - SIOCIWFIRST] = {
2416 .header_type = IW_HEADER_TYPE_UINT,
2417 .flags = IW_DESCR_FLAG_EVENT,
2419 [SIOCGIWMODE - SIOCIWFIRST] = {
2420 .header_type = IW_HEADER_TYPE_UINT,
2421 .flags = IW_DESCR_FLAG_DUMP,
2423 [SIOCSIWSENS - SIOCIWFIRST] = {
2424 .header_type = IW_HEADER_TYPE_PARAM,
2426 [SIOCGIWSENS - SIOCIWFIRST] = {
2427 .header_type = IW_HEADER_TYPE_PARAM,
2429 [SIOCSIWRANGE - SIOCIWFIRST] = {
2430 .header_type = IW_HEADER_TYPE_NULL,
2432 [SIOCGIWRANGE - SIOCIWFIRST] = {
2433 .header_type = IW_HEADER_TYPE_POINT,
2435 .max_tokens = sizeof(struct iw_range),
2436 .flags = IW_DESCR_FLAG_DUMP,
2438 [SIOCSIWPRIV - SIOCIWFIRST] = {
2439 .header_type = IW_HEADER_TYPE_NULL,
2441 [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */
2442 .header_type = IW_HEADER_TYPE_NULL,
2444 [SIOCSIWSTATS - SIOCIWFIRST] = {
2445 .header_type = IW_HEADER_TYPE_NULL,
2447 [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */
2448 .header_type = IW_HEADER_TYPE_NULL,
2449 .flags = IW_DESCR_FLAG_DUMP,
2451 [SIOCSIWSPY - SIOCIWFIRST] = {
2452 .header_type = IW_HEADER_TYPE_POINT,
2453 .token_size = sizeof(struct sockaddr),
2454 .max_tokens = IW_MAX_SPY,
2456 [SIOCGIWSPY - SIOCIWFIRST] = {
2457 .header_type = IW_HEADER_TYPE_POINT,
2458 .token_size = sizeof(struct sockaddr) +
2459 sizeof(struct iw_quality),
2460 .max_tokens = IW_MAX_SPY,
2462 [SIOCSIWTHRSPY - SIOCIWFIRST] = {
2463 .header_type = IW_HEADER_TYPE_POINT,
2464 .token_size = sizeof(struct iw_thrspy),
2468 [SIOCGIWTHRSPY - SIOCIWFIRST] = {
2469 .header_type = IW_HEADER_TYPE_POINT,
2470 .token_size = sizeof(struct iw_thrspy),
2474 [SIOCSIWAP - SIOCIWFIRST] = {
2475 .header_type = IW_HEADER_TYPE_ADDR,
2477 [SIOCGIWAP - SIOCIWFIRST] = {
2478 .header_type = IW_HEADER_TYPE_ADDR,
2479 .flags = IW_DESCR_FLAG_DUMP,
2481 [SIOCSIWMLME - SIOCIWFIRST] = {
2482 .header_type = IW_HEADER_TYPE_POINT,
2484 .min_tokens = sizeof(struct iw_mlme),
2485 .max_tokens = sizeof(struct iw_mlme),
2487 [SIOCGIWAPLIST - SIOCIWFIRST] = {
2488 .header_type = IW_HEADER_TYPE_POINT,
2489 .token_size = sizeof(struct sockaddr) +
2490 sizeof(struct iw_quality),
2491 .max_tokens = IW_MAX_AP,
2492 .flags = IW_DESCR_FLAG_NOMAX,
2494 [SIOCSIWSCAN - SIOCIWFIRST] = {
2495 .header_type = IW_HEADER_TYPE_POINT,
2498 .max_tokens = sizeof(struct iw_scan_req),
2500 [SIOCGIWSCAN - SIOCIWFIRST] = {
2501 .header_type = IW_HEADER_TYPE_POINT,
2503 .max_tokens = IW_SCAN_MAX_DATA,
2504 .flags = IW_DESCR_FLAG_NOMAX,
2506 [SIOCSIWESSID - SIOCIWFIRST] = {
2507 .header_type = IW_HEADER_TYPE_POINT,
2509 .max_tokens = IW_ESSID_MAX_SIZE + 1,
2510 .flags = IW_DESCR_FLAG_EVENT,
2512 [SIOCGIWESSID - SIOCIWFIRST] = {
2513 .header_type = IW_HEADER_TYPE_POINT,
2515 .max_tokens = IW_ESSID_MAX_SIZE + 1,
2516 .flags = IW_DESCR_FLAG_DUMP,
2518 [SIOCSIWNICKN - SIOCIWFIRST] = {
2519 .header_type = IW_HEADER_TYPE_POINT,
2521 .max_tokens = IW_ESSID_MAX_SIZE + 1,
2523 [SIOCGIWNICKN - SIOCIWFIRST] = {
2524 .header_type = IW_HEADER_TYPE_POINT,
2526 .max_tokens = IW_ESSID_MAX_SIZE + 1,
2528 [SIOCSIWRATE - SIOCIWFIRST] = {
2529 .header_type = IW_HEADER_TYPE_PARAM,
2531 [SIOCGIWRATE - SIOCIWFIRST] = {
2532 .header_type = IW_HEADER_TYPE_PARAM,
2534 [SIOCSIWRTS - SIOCIWFIRST] = {
2535 .header_type = IW_HEADER_TYPE_PARAM,
2537 [SIOCGIWRTS - SIOCIWFIRST] = {
2538 .header_type = IW_HEADER_TYPE_PARAM,
2540 [SIOCSIWFRAG - SIOCIWFIRST] = {
2541 .header_type = IW_HEADER_TYPE_PARAM,
2543 [SIOCGIWFRAG - SIOCIWFIRST] = {
2544 .header_type = IW_HEADER_TYPE_PARAM,
2546 [SIOCSIWTXPOW - SIOCIWFIRST] = {
2547 .header_type = IW_HEADER_TYPE_PARAM,
2549 [SIOCGIWTXPOW - SIOCIWFIRST] = {
2550 .header_type = IW_HEADER_TYPE_PARAM,
2552 [SIOCSIWRETRY - SIOCIWFIRST] = {
2553 .header_type = IW_HEADER_TYPE_PARAM,
2555 [SIOCGIWRETRY - SIOCIWFIRST] = {
2556 .header_type = IW_HEADER_TYPE_PARAM,
2558 [SIOCSIWENCODE - SIOCIWFIRST] = {
2559 .header_type = IW_HEADER_TYPE_POINT,
2561 .max_tokens = IW_ENCODING_TOKEN_MAX,
2562 .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
2564 [SIOCGIWENCODE - SIOCIWFIRST] = {
2565 .header_type = IW_HEADER_TYPE_POINT,
2567 .max_tokens = IW_ENCODING_TOKEN_MAX,
2568 .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
2570 [SIOCSIWPOWER - SIOCIWFIRST] = {
2571 .header_type = IW_HEADER_TYPE_PARAM,
2573 [SIOCGIWPOWER - SIOCIWFIRST] = {
2574 .header_type = IW_HEADER_TYPE_PARAM,
2576 [SIOCSIWMODUL - SIOCIWFIRST] = {
2577 .header_type = IW_HEADER_TYPE_PARAM,
2579 [SIOCGIWMODUL - SIOCIWFIRST] = {
2580 .header_type = IW_HEADER_TYPE_PARAM,
2582 [SIOCSIWGENIE - SIOCIWFIRST] = {
2583 .header_type = IW_HEADER_TYPE_POINT,
2585 .max_tokens = IW_GENERIC_IE_MAX,
2587 [SIOCGIWGENIE - SIOCIWFIRST] = {
2588 .header_type = IW_HEADER_TYPE_POINT,
2590 .max_tokens = IW_GENERIC_IE_MAX,
2592 [SIOCSIWAUTH - SIOCIWFIRST] = {
2593 .header_type = IW_HEADER_TYPE_PARAM,
2595 [SIOCGIWAUTH - SIOCIWFIRST] = {
2596 .header_type = IW_HEADER_TYPE_PARAM,
2598 [SIOCSIWENCODEEXT - SIOCIWFIRST] = {
2599 .header_type = IW_HEADER_TYPE_POINT,
2601 .min_tokens = sizeof(struct iw_encode_ext),
2602 .max_tokens = sizeof(struct iw_encode_ext) +
2603 IW_ENCODING_TOKEN_MAX,
2605 [SIOCGIWENCODEEXT - SIOCIWFIRST] = {
2606 .header_type = IW_HEADER_TYPE_POINT,
2608 .min_tokens = sizeof(struct iw_encode_ext),
2609 .max_tokens = sizeof(struct iw_encode_ext) +
2610 IW_ENCODING_TOKEN_MAX,
2612 [SIOCSIWPMKSA - SIOCIWFIRST] = {
2613 .header_type = IW_HEADER_TYPE_POINT,
2615 .min_tokens = sizeof(struct iw_pmksa),
2616 .max_tokens = sizeof(struct iw_pmksa),
2619 static const unsigned int standard_ioctl_num = (sizeof(standard_ioctl_descr) /
2620 sizeof(struct iw_ioctl_description));
2623 * Meta-data about all the additional standard Wireless Extension events
2626 static const struct iw_ioctl_description standard_event_descr[] = {
2627 [IWEVTXDROP - IWEVFIRST] = {
2628 .header_type = IW_HEADER_TYPE_ADDR,
2630 [IWEVQUAL - IWEVFIRST] = {
2631 .header_type = IW_HEADER_TYPE_QUAL,
2633 [IWEVCUSTOM - IWEVFIRST] = {
2634 .header_type = IW_HEADER_TYPE_POINT,
2636 .max_tokens = IW_CUSTOM_MAX,
2638 [IWEVREGISTERED - IWEVFIRST] = {
2639 .header_type = IW_HEADER_TYPE_ADDR,
2641 [IWEVEXPIRED - IWEVFIRST] = {
2642 .header_type = IW_HEADER_TYPE_ADDR,
2644 [IWEVGENIE - IWEVFIRST] = {
2645 .header_type = IW_HEADER_TYPE_POINT,
2647 .max_tokens = IW_GENERIC_IE_MAX,
2649 [IWEVMICHAELMICFAILURE - IWEVFIRST] = {
2650 .header_type = IW_HEADER_TYPE_POINT,
2652 .max_tokens = sizeof(struct iw_michaelmicfailure),
2654 [IWEVASSOCREQIE - IWEVFIRST] = {
2655 .header_type = IW_HEADER_TYPE_POINT,
2657 .max_tokens = IW_GENERIC_IE_MAX,
2659 [IWEVASSOCRESPIE - IWEVFIRST] = {
2660 .header_type = IW_HEADER_TYPE_POINT,
2662 .max_tokens = IW_GENERIC_IE_MAX,
2664 [IWEVPMKIDCAND - IWEVFIRST] = {
2665 .header_type = IW_HEADER_TYPE_POINT,
2667 .max_tokens = sizeof(struct iw_pmkid_cand),
2670 static const unsigned int standard_event_num = (sizeof(standard_event_descr) /
2671 sizeof(struct iw_ioctl_description));
2673 /* Size (in bytes) of various events */
2674 static const int event_type_size[] = {
2675 IW_EV_LCP_PK_LEN, /* IW_HEADER_TYPE_NULL */
2677 IW_EV_CHAR_PK_LEN, /* IW_HEADER_TYPE_CHAR */
2679 IW_EV_UINT_PK_LEN, /* IW_HEADER_TYPE_UINT */
2680 IW_EV_FREQ_PK_LEN, /* IW_HEADER_TYPE_FREQ */
2681 IW_EV_ADDR_PK_LEN, /* IW_HEADER_TYPE_ADDR */
2683 IW_EV_POINT_PK_LEN, /* Without variable payload */
2684 IW_EV_PARAM_PK_LEN, /* IW_HEADER_TYPE_PARAM */
2685 IW_EV_QUAL_PK_LEN, /* IW_HEADER_TYPE_QUAL */
2688 /*------------------------------------------------------------------*/
2690 * Initialise the struct stream_descr so that we can extract
2691 * individual events from the event stream.
2694 iw_init_event_stream(struct stream_descr * stream, /* Stream of events */
2699 memset((char *) stream, '\0', sizeof(struct stream_descr));
2702 stream->current = data;
2703 stream->end = data + len;
2706 /*------------------------------------------------------------------*/
2708 * Extract the next event from the event stream.
2711 iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */
2712 struct iw_event * iwe, /* Extracted event */
2715 const struct iw_ioctl_description * descr = NULL;
2717 unsigned int event_len = 1; /* Invalid */
2719 /* Don't "optimise" the following variable, it will crash */
2720 unsigned cmd_index; /* *MUST* be unsigned */
2722 /* Check for end of stream */
2723 if((stream->current + IW_EV_LCP_PK_LEN) > stream->end)
2727 printf("DBG - stream->current = %p, stream->value = %p, stream->end = %p\n",
2728 stream->current, stream->value, stream->end);
2731 /* Extract the event header (to get the event id).
2732 * Note : the event may be unaligned, therefore copy... */
2733 memcpy((char *) iwe, stream->current, IW_EV_LCP_PK_LEN);
2736 printf("DBG - iwe->cmd = 0x%X, iwe->len = %d\n",
2737 iwe->cmd, iwe->len);
2740 /* Check invalid events */
2741 if(iwe->len <= IW_EV_LCP_PK_LEN)
2744 /* Get the type and length of that event */
2745 if(iwe->cmd <= SIOCIWLAST)
2747 cmd_index = iwe->cmd - SIOCIWFIRST;
2748 if(cmd_index < standard_ioctl_num)
2749 descr = &(standard_ioctl_descr[cmd_index]);
2753 cmd_index = iwe->cmd - IWEVFIRST;
2754 if(cmd_index < standard_event_num)
2755 descr = &(standard_event_descr[cmd_index]);
2758 event_type = descr->header_type;
2759 /* Unknown events -> event_type=0 => IW_EV_LCP_PK_LEN */
2760 event_len = event_type_size[event_type];
2761 /* Fixup for earlier version of WE */
2762 if((we_version <= 18) && (event_type == IW_HEADER_TYPE_POINT))
2763 event_len += IW_EV_POINT_OFF;
2765 /* Check if we know about this event */
2766 if(event_len <= IW_EV_LCP_PK_LEN)
2768 /* Skip to next event */
2769 stream->current += iwe->len;
2772 event_len -= IW_EV_LCP_PK_LEN;
2774 /* Set pointer on data */
2775 if(stream->value != NULL)
2776 pointer = stream->value; /* Next value in event */
2778 pointer = stream->current + IW_EV_LCP_PK_LEN; /* First value in event */
2781 printf("DBG - event_type = %d, event_len = %d, pointer = %p\n",
2782 event_type, event_len, pointer);
2785 /* Copy the rest of the event (at least, fixed part) */
2786 if((pointer + event_len) > stream->end)
2788 /* Go to next event */
2789 stream->current += iwe->len;
2792 /* Fixup for WE-19 and later : pointer no longer in the stream */
2793 /* Beware of alignement. Dest has local alignement, not packed */
2794 if((we_version > 18) && (event_type == IW_HEADER_TYPE_POINT))
2795 memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
2796 pointer, event_len);
2798 memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
2800 /* Skip event in the stream */
2801 pointer += event_len;
2803 /* Special processing for iw_point events */
2804 if(event_type == IW_HEADER_TYPE_POINT)
2806 /* Check the length of the payload */
2807 unsigned int extra_len = iwe->len - (event_len + IW_EV_LCP_PK_LEN);
2810 /* Set pointer on variable part (warning : non aligned) */
2811 iwe->u.data.pointer = pointer;
2813 /* Check that we have a descriptor for the command */
2815 /* Can't check payload -> unsafe... */
2816 iwe->u.data.pointer = NULL; /* Discard paylod */
2819 /* Those checks are actually pretty hard to trigger,
2820 * because of the checks done in the kernel... */
2822 unsigned int token_len = iwe->u.data.length * descr->token_size;
2824 /* Ugly fixup for alignement issues.
2825 * If the kernel is 64 bits and userspace 32 bits,
2826 * we have an extra 4+4 bytes.
2827 * Fixing that in the kernel would break 64 bits userspace. */
2828 if((token_len != extra_len) && (extra_len >= 4))
2830 __u16 alt_dlen = *((__u16 *) pointer);
2831 unsigned int alt_token_len = alt_dlen * descr->token_size;
2832 if((alt_token_len + 8) == extra_len)
2835 printf("DBG - alt_token_len = %d\n", alt_token_len);
2837 /* Ok, let's redo everything */
2838 pointer -= event_len;
2840 /* Dest has local alignement, not packed */
2841 memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
2842 pointer, event_len);
2843 pointer += event_len + 4;
2844 iwe->u.data.pointer = pointer;
2845 token_len = alt_token_len;
2849 /* Discard bogus events which advertise more tokens than
2850 * what they carry... */
2851 if(token_len > extra_len)
2852 iwe->u.data.pointer = NULL; /* Discard paylod */
2853 /* Check that the advertised token size is not going to
2854 * produce buffer overflow to our caller... */
2855 if((iwe->u.data.length > descr->max_tokens)
2856 && !(descr->flags & IW_DESCR_FLAG_NOMAX))
2857 iwe->u.data.pointer = NULL; /* Discard paylod */
2858 /* Same for underflows... */
2859 if(iwe->u.data.length < descr->min_tokens)
2860 iwe->u.data.pointer = NULL; /* Discard paylod */
2862 printf("DBG - extra_len = %d, token_len = %d, token = %d, max = %d, min = %d\n",
2863 extra_len, token_len, iwe->u.data.length, descr->max_tokens, descr->min_tokens);
2869 iwe->u.data.pointer = NULL;
2871 /* Go to next event */
2872 stream->current += iwe->len;
2876 /* Ugly fixup for alignement issues.
2877 * If the kernel is 64 bits and userspace 32 bits,
2878 * we have an extra 4 bytes.
2879 * Fixing that in the kernel would break 64 bits userspace. */
2880 if((stream->value == NULL)
2881 && ((((iwe->len - IW_EV_LCP_PK_LEN) % event_len) == 4)
2882 || ((iwe->len == 12) && ((event_type == IW_HEADER_TYPE_UINT) ||
2883 (event_type == IW_HEADER_TYPE_QUAL))) ))
2886 printf("DBG - alt iwe->len = %d\n", iwe->len - 4);
2888 pointer -= event_len;
2890 /* Beware of alignement. Dest has local alignement, not packed */
2891 memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
2892 pointer += event_len;
2895 /* Is there more value in the event ? */
2896 if((pointer + event_len) <= (stream->current + iwe->len))
2897 /* Go to next value */
2898 stream->value = pointer;
2901 /* Go to next event */
2902 stream->value = NULL;
2903 stream->current += iwe->len;
2909 /*********************** SCANNING SUBROUTINES ***********************/
2911 * The Wireless Extension API 14 and greater define Wireless Scanning.
2912 * The normal API is complex, this is an easy API that return
2913 * a subset of the scanning results. This should be enough for most
2914 * applications that want to use Scanning.
2915 * If you want to have use the full/normal API, check iwlist.c...
2917 * Precaution when using scanning :
2918 * The scanning operation disable normal network traffic, and therefore
2919 * you should not abuse of scan.
2920 * The scan need to check the presence of network on other frequencies.
2921 * While you are checking those other frequencies, you can *NOT* be on
2922 * your normal frequency to listen to normal traffic in the cell.
2923 * You need typically in the order of one second to actively probe all
2924 * 802.11b channels (do the maths). Some cards may do that in background,
2925 * to reply to scan commands faster, but they still have to do it.
2926 * Leaving the cell for such an extended period of time is pretty bad.
2927 * Any kind of streaming/low latency traffic will be impacted, and the
2928 * user will perceive it (easily checked with telnet). People trying to
2929 * send traffic to you will retry packets and waste bandwidth. Some
2930 * applications may be sensitive to those packet losses in weird ways,
2931 * and tracing those weird behavior back to scanning may take time.
2932 * If you are in ad-hoc mode, if two nodes scan approx at the same
2933 * time, they won't see each other, which may create associations issues.
2934 * For those reasons, the scanning activity should be limited to
2935 * what's really needed, and continuous scanning is a bad idea.
2939 /*------------------------------------------------------------------*/
2941 * Process/store one element from the scanning results in wireless_scan
2943 static inline struct wireless_scan *
2944 iw_process_scanning_token(struct iw_event * event,
2945 struct wireless_scan * wscan)
2947 struct wireless_scan * oldwscan;
2949 /* Now, let's decode the event */
2953 /* New cell description. Allocate new cell descriptor, zero it. */
2955 wscan = (struct wireless_scan *) malloc(sizeof(struct wireless_scan));
2958 /* Link at the end of the list */
2959 if(oldwscan != NULL)
2960 oldwscan->next = wscan;
2963 bzero(wscan, sizeof(struct wireless_scan));
2965 /* Save cell identifier */
2966 wscan->has_ap_addr = 1;
2967 memcpy(&(wscan->ap_addr), &(event->u.ap_addr), sizeof (sockaddr));
2970 wscan->b.has_nwid = 1;
2971 memcpy(&(wscan->b.nwid), &(event->u.nwid), sizeof(iwparam));
2974 wscan->b.has_freq = 1;
2975 wscan->b.freq = iw_freq2float(&(event->u.freq));
2976 wscan->b.freq_flags = event->u.freq.flags;
2979 wscan->b.mode = event->u.mode;
2980 if((wscan->b.mode < IW_NUM_OPER_MODE) && (wscan->b.mode >= 0))
2981 wscan->b.has_mode = 1;
2984 wscan->b.has_essid = 1;
2985 wscan->b.essid_on = event->u.data.flags;
2986 memset(wscan->b.essid, '\0', IW_ESSID_MAX_SIZE+1);
2987 if((event->u.essid.pointer) && (event->u.essid.length))
2988 memcpy(wscan->b.essid, event->u.essid.pointer, event->u.essid.length);
2991 wscan->b.has_key = 1;
2992 wscan->b.key_size = event->u.data.length;
2993 wscan->b.key_flags = event->u.data.flags;
2994 if(event->u.data.pointer)
2995 memcpy(wscan->b.key, event->u.essid.pointer, event->u.data.length);
2997 wscan->b.key_flags |= IW_ENCODE_NOKEY;
3000 /* We don't get complete stats, only qual */
3001 wscan->has_stats = 1;
3002 memcpy(&wscan->stats.qual, &event->u.qual, sizeof(struct iw_quality));
3005 /* Scan may return a list of bitrates. As we have space for only
3006 * a single bitrate, we only keep the largest one. */
3007 if((!wscan->has_maxbitrate) ||
3008 (event->u.bitrate.value > wscan->maxbitrate.value))
3010 wscan->has_maxbitrate = 1;
3011 memcpy(&(wscan->maxbitrate), &(event->u.bitrate), sizeof(iwparam));
3014 /* How can we deal with those sanely ? Jean II */
3017 } /* switch(event->cmd) */
3022 /*------------------------------------------------------------------*/
3024 * Initiate the scan procedure, and process results.
3025 * This is a non-blocking procedure and it will return each time
3026 * it would block, returning the amount of time the caller should wait
3027 * before calling again.
3028 * Return -1 for error, delay to wait for (in ms), or 0 for success.
3029 * Error code is in errno
3032 iw_process_scan(int skfd,
3035 wireless_scan_head * context)
3038 unsigned char * buffer = NULL; /* Results */
3039 int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
3040 unsigned char * newbuf;
3042 /* Don't waste too much time on interfaces (150 * 100 = 15s) */
3044 if(context->retry > 150)
3050 /* If we have not yet initiated scanning on the interface */
3051 if(context->retry == 1)
3054 wrq.u.data.pointer = NULL; /* Later */
3055 wrq.u.data.flags = 0;
3056 wrq.u.data.length = 0;
3057 /* Remember that as non-root, we will get an EPERM here */
3058 if((iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0)
3059 && (errno != EPERM))
3061 /* Success : now, just wait for event or results */
3062 return(250); /* Wait 250 ms */
3066 /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
3067 newbuf = realloc(buffer, buflen);
3070 /* man says : If realloc() fails the original block is left untouched */
3078 /* Try to read the results */
3079 wrq.u.data.pointer = buffer;
3080 wrq.u.data.flags = 0;
3081 wrq.u.data.length = buflen;
3082 if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0)
3084 /* Check if buffer was too small (WE-17 only) */
3085 if((errno == E2BIG) && (we_version > 16))
3087 /* Some driver may return very large scan results, either
3088 * because there are many cells, or because they have many
3089 * large elements in cells (like IWEVCUSTOM). Most will
3090 * only need the regular sized buffer. We now use a dynamic
3091 * allocation of the buffer to satisfy everybody. Of course,
3092 * as we don't know in advance the size of the array, we try
3093 * various increasing sizes. Jean II */
3095 /* Check if the driver gave us any hints. */
3096 if(wrq.u.data.length > buflen)
3097 buflen = wrq.u.data.length;
3105 /* Check if results not available yet */
3109 /* Wait for only 100ms from now on */
3110 return(100); /* Wait 100 ms */
3114 /* Bad error, please don't come back... */
3118 /* We have the results, process them */
3119 if(wrq.u.data.length)
3121 struct iw_event iwe;
3122 struct stream_descr stream;
3123 struct wireless_scan * wscan = NULL;
3126 /* Debugging code. In theory useless, because it's debugged ;-) */
3128 printf("Scan result [%02X", buffer[0]);
3129 for(i = 1; i < wrq.u.data.length; i++)
3130 printf(":%02X", buffer[i]);
3135 iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
3136 /* This is dangerous, we may leak user data... */
3137 context->result = NULL;
3139 /* Look every token */
3142 /* Extract an event and print it */
3143 ret = iw_extract_event_stream(&stream, &iwe, we_version);
3146 /* Convert to wireless_scan struct */
3147 wscan = iw_process_scanning_token(&iwe, wscan);
3148 /* Check problems */
3155 /* Save head of list */
3156 if(context->result == NULL)
3157 context->result = wscan;
3163 /* Done with this interface - return success */
3168 /*------------------------------------------------------------------*/
3170 * Perform a wireless scan on the specified interface.
3171 * This is a blocking procedure and it will when the scan is completed
3172 * or when an error occur.
3174 * The scan results are given in a linked list of wireless_scan objects.
3175 * The caller *must* free the result himself (by walking the list).
3176 * If there is an error, -1 is returned and the error code is available
3179 * The parameter we_version can be extracted from the range structure
3180 * (range.we_version_compiled - see iw_get_range_info()), or using
3181 * iw_get_kernel_we_version(). For performance reason, you should
3182 * cache this parameter when possible rather than querying it every time.
3184 * Return -1 for error and 0 for success.
3190 wireless_scan_head * context)
3192 int delay; /* in ms */
3194 /* Clean up context. Potential memory leak if(context.result != NULL) */
3195 context->result = NULL;
3198 /* Wait until we get results or error */
3201 /* Try to get scan results */
3202 delay = iw_process_scan(skfd, ifname, we_version, context);
3204 /* Check termination */
3209 usleep(delay * 1000);
3212 /* End - return -1 or 0 */