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 * 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 int ipx_sock = -1; /* IPX socket */
35 int ax25_sock = -1; /* AX.25 socket */
36 int inet_sock = -1; /* INET socket */
37 int ddp_sock = -1; /* Appletalk DDP socket */
40 * Now pick any (exisiting) useful socket family for generic queries
41 * Note : don't open all the socket, only returns when one matches,
42 * all protocols might not be valid.
43 * Workaround by Jim Kaba <jkaba@sarnoff.com>
44 * Note : in 99% of the case, we will just open the inet_sock.
45 * The remaining 1% case are not fully correct...
47 inet_sock=socket(AF_INET, SOCK_DGRAM, 0);
50 ipx_sock=socket(AF_IPX, SOCK_DGRAM, 0);
53 ax25_sock=socket(AF_AX25, SOCK_DGRAM, 0);
56 ddp_sock=socket(AF_APPLETALK, SOCK_DGRAM, 0);
58 * If this is -1 we have no known network layers and its time to jump.
63 /*********************** WIRELESS SUBROUTINES ************************/
65 /*------------------------------------------------------------------*/
67 * Get the range information out of the driver
70 iw_get_range_info(int skfd,
75 char buffer[sizeof(iwrange) * 2]; /* Large enough */
78 memset(buffer, 0, sizeof(iwrange) * 2);
80 wrq.u.data.pointer = (caddr_t) buffer;
81 wrq.u.data.length = sizeof(iwrange) * 2;
83 if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
86 /* Copy stuff at the right place, ignore extra */
87 memcpy((char *) range, buffer, sizeof(iwrange));
89 /* Lot's of people have driver and tools out of sync as far as Wireless
90 * Extensions are concerned. It's because /usr/include/linux/wireless.h
91 * and /usr/src/linux/include/linux/wireless.h are different.
92 * We try to catch this stuff here... */
94 /* For new versions, we can check the version directly, for old versions
95 * we use magic. 300 bytes is a also magic number, don't touch... */
96 if((WIRELESS_EXT > 10) && (wrq.u.data.length >= 300))
99 /* Version verification - for new versions */
100 if(range->we_version_compiled != WIRELESS_EXT)
102 fprintf(stderr, "Warning : Device %s has been compiled with version %d\n", ifname, range->we_version_compiled);
103 fprintf(stderr, "of Wireless Extension, while we are using version %d.\n", WIRELESS_EXT);
104 fprintf(stderr, "Some things may be broken...\n\n");
106 #endif /* WIRELESS_EXT > 10 */
110 /* Version verification - for old versions */
111 if(wrq.u.data.length != sizeof(iwrange))
113 fprintf(stderr, "Warning : Device %s has been compiled with a different version\n", ifname);
114 fprintf(stderr, "of Wireless Extension than ours (we are using version %d).\n", WIRELESS_EXT);
115 fprintf(stderr, "Some things may be broken...\n\n");
119 /* Note : we are only trying to catch compile difference, not source.
120 * If the driver source has not been updated to the latest, it doesn't
121 * matter because the new fields are set to zero */
126 /*------------------------------------------------------------------*/
128 * Get information about what private ioctls are supported by the driver
131 iw_get_priv_info(int skfd,
138 wrq.u.data.pointer = (caddr_t) priv;
139 wrq.u.data.length = 32;
140 wrq.u.data.flags = 0;
141 if(iw_get_ext(skfd, ifname, SIOCGIWPRIV, &wrq) < 0)
144 /* Return the number of ioctls */
145 return(wrq.u.data.length);
148 /*------------------------------------------------------------------*/
150 * Get essential wireless config from the device driver
151 * We will call all the classical wireless ioctl on the driver through
152 * the socket to know what is supported and to get the settings...
153 * Note : compare to the version in iwconfig, we extract only
154 * what's *really* needed to configure a device...
157 iw_get_basic_config(int skfd,
159 wireless_config * info)
163 memset((char *) info, 0, sizeof(struct wireless_config));
165 /* Get wireless name */
166 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
167 /* If no wireless name : no wireless extensions */
170 strcpy(info->name, wrq.u.name);
173 if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) >= 0)
176 memcpy(&(info->nwid), &(wrq.u.nwid), sizeof(iwparam));
179 /* Get frequency / channel */
180 if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
183 info->freq = iw_freq2float(&(wrq.u.freq));
186 /* Get encryption information */
187 wrq.u.data.pointer = (caddr_t) info->key;
188 wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
189 wrq.u.data.flags = 0;
190 if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
193 info->key_size = wrq.u.data.length;
194 info->key_flags = wrq.u.data.flags;
198 wrq.u.essid.pointer = (caddr_t) info->essid;
199 wrq.u.essid.length = IW_ESSID_MAX_SIZE;
200 wrq.u.essid.flags = 0;
201 if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) >= 0)
204 info->essid_on = wrq.u.data.flags;
207 /* Get operation mode */
208 if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) >= 0)
210 if((wrq.u.mode < 6) && (wrq.u.mode >= 0))
212 info->mode = wrq.u.mode;
218 /*------------------------------------------------------------------*/
220 * Set essential wireless config in the device driver
221 * We will call all the classical wireless ioctl on the driver through
222 * the socket to know what is supported and to set the settings...
223 * We support only the restricted set as above...
226 iw_set_basic_config(int skfd,
228 wireless_config * info)
233 /* Get wireless name (check if interface is valid) */
234 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
235 /* If no wireless name : no wireless extensions */
238 /* Set Network ID, if available (this is for non-802.11 cards) */
241 memcpy(&(wrq.u.nwid), &(info->nwid), sizeof(iwparam));
242 wrq.u.nwid.fixed = 1; /* Hum... When in Rome... */
244 if(iw_set_ext(skfd, ifname, SIOCSIWNWID, &wrq) < 0)
246 fprintf(stderr, "SIOCSIWNWID: %s\n", strerror(errno));
251 /* Set frequency / channel */
254 iw_float2freq(info->freq, &(wrq.u.freq));
256 if(iw_set_ext(skfd, ifname, SIOCSIWFREQ, &wrq) < 0)
258 fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
263 /* Set encryption information */
266 int flags = info->key_flags;
268 /* Check if there is a key index */
269 if((flags & IW_ENCODE_INDEX) > 0)
272 wrq.u.data.pointer = (caddr_t) NULL;
273 wrq.u.data.flags = (flags & (IW_ENCODE_INDEX)) | IW_ENCODE_NOKEY;
274 wrq.u.data.length = 0;
276 if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
278 fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
279 errno, strerror(errno));
284 /* Mask out index to minimise probability of reject when setting key */
285 flags = flags & (~IW_ENCODE_INDEX);
287 /* Set the key itself (set current key in this case) */
288 wrq.u.data.pointer = (caddr_t) info->key;
289 wrq.u.data.length = info->key_size;
290 wrq.u.data.flags = flags;
292 if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
294 fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
295 errno, strerror(errno));
300 /* Set ESSID (extended network), if available */
303 wrq.u.essid.pointer = (caddr_t) info->essid;
304 wrq.u.essid.length = strlen(info->essid) + 1;
305 wrq.u.data.flags = info->essid_on;
307 if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0)
309 fprintf(stderr, "SIOCSIWESSID: %s\n", strerror(errno));
314 /* Set the current mode of operation */
317 strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
318 wrq.u.mode = info->mode;
320 if(iw_get_ext(skfd, ifname, SIOCSIWMODE, &wrq) < 0)
322 fprintf(stderr, "SIOCSIWMODE: %s\n", strerror(errno));
330 /********************** FREQUENCY SUBROUTINES ***********************/
332 /*------------------------------------------------------------------*/
334 * Convert a floating point the our internal representation of
336 * The kernel doesn't want to hear about floating point, so we use
337 * this custom format instead.
340 iw_float2freq(double in,
343 out->e = (short) (floor(log10(in)));
346 out->m = ((long) (floor(in / pow(10,out->e - 6)))) * 100;
356 /*------------------------------------------------------------------*/
358 * Convert our internal representation of frequencies to a floating point.
361 iw_freq2float(iwfreq * in)
363 return ((double) in->m) * pow(10,in->e);
366 /************************ POWER SUBROUTINES *************************/
368 /*------------------------------------------------------------------*/
370 * Convert a value in dBm to a value in milliWatt.
375 return((int) (floor(pow(10.0, (((double) in) / 10.0)))));
378 /*------------------------------------------------------------------*/
380 * Convert a value in milliWatt to a value in dBm.
385 return((int) (ceil(10.0 * log10((double) in))));
388 /********************** STATISTICS SUBROUTINES **********************/
390 /*------------------------------------------------------------------*/
392 * Read /proc/net/wireless to get the latest statistics
395 iw_get_stats(int skfd,
399 #if WIRELESS_EXT > 11
401 wrq.u.data.pointer = (caddr_t) stats;
402 wrq.u.data.length = 0;
403 wrq.u.data.flags = 1; /* Clear updated flag */
404 strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
405 if(iw_get_ext(skfd, ifname, SIOCGIWSTATS, &wrq) < 0)
409 #else /* WIRELESS_EXT > 11 */
410 FILE * f=fopen("/proc/net/wireless","r");
416 /* Loop on all devices */
417 while(fgets(buf,255,f))
420 while(*bp&&isspace(*bp))
422 /* Is it the good device ? */
423 if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':')
429 bp = strtok(bp, " ");
430 sscanf(bp, "%X", &t);
431 stats->status = (unsigned short) t;
432 /* -- link quality -- */
433 bp = strtok(NULL, " ");
434 if(strchr(bp,'.') != NULL)
435 stats->qual.updated |= 1;
436 sscanf(bp, "%d", &t);
437 stats->qual.qual = (unsigned char) t;
438 /* -- signal level -- */
439 bp = strtok(NULL, " ");
440 if(strchr(bp,'.') != NULL)
441 stats->qual.updated |= 2;
442 sscanf(bp, "%d", &t);
443 stats->qual.level = (unsigned char) t;
444 /* -- noise level -- */
445 bp = strtok(NULL, " ");
446 if(strchr(bp,'.') != NULL)
447 stats->qual.updated += 4;
448 sscanf(bp, "%d", &t);
449 stats->qual.noise = (unsigned char) t;
450 /* -- discarded packets -- */
451 bp = strtok(NULL, " ");
452 sscanf(bp, "%d", &stats->discard.nwid);
453 bp = strtok(NULL, " ");
454 sscanf(bp, "%d", &stats->discard.code);
455 bp = strtok(NULL, " ");
456 sscanf(bp, "%d", &stats->discard.misc);
463 #endif /* WIRELESS_EXT > 11 */
466 /*------------------------------------------------------------------*/
468 * Output the link statistics, taking care of formating
471 iw_print_stats(char * buffer,
477 if(has_range && (qual->level != 0))
479 /* If the statistics are in dBm */
480 if(qual->level > range->max_qual.level)
482 /* Statistics are in dBm (absolute power measurement) */
484 "Quality:%d/%d Signal level:%d dBm Noise level:%d dBm%s",
485 qual->qual, range->max_qual.qual,
486 qual->level - 0x100, qual->noise - 0x100,
487 (qual->updated & 0x7) ? " (updated)" : "");
491 /* Statistics are relative values (0 -> max) */
493 "Quality:%d/%d Signal level:%d/%d Noise level:%d/%d%s",
494 qual->qual, range->max_qual.qual,
495 qual->level, range->max_qual.level,
496 qual->noise, range->max_qual.noise,
497 (qual->updated & 0x7) ? " (updated)" : "");
502 /* We can't read the range, so we don't know... */
503 sprintf(buffer, "Quality:%d Signal level:%d Noise level:%d%s",
504 qual->qual, qual->level, qual->noise,
505 (qual->updated & 0x7) ? " (updated)" : "");
509 /*********************** ENCODING SUBROUTINES ***********************/
511 /*------------------------------------------------------------------*/
513 * Output the encoding key, with a nice formating
516 iw_print_key(char * buffer,
523 /* Is the key present ??? */
524 if(key_flags & IW_ENCODE_NOKEY)
526 /* Nope : print dummy */
527 strcpy(buffer, "**");
529 for(i = 1; i < key_size; i++)
532 strcpy(buffer++, "-");
533 strcpy(buffer, "**");
539 /* Yes : print the key */
540 sprintf(buffer, "%.2X", key[0]);
542 for(i = 1; i < key_size; i++)
545 strcpy(buffer++, "-");
546 sprintf(buffer, "%.2X", key[i]);
553 /******************* POWER MANAGEMENT SUBROUTINES *******************/
555 /*------------------------------------------------------------------*/
557 * Output a power management value with all attributes...
560 iw_print_pm_value(char * buffer,
565 if(flags & IW_POWER_MIN)
567 strcpy(buffer, " min");
570 if(flags & IW_POWER_MAX)
572 strcpy(buffer, " max");
577 if(flags & IW_POWER_TIMEOUT)
579 strcpy(buffer, " timeout:");
584 strcpy(buffer, " period:");
588 /* Display value without units */
589 if(flags & IW_POWER_RELATIVE)
590 sprintf(buffer, "%g ", ((double) value) / MEGA);
593 /* Display value with units */
594 if(value >= (int) MEGA)
595 sprintf(buffer, "%gs ", ((double) value) / MEGA);
597 if(value >= (int) KILO)
598 sprintf(buffer, "%gms ", ((double) value) / KILO);
600 sprintf(buffer, "%dus ", value);
604 /*------------------------------------------------------------------*/
606 * Output a power management mode
609 iw_print_pm_mode(char * buffer,
612 /* Print the proper mode... */
613 switch(flags & IW_POWER_MODE)
615 case IW_POWER_UNICAST_R:
616 strcpy(buffer, " mode:Unicast only received");
618 case IW_POWER_MULTICAST_R:
619 strcpy(buffer, " mode:Multicast only received");
622 strcpy(buffer, " mode:All packets received");
624 case IW_POWER_FORCE_S:
625 strcpy(buffer, " mode:Force sending");
627 case IW_POWER_REPEATER:
628 strcpy(buffer, " mode:Repeat multicasts");
634 /***************** RETRY LIMIT/LIFETIME SUBROUTINES *****************/
636 #if WIRELESS_EXT > 10
637 /*------------------------------------------------------------------*/
639 * Output a retry value with all attributes...
642 iw_print_retry_value(char * buffer,
647 if(flags & IW_RETRY_MIN)
649 strcpy(buffer, " min");
652 if(flags & IW_RETRY_MAX)
654 strcpy(buffer, " max");
658 /* Type lifetime of limit */
659 if(flags & IW_RETRY_LIFETIME)
661 strcpy(buffer, " lifetime:");
664 /* Display value without units */
665 if(flags & IW_POWER_RELATIVE)
666 sprintf(buffer, "%g", ((double) value) / MEGA);
669 /* Display value with units */
670 if(value >= (int) MEGA)
671 sprintf(buffer, "%gs", ((double) value) / MEGA);
673 if(value >= (int) KILO)
674 sprintf(buffer, "%gms", ((double) value) / KILO);
676 sprintf(buffer, "%dus", value);
680 sprintf(buffer, " limit:%d", value);
682 #endif /* WIRELESS_EXT > 10 */
684 /*********************** ADDRESS SUBROUTINES ************************/
686 * This section is mostly a cut & past from net-tools-1.2.0
687 * manage address display and input...
690 /*------------------------------------------------------------------*/
692 * Check if interface support the right MAC address type...
695 iw_check_mac_addr_type(int skfd,
700 /* Get the type of hardware address */
701 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
702 if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) ||
703 (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER))
705 /* Deep trouble... */
706 fprintf(stderr, "Interface %s doesn't support MAC addresses\n",
712 printf("Hardware : %d - %s\n", ifr.ifr_hwaddr.sa_family,
713 pr_ether(ifr.ifr_hwaddr.sa_data));
720 /*------------------------------------------------------------------*/
722 * Check if interface support the right interface address type...
725 iw_check_if_addr_type(int skfd,
730 /* Get the type of interface address */
731 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
732 if((ioctl(skfd, SIOCGIFADDR, &ifr) < 0) ||
733 (ifr.ifr_addr.sa_family != AF_INET))
735 /* Deep trouble... */
736 fprintf(stderr, "Interface %s doesn't support IP addresses\n", ifname);
741 printf("Interface : %d - 0x%lX\n", ifr.ifr_addr.sa_family,
742 *((unsigned long *) ifr.ifr_addr.sa_data));
749 /*------------------------------------------------------------------*/
751 * Check if interface support the right address types...
754 iw_check_addr_type(int skfd,
757 /* Check the interface address type */
758 if(iw_check_if_addr_type(skfd, ifname) < 0)
761 /* Check the interface address type */
762 if(iw_check_mac_addr_type(skfd, ifname) < 0)
769 /*------------------------------------------------------------------*/
771 * Display an Ethernet address in readable format.
774 iw_pr_ether(char * buffer,
777 sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X",
778 (ptr[0] & 0xFF), (ptr[1] & 0xFF), (ptr[2] & 0xFF),
779 (ptr[3] & 0xFF), (ptr[4] & 0xFF), (ptr[5] & 0xFF)
784 /*------------------------------------------------------------------*/
786 * Input an Ethernet address and convert to binary.
789 iw_in_ether(char *bufp, struct sockaddr *sap)
795 sap->sa_family = ARPHRD_ETHER;
800 while((*bufp != '\0') && (i < ETH_ALEN)) {
803 if (isdigit(c)) val = c - '0';
804 else if (c >= 'a' && c <= 'f') val = c - 'a' + 10;
805 else if (c >= 'A' && c <= 'F') val = c - 'A' + 10;
808 fprintf(stderr, "in_ether(%s): invalid ether address!\n", orig);
815 if (isdigit(c)) val |= c - '0';
816 else if (c >= 'a' && c <= 'f') val |= c - 'a' + 10;
817 else if (c >= 'A' && c <= 'F') val |= c - 'A' + 10;
820 fprintf(stderr, "in_ether(%s): invalid ether address!\n", orig);
825 *ptr++ = (unsigned char) (val & 0377);
828 /* We might get a semicolon here - not required. */
832 fprintf(stderr, "in_ether(%s): trailing : ignored!\n",
841 /* That's it. Any trailing junk? */
842 if ((i == ETH_ALEN) && (*bufp != '\0')) {
844 fprintf(stderr, "in_ether(%s): trailing junk!\n", orig);
851 fprintf(stderr, "in_ether(%s): %s\n", orig, pr_ether(sap->sa_data));
857 /*------------------------------------------------------------------*/
859 * Input an Internet address and convert to binary.
862 iw_in_inet(char *bufp, struct sockaddr *sap)
867 struct sockaddr_in *sin = (struct sockaddr_in *) sap;
870 sin->sin_family = AF_INET;
873 /* Default is special, meaning 0.0.0.0. */
874 if (!strcmp(name, "default")) {
875 sin->sin_addr.s_addr = INADDR_ANY;
879 /* Try the NETWORKS database to see if this is a known network. */
880 if ((np = getnetbyname(name)) != (struct netent *)NULL) {
881 sin->sin_addr.s_addr = htonl(np->n_net);
882 strcpy(name, np->n_name);
886 if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
890 memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], hp->h_length);
891 strcpy(name, hp->h_name);
895 /*------------------------------------------------------------------*/
897 * Input an address and convert to binary.
903 struct sockaddr *sap)
905 /* Check if it is a hardware or IP address */
906 if(index(bufp, ':') == NULL)
908 struct sockaddr if_address;
909 struct arpreq arp_query;
911 /* Check if we have valid interface address type */
912 if(iw_check_if_addr_type(skfd, ifname) < 0)
914 fprintf(stderr, "%-8.8s Interface doesn't support IP addresses\n", ifname);
918 /* Read interface address */
919 if(iw_in_inet(bufp, &if_address) < 0)
921 fprintf(stderr, "Invalid interface address %s\n", bufp);
925 /* Translate IP addresses to MAC addresses */
926 memcpy((char *) &(arp_query.arp_pa),
927 (char *) &if_address,
928 sizeof(struct sockaddr));
929 arp_query.arp_ha.sa_family = 0;
930 arp_query.arp_flags = 0;
931 /* The following restrict the search to the interface only */
932 /* For old kernels which complain, just comment it... */
933 strncpy(arp_query.arp_dev, ifname, IFNAMSIZ);
934 if((ioctl(skfd, SIOCGARP, &arp_query) < 0) ||
935 !(arp_query.arp_flags & ATF_COM))
937 fprintf(stderr, "Arp failed for %s on %s... (%d)\nTry to ping the address before setting it.\n",
938 bufp, ifname, errno);
942 /* Store new MAC address */
944 (char *) &(arp_query.arp_ha),
945 sizeof(struct sockaddr));
948 printf("IP Address %s => Hw Address = %s\n",
949 bufp, pr_ether(sap->sa_data));
952 else /* If it's an hardware address */
954 /* Check if we have valid mac address type */
955 if(iw_check_mac_addr_type(skfd, ifname) < 0)
957 fprintf(stderr, "%-8.8s Interface doesn't support MAC addresses\n", ifname);
961 /* Get the hardware address */
962 if(iw_in_ether(bufp, sap) < 0)
964 fprintf(stderr, "Invalid hardware address %s\n", bufp);
970 printf("Hw Address = %s\n", pr_ether(sap->sa_data));
976 /************************* MISC SUBROUTINES **************************/
978 /*------------------------------------------------------------------*/
982 iw_byte_size(int args)
984 int ret = args & IW_PRIV_SIZE_MASK;
986 if(((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_INT) ||
987 ((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_FLOAT))
990 if((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_NONE)