4 * Jean II - HPLB 97->99 - HPL 99->01
6 * Common subroutines to all the wireless tools...
8 * This file is released under the GPL license.
9 * Copyright (c) 1997-2002 Jean Tourrilhes <jt@hpl.hp.com>
12 #include "iwlib.h" /* Header */
14 /**************************** VARIABLES ****************************/
16 const char * const iw_operation_mode[] = { "Auto",
23 /************************ SOCKET SUBROUTINES *************************/
25 /*------------------------------------------------------------------*/
28 * Depending on the protocol present, open the right socket. The socket
29 * will allow us to talk to the driver.
34 static const int families[] = {
35 AF_INET, AF_IPX, AF_AX25, AF_APPLETALK
41 * Now pick any (exisiting) useful socket family for generic queries
42 * Note : don't open all the socket, only returns when one matches,
43 * all protocols might not be valid.
44 * Workaround by Jim Kaba <jkaba@sarnoff.com>
45 * Note : in 99% of the case, we will just open the inet_sock.
46 * The remaining 1% case are not fully correct...
49 /* Try all families we support */
50 for(i = 0; i < sizeof(families)/sizeof(int); ++i)
52 /* Try to open the socket, if success returns it */
53 sock = socket(families[i], SOCK_DGRAM, 0);
61 /*------------------------------------------------------------------*/
63 * Extract the interface name out of /proc/net/wireless
64 * Important note : this procedure will work only with /proc/net/wireless
65 * and not /proc/net/dev, because it doesn't guarantee a ' ' after the ':'.
68 iw_get_ifname(char * name, /* Where to store the name */
69 int nsize, /* Size of name buffer */
70 char * buf) /* Current position in buffer */
74 /* Skip leading spaces */
78 /* Get name up to ": "
79 * Note : we compare to ": " to make sure to process aliased interfaces
81 end = strstr(buf, ": ");
83 /* Not found ??? To big ??? */
84 if((end == NULL) || (((end - buf) + 1) > nsize))
88 memcpy(name, buf, (end - buf));
89 name[end - buf] = '\0';
94 /*------------------------------------------------------------------*/
96 * Enumerate devices and call specified routine
97 * The new way just use /proc/net/wireless, so get all wireless interfaces,
98 * whether configured or not. This is the default if available.
99 * The old way use SIOCGIFCONF, so get only configured interfaces (wireless
103 iw_enum_devices(int skfd,
114 /* Check if /proc/net/wireless is available */
115 fh = fopen(PROC_NET_WIRELESS, "r");
119 /* Success : use data from /proc/net/wireless */
121 /* Eat 2 lines of header */
122 fgets(buff, sizeof(buff), fh);
123 fgets(buff, sizeof(buff), fh);
125 /* Read each device line */
126 while(fgets(buff, sizeof(buff), fh))
128 char name[IFNAMSIZ + 1];
131 /* Extract interface name */
132 s = iw_get_ifname(name, sizeof(name), buff);
135 /* Failed to parse, complain and continue */
136 fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
138 /* Got it, print info about this interface */
139 (*fn)(skfd, name, args, count);
146 /* Get list of configured devices using "traditional" way */
147 ifc.ifc_len = sizeof(buff);
149 if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
151 fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
157 for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
158 (*fn)(skfd, ifr->ifr_name, args, count);
162 /*********************** WIRELESS SUBROUTINES ************************/
164 /*------------------------------------------------------------------*/
166 * Get the range information out of the driver
169 iw_get_range_info(int skfd,
174 char buffer[sizeof(iwrange) * 2]; /* Large enough */
177 memset(buffer, 0, sizeof(buffer));
179 wrq.u.data.pointer = (caddr_t) buffer;
180 wrq.u.data.length = sizeof(buffer);
181 wrq.u.data.flags = 0;
182 if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
185 /* Copy stuff at the right place, ignore extra */
186 memcpy((char *) range, buffer, sizeof(iwrange));
188 /* Lots of people have driver and tools out of sync as far as Wireless
189 * Extensions are concerned. It's because /usr/include/linux/wireless.h
190 * and /usr/src/linux/include/linux/wireless.h are different.
191 * We try to catch this stuff here... */
193 /* For new versions, we can check the version directly, for old versions
194 * we use magic. 300 bytes is a also magic number, don't touch... */
195 if((WIRELESS_EXT > 10) && (wrq.u.data.length >= 300))
197 #if WIRELESS_EXT > 10
198 /* Version verification - for new versions */
199 if(range->we_version_compiled != WIRELESS_EXT)
201 fprintf(stderr, "Warning : Device %s has been compiled with version %d\n", ifname, range->we_version_compiled);
202 fprintf(stderr, "of Wireless Extension, while we are using version %d.\n", WIRELESS_EXT);
203 fprintf(stderr, "Some things may be broken...\n\n");
205 #endif /* WIRELESS_EXT > 10 */
209 /* Version verification - for old versions */
210 if(wrq.u.data.length != sizeof(iwrange))
212 fprintf(stderr, "Warning : Device %s has been compiled with a different version\n", ifname);
213 fprintf(stderr, "of Wireless Extension than ours (we are using version %d).\n", WIRELESS_EXT);
214 fprintf(stderr, "Some things may be broken...\n\n");
218 /* Note : we are only trying to catch compile difference, not source.
219 * If the driver source has not been updated to the latest, it doesn't
220 * matter because the new fields are set to zero */
225 /*------------------------------------------------------------------*/
227 * Get information about what private ioctls are supported by the driver
230 iw_get_priv_info(int skfd,
237 wrq.u.data.pointer = (caddr_t) priv;
238 wrq.u.data.length = 32;
239 wrq.u.data.flags = 0;
240 if(iw_get_ext(skfd, ifname, SIOCGIWPRIV, &wrq) < 0)
243 /* Return the number of ioctls */
244 return(wrq.u.data.length);
247 /*------------------------------------------------------------------*/
249 * Get essential wireless config from the device driver
250 * We will call all the classical wireless ioctl on the driver through
251 * the socket to know what is supported and to get the settings...
252 * Note : compare to the version in iwconfig, we extract only
253 * what's *really* needed to configure a device...
256 iw_get_basic_config(int skfd,
258 wireless_config * info)
262 memset((char *) info, 0, sizeof(struct wireless_config));
264 /* Get wireless name */
265 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
266 /* If no wireless name : no wireless extensions */
269 strcpy(info->name, wrq.u.name);
272 if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) >= 0)
275 memcpy(&(info->nwid), &(wrq.u.nwid), sizeof(iwparam));
278 /* Get frequency / channel */
279 if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
282 info->freq = iw_freq2float(&(wrq.u.freq));
285 /* Get encryption information */
286 wrq.u.data.pointer = (caddr_t) info->key;
287 wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
288 wrq.u.data.flags = 0;
289 if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
292 info->key_size = wrq.u.data.length;
293 info->key_flags = wrq.u.data.flags;
297 wrq.u.essid.pointer = (caddr_t) info->essid;
298 wrq.u.essid.length = IW_ESSID_MAX_SIZE;
299 wrq.u.essid.flags = 0;
300 if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) >= 0)
303 info->essid_on = wrq.u.data.flags;
306 /* Get operation mode */
307 if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) >= 0)
309 info->mode = wrq.u.mode;
310 if((info->mode < 6) && (info->mode >= 0))
317 /*------------------------------------------------------------------*/
319 * Set essential wireless config in the device driver
320 * We will call all the classical wireless ioctl on the driver through
321 * the socket to know what is supported and to set the settings...
322 * We support only the restricted set as above...
325 iw_set_basic_config(int skfd,
327 wireless_config * info)
332 /* Get wireless name (check if interface is valid) */
333 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
334 /* If no wireless name : no wireless extensions */
337 /* Set Network ID, if available (this is for non-802.11 cards) */
340 memcpy(&(wrq.u.nwid), &(info->nwid), sizeof(iwparam));
341 wrq.u.nwid.fixed = 1; /* Hum... When in Rome... */
343 if(iw_set_ext(skfd, ifname, SIOCSIWNWID, &wrq) < 0)
345 fprintf(stderr, "SIOCSIWNWID: %s\n", strerror(errno));
350 /* Set frequency / channel */
353 iw_float2freq(info->freq, &(wrq.u.freq));
355 if(iw_set_ext(skfd, ifname, SIOCSIWFREQ, &wrq) < 0)
357 fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
362 /* Set encryption information */
365 int flags = info->key_flags;
367 /* Check if there is a key index */
368 if((flags & IW_ENCODE_INDEX) > 0)
371 wrq.u.data.pointer = (caddr_t) NULL;
372 wrq.u.data.flags = (flags & (IW_ENCODE_INDEX)) | IW_ENCODE_NOKEY;
373 wrq.u.data.length = 0;
375 if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
377 fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
378 errno, strerror(errno));
383 /* Mask out index to minimise probability of reject when setting key */
384 flags = flags & (~IW_ENCODE_INDEX);
386 /* Set the key itself (set current key in this case) */
387 wrq.u.data.pointer = (caddr_t) info->key;
388 wrq.u.data.length = info->key_size;
389 wrq.u.data.flags = flags;
391 if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
393 fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
394 errno, strerror(errno));
399 /* Set ESSID (extended network), if available */
402 wrq.u.essid.pointer = (caddr_t) info->essid;
403 wrq.u.essid.length = strlen(info->essid) + 1;
404 wrq.u.data.flags = info->essid_on;
406 if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0)
408 fprintf(stderr, "SIOCSIWESSID: %s\n", strerror(errno));
413 /* Set the current mode of operation */
416 strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
417 wrq.u.mode = info->mode;
419 if(iw_get_ext(skfd, ifname, SIOCSIWMODE, &wrq) < 0)
421 fprintf(stderr, "SIOCSIWMODE: %s\n", strerror(errno));
429 /********************** FREQUENCY SUBROUTINES ***********************/
431 /*------------------------------------------------------------------*/
433 * Convert a floating point the our internal representation of
435 * The kernel doesn't want to hear about floating point, so we use
436 * this custom format instead.
439 iw_float2freq(double in,
442 out->e = (short) (floor(log10(in)));
445 out->m = ((long) (floor(in / pow(10,out->e - 6)))) * 100;
455 /*------------------------------------------------------------------*/
457 * Convert our internal representation of frequencies to a floating point.
460 iw_freq2float(iwfreq * in)
462 return ((double) in->m) * pow(10,in->e);
465 /*------------------------------------------------------------------*/
467 * Output a frequency with proper scaling
470 iw_print_freq(char * buffer,
474 sprintf(buffer, "Channel:%g", freq);
478 sprintf(buffer, "Frequency:%gGHz", freq / GIGA);
482 sprintf(buffer, "Frequency:%gMHz", freq / MEGA);
484 sprintf(buffer, "Frequency:%gkHz", freq / KILO);
489 /*********************** BITRATE SUBROUTINES ***********************/
491 /*------------------------------------------------------------------*/
493 * Output a bitrate with proper scaling
496 iw_print_bitrate(char * buffer,
499 double rate = bitrate;
502 sprintf(buffer, "%gGb/s", rate / GIGA);
505 sprintf(buffer, "%gMb/s", rate / MEGA);
507 sprintf(buffer, "%gkb/s", rate / KILO);
510 /************************ POWER SUBROUTINES *************************/
512 /*------------------------------------------------------------------*/
514 * Convert a value in dBm to a value in milliWatt.
519 return((int) (floor(pow(10.0, (((double) in) / 10.0)))));
522 /*------------------------------------------------------------------*/
524 * Convert a value in milliWatt to a value in dBm.
529 return((int) (ceil(10.0 * log10((double) in))));
532 /********************** STATISTICS SUBROUTINES **********************/
534 /*------------------------------------------------------------------*/
536 * Read /proc/net/wireless to get the latest statistics
539 iw_get_stats(int skfd,
543 #if WIRELESS_EXT > 11
545 wrq.u.data.pointer = (caddr_t) stats;
546 wrq.u.data.length = 0;
547 wrq.u.data.flags = 1; /* Clear updated flag */
548 strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
549 if(iw_get_ext(skfd, ifname, SIOCGIWSTATS, &wrq) < 0)
553 #else /* WIRELESS_EXT > 11 */
554 FILE * f = fopen(PROC_NET_WIRELESS, "r");
560 /* Loop on all devices */
561 while(fgets(buf,255,f))
564 while(*bp&&isspace(*bp))
566 /* Is it the good device ? */
567 if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':')
573 bp = strtok(bp, " ");
574 sscanf(bp, "%X", &t);
575 stats->status = (unsigned short) t;
576 /* -- link quality -- */
577 bp = strtok(NULL, " ");
578 if(strchr(bp,'.') != NULL)
579 stats->qual.updated |= 1;
580 sscanf(bp, "%d", &t);
581 stats->qual.qual = (unsigned char) t;
582 /* -- signal level -- */
583 bp = strtok(NULL, " ");
584 if(strchr(bp,'.') != NULL)
585 stats->qual.updated |= 2;
586 sscanf(bp, "%d", &t);
587 stats->qual.level = (unsigned char) t;
588 /* -- noise level -- */
589 bp = strtok(NULL, " ");
590 if(strchr(bp,'.') != NULL)
591 stats->qual.updated += 4;
592 sscanf(bp, "%d", &t);
593 stats->qual.noise = (unsigned char) t;
594 /* -- discarded packets -- */
595 bp = strtok(NULL, " ");
596 sscanf(bp, "%d", &stats->discard.nwid);
597 bp = strtok(NULL, " ");
598 sscanf(bp, "%d", &stats->discard.code);
599 bp = strtok(NULL, " ");
600 sscanf(bp, "%d", &stats->discard.misc);
607 #endif /* WIRELESS_EXT > 11 */
610 /*------------------------------------------------------------------*/
612 * Output the link statistics, taking care of formating
615 iw_print_stats(char * buffer,
621 if(has_range && (qual->level != 0))
623 /* If the statistics are in dBm */
624 if(qual->level > range->max_qual.level)
626 /* Statistics are in dBm (absolute power measurement) */
628 "Quality:%d/%d Signal level:%d dBm Noise level:%d dBm%s",
629 qual->qual, range->max_qual.qual,
630 qual->level - 0x100, qual->noise - 0x100,
631 (qual->updated & 0x7) ? " (updated)" : "");
635 /* Statistics are relative values (0 -> max) */
637 "Quality:%d/%d Signal level:%d/%d Noise level:%d/%d%s",
638 qual->qual, range->max_qual.qual,
639 qual->level, range->max_qual.level,
640 qual->noise, range->max_qual.noise,
641 (qual->updated & 0x7) ? " (updated)" : "");
646 /* We can't read the range, so we don't know... */
647 sprintf(buffer, "Quality:%d Signal level:%d Noise level:%d%s",
648 qual->qual, qual->level, qual->noise,
649 (qual->updated & 0x7) ? " (updated)" : "");
653 /*********************** ENCODING SUBROUTINES ***********************/
655 /*------------------------------------------------------------------*/
657 * Output the encoding key, with a nice formating
660 iw_print_key(char * buffer,
667 /* Is the key present ??? */
668 if(key_flags & IW_ENCODE_NOKEY)
670 /* Nope : print on or dummy */
672 strcpy(buffer, "on");
675 strcpy(buffer, "**");
677 for(i = 1; i < key_size; i++)
680 strcpy(buffer++, "-");
681 strcpy(buffer, "**");
688 /* Yes : print the key */
689 sprintf(buffer, "%.2X", key[0]);
691 for(i = 1; i < key_size; i++)
694 strcpy(buffer++, "-");
695 sprintf(buffer, "%.2X", key[i]);
701 /*------------------------------------------------------------------*/
703 * Parse a key from the command line.
704 * Return size of the key, or 0 (no key) or -1 (error)
707 iw_in_key(char * input,
715 /* Check the type of key */
716 if(!strncmp(input, "s:", 2))
718 /* First case : as an ASCII string */
719 keylen = strlen(input + 2); /* skip "s:" */
720 if(keylen > IW_ENCODING_TOKEN_MAX)
721 keylen = IW_ENCODING_TOKEN_MAX;
722 strncpy(key, input + 2, keylen);
726 /* Second case : as hexadecimal digits */
727 buff = malloc(strlen(input) + 1);
730 fprintf(stderr, "Malloc failed (string too long ?)\n");
733 /* Preserve original buffer */
737 p = strtok(buff, "-:;.,");
738 while((p != (char *) NULL) && (keylen < IW_ENCODING_TOKEN_MAX))
740 if(sscanf(p, "%2X", &temp) != 1)
741 return(-1); /* Error */
742 key[keylen++] = (unsigned char) (temp & 0xFF);
743 if(strlen(p) > 2) /* Token not finished yet */
746 p = strtok((char *) NULL, "-:;.,");
754 /******************* POWER MANAGEMENT SUBROUTINES *******************/
756 /*------------------------------------------------------------------*/
758 * Output a power management value with all attributes...
761 iw_print_pm_value(char * buffer,
766 if(flags & IW_POWER_MIN)
768 strcpy(buffer, " min");
771 if(flags & IW_POWER_MAX)
773 strcpy(buffer, " max");
778 if(flags & IW_POWER_TIMEOUT)
780 strcpy(buffer, " timeout:");
785 strcpy(buffer, " period:");
789 /* Display value without units */
790 if(flags & IW_POWER_RELATIVE)
791 sprintf(buffer, "%g", ((double) value) / MEGA);
794 /* Display value with units */
795 if(value >= (int) MEGA)
796 sprintf(buffer, "%gs", ((double) value) / MEGA);
798 if(value >= (int) KILO)
799 sprintf(buffer, "%gms", ((double) value) / KILO);
801 sprintf(buffer, "%dus", value);
805 /*------------------------------------------------------------------*/
807 * Output a power management mode
810 iw_print_pm_mode(char * buffer,
813 /* Print the proper mode... */
814 switch(flags & IW_POWER_MODE)
816 case IW_POWER_UNICAST_R:
817 strcpy(buffer, "mode:Unicast only received");
819 case IW_POWER_MULTICAST_R:
820 strcpy(buffer, "mode:Multicast only received");
823 strcpy(buffer, "mode:All packets received");
825 case IW_POWER_FORCE_S:
826 strcpy(buffer, "mode:Force sending");
828 case IW_POWER_REPEATER:
829 strcpy(buffer, "mode:Repeat multicasts");
835 /***************** RETRY LIMIT/LIFETIME SUBROUTINES *****************/
837 #if WIRELESS_EXT > 10
838 /*------------------------------------------------------------------*/
840 * Output a retry value with all attributes...
843 iw_print_retry_value(char * buffer,
848 if(flags & IW_RETRY_MIN)
850 strcpy(buffer, " min");
853 if(flags & IW_RETRY_MAX)
855 strcpy(buffer, " max");
859 /* Type lifetime of limit */
860 if(flags & IW_RETRY_LIFETIME)
862 strcpy(buffer, " lifetime:");
865 /* Display value without units */
866 if(flags & IW_POWER_RELATIVE)
867 sprintf(buffer, "%g", ((double) value) / MEGA);
870 /* Display value with units */
871 if(value >= (int) MEGA)
872 sprintf(buffer, "%gs", ((double) value) / MEGA);
874 if(value >= (int) KILO)
875 sprintf(buffer, "%gms", ((double) value) / KILO);
877 sprintf(buffer, "%dus", value);
881 sprintf(buffer, " limit:%d", value);
883 #endif /* WIRELESS_EXT > 10 */
885 /************************* TIME SUBROUTINES *************************/
887 /*------------------------------------------------------------------*/
890 * Inspired from irdadump...
893 iw_print_timeval(char * buffer,
894 const struct timeval * time)
898 s = (time->tv_sec) % 86400;
899 sprintf(buffer, "%02d:%02d:%02d.%06u ",
900 s / 3600, (s % 3600) / 60,
901 s % 60, (u_int32_t) time->tv_usec);
904 /*********************** ADDRESS SUBROUTINES ************************/
906 * This section is mostly a cut & past from net-tools-1.2.0
907 * manage address display and input...
910 /*------------------------------------------------------------------*/
912 * Check if interface support the right MAC address type...
915 iw_check_mac_addr_type(int skfd,
920 /* Get the type of hardware address */
921 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
922 if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) ||
923 (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER))
925 /* Deep trouble... */
926 fprintf(stderr, "Interface %s doesn't support MAC addresses\n",
932 printf("Hardware : %d - %s\n", ifr.ifr_hwaddr.sa_family,
933 iw_ether_ntoa((struct ether_addr *) ifr.ifr_hwaddr.sa_data));
940 /*------------------------------------------------------------------*/
942 * Check if interface support the right interface address type...
945 iw_check_if_addr_type(int skfd,
950 /* Get the type of interface address */
951 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
952 if((ioctl(skfd, SIOCGIFADDR, &ifr) < 0) ||
953 (ifr.ifr_addr.sa_family != AF_INET))
955 /* Deep trouble... */
956 fprintf(stderr, "Interface %s doesn't support IP addresses\n", ifname);
961 printf("Interface : %d - 0x%lX\n", ifr.ifr_addr.sa_family,
962 *((unsigned long *) ifr.ifr_addr.sa_data));
969 /*------------------------------------------------------------------*/
971 * Check if interface support the right address types...
974 iw_check_addr_type(int skfd,
977 /* Check the interface address type */
978 if(iw_check_if_addr_type(skfd, ifname) < 0)
981 /* Check the interface address type */
982 if(iw_check_mac_addr_type(skfd, ifname) < 0)
989 /*------------------------------------------------------------------*/
991 * Display an Ethernet address in readable format.
994 iw_ether_ntop(const struct ether_addr* eth, char* buf)
996 sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
997 eth->ether_addr_octet[0], eth->ether_addr_octet[1],
998 eth->ether_addr_octet[2], eth->ether_addr_octet[3],
999 eth->ether_addr_octet[4], eth->ether_addr_octet[5]);
1002 /*------------------------------------------------------------------*/
1004 * Display an Ethernet address in readable format.
1005 * Same with a static buffer
1008 iw_ether_ntoa(const struct ether_addr* eth)
1010 static char buf[20];
1011 iw_ether_ntop(eth, buf);
1015 /*------------------------------------------------------------------*/
1017 * Input an Ethernet address and convert to binary.
1020 iw_ether_aton(const char *orig, struct ether_addr *eth)
1026 for(bufp = orig; *bufp != '\0'; ++bufp) {
1028 unsigned char c = *bufp++;
1029 if (isdigit(c)) val = c - '0';
1030 else if (c >= 'a' && c <= 'f') val = c - 'a' + 10;
1031 else if (c >= 'A' && c <= 'F') val = c - 'A' + 10;
1036 if (isdigit(c)) val |= c - '0';
1037 else if (c >= 'a' && c <= 'f') val |= c - 'a' + 10;
1038 else if (c >= 'A' && c <= 'F') val |= c - 'A' + 10;
1041 eth->ether_addr_octet[i] = (unsigned char) (val & 0377);
1042 if(++i == ETH_ALEN) {
1043 /* That's it. Any trailing junk? */
1044 if (*bufp != '\0') {
1046 fprintf(stderr, "iw_ether_aton(%s): trailing junk!\n", orig);
1052 fprintf(stderr, "iw_ether_aton(%s): %s\n",
1053 orig, ether_ntoa(eth));
1062 fprintf(stderr, "iw_ether_aton(%s): invalid ether address!\n", orig);
1069 /*------------------------------------------------------------------*/
1071 * Input an Internet address and convert to binary.
1074 iw_in_inet(char *name, struct sockaddr *sap)
1078 struct sockaddr_in *sin = (struct sockaddr_in *) sap;
1081 sin->sin_family = AF_INET;
1084 /* Default is special, meaning 0.0.0.0. */
1085 if (!strcmp(name, "default")) {
1086 sin->sin_addr.s_addr = INADDR_ANY;
1090 /* Try the NETWORKS database to see if this is a known network. */
1091 if ((np = getnetbyname(name)) != (struct netent *)NULL) {
1092 sin->sin_addr.s_addr = htonl(np->n_net);
1093 strcpy(name, np->n_name);
1097 if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
1101 memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], hp->h_length);
1102 strcpy(name, hp->h_name);
1106 /*------------------------------------------------------------------*/
1108 * Input an address and convert to binary.
1111 iw_in_addr(int skfd,
1114 struct sockaddr *sap)
1116 /* Check if it is a hardware or IP address */
1117 if(index(bufp, ':') == NULL)
1119 struct sockaddr if_address;
1120 struct arpreq arp_query;
1122 /* Check if we have valid interface address type */
1123 if(iw_check_if_addr_type(skfd, ifname) < 0)
1125 fprintf(stderr, "%-8.8s Interface doesn't support IP addresses\n", ifname);
1129 /* Read interface address */
1130 if(iw_in_inet(bufp, &if_address) < 0)
1132 fprintf(stderr, "Invalid interface address %s\n", bufp);
1136 /* Translate IP addresses to MAC addresses */
1137 memcpy((char *) &(arp_query.arp_pa),
1138 (char *) &if_address,
1139 sizeof(struct sockaddr));
1140 arp_query.arp_ha.sa_family = 0;
1141 arp_query.arp_flags = 0;
1142 /* The following restrict the search to the interface only */
1143 /* For old kernels which complain, just comment it... */
1144 strncpy(arp_query.arp_dev, ifname, IFNAMSIZ);
1145 if((ioctl(skfd, SIOCGARP, &arp_query) < 0) ||
1146 !(arp_query.arp_flags & ATF_COM))
1148 fprintf(stderr, "Arp failed for %s on %s... (%d)\nTry to ping the address before setting it.\n",
1149 bufp, ifname, errno);
1153 /* Store new MAC address */
1154 memcpy((char *) sap,
1155 (char *) &(arp_query.arp_ha),
1156 sizeof(struct sockaddr));
1159 printf("IP Address %s => Hw Address = %s\n",
1160 bufp, iw_ether_ntoa((struct ether_addr *) sap->sa_data));
1163 else /* If it's an hardware address */
1165 /* Check if we have valid mac address type */
1166 if(iw_check_mac_addr_type(skfd, ifname) < 0)
1168 fprintf(stderr, "%-8.8s Interface doesn't support MAC addresses\n", ifname);
1172 /* Get the hardware address */
1173 if(iw_in_ether(bufp, sap) < 0)
1175 fprintf(stderr, "Invalid hardware address %s\n", bufp);
1181 printf("Hw Address = %s\n", iw_ether_ntoa((struct ether_addr *) sap->sa_data));
1187 /************************* MISC SUBROUTINES **************************/
1189 /*------------------------------------------------------------------*/
1191 * Max size in bytes of an private argument.
1194 iw_byte_size(int args)
1196 int ret = args & IW_PRIV_SIZE_MASK;
1198 if(((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_INT) ||
1199 ((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_FLOAT))
1202 if((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_NONE)
1208 /************************ EVENT SUBROUTINES ************************/
1210 * The Wireless Extension API 14 and greater define Wireless Events,
1211 * that are used for various events and scanning.
1212 * Those functions help the decoding of events, so are needed only in
1215 #if WIRELESS_EXT > 13
1217 /* Type of headers we know about (basically union iwreq_data) */
1218 #define IW_HEADER_TYPE_NULL 0 /* Not available */
1219 #define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */
1220 #define IW_HEADER_TYPE_UINT 4 /* __u32 */
1221 #define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */
1222 #define IW_HEADER_TYPE_POINT 6 /* struct iw_point */
1223 #define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */
1224 #define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */
1225 #define IW_HEADER_TYPE_QUAL 9 /* struct iw_quality */
1227 /* Headers for the various requests */
1228 static const char standard_ioctl_hdr[] = {
1229 IW_HEADER_TYPE_NULL, /* SIOCSIWCOMMIT */
1230 IW_HEADER_TYPE_CHAR, /* SIOCGIWNAME */
1231 IW_HEADER_TYPE_PARAM, /* SIOCSIWNWID */
1232 IW_HEADER_TYPE_PARAM, /* SIOCGIWNWID */
1233 IW_HEADER_TYPE_FREQ, /* SIOCSIWFREQ */
1234 IW_HEADER_TYPE_FREQ, /* SIOCGIWFREQ */
1235 IW_HEADER_TYPE_UINT, /* SIOCSIWMODE */
1236 IW_HEADER_TYPE_UINT, /* SIOCGIWMODE */
1237 IW_HEADER_TYPE_PARAM, /* SIOCSIWSENS */
1238 IW_HEADER_TYPE_PARAM, /* SIOCGIWSENS */
1239 IW_HEADER_TYPE_NULL, /* SIOCSIWRANGE */
1240 IW_HEADER_TYPE_POINT, /* SIOCGIWRANGE */
1241 IW_HEADER_TYPE_NULL, /* SIOCSIWPRIV */
1242 IW_HEADER_TYPE_POINT, /* SIOCGIWPRIV */
1243 IW_HEADER_TYPE_NULL, /* SIOCSIWSTATS */
1244 IW_HEADER_TYPE_POINT, /* SIOCGIWSTATS */
1245 IW_HEADER_TYPE_POINT, /* SIOCSIWSPY */
1246 IW_HEADER_TYPE_POINT, /* SIOCGIWSPY */
1247 IW_HEADER_TYPE_NULL, /* -- hole -- */
1248 IW_HEADER_TYPE_NULL, /* -- hole -- */
1249 IW_HEADER_TYPE_ADDR, /* SIOCSIWAP */
1250 IW_HEADER_TYPE_ADDR, /* SIOCGIWAP */
1251 IW_HEADER_TYPE_NULL, /* -- hole -- */
1252 IW_HEADER_TYPE_POINT, /* SIOCGIWAPLIST */
1253 IW_HEADER_TYPE_PARAM, /* SIOCSIWSCAN */
1254 IW_HEADER_TYPE_POINT, /* SIOCGIWSCAN */
1255 IW_HEADER_TYPE_POINT, /* SIOCSIWESSID */
1256 IW_HEADER_TYPE_POINT, /* SIOCGIWESSID */
1257 IW_HEADER_TYPE_POINT, /* SIOCSIWNICKN */
1258 IW_HEADER_TYPE_POINT, /* SIOCGIWNICKN */
1259 IW_HEADER_TYPE_NULL, /* -- hole -- */
1260 IW_HEADER_TYPE_NULL, /* -- hole -- */
1261 IW_HEADER_TYPE_PARAM, /* SIOCSIWRATE */
1262 IW_HEADER_TYPE_PARAM, /* SIOCGIWRATE */
1263 IW_HEADER_TYPE_PARAM, /* SIOCSIWRTS */
1264 IW_HEADER_TYPE_PARAM, /* SIOCGIWRTS */
1265 IW_HEADER_TYPE_PARAM, /* SIOCSIWFRAG */
1266 IW_HEADER_TYPE_PARAM, /* SIOCGIWFRAG */
1267 IW_HEADER_TYPE_PARAM, /* SIOCSIWTXPOW */
1268 IW_HEADER_TYPE_PARAM, /* SIOCGIWTXPOW */
1269 IW_HEADER_TYPE_PARAM, /* SIOCSIWRETRY */
1270 IW_HEADER_TYPE_PARAM, /* SIOCGIWRETRY */
1271 IW_HEADER_TYPE_POINT, /* SIOCSIWENCODE */
1272 IW_HEADER_TYPE_POINT, /* SIOCGIWENCODE */
1273 IW_HEADER_TYPE_PARAM, /* SIOCSIWPOWER */
1274 IW_HEADER_TYPE_PARAM, /* SIOCGIWPOWER */
1276 static const unsigned int standard_ioctl_num = sizeof(standard_ioctl_hdr);
1279 * Meta-data about all the additional standard Wireless Extension events
1282 static const char standard_event_hdr[] = {
1283 IW_HEADER_TYPE_ADDR, /* IWEVTXDROP */
1284 IW_HEADER_TYPE_QUAL, /* IWEVQUAL */
1286 static const unsigned int standard_event_num = sizeof(standard_event_hdr);
1288 /* Size (in bytes) of various events */
1289 static const int event_type_size[] = {
1296 IW_EV_POINT_LEN, /* Without variable payload */
1302 /*------------------------------------------------------------------*/
1304 * Initialise the struct stream_descr so that we can extract
1305 * individual events from the event stream.
1308 iw_init_event_stream(struct stream_descr * stream, /* Stream of events */
1313 memset((char *) stream, '\0', sizeof(struct stream_descr));
1316 stream->current = data;
1317 stream->end = data + len;
1320 /*------------------------------------------------------------------*/
1322 * Extract the next event from the event stream.
1325 iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */
1326 struct iw_event * iwe) /* Extracted event */
1329 int event_len = 1; /* Invalid */
1331 /* Don't "optimise" the following variable, it will crash */
1332 unsigned cmd_index; /* *MUST* be unsigned */
1334 /* Check for end of stream */
1335 if((stream->current + IW_EV_LCP_LEN) > stream->end)
1339 printf("DBG - stream->current = %p, stream->value = %p, stream->end = %p\n",
1340 stream->current, stream->value, stream->end);
1343 /* Extract the event header (to get the event id).
1344 * Note : the event may be unaligned, therefore copy... */
1345 memcpy((char *) iwe, stream->current, IW_EV_LCP_LEN);
1348 printf("DBG - iwe->cmd = 0x%X, iwe->len = %d\n",
1349 iwe->cmd, iwe->len);
1352 /* Get the type and length of that event */
1353 if(iwe->cmd <= SIOCIWLAST)
1355 cmd_index = iwe->cmd - SIOCIWFIRST;
1356 if(cmd_index < standard_ioctl_num)
1357 event_type = standard_ioctl_hdr[cmd_index];
1361 cmd_index = iwe->cmd - IWEVFIRST;
1362 if(cmd_index < standard_event_num)
1363 event_type = standard_event_hdr[cmd_index];
1365 event_len = event_type_size[event_type];
1367 /* Check if we know about this event */
1368 if((event_len == 0) || (iwe->len == 0))
1370 event_len -= IW_EV_LCP_LEN;
1372 /* Set pointer on data */
1373 if(stream->value != NULL)
1374 pointer = stream->value; /* Next value in event */
1376 pointer = stream->current + IW_EV_LCP_LEN; /* First value in event */
1379 printf("DBG - event_type = %d, event_len = %d, pointer = %p\n",
1380 event_type, event_len, pointer);
1383 /* Copy the rest of the event (at least, fixed part) */
1384 if((pointer + event_len) > stream->end)
1386 memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
1388 /* Skip event in the stream */
1389 pointer += event_len;
1391 /* Special processing for iw_point events */
1392 if(event_type == IW_HEADER_TYPE_POINT)
1394 /* Check the length of the payload */
1395 if((iwe->len - (event_len + IW_EV_LCP_LEN)) > 0)
1396 /* Set pointer on variable part (warning : non aligned) */
1397 iwe->u.data.pointer = pointer;
1400 iwe->u.data.pointer = NULL;
1402 /* Go to next event */
1403 stream->current += iwe->len;
1407 /* Is there more value in the event ? */
1408 if((pointer + event_len) <= (stream->current + iwe->len))
1409 /* Go to next value */
1410 stream->value = pointer;
1413 /* Go to next event */
1414 stream->value = NULL;
1415 stream->current += iwe->len;
1421 #endif /* WIRELESS_EXT > 13 */