4 * Jean II - HPLB 97->99 - HPL 99->03
6 * Common subroutines to all the wireless tools...
8 * This file is released under the GPL license.
9 * Copyright (c) 1997-2003 Jean Tourrilhes <jt@hpl.hp.com>
12 /***************************** INCLUDES *****************************/
14 #include "iwlib.h" /* Header */
16 /************************ CONSTANTS & MACROS ************************/
18 /* Various versions information */
19 /* Recommended Wireless Extension version */
20 #define WE_VERSION 16 /* ### don't forget #warning ### */
21 /* Version of Wireless Tools */
25 * Verify a few things about Wireless Extensions.
26 * I try to maximise backward and forward compatibility, but things are
27 * tricky because I'm fixing bugs and adding new features.
28 * Wireless Tools *must* be compiled with the same version of WE
29 * as the driver. Sometime, the size or layout of some structure changes,
30 * and might produce interesting results.
31 * Wireless Tools will usually compile properly against different
32 * versions of WE, thanks to the zillions of #ifdefs in my code.
36 #error "Wireless Extension v9 or newer required :-("
37 #error "Use Wireless Tools v19 or update your kernel headers !"
39 #if WIRELESS_EXT < WE_VERSION && !defined(WEXT_HEADER)
40 #warning "Wireless Extension earlier than v16 detected,"
41 #warning "Not all tools features will be compiled in !"
42 #warning "No worry, I'll try to make the best of it ;-)"
44 #if WIRELESS_EXT > WE_VERSION && !defined(WEXT_HEADER)
45 #warning "Wireless Extension later than v16 detected,"
46 #warning "Maybe you should get a more recent version"
47 #warning "of the Wireless Tools package !"
50 /**************************** VARIABLES ****************************/
52 const char * const iw_operation_mode[] = { "Auto",
60 /* Disable runtime version warning in iw_get_range_info() */
61 int iw_ignore_version = 0;
63 /************************ SOCKET SUBROUTINES *************************/
65 /*------------------------------------------------------------------*/
68 * Depending on the protocol present, open the right socket. The socket
69 * will allow us to talk to the driver.
74 static const int families[] = {
75 AF_INET, AF_IPX, AF_AX25, AF_APPLETALK
81 * Now pick any (exisiting) useful socket family for generic queries
82 * Note : don't open all the socket, only returns when one matches,
83 * all protocols might not be valid.
84 * Workaround by Jim Kaba <jkaba@sarnoff.com>
85 * Note : in 99% of the case, we will just open the inet_sock.
86 * The remaining 1% case are not fully correct...
89 /* Try all families we support */
90 for(i = 0; i < sizeof(families)/sizeof(int); ++i)
92 /* Try to open the socket, if success returns it */
93 sock = socket(families[i], SOCK_DGRAM, 0);
101 /*------------------------------------------------------------------*/
103 * Extract the interface name out of /proc/net/wireless or /proc/net/dev.
106 iw_get_ifname(char * name, /* Where to store the name */
107 int nsize, /* Size of name buffer */
108 char * buf) /* Current position in buffer */
112 /* Skip leading spaces */
116 #ifndef IW_RESTRIC_ENUM
117 /* Get name up to the last ':'. Aliases may contain ':' in them,
118 * but the last one should be the separator */
119 end = strrchr(buf, ':');
121 /* Get name up to ": "
122 * Note : we compare to ": " to make sure to process aliased interfaces
123 * properly. Doesn't work on /proc/net/dev, because it doesn't guarantee
124 * a ' ' after the ':'*/
125 end = strstr(buf, ": ");
128 /* Not found ??? To big ??? */
129 if((end == NULL) || (((end - buf) + 1) > nsize))
133 memcpy(name, buf, (end - buf));
134 name[end - buf] = '\0';
139 /*------------------------------------------------------------------*/
141 * Enumerate devices and call specified routine
142 * The new way just use /proc/net/wireless, so get all wireless interfaces,
143 * whether configured or not. This is the default if available.
144 * The old way use SIOCGIFCONF, so get only configured interfaces (wireless
148 iw_enum_devices(int skfd,
159 #ifndef IW_RESTRIC_ENUM
160 /* Check if /proc/net/wireless is available */
161 fh = fopen(PROC_NET_DEV, "r");
163 /* Check if /proc/net/wireless is available */
164 fh = fopen(PROC_NET_WIRELESS, "r");
169 /* Success : use data from /proc/net/wireless */
171 /* Eat 2 lines of header */
172 fgets(buff, sizeof(buff), fh);
173 fgets(buff, sizeof(buff), fh);
175 /* Read each device line */
176 while(fgets(buff, sizeof(buff), fh))
178 char name[IFNAMSIZ + 1];
181 /* Extract interface name */
182 s = iw_get_ifname(name, sizeof(name), buff);
185 /* Failed to parse, complain and continue */
186 #ifndef IW_RESTRIC_ENUM
187 fprintf(stderr, "Cannot parse " PROC_NET_DEV "\n");
189 fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
192 /* Got it, print info about this interface */
193 (*fn)(skfd, name, args, count);
200 /* Get list of configured devices using "traditional" way */
201 ifc.ifc_len = sizeof(buff);
203 if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
205 fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
211 for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
212 (*fn)(skfd, ifr->ifr_name, args, count);
216 /*********************** WIRELESS SUBROUTINES ************************/
218 /*------------------------------------------------------------------*/
220 * Get the range information out of the driver
223 iw_get_range_info(int skfd,
228 char buffer[sizeof(iwrange) * 2]; /* Large enough */
231 memset(buffer, 0, sizeof(buffer));
233 wrq.u.data.pointer = (caddr_t) buffer;
234 wrq.u.data.length = sizeof(buffer);
235 wrq.u.data.flags = 0;
236 if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
239 /* Copy stuff at the right place, ignore extra */
240 memcpy((char *) range, buffer, sizeof(iwrange));
242 /* Lots of people have driver and tools out of sync as far as Wireless
243 * Extensions are concerned. It's because /usr/include/linux/wireless.h
244 * and /usr/src/linux/include/linux/wireless.h are different.
245 * We try to catch this stuff here... */
246 if(!iw_ignore_version)
248 /* For new versions, we can check the version directly, for old versions
249 * we use magic. 300 bytes is a also magic number, don't touch... */
250 if((WIRELESS_EXT > 10) && (wrq.u.data.length >= 300))
252 #if WIRELESS_EXT > 10
253 /* Version verification - for new versions */
254 if(range->we_version_compiled != WIRELESS_EXT)
256 fprintf(stderr, "Warning: Driver for device %s has been compiled with version %d\n", ifname, range->we_version_compiled);
257 fprintf(stderr, "of Wireless Extension, while this program is using version %d.\n", WIRELESS_EXT);
258 fprintf(stderr, "Some things may be broken...\n\n");
260 /* Driver version verification */
261 if(range->we_version_compiled < range->we_version_source)
263 fprintf(stderr, "Warning: Driver for device %s recommend version %d of Wireless Extension,\n", ifname, range->we_version_source);
264 fprintf(stderr, "but has been compiled with version %d, therefore some driver features\n", range->we_version_compiled);
265 fprintf(stderr, "may not be available...\n\n");
267 #endif /* WIRELESS_EXT > 10 */
271 /* Version verification - for old versions */
272 if(wrq.u.data.length != sizeof(iwrange))
274 fprintf(stderr, "Warning: Driver for device %s has been compiled with an ancient version\n", ifname);
275 fprintf(stderr, "of Wireless Extension, while this program is using version %d.\n", WIRELESS_EXT);
276 fprintf(stderr, "Some things may be broken...\n\n");
280 /* Don't complain twice.
281 * In theory, the test apply to each individual driver, but usually
282 * all drivers are compiled from the same kernel, and most often
283 * problem is the system/glibc headers. */
284 iw_ignore_version = 1;
286 /* Note : we are only trying to catch compile difference, not source.
287 * If the driver source has not been updated to the latest, it doesn't
288 * matter because the new fields are set to zero */
293 /*------------------------------------------------------------------*/
295 * Print the WE versions of the interface.
298 print_iface_version_info(int skfd,
300 char * args[], /* Command line args */
301 int count) /* Args count */
304 char buffer[sizeof(iwrange) * 2]; /* Large enough */
305 struct iw_range * range;
307 /* Avoid "Unused parameter" warning */
308 args = args; count = count;
310 /* If no wireless name : no wireless extensions.
311 * This enable us to treat the SIOCGIWRANGE failure below properly. */
312 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
316 memset(buffer, 0, sizeof(buffer));
318 wrq.u.data.pointer = (caddr_t) buffer;
319 wrq.u.data.length = sizeof(buffer);
320 wrq.u.data.flags = 0;
321 if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
323 /* Interface support WE (see above), but not IWRANGE */
324 fprintf(stderr, "%-8.8s Driver has no Wireless Extension version information.\n\n", ifname);
328 /* Copy stuff at the right place, ignore extra */
329 range = (struct iw_range *) buffer;
331 /* For new versions, we can check the version directly, for old versions
332 * we use magic. 300 bytes is a also magic number, don't touch... */
333 if((WIRELESS_EXT > 10) && (wrq.u.data.length >= 300))
335 #if WIRELESS_EXT > 10
336 printf("%-8.8s Recommend Wireless Extension v%d or later,\n",
337 ifname, range->we_version_source);
338 printf(" Currently compiled with Wireless Extension v%d.\n\n",
339 range->we_version_compiled);
340 #endif /* WIRELESS_EXT > 10 */
345 fprintf(stderr, "%-8.8s Wireless Extension version too old.\n\n",
354 /*------------------------------------------------------------------*/
356 * Print the WE versions of the tools.
359 iw_print_version_info(char * toolname)
361 int skfd; /* generic raw socket desc. */
367 /* Create a channel to the NET kernel. */
368 if((skfd = iw_sockets_open()) < 0)
374 /* Information about the tools themselves */
376 printf("%-8.8s Version %d\n", toolname, WT_VERSION);
377 printf(" Compatible with Wireless Extension v%d or earlier,\n",
379 printf(" Currently compiled with Wireless Extension v%d.\n\n",
382 /* Check if /proc/net/wireless is available */
383 fh = fopen(PROC_NET_WIRELESS, "r");
386 /* Read the first line of buffer */
387 fgets(buff, sizeof(buff), fh);
389 /* Check if it's WE-16 or later */
390 if(strstr(buff, "| WE") != NULL)
392 /* Read the second line of buffer */
393 fgets(buff, sizeof(buff), fh);
395 /* Get to the last separator, to get the version */
396 p = strrchr(buff, '|');
397 if((p != NULL) && (sscanf(p + 1, "%d", &v) == 1))
399 printf("Kernel Currently compiled with Wireless Extension v%d.\n\n", v);
405 /* Version for each device */
406 iw_enum_devices(skfd, &print_iface_version_info, NULL, 0);
413 /*------------------------------------------------------------------*/
415 * Get information about what private ioctls are supported by the driver
418 iw_get_priv_info(int skfd,
426 wrq.u.data.pointer = (caddr_t) priv;
427 wrq.u.data.length = maxpriv;
428 wrq.u.data.flags = 0;
429 if(iw_get_ext(skfd, ifname, SIOCGIWPRIV, &wrq) < 0)
432 /* Return the number of ioctls */
433 return(wrq.u.data.length);
436 /*------------------------------------------------------------------*/
438 * Get essential wireless config from the device driver
439 * We will call all the classical wireless ioctl on the driver through
440 * the socket to know what is supported and to get the settings...
441 * Note : compare to the version in iwconfig, we extract only
442 * what's *really* needed to configure a device...
445 iw_get_basic_config(int skfd,
447 wireless_config * info)
451 memset((char *) info, 0, sizeof(struct wireless_config));
453 /* Get wireless name */
454 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
455 /* If no wireless name : no wireless extensions */
459 strncpy(info->name, wrq.u.name, IFNAMSIZ);
460 info->name[IFNAMSIZ] = '\0';
464 if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) >= 0)
467 memcpy(&(info->nwid), &(wrq.u.nwid), sizeof(iwparam));
470 /* Get frequency / channel */
471 if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
474 info->freq = iw_freq2float(&(wrq.u.freq));
477 /* Get encryption information */
478 wrq.u.data.pointer = (caddr_t) info->key;
479 wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
480 wrq.u.data.flags = 0;
481 if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
484 info->key_size = wrq.u.data.length;
485 info->key_flags = wrq.u.data.flags;
489 wrq.u.essid.pointer = (caddr_t) info->essid;
490 wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
491 wrq.u.essid.flags = 0;
492 if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) >= 0)
495 info->essid_on = wrq.u.data.flags;
498 /* Get operation mode */
499 if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) >= 0)
501 info->mode = wrq.u.mode;
502 if((info->mode < 6) && (info->mode >= 0))
509 /*------------------------------------------------------------------*/
511 * Set essential wireless config in the device driver
512 * We will call all the classical wireless ioctl on the driver through
513 * the socket to know what is supported and to set the settings...
514 * We support only the restricted set as above...
517 iw_set_basic_config(int skfd,
519 wireless_config * info)
524 /* Get wireless name (check if interface is valid) */
525 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
526 /* If no wireless name : no wireless extensions */
529 /* Set Network ID, if available (this is for non-802.11 cards) */
532 memcpy(&(wrq.u.nwid), &(info->nwid), sizeof(iwparam));
533 wrq.u.nwid.fixed = 1; /* Hum... When in Rome... */
535 if(iw_set_ext(skfd, ifname, SIOCSIWNWID, &wrq) < 0)
537 fprintf(stderr, "SIOCSIWNWID: %s\n", strerror(errno));
542 /* Set frequency / channel */
545 iw_float2freq(info->freq, &(wrq.u.freq));
547 if(iw_set_ext(skfd, ifname, SIOCSIWFREQ, &wrq) < 0)
549 fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
554 /* Set encryption information */
557 int flags = info->key_flags;
559 /* Check if there is a key index */
560 if((flags & IW_ENCODE_INDEX) > 0)
563 wrq.u.data.pointer = (caddr_t) NULL;
564 wrq.u.data.flags = (flags & (IW_ENCODE_INDEX)) | IW_ENCODE_NOKEY;
565 wrq.u.data.length = 0;
567 if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
569 fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
570 errno, strerror(errno));
575 /* Mask out index to minimise probability of reject when setting key */
576 flags = flags & (~IW_ENCODE_INDEX);
578 /* Set the key itself (set current key in this case) */
579 wrq.u.data.pointer = (caddr_t) info->key;
580 wrq.u.data.length = info->key_size;
581 wrq.u.data.flags = flags;
583 if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
585 fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
586 errno, strerror(errno));
591 /* Set ESSID (extended network), if available */
594 wrq.u.essid.pointer = (caddr_t) info->essid;
595 wrq.u.essid.length = strlen(info->essid) + 1;
596 wrq.u.data.flags = info->essid_on;
598 if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0)
600 fprintf(stderr, "SIOCSIWESSID: %s\n", strerror(errno));
605 /* Set the current mode of operation */
608 strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
609 wrq.u.mode = info->mode;
611 if(iw_get_ext(skfd, ifname, SIOCSIWMODE, &wrq) < 0)
613 fprintf(stderr, "SIOCSIWMODE: %s\n", strerror(errno));
621 /*********************** PROTOCOL SUBROUTINES ***********************/
623 * Fun stuff with protocol identifiers (SIOCGIWNAME).
624 * We assume that drivers are returning sensible values in there,
625 * which is not always the case :-(
628 /*------------------------------------------------------------------*/
630 * Compare protocol identifiers.
631 * We don't want to know if the two protocols are the exactly same,
632 * but if they interoperate at some level, and also if they accept the
633 * same type of config (ESSID vs NWID, freq...).
634 * This is supposed to work around the alphabet soup.
635 * Return 1 if protocols are compatible
638 iw_protocol_compare(char * protocol1,
641 char * dot11 = "IEEE 802.11";
642 char * dot11_ds = "Dbg";
644 /* If the strings are the same -> easy */
645 if(!strncmp(protocol1, protocol2, IFNAMSIZ))
648 /* Are we dealing with one of the 802.11 variant ? */
649 if( (!strncmp(protocol1, dot11, strlen(dot11))) &&
650 (!strncmp(protocol2, dot11, strlen(dot11))) )
652 char * sub1 = protocol1 + strlen(dot11);
653 char * sub2 = protocol2 + strlen(dot11);
655 /* Skip optional separator */
661 /* Check if they are both 2.4 GHz Direct Sequence compatible */
662 if( (strchr(dot11_ds, *sub1) != NULL) &&
663 (strchr(dot11_ds, *sub2) != NULL) )
670 /********************** FREQUENCY SUBROUTINES ***********************/
672 * Note : the two functions below are the cause of troubles on
673 * various embeeded platforms, as they are the reason we require
674 * libm (math library).
675 * In this case, please use enable BUILD_NOLIBM in the makefile
677 * FIXME : check negative mantissa and exponent
680 /*------------------------------------------------------------------*/
682 * Convert a floating point the our internal representation of
684 * The kernel doesn't want to hear about floating point, so we use
685 * this custom format instead.
688 iw_float2freq(double in,
692 /* Version without libm : slower */
700 #else /* WE_NOLIBM */
701 /* Version with libm : faster */
702 out->e = (short) (floor(log10(in)));
705 out->m = ((long) (floor(in / pow(10,out->e - 6)))) * 100;
713 #endif /* WE_NOLIBM */
716 /*------------------------------------------------------------------*/
718 * Convert our internal representation of frequencies to a floating point.
721 iw_freq2float(iwfreq * in)
724 /* Version without libm : slower */
726 double res = (double) in->m;
727 for(i = 0; i < in->e; i++)
730 #else /* WE_NOLIBM */
731 /* Version with libm : faster */
732 return ((double) in->m) * pow(10,in->e);
733 #endif /* WE_NOLIBM */
736 /*------------------------------------------------------------------*/
738 * Output a frequency with proper scaling
741 iw_print_freq(char * buffer,
745 sprintf(buffer, "Channel:%g", freq);
749 sprintf(buffer, "Frequency:%gGHz", freq / GIGA);
753 sprintf(buffer, "Frequency:%gMHz", freq / MEGA);
755 sprintf(buffer, "Frequency:%gkHz", freq / KILO);
760 /*------------------------------------------------------------------*/
762 * Convert a frequency to a channel (negative -> error)
765 iw_freq_to_channel(double freq,
766 struct iw_range * range)
771 /* Check if it's a frequency or not already a channel */
775 /* We compare the frequencies as double to ignore differences
776 * in encoding. Slower, but safer... */
777 for(k = 0; k < range->num_frequency; k++)
779 ref_freq = iw_freq2float(&(range->freq[k]));
781 return(range->freq[k].i);
787 /*********************** BITRATE SUBROUTINES ***********************/
789 /*------------------------------------------------------------------*/
791 * Output a bitrate with proper scaling
794 iw_print_bitrate(char * buffer,
797 double rate = bitrate;
800 sprintf(buffer, "%gGb/s", rate / GIGA);
803 sprintf(buffer, "%gMb/s", rate / MEGA);
805 sprintf(buffer, "%gkb/s", rate / KILO);
808 /************************ POWER SUBROUTINES *************************/
810 /*------------------------------------------------------------------*/
812 * Convert a value in dBm to a value in milliWatt.
818 /* Version without libm : slower */
824 /* Split integral and floating part to avoid accumulating rounding errors */
825 for(k = 0; k < ip; k++)
827 for(k = 0; k < fp; k++)
830 #else /* WE_NOLIBM */
831 /* Version with libm : faster */
832 return((int) (floor(pow(10.0, (((double) in) / 10.0)))));
833 #endif /* WE_NOLIBM */
836 /*------------------------------------------------------------------*/
838 * Convert a value in milliWatt to a value in dBm.
844 /* Version without libm : slower */
845 double fin = (double) in;
848 /* Split integral and floating part to avoid accumulating rounding errors */
854 while(fin > 1.000001) /* Eliminate rounding errors, take ceil */
860 #else /* WE_NOLIBM */
861 /* Version with libm : faster */
862 return((int) (ceil(10.0 * log10((double) in))));
863 #endif /* WE_NOLIBM */
866 /********************** STATISTICS SUBROUTINES **********************/
868 /*------------------------------------------------------------------*/
870 * Read /proc/net/wireless to get the latest statistics
873 iw_get_stats(int skfd,
877 #if WIRELESS_EXT > 11
879 wrq.u.data.pointer = (caddr_t) stats;
880 wrq.u.data.length = 0;
881 wrq.u.data.flags = 1; /* Clear updated flag */
882 strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
883 if(iw_get_ext(skfd, ifname, SIOCGIWSTATS, &wrq) < 0)
887 #else /* WIRELESS_EXT > 11 */
888 FILE * f = fopen(PROC_NET_WIRELESS, "r");
892 skfd = skfd; /* Avoid "Unused parameter" warning */
895 /* Loop on all devices */
896 while(fgets(buf,255,f))
899 while(*bp&&isspace(*bp))
901 /* Is it the good device ? */
902 if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':')
908 bp = strtok(bp, " ");
909 sscanf(bp, "%X", &t);
910 stats->status = (unsigned short) t;
911 /* -- link quality -- */
912 bp = strtok(NULL, " ");
913 if(strchr(bp,'.') != NULL)
914 stats->qual.updated |= 1;
915 sscanf(bp, "%d", &t);
916 stats->qual.qual = (unsigned char) t;
917 /* -- signal level -- */
918 bp = strtok(NULL, " ");
919 if(strchr(bp,'.') != NULL)
920 stats->qual.updated |= 2;
921 sscanf(bp, "%d", &t);
922 stats->qual.level = (unsigned char) t;
923 /* -- noise level -- */
924 bp = strtok(NULL, " ");
925 if(strchr(bp,'.') != NULL)
926 stats->qual.updated += 4;
927 sscanf(bp, "%d", &t);
928 stats->qual.noise = (unsigned char) t;
929 /* -- discarded packets -- */
930 bp = strtok(NULL, " ");
931 sscanf(bp, "%d", &stats->discard.nwid);
932 bp = strtok(NULL, " ");
933 sscanf(bp, "%d", &stats->discard.code);
934 bp = strtok(NULL, " ");
935 sscanf(bp, "%d", &stats->discard.misc);
942 #endif /* WIRELESS_EXT > 11 */
945 /*------------------------------------------------------------------*/
947 * Output the link statistics, taking care of formating
950 iw_print_stats(char * buffer,
956 if(has_range && (qual->level != 0))
958 /* If the statistics are in dBm */
959 if(qual->level > range->max_qual.level)
961 /* Statistics are in dBm (absolute power measurement) */
963 "Quality:%d/%d Signal level:%d dBm Noise level:%d dBm%s",
964 qual->qual, range->max_qual.qual,
965 qual->level - 0x100, qual->noise - 0x100,
966 (qual->updated & 0x7) ? " (updated)" : "");
970 /* Statistics are relative values (0 -> max) */
972 "Quality:%d/%d Signal level:%d/%d Noise level:%d/%d%s",
973 qual->qual, range->max_qual.qual,
974 qual->level, range->max_qual.level,
975 qual->noise, range->max_qual.noise,
976 (qual->updated & 0x7) ? " (updated)" : "");
981 /* We can't read the range, so we don't know... */
982 sprintf(buffer, "Quality:%d Signal level:%d Noise level:%d%s",
983 qual->qual, qual->level, qual->noise,
984 (qual->updated & 0x7) ? " (updated)" : "");
988 /*********************** ENCODING SUBROUTINES ***********************/
990 /*------------------------------------------------------------------*/
992 * Output the encoding key, with a nice formating
995 iw_print_key(char * buffer,
1002 /* Is the key present ??? */
1003 if(key_flags & IW_ENCODE_NOKEY)
1005 /* Nope : print on or dummy */
1007 strcpy(buffer, "on");
1010 strcpy(buffer, "**");
1012 for(i = 1; i < key_size; i++)
1015 strcpy(buffer++, "-");
1016 strcpy(buffer, "**");
1023 /* Yes : print the key */
1024 sprintf(buffer, "%.2X", key[0]);
1026 for(i = 1; i < key_size; i++)
1029 strcpy(buffer++, "-");
1030 sprintf(buffer, "%.2X", key[i]);
1036 /*------------------------------------------------------------------*/
1038 * Convert a passphrase into a key
1039 * ### NOT IMPLEMENTED ###
1040 * Return size of the key, or 0 (no key) or -1 (error)
1043 iw_pass_key(char * input,
1044 unsigned char * key)
1046 input = input; key = key;
1047 fprintf(stderr, "Error: Passphrase not implemented\n");
1051 /*------------------------------------------------------------------*/
1053 * Parse a key from the command line.
1054 * Return size of the key, or 0 (no key) or -1 (error)
1057 iw_in_key(char * input,
1058 unsigned char * key)
1062 /* Check the type of key */
1063 if(!strncmp(input, "s:", 2))
1065 /* First case : as an ASCII string (Lucent/Agere cards) */
1066 keylen = strlen(input + 2); /* skip "s:" */
1067 if(keylen > IW_ENCODING_TOKEN_MAX)
1068 keylen = IW_ENCODING_TOKEN_MAX;
1069 strncpy(key, input + 2, keylen);
1072 if(!strncmp(input, "p:", 2))
1074 /* Second case : as a passphrase (PrismII cards) */
1075 return(iw_pass_key(input + 2, key)); /* skip "p:" */
1084 /* Third case : as hexadecimal digits */
1085 buff = malloc(IW_ENCODING_TOKEN_MAX + strlen(input) + 1);
1088 fprintf(stderr, "Malloc failed (string too long ?)\n");
1091 /* Preserve original buffers (both in & out) */
1092 hex = buff + IW_ENCODING_TOKEN_MAX;
1097 p = strtok(hex, "-:;.,");
1098 while((p != (char *) NULL) && (keylen < IW_ENCODING_TOKEN_MAX))
1104 /* Get each char separatly (and not by two) so that we don't
1105 * get confused by 'enc' (=> '0E'+'0C') and similar */
1106 count = sscanf(p, "%1X%1X", &temph, &templ);
1108 return(-1); /* Error -> non-hex char */
1109 /* Fixup odd strings such as '123' is '01'+'23' and not '12'+'03'*/
1113 /* Put back two chars as one byte */
1115 templ |= temph << 4;
1118 out[keylen++] = (unsigned char) (templ & 0xFF);
1119 /* Check where to get next char from */
1120 if(len > count) /* Token not finished yet */
1123 p = strtok((char *) NULL, "-:;.,");
1125 memcpy(key, out, keylen);
1132 /*------------------------------------------------------------------*/
1134 * Parse a key from the command line.
1135 * Return size of the key, or 0 (no key) or -1 (error)
1138 iw_in_key_full(int skfd,
1141 unsigned char * key,
1147 if(!strncmp(input, "l:", 2))
1149 #if WIRELESS_EXT > 15
1150 struct iw_range range;
1153 /* Extra case : as a login (user:passwd - Cisco LEAP) */
1154 keylen = strlen(input + 2) + 1; /* skip "l:", add '\0' */
1155 /* Most user/password is 8 char, so 18 char total, < 32 */
1156 if(keylen > IW_ENCODING_TOKEN_MAX)
1157 keylen = IW_ENCODING_TOKEN_MAX;
1158 memcpy(key, input + 2, keylen);
1160 /* Separate the two strings */
1161 p = strchr(key, ':');
1164 fprintf(stderr, "Error: Invalid login format\n");
1169 #if WIRELESS_EXT > 15
1170 printf("flags = %X, index = %X\n", *flags, range.encoding_login_index);
1171 if((*flags & IW_ENCODE_INDEX) == 0)
1173 /* Extract range info */
1174 if(iw_get_range_info(skfd, ifname, &range) < 0)
1175 memset(&range, 0, sizeof(range));
1176 printf("flags = %X, index = %X\n", *flags, range.encoding_login_index);
1177 /* Set the index the driver expects */
1178 *flags |= range.encoding_login_index & IW_ENCODE_INDEX;
1180 printf("flags = %X, index = %X\n", *flags, range.encoding_login_index);
1182 /* Avoid "Unused parameter" warning */
1183 skfd = skfd; ifname = ifname; flags = flags;
1187 /* Simpler routine above */
1188 keylen = iw_in_key(input, key);
1193 /******************* POWER MANAGEMENT SUBROUTINES *******************/
1195 /*------------------------------------------------------------------*/
1197 * Output a power management value with all attributes...
1200 iw_print_pm_value(char * buffer,
1205 if(flags & IW_POWER_MIN)
1207 strcpy(buffer, " min");
1210 if(flags & IW_POWER_MAX)
1212 strcpy(buffer, " max");
1217 if(flags & IW_POWER_TIMEOUT)
1219 strcpy(buffer, " timeout:");
1224 strcpy(buffer, " period:");
1228 /* Display value without units */
1229 if(flags & IW_POWER_RELATIVE)
1230 sprintf(buffer, "%g", ((double) value) / MEGA);
1233 /* Display value with units */
1234 if(value >= (int) MEGA)
1235 sprintf(buffer, "%gs", ((double) value) / MEGA);
1237 if(value >= (int) KILO)
1238 sprintf(buffer, "%gms", ((double) value) / KILO);
1240 sprintf(buffer, "%dus", value);
1244 /*------------------------------------------------------------------*/
1246 * Output a power management mode
1249 iw_print_pm_mode(char * buffer,
1252 /* Print the proper mode... */
1253 switch(flags & IW_POWER_MODE)
1255 case IW_POWER_UNICAST_R:
1256 strcpy(buffer, "mode:Unicast only received");
1258 case IW_POWER_MULTICAST_R:
1259 strcpy(buffer, "mode:Multicast only received");
1261 case IW_POWER_ALL_R:
1262 strcpy(buffer, "mode:All packets received");
1264 case IW_POWER_FORCE_S:
1265 strcpy(buffer, "mode:Force sending");
1267 case IW_POWER_REPEATER:
1268 strcpy(buffer, "mode:Repeat multicasts");
1276 /***************** RETRY LIMIT/LIFETIME SUBROUTINES *****************/
1278 #if WIRELESS_EXT > 10
1279 /*------------------------------------------------------------------*/
1281 * Output a retry value with all attributes...
1284 iw_print_retry_value(char * buffer,
1289 if(flags & IW_RETRY_MIN)
1291 strcpy(buffer, " min");
1294 if(flags & IW_RETRY_MAX)
1296 strcpy(buffer, " max");
1300 /* Type lifetime of limit */
1301 if(flags & IW_RETRY_LIFETIME)
1303 strcpy(buffer, " lifetime:");
1306 /* Display value without units */
1307 if(flags & IW_POWER_RELATIVE)
1308 sprintf(buffer, "%g", ((double) value) / MEGA);
1311 /* Display value with units */
1312 if(value >= (int) MEGA)
1313 sprintf(buffer, "%gs", ((double) value) / MEGA);
1315 if(value >= (int) KILO)
1316 sprintf(buffer, "%gms", ((double) value) / KILO);
1318 sprintf(buffer, "%dus", value);
1322 sprintf(buffer, " limit:%d", value);
1324 #endif /* WIRELESS_EXT > 10 */
1326 /************************* TIME SUBROUTINES *************************/
1328 /*------------------------------------------------------------------*/
1331 * Inspired from irdadump...
1334 iw_print_timeval(char * buffer,
1335 const struct timeval * time)
1339 s = (time->tv_sec) % 86400;
1340 sprintf(buffer, "%02d:%02d:%02d.%06u ",
1341 s / 3600, (s % 3600) / 60,
1342 s % 60, (u_int32_t) time->tv_usec);
1345 /*********************** ADDRESS SUBROUTINES ************************/
1347 * This section is mostly a cut & past from net-tools-1.2.0
1348 * manage address display and input...
1351 /*------------------------------------------------------------------*/
1353 * Check if interface support the right MAC address type...
1356 iw_check_mac_addr_type(int skfd,
1361 /* Get the type of hardware address */
1362 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
1363 if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) ||
1364 (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER))
1366 /* Deep trouble... */
1367 fprintf(stderr, "Interface %s doesn't support MAC addresses\n",
1373 printf("Hardware : %d - %s\n", ifr.ifr_hwaddr.sa_family,
1374 iw_ether_ntoa((struct ether_addr *) ifr.ifr_hwaddr.sa_data));
1381 /*------------------------------------------------------------------*/
1383 * Check if interface support the right interface address type...
1386 iw_check_if_addr_type(int skfd,
1391 /* Get the type of interface address */
1392 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
1393 if((ioctl(skfd, SIOCGIFADDR, &ifr) < 0) ||
1394 (ifr.ifr_addr.sa_family != AF_INET))
1396 /* Deep trouble... */
1397 fprintf(stderr, "Interface %s doesn't support IP addresses\n", ifname);
1402 printf("Interface : %d - 0x%lX\n", ifr.ifr_addr.sa_family,
1403 *((unsigned long *) ifr.ifr_addr.sa_data));
1410 /*------------------------------------------------------------------*/
1412 * Check if interface support the right address types...
1415 iw_check_addr_type(int skfd,
1418 /* Check the interface address type */
1419 if(iw_check_if_addr_type(skfd, ifname) < 0)
1422 /* Check the interface address type */
1423 if(iw_check_mac_addr_type(skfd, ifname) < 0)
1430 /*------------------------------------------------------------------*/
1432 * Display an Ethernet address in readable format.
1435 iw_ether_ntop(const struct ether_addr* eth, char* buf)
1437 sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
1438 eth->ether_addr_octet[0], eth->ether_addr_octet[1],
1439 eth->ether_addr_octet[2], eth->ether_addr_octet[3],
1440 eth->ether_addr_octet[4], eth->ether_addr_octet[5]);
1443 /*------------------------------------------------------------------*/
1445 * Display an Ethernet address in readable format.
1446 * Same with a static buffer
1449 iw_ether_ntoa(const struct ether_addr* eth)
1451 static char buf[20];
1452 iw_ether_ntop(eth, buf);
1456 /*------------------------------------------------------------------*/
1458 * Input an Ethernet address and convert to binary.
1461 iw_ether_aton(const char *orig, struct ether_addr *eth)
1467 for(bufp = orig; *bufp != '\0'; ++bufp) {
1469 unsigned char c = *bufp++;
1470 if (isdigit(c)) val = c - '0';
1471 else if (c >= 'a' && c <= 'f') val = c - 'a' + 10;
1472 else if (c >= 'A' && c <= 'F') val = c - 'A' + 10;
1477 if (isdigit(c)) val |= c - '0';
1478 else if (c >= 'a' && c <= 'f') val |= c - 'a' + 10;
1479 else if (c >= 'A' && c <= 'F') val |= c - 'A' + 10;
1482 eth->ether_addr_octet[i] = (unsigned char) (val & 0377);
1483 if(++i == ETH_ALEN) {
1484 /* That's it. Any trailing junk? */
1485 if (*bufp != '\0') {
1487 fprintf(stderr, "iw_ether_aton(%s): trailing junk!\n", orig);
1493 fprintf(stderr, "iw_ether_aton(%s): %s\n",
1494 orig, ether_ntoa(eth));
1503 fprintf(stderr, "iw_ether_aton(%s): invalid ether address!\n", orig);
1510 /*------------------------------------------------------------------*/
1512 * Input an Internet address and convert to binary.
1515 iw_in_inet(char *name, struct sockaddr *sap)
1519 struct sockaddr_in *sin = (struct sockaddr_in *) sap;
1522 sin->sin_family = AF_INET;
1525 /* Default is special, meaning 0.0.0.0. */
1526 if (!strcmp(name, "default")) {
1527 sin->sin_addr.s_addr = INADDR_ANY;
1531 /* Try the NETWORKS database to see if this is a known network. */
1532 if ((np = getnetbyname(name)) != (struct netent *)NULL) {
1533 sin->sin_addr.s_addr = htonl(np->n_net);
1534 strcpy(name, np->n_name);
1538 /* Always use the resolver (DNS name + IP addresses) */
1539 if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
1543 memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], hp->h_length);
1544 strcpy(name, hp->h_name);
1548 /*------------------------------------------------------------------*/
1550 * Input an address and convert to binary.
1553 iw_in_addr(int skfd,
1556 struct sockaddr *sap)
1558 /* Check if it is a hardware or IP address */
1559 if(index(bufp, ':') == NULL)
1561 struct sockaddr if_address;
1562 struct arpreq arp_query;
1564 /* Check if we have valid interface address type */
1565 if(iw_check_if_addr_type(skfd, ifname) < 0)
1567 fprintf(stderr, "%-8.8s Interface doesn't support IP addresses\n", ifname);
1571 /* Read interface address */
1572 if(iw_in_inet(bufp, &if_address) < 0)
1574 fprintf(stderr, "Invalid interface address %s\n", bufp);
1578 /* Translate IP addresses to MAC addresses */
1579 memcpy((char *) &(arp_query.arp_pa),
1580 (char *) &if_address,
1581 sizeof(struct sockaddr));
1582 arp_query.arp_ha.sa_family = 0;
1583 arp_query.arp_flags = 0;
1584 /* The following restrict the search to the interface only */
1585 /* For old kernels which complain, just comment it... */
1586 strncpy(arp_query.arp_dev, ifname, IFNAMSIZ);
1587 if((ioctl(skfd, SIOCGARP, &arp_query) < 0) ||
1588 !(arp_query.arp_flags & ATF_COM))
1590 fprintf(stderr, "Arp failed for %s on %s... (%d)\nTry to ping the address before setting it.\n",
1591 bufp, ifname, errno);
1595 /* Store new MAC address */
1596 memcpy((char *) sap,
1597 (char *) &(arp_query.arp_ha),
1598 sizeof(struct sockaddr));
1601 printf("IP Address %s => Hw Address = %s\n",
1602 bufp, iw_ether_ntoa((struct ether_addr *) sap->sa_data));
1605 else /* If it's an hardware address */
1607 /* Check if we have valid mac address type */
1608 if(iw_check_mac_addr_type(skfd, ifname) < 0)
1610 fprintf(stderr, "%-8.8s Interface doesn't support MAC addresses\n", ifname);
1614 /* Get the hardware address */
1615 if(iw_in_ether(bufp, sap) < 0)
1617 fprintf(stderr, "Invalid hardware address %s\n", bufp);
1623 printf("Hw Address = %s\n", iw_ether_ntoa((struct ether_addr *) sap->sa_data));
1629 /************************* MISC SUBROUTINES **************************/
1631 /* Size (in bytes) of various events */
1632 static const int priv_type_size[] = {
1633 0, /* IW_PRIV_TYPE_NONE */
1634 1, /* IW_PRIV_TYPE_BYTE */
1635 1, /* IW_PRIV_TYPE_CHAR */
1636 0, /* Not defined */
1637 sizeof(__u32), /* IW_PRIV_TYPE_INT */
1638 sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
1639 sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
1640 0, /* Not defined */
1643 /*------------------------------------------------------------------*/
1645 * Max size in bytes of an private argument.
1648 iw_get_priv_size(int args)
1650 int num = args & IW_PRIV_SIZE_MASK;
1651 int type = (args & IW_PRIV_TYPE_MASK) >> 12;
1653 return(num * priv_type_size[type]);
1656 /************************ EVENT SUBROUTINES ************************/
1658 * The Wireless Extension API 14 and greater define Wireless Events,
1659 * that are used for various events and scanning.
1660 * Those functions help the decoding of events, so are needed only in
1663 #if WIRELESS_EXT > 13
1665 /* Type of headers we know about (basically union iwreq_data) */
1666 #define IW_HEADER_TYPE_NULL 0 /* Not available */
1667 #define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */
1668 #define IW_HEADER_TYPE_UINT 4 /* __u32 */
1669 #define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */
1670 #define IW_HEADER_TYPE_ADDR 6 /* struct sockaddr */
1671 #define IW_HEADER_TYPE_POINT 8 /* struct iw_point */
1672 #define IW_HEADER_TYPE_PARAM 9 /* struct iw_param */
1673 #define IW_HEADER_TYPE_QUAL 10 /* struct iw_quality */
1675 /* Headers for the various requests */
1676 static const char standard_ioctl_hdr[] = {
1677 IW_HEADER_TYPE_NULL, /* SIOCSIWCOMMIT */
1678 IW_HEADER_TYPE_CHAR, /* SIOCGIWNAME */
1679 IW_HEADER_TYPE_PARAM, /* SIOCSIWNWID */
1680 IW_HEADER_TYPE_PARAM, /* SIOCGIWNWID */
1681 IW_HEADER_TYPE_FREQ, /* SIOCSIWFREQ */
1682 IW_HEADER_TYPE_FREQ, /* SIOCGIWFREQ */
1683 IW_HEADER_TYPE_UINT, /* SIOCSIWMODE */
1684 IW_HEADER_TYPE_UINT, /* SIOCGIWMODE */
1685 IW_HEADER_TYPE_PARAM, /* SIOCSIWSENS */
1686 IW_HEADER_TYPE_PARAM, /* SIOCGIWSENS */
1687 IW_HEADER_TYPE_NULL, /* SIOCSIWRANGE */
1688 IW_HEADER_TYPE_POINT, /* SIOCGIWRANGE */
1689 IW_HEADER_TYPE_NULL, /* SIOCSIWPRIV */
1690 IW_HEADER_TYPE_POINT, /* SIOCGIWPRIV */
1691 IW_HEADER_TYPE_NULL, /* SIOCSIWSTATS */
1692 IW_HEADER_TYPE_POINT, /* SIOCGIWSTATS */
1693 IW_HEADER_TYPE_POINT, /* SIOCSIWSPY */
1694 IW_HEADER_TYPE_POINT, /* SIOCGIWSPY */
1695 IW_HEADER_TYPE_POINT, /* SIOCSIWTHRSPY */
1696 IW_HEADER_TYPE_POINT, /* SIOCGIWTHRSPY */
1697 IW_HEADER_TYPE_ADDR, /* SIOCSIWAP */
1698 IW_HEADER_TYPE_ADDR, /* SIOCGIWAP */
1699 IW_HEADER_TYPE_NULL, /* -- hole -- */
1700 IW_HEADER_TYPE_POINT, /* SIOCGIWAPLIST */
1701 IW_HEADER_TYPE_PARAM, /* SIOCSIWSCAN */
1702 IW_HEADER_TYPE_POINT, /* SIOCGIWSCAN */
1703 IW_HEADER_TYPE_POINT, /* SIOCSIWESSID */
1704 IW_HEADER_TYPE_POINT, /* SIOCGIWESSID */
1705 IW_HEADER_TYPE_POINT, /* SIOCSIWNICKN */
1706 IW_HEADER_TYPE_POINT, /* SIOCGIWNICKN */
1707 IW_HEADER_TYPE_NULL, /* -- hole -- */
1708 IW_HEADER_TYPE_NULL, /* -- hole -- */
1709 IW_HEADER_TYPE_PARAM, /* SIOCSIWRATE */
1710 IW_HEADER_TYPE_PARAM, /* SIOCGIWRATE */
1711 IW_HEADER_TYPE_PARAM, /* SIOCSIWRTS */
1712 IW_HEADER_TYPE_PARAM, /* SIOCGIWRTS */
1713 IW_HEADER_TYPE_PARAM, /* SIOCSIWFRAG */
1714 IW_HEADER_TYPE_PARAM, /* SIOCGIWFRAG */
1715 IW_HEADER_TYPE_PARAM, /* SIOCSIWTXPOW */
1716 IW_HEADER_TYPE_PARAM, /* SIOCGIWTXPOW */
1717 IW_HEADER_TYPE_PARAM, /* SIOCSIWRETRY */
1718 IW_HEADER_TYPE_PARAM, /* SIOCGIWRETRY */
1719 IW_HEADER_TYPE_POINT, /* SIOCSIWENCODE */
1720 IW_HEADER_TYPE_POINT, /* SIOCGIWENCODE */
1721 IW_HEADER_TYPE_PARAM, /* SIOCSIWPOWER */
1722 IW_HEADER_TYPE_PARAM, /* SIOCGIWPOWER */
1724 static const unsigned int standard_ioctl_num = sizeof(standard_ioctl_hdr);
1727 * Meta-data about all the additional standard Wireless Extension events
1730 static const char standard_event_hdr[] = {
1731 IW_HEADER_TYPE_ADDR, /* IWEVTXDROP */
1732 IW_HEADER_TYPE_QUAL, /* IWEVQUAL */
1733 IW_HEADER_TYPE_POINT, /* IWEVCUSTOM */
1734 IW_HEADER_TYPE_ADDR, /* IWEVREGISTERED */
1735 IW_HEADER_TYPE_ADDR, /* IWEVEXPIRED */
1737 static const unsigned int standard_event_num = sizeof(standard_event_hdr);
1739 /* Size (in bytes) of various events */
1740 static const int event_type_size[] = {
1741 IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */
1743 IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */
1745 IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */
1746 IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */
1747 IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */
1749 IW_EV_POINT_LEN, /* Without variable payload */
1750 IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */
1751 IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */
1754 /*------------------------------------------------------------------*/
1756 * Initialise the struct stream_descr so that we can extract
1757 * individual events from the event stream.
1760 iw_init_event_stream(struct stream_descr * stream, /* Stream of events */
1765 memset((char *) stream, '\0', sizeof(struct stream_descr));
1768 stream->current = data;
1769 stream->end = data + len;
1772 /*------------------------------------------------------------------*/
1774 * Extract the next event from the event stream.
1777 iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */
1778 struct iw_event * iwe) /* Extracted event */
1781 unsigned int event_len = 1; /* Invalid */
1783 /* Don't "optimise" the following variable, it will crash */
1784 unsigned cmd_index; /* *MUST* be unsigned */
1786 /* Check for end of stream */
1787 if((stream->current + IW_EV_LCP_LEN) > stream->end)
1791 printf("DBG - stream->current = %p, stream->value = %p, stream->end = %p\n",
1792 stream->current, stream->value, stream->end);
1795 /* Extract the event header (to get the event id).
1796 * Note : the event may be unaligned, therefore copy... */
1797 memcpy((char *) iwe, stream->current, IW_EV_LCP_LEN);
1800 printf("DBG - iwe->cmd = 0x%X, iwe->len = %d\n",
1801 iwe->cmd, iwe->len);
1804 /* Check invalid events */
1805 if(iwe->len <= IW_EV_LCP_LEN)
1808 /* Get the type and length of that event */
1809 if(iwe->cmd <= SIOCIWLAST)
1811 cmd_index = iwe->cmd - SIOCIWFIRST;
1812 if(cmd_index < standard_ioctl_num)
1813 event_type = standard_ioctl_hdr[cmd_index];
1817 cmd_index = iwe->cmd - IWEVFIRST;
1818 if(cmd_index < standard_event_num)
1819 event_type = standard_event_hdr[cmd_index];
1821 /* Unknown events -> event_type=0 => IW_EV_LCP_LEN */
1822 event_len = event_type_size[event_type];
1824 /* Check if we know about this event */
1825 if(event_len <= IW_EV_LCP_LEN)
1827 /* Skip to next event */
1828 stream->current += iwe->len;
1831 event_len -= IW_EV_LCP_LEN;
1833 /* Set pointer on data */
1834 if(stream->value != NULL)
1835 pointer = stream->value; /* Next value in event */
1837 pointer = stream->current + IW_EV_LCP_LEN; /* First value in event */
1840 printf("DBG - event_type = %d, event_len = %d, pointer = %p\n",
1841 event_type, event_len, pointer);
1844 /* Copy the rest of the event (at least, fixed part) */
1845 if((pointer + event_len) > stream->end)
1847 /* Go to next event */
1848 stream->current += iwe->len;
1851 memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
1853 /* Skip event in the stream */
1854 pointer += event_len;
1856 /* Special processing for iw_point events */
1857 if(event_type == IW_HEADER_TYPE_POINT)
1859 /* Check the length of the payload */
1860 if((iwe->len - (event_len + IW_EV_LCP_LEN)) > 0)
1861 /* Set pointer on variable part (warning : non aligned) */
1862 iwe->u.data.pointer = pointer;
1865 iwe->u.data.pointer = NULL;
1867 /* Go to next event */
1868 stream->current += iwe->len;
1872 /* Is there more value in the event ? */
1873 if((pointer + event_len) <= (stream->current + iwe->len))
1874 /* Go to next value */
1875 stream->value = pointer;
1878 /* Go to next event */
1879 stream->value = NULL;
1880 stream->current += iwe->len;
1886 #endif /* WIRELESS_EXT > 13 */