OSDN Git Service

v21
[android-x86/external-wireless-tools.git] / wireless_tools / iwcommon.c
1 /*
2  *      Wireless Tools
3  *
4  *              Jean II - HPLB 97->99 - HPL 99->00
5  *
6  * Common subroutines to all the wireless tools...
7  *
8  * This file is released under the GPL license.
9  */
10
11 #include "iwcommon.h"           /* Header */
12
13 /************************ SOCKET SUBROUTINES *************************/
14
15 /*------------------------------------------------------------------*/
16 /*
17  * Open a socket.
18  * Depending on the protocol present, open the right socket. The socket
19  * will allow us to talk to the driver.
20  */
21 int
22 sockets_open(void)
23 {
24         int ipx_sock = -1;              /* IPX socket                   */
25         int ax25_sock = -1;             /* AX.25 socket                 */
26         int inet_sock = -1;             /* INET socket                  */
27         int ddp_sock = -1;              /* Appletalk DDP socket         */
28
29         inet_sock=socket(AF_INET, SOCK_DGRAM, 0);
30         ipx_sock=socket(AF_IPX, SOCK_DGRAM, 0);
31         ax25_sock=socket(AF_AX25, SOCK_DGRAM, 0);
32         ddp_sock=socket(AF_APPLETALK, SOCK_DGRAM, 0);
33         /*
34          * Now pick any (exisiting) useful socket family for generic queries
35          */
36         if(inet_sock!=-1)
37                 return inet_sock;
38         if(ipx_sock!=-1)
39                 return ipx_sock;
40         if(ax25_sock!=-1)
41                 return ax25_sock;
42         /*
43          * If this is -1 we have no known network layers and its time to jump.
44          */
45          
46         return ddp_sock;
47 }
48
49 /*********************** WIRELESS SUBROUTINES ************************/
50
51 /*------------------------------------------------------------------*/
52 /*
53  * Get the range information out of the driver
54  */
55 int
56 get_range_info(int              skfd,
57                char *           ifname,
58                iwrange *        range)
59 {
60   struct iwreq          wrq;
61   char                  buffer[sizeof(iwrange) * 2];    /* Large enough */
62
63   /* Cleanup */
64   memset(buffer, 0, sizeof(range));
65
66   strcpy(wrq.ifr_name, ifname);
67   wrq.u.data.pointer = (caddr_t) buffer;
68   wrq.u.data.length = 0;
69   wrq.u.data.flags = 0;
70   if(ioctl(skfd, SIOCGIWRANGE, &wrq) < 0)
71     return(-1);
72
73   /* Copy stuff at the right place, ignore extra */
74   memcpy((char *) range, buffer, sizeof(iwrange));
75
76   /* Lot's of people have driver and tools out of sync as far as Wireless
77    * Extensions are concerned. It's because /usr/include/linux/wireless.h
78    * and /usr/src/linux/include/linux/wireless.h are different.
79    * We try to catch this stuff here... */
80
81   /* For new versions, we can check the version directly, for old versions
82    * we use magic. 300 bytes is a also magic number, don't touch... */
83   if((WIRELESS_EXT > 10) && (wrq.u.data.length >= 300))
84     {
85 #if WIRELESS_EXT > 10
86       /* Version verification - for new versions */
87       if(range->we_version_compiled != WIRELESS_EXT)
88         {
89           fprintf(stderr, "Warning : Device %s has been compiled with version %d\n", ifname, range->we_version_compiled);
90           fprintf(stderr, "of Wireless Extension, while we are using version %d.\n", WIRELESS_EXT);
91           fprintf(stderr, "Some things may be broken...\n\n");
92         }
93 #endif /* WIRELESS_EXT > 10 */
94     }
95   else
96     {
97       /* Version verification - for old versions */
98       if(wrq.u.data.length != sizeof(iwrange))
99         {
100           fprintf(stderr, "Warning : Device %s has been compiled with a different version\n", ifname);
101           fprintf(stderr, "of Wireless Extension than ours (we are using version %d).\n", WIRELESS_EXT);
102           fprintf(stderr, "Some things may be broken...\n\n");
103         }
104     }
105
106   /* Note : we are only trying to catch compile difference, not source.
107    * If the driver source has not been updated to the latest, it doesn't
108    * matter because the new fields are set to zero */
109
110   return(0);
111 }
112
113 /*------------------------------------------------------------------*/
114 /*
115  * Get information about what private ioctls are supported by the driver
116  */
117 int
118 get_priv_info(int               skfd,
119               char *            ifname,
120               iwprivargs *      priv)
121 {
122   struct iwreq          wrq;
123
124   /* Ask the driver */
125   strcpy(wrq.ifr_name, ifname);
126   wrq.u.data.pointer = (caddr_t) priv;
127   wrq.u.data.length = 0;
128   wrq.u.data.flags = 0;
129   if(ioctl(skfd, SIOCGIWPRIV, &wrq) < 0)
130     return(-1);
131
132   /* Return the number of ioctls */
133   return(wrq.u.data.length);
134 }
135
136 /********************** FREQUENCY SUBROUTINES ***********************/
137
138 /*------------------------------------------------------------------*/
139 /*
140  * Convert a floating point the our internal representation of
141  * frequencies.
142  * The kernel doesn't want to hear about floating point, so we use
143  * this custom format instead.
144  */
145 void
146 float2freq(double       in,
147            iwfreq *     out)
148 {
149   out->e = (short) (floor(log10(in)));
150   if(out->e > 8)
151     {
152       out->m = ((long) (floor(in / pow(10,out->e - 6)))) * 100;
153       out->e -= 8;
154     }
155   else
156     {
157       out->m = in;
158       out->e = 0;
159     }
160 }
161
162 /*------------------------------------------------------------------*/
163 /*
164  * Convert our internal representation of frequencies to a floating point.
165  */
166 double
167 freq2float(iwfreq *     in)
168 {
169   return ((double) in->m) * pow(10,in->e);
170 }
171
172 /************************ POWER SUBROUTINES *************************/
173
174 /*------------------------------------------------------------------*/
175 /*
176  * Convert a value in dBm to a value in milliWatt.
177  */
178 int
179 dbm2mwatt(int   in)
180 {
181   return((int) (floor(pow(10.0, (((double) in) / 10.0)))));
182 }
183
184 /*------------------------------------------------------------------*/
185 /*
186  * Convert a value in milliWatt to a value in dBm.
187  */
188 int
189 mwatt2dbm(int   in)
190 {
191   return((int) (ceil(10.0 * log10((double) in))));
192 }
193
194 /********************** STATISTICS SUBROUTINES **********************/
195
196 /*------------------------------------------------------------------*/
197 /*
198  * Output the link statistics, taking care of formating
199  */
200 void
201 print_stats(FILE *      stream,
202             iwqual *    qual,
203             iwrange *   range,
204             int         has_range)
205 {
206   /* Just do it */
207   if(has_range && (qual->level != 0))
208     {
209       /* If the statistics are in dBm */
210       if(qual->level > range->max_qual.level)
211         {
212           /* Statistics are in dBm (absolute power measurement) */
213           fprintf(stream,
214                   "Quality:%d/%d  Signal level:%d dBm  Noise level:%d dBm%s\n",
215                   qual->qual, range->max_qual.qual,
216                   qual->level - 0x100, qual->noise - 0x100,
217                   (qual->updated & 0x7) ? " (updated)" : "");
218         }
219       else
220         {
221           /* Statistics are relative values (0 -> max) */
222           fprintf(stream,
223                   "Quality:%d/%d  Signal level:%d/%d  Noise level:%d/%d%s\n",
224                   qual->qual, range->max_qual.qual,
225                   qual->level, range->max_qual.level,
226                   qual->noise, range->max_qual.noise,
227                   (qual->updated & 0x7) ? " (updated)" : "");
228         }
229     }
230   else
231     {
232       /* We can't read the range, so we don't know... */
233       fprintf(stream, "Quality:%d  Signal level:%d  Noise level:%d%s\n",
234               qual->qual, qual->level, qual->noise,
235               (qual->updated & 0x7) ? " (updated)" : "");
236     }
237 }
238
239 /*********************** ENCODING SUBROUTINES ***********************/
240
241 /*------------------------------------------------------------------*/
242 /*
243  * Output the encoding key, with a nice formating
244  */
245 void
246 print_key(FILE *                stream,
247           unsigned char *       key,
248           int                   key_size,
249           int                   key_flags)
250 {
251   int   i;
252
253   /* Is the key present ??? */
254   if(key_flags & IW_ENCODE_NOKEY)
255     {
256       /* Nope : print dummy */
257       printf("**");
258       for(i = 1; i < key_size; i++)
259         {
260           if((i & 0x1) == 0)
261             printf("-");
262           printf("**");
263         }
264     }
265   else
266     {
267       /* Yes : print the key */
268       printf("%.2X", key[0]);
269       for(i = 1; i < key_size; i++)
270         {
271           if((i & 0x1) == 0)
272             printf("-");
273           printf("%.2X", key[i]);
274         }
275     }
276 }
277
278
279 /******************* POWER MANAGEMENT SUBROUTINES *******************/
280
281 /*------------------------------------------------------------------*/
282 /*
283  * Output a power management value with all attributes...
284  */
285 void
286 print_pm_value(FILE *   stream,
287                int      value,
288                int      flags)
289 {
290   /* Modifiers */
291   if(flags & IW_POWER_MIN)
292     fprintf(stream, " min");
293   if(flags & IW_POWER_MAX)
294     fprintf(stream, " max");
295
296   /* Type */
297   if(flags & IW_POWER_TIMEOUT)
298     fprintf(stream, " timeout:");
299   else
300     fprintf(stream, " period:");
301
302   /* Display value without units */
303   if(flags & IW_POWER_RELATIVE)
304     fprintf(stream, "%g  ", ((double) value) / MEGA);
305   else
306     {
307       /* Display value with units */
308       if(value >= (int) MEGA)
309         fprintf(stream, "%gs  ", ((double) value) / MEGA);
310       else
311         if(value >= (int) KILO)
312           fprintf(stream, "%gms  ", ((double) value) / KILO);
313         else
314           fprintf(stream, "%dus  ", value);
315     }
316 }
317
318 /*------------------------------------------------------------------*/
319 /*
320  * Output a power management mode
321  */
322 void
323 print_pm_mode(FILE *    stream,
324               int       flags)
325 {
326   /* Print the proper mode... */
327   switch(flags & IW_POWER_MODE)
328     {
329     case IW_POWER_UNICAST_R:
330       fprintf(stream, " mode:Unicast only received");
331       break;
332     case IW_POWER_MULTICAST_R:
333       fprintf(stream, " mode:Multicast only received");
334       break;
335     case IW_POWER_ALL_R:
336       fprintf(stream, " mode:All packets received");
337       break;
338     case IW_POWER_FORCE_S:
339       fprintf(stream, " mode:Force sending");
340       break;
341     case IW_POWER_REPEATER:
342       fprintf(stream, " mode:Repeat multicasts");
343       break;
344     default:
345     }
346 }
347
348 /***************** RETRY LIMIT/LIFETIME SUBROUTINES *****************/
349
350 #if WIRELESS_EXT > 10
351 /*------------------------------------------------------------------*/
352 /*
353  * Output a retry value with all attributes...
354  */
355 void
356 print_retry_value(FILE *        stream,
357                   int           value,
358                   int           flags)
359 {
360   /* Modifiers */
361   if(flags & IW_RETRY_MIN)
362     fprintf(stream, " min");
363   if(flags & IW_RETRY_MAX)
364     fprintf(stream, " max");
365
366   /* Type lifetime of limit */
367   if(flags & IW_RETRY_LIFETIME)
368     {
369       fprintf(stream, " lifetime:");
370
371       /* Display value without units */
372       if(flags & IW_POWER_RELATIVE)
373         fprintf(stream, "%g", ((double) value) / MEGA);
374       else
375         {
376           /* Display value with units */
377           if(value >= (int) MEGA)
378             fprintf(stream, "%gs", ((double) value) / MEGA);
379           else
380             if(value >= (int) KILO)
381               fprintf(stream, "%gms", ((double) value) / KILO);
382             else
383               fprintf(stream, "%dus", value);
384         }
385     }
386   else
387     fprintf(stream, " limit:%d", value);
388 }
389 #endif  /* WIRELESS_EXT > 10 */
390
391 /*********************** ADDRESS SUBROUTINES ************************/
392 /*
393  * This section is mostly a cut & past from net-tools-1.2.0
394  * manage address display and input...
395  */
396
397 /*------------------------------------------------------------------*/
398 /*
399  * Check if interface support the right address types...
400  */
401 int
402 check_addr_type(int     skfd,
403                 char *  ifname)
404 {
405   struct ifreq          ifr;
406
407   /* Get the type of interface address */
408   strcpy(ifr.ifr_name, ifname);
409   if((ioctl(skfd, SIOCGIFADDR, &ifr) < 0) ||
410      (ifr.ifr_addr.sa_family !=  AF_INET))
411     {
412       /* Deep trouble... */
413       fprintf(stderr, "Interface %s doesn't support IP addresses\n", ifname);
414       return(-1);
415     }
416
417 #ifdef DEBUG
418   printf("Interface : %d - 0x%lX\n", ifr.ifr_addr.sa_family,
419          *((unsigned long *) ifr.ifr_addr.sa_data));
420 #endif
421
422   /* Get the type of hardware address */
423   strcpy(ifr.ifr_name, ifname);
424   if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) ||
425      (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER))
426     {
427       /* Deep trouble... */
428       fprintf(stderr, "Interface %s doesn't support MAC addresses\n",
429              ifname);
430       return(-1);
431     }
432
433 #ifdef DEBUG
434   printf("Hardware : %d - %s\n", ifr.ifr_hwaddr.sa_family,
435          pr_ether(ifr.ifr_hwaddr.sa_data));
436 #endif
437
438   return(0);
439 }
440
441
442 /*------------------------------------------------------------------*/
443 /*
444  * Display an Ethernet address in readable format.
445  */
446 char *
447 pr_ether(unsigned char *ptr)
448 {
449   static char buff[64];
450
451   sprintf(buff, "%02X:%02X:%02X:%02X:%02X:%02X",
452         (ptr[0] & 0xFF), (ptr[1] & 0xFF), (ptr[2] & 0xFF),
453         (ptr[3] & 0xFF), (ptr[4] & 0xFF), (ptr[5] & 0xFF)
454   );
455   return(buff);
456 }
457
458 /*------------------------------------------------------------------*/
459 /*
460  * Input an Ethernet address and convert to binary.
461  */
462 int
463 in_ether(char *bufp, struct sockaddr *sap)
464 {
465   unsigned char *ptr;
466   char c, *orig;
467   int i, val;
468
469   sap->sa_family = ARPHRD_ETHER;
470   ptr = sap->sa_data;
471
472   i = 0;
473   orig = bufp;
474   while((*bufp != '\0') && (i < ETH_ALEN)) {
475         val = 0;
476         c = *bufp++;
477         if (isdigit(c)) val = c - '0';
478           else if (c >= 'a' && c <= 'f') val = c - 'a' + 10;
479           else if (c >= 'A' && c <= 'F') val = c - 'A' + 10;
480           else {
481 #ifdef DEBUG
482                 fprintf(stderr, "in_ether(%s): invalid ether address!\n", orig);
483 #endif
484                 errno = EINVAL;
485                 return(-1);
486         }
487         val <<= 4;
488         c = *bufp++;
489         if (isdigit(c)) val |= c - '0';
490           else if (c >= 'a' && c <= 'f') val |= c - 'a' + 10;
491           else if (c >= 'A' && c <= 'F') val |= c - 'A' + 10;
492           else {
493 #ifdef DEBUG
494                 fprintf(stderr, "in_ether(%s): invalid ether address!\n", orig);
495 #endif
496                 errno = EINVAL;
497                 return(-1);
498         }
499         *ptr++ = (unsigned char) (val & 0377);
500         i++;
501
502         /* We might get a semicolon here - not required. */
503         if (*bufp == ':') {
504                 if (i == ETH_ALEN) {
505 #ifdef DEBUG
506                         fprintf(stderr, "in_ether(%s): trailing : ignored!\n",
507                                 orig)
508 #endif
509                                                 ; /* nothing */
510                 }
511                 bufp++;
512         }
513   }
514
515   /* That's it.  Any trailing junk? */
516   if ((i == ETH_ALEN) && (*bufp != '\0')) {
517 #ifdef DEBUG
518         fprintf(stderr, "in_ether(%s): trailing junk!\n", orig);
519         errno = EINVAL;
520         return(-1);
521 #endif
522   }
523
524 #ifdef DEBUG
525   fprintf(stderr, "in_ether(%s): %s\n", orig, pr_ether(sap->sa_data));
526 #endif
527
528   return(0);
529 }
530
531 /*------------------------------------------------------------------*/
532 /*
533  * Input an Internet address and convert to binary.
534  */
535 int
536 in_inet(char *bufp, struct sockaddr *sap)
537 {
538   struct hostent *hp;
539   struct netent *np;
540   char *name = bufp;
541   struct sockaddr_in *sin = (struct sockaddr_in *) sap;
542
543   /* Grmpf. -FvK */
544   sin->sin_family = AF_INET;
545   sin->sin_port = 0;
546
547   /* Default is special, meaning 0.0.0.0. */
548   if (!strcmp(name, "default")) {
549         sin->sin_addr.s_addr = INADDR_ANY;
550         return(1);
551   }
552
553   /* Try the NETWORKS database to see if this is a known network. */
554   if ((np = getnetbyname(name)) != (struct netent *)NULL) {
555         sin->sin_addr.s_addr = htonl(np->n_net);
556         strcpy(name, np->n_name);
557         return(1);
558   }
559
560   if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
561         errno = h_errno;
562         return(-1);
563   }
564   memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], hp->h_length);
565   strcpy(name, hp->h_name);
566   return(0);
567 }
568
569 /*------------------------------------------------------------------*/
570 /*
571  * Input an address and convert to binary.
572  */
573 int
574 in_addr(int             skfd,
575         char *          ifname,
576         char *          bufp,
577         struct sockaddr *sap)
578 {
579   /* Check if it is a hardware or IP address */
580   if(index(bufp, ':') == NULL)
581     {
582       struct sockaddr   if_address;
583       struct arpreq     arp_query;
584
585       /* Read interface address */
586       if(in_inet(bufp, &if_address) < 0)
587         {
588           fprintf(stderr, "Invalid interface address %s\n", bufp);
589           return(-1);
590         }
591
592       /* Translate IP addresses to MAC addresses */
593       memcpy((char *) &(arp_query.arp_pa),
594              (char *) &if_address,
595              sizeof(struct sockaddr));
596       arp_query.arp_ha.sa_family = 0;
597       arp_query.arp_flags = 0;
598       /* The following restrict the search to the interface only */
599       /* For old kernels which complain, just comment it... */
600       strcpy(arp_query.arp_dev, ifname);
601       if((ioctl(skfd, SIOCGARP, &arp_query) < 0) ||
602          !(arp_query.arp_flags & ATF_COM))
603         {
604           fprintf(stderr, "Arp failed for %s on %s... (%d)\nTry to ping the address before setting it.\n",
605                   bufp, ifname, errno);
606           return(-1);
607         }
608
609       /* Store new MAC address */
610       memcpy((char *) sap,
611              (char *) &(arp_query.arp_ha),
612              sizeof(struct sockaddr));
613
614 #ifdef DEBUG
615       printf("IP Address %s => Hw Address = %s\n",
616              bufp, pr_ether(sap->sa_data));
617 #endif
618     }
619   else  /* If it's an hardware address */
620     /* Get the hardware address */
621     if(in_ether(bufp, sap) < 0)
622       {
623         fprintf(stderr, "Invalid hardware address %s\n", bufp);
624         return(-1);
625       }
626
627 #ifdef DEBUG
628   printf("Hw Address = %s\n", pr_ether(sap->sa_data));
629 #endif
630
631   return(0);
632 }
633
634 /************************* MISC SUBROUTINES **************************/
635
636 /*------------------------------------------------------------------*/
637 /*
638  */
639 int
640 byte_size(int   args)
641 {
642   int   ret = args & IW_PRIV_SIZE_MASK;
643
644   if(((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_INT) ||
645      ((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_FLOAT))
646     ret <<= 2;
647
648   if((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_NONE)
649     return 0;
650
651   return ret;
652 }
653