OSDN Git Service

v19
[android-x86/external-wireless-tools.git] / wireless_tools / iwspy.c
1 /*
2  *      Wireless Tools
3  *
4  *              Jean II - HPLB '99
5  *
6  * Main code for "iwconfig". This is the generic tool for most
7  * manipulations...
8  * You need to link this code against "iwcommon.c" and "-lm".
9  */
10
11 #include "iwcommon.h"           /* Header */
12
13 /************************* DISPLAY ROUTINES **************************/
14
15 /*------------------------------------------------------------------*/
16 /*
17  * Display the spy list of addresses and the associated stats
18  */
19 static void
20 print_spy_info(int      skfd,
21                char *   ifname)
22 {
23   struct iwreq          wrq;
24   char          buffer[(sizeof(struct iw_quality) +
25                         sizeof(struct sockaddr)) * IW_MAX_SPY];
26   struct sockaddr       hwa[IW_MAX_SPY];
27   struct iw_quality     qual[IW_MAX_SPY];
28   iwrange       range;
29   int           has_range = 0;
30   int           n;
31   int           i;
32
33   /* Collect stats */
34   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
35   wrq.u.data.pointer = (caddr_t) buffer;
36   wrq.u.data.length = 0;
37   wrq.u.data.flags = 0;
38   if(ioctl(skfd, SIOCGIWSPY, &wrq) < 0)
39     {
40       fprintf(stderr, "%-8.8s  Interface doesn't support wireless statistic collection\n\n", ifname);
41       return;
42     }
43
44   /* Number of addresses */
45   n = wrq.u.data.length;
46
47
48
49   /* Check if we have valid address types */
50   if(check_addr_type(skfd, ifname) < 0)
51     {
52       fprintf(stderr, "%-8.8s  Interface doesn't support MAC & IP addresses\n\n", ifname);
53       return;
54     }
55
56   /* Get range info if we can */
57   if(get_range_info(skfd, ifname, &(range)) >= 0)
58     has_range = 1;
59
60   /* Display it */
61   if(n == 0)
62     printf("%-8.8s  No statistics to collect\n", ifname);
63   else
64     printf("%-8.8s  Statistics collected:\n", ifname);
65  
66   /* The two lists */
67
68   memcpy(hwa, buffer, n * sizeof(struct sockaddr));
69   memcpy(qual, buffer + n*sizeof(struct sockaddr), n*sizeof(struct iw_quality));
70
71   for(i = 0; i < n; i++)
72     {
73       if(has_range && (qual[i].level != 0))
74         /* If the statistics are in dBm */
75         if(qual[i].level > range.max_qual.level)
76           printf("    %s : Quality %d/%d ; Signal %d dBm ; Noise %d dBm %s\n",
77                  pr_ether(hwa[i].sa_data),
78                  qual[i].qual, range.max_qual.qual,
79                  qual[i].level - 0x100, qual[i].noise - 0x100,
80                  qual[i].updated & 0x7 ? "(updated)" : "");
81         else
82           printf("    %s : Quality %d/%d ; Signal %d/%d ; Noise %d/%d %s\n",
83                  pr_ether(hwa[i].sa_data),
84                  qual[i].qual, range.max_qual.qual,
85                  qual[i].level, range.max_qual.level,
86                  qual[i].noise, range.max_qual.noise,
87                  qual[i].updated & 0x7 ? "(updated)" : "");
88       else
89         printf("    %s : Quality %d ; Signal %d ; Noise %d %s\n",
90                pr_ether(hwa[i].sa_data),
91                qual[i].qual, qual[i].level, qual[i].noise,
92                qual[i].updated & 0x7 ? "(updated)" : "");
93     }
94   printf("\n");
95 }
96
97 /*------------------------------------------------------------------*/
98 /*
99  * Get info on all devices and print it on the screen
100  */
101 static void
102 print_spy_devices(int           skfd)
103 {
104   char          buff[1024];
105   struct ifconf ifc;
106   struct ifreq *ifr;
107   int i;
108
109   /* Get list of active devices */
110   ifc.ifc_len = sizeof(buff);
111   ifc.ifc_buf = buff;
112   if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
113     {
114       fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
115       return;
116     }
117   ifr = ifc.ifc_req;
118
119   /* Print them */
120   for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
121     print_spy_info(skfd, ifr->ifr_name);
122 }
123
124 /*------------------------------------------------------------------*/
125 /*
126  * Print the number of channels and available frequency for the device
127  */
128 static void
129 print_freq_info(int             skfd,
130                 char *          ifname)
131 {
132   struct iwreq          wrq;
133   float                 freq;
134   struct iw_range       range;
135   int                   k;
136
137   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
138   wrq.u.data.pointer = (caddr_t) &range;
139   wrq.u.data.length = 0;
140   wrq.u.data.flags = 0;
141   if(ioctl(skfd, SIOCGIWRANGE, &wrq) < 0)
142       fprintf(stderr, "%-8.8s  no frequency information.\n\n",
143                       ifname);
144   else
145     {
146       if(range.num_frequency > 0)
147         {
148           printf("%-8.8s  %d channels in total; available frequencies :\n",
149                  ifname, range.num_channels);
150           /* Print them all */
151           for(k = 0; k < range.num_frequency; k++)
152             {
153 #if WIRELESS_EXT > 7
154                 printf("\t  Channel %.2d : ", range.freq[k].i);
155 #else
156                 printf("\t  ");
157 #endif
158               freq = freq2float(&(range.freq[k]));
159               if(freq >= GIGA)
160                 printf("%g GHz\n", freq / GIGA);
161               else
162                 if(freq >= MEGA)
163                   printf("%g MHz\n", freq / MEGA);
164                 else
165                   printf("%g kHz\n", freq / KILO);
166             }
167           printf("\n\n");
168         }
169       else
170         printf("%-8.8s  %d channels\n\n",
171                ifname, range.num_channels);
172     }
173 }
174
175 /*------------------------------------------------------------------*/
176 /*
177  * Get frequency info on all devices and print it on the screen
178  */
179 static void
180 print_freq_devices(int          skfd)
181 {
182   char          buff[1024];
183   struct ifconf ifc;
184   struct ifreq *ifr;
185   int i;
186
187   /* Get list of active devices */
188   ifc.ifc_len = sizeof(buff);
189   ifc.ifc_buf = buff;
190   if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
191     {
192       fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
193       return;
194     }
195   ifr = ifc.ifc_req;
196
197   /* Print them */
198   for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
199     print_freq_info(skfd, ifr->ifr_name);
200 }
201
202 #if WIRELESS_EXT > 5
203 /*------------------------------------------------------------------*/
204 /*
205  * Display the list of ap addresses and the associated stats
206  * Exacly the same as the spy list, only with different IOCTL and messages
207  */
208 static void
209 print_ap_info(int       skfd,
210                char *   ifname)
211 {
212   struct iwreq          wrq;
213   char          buffer[(sizeof(struct iw_quality) +
214                         sizeof(struct sockaddr)) * IW_MAX_AP];
215   struct sockaddr *     hwa;
216   struct iw_quality *   qual;
217   iwrange       range;
218   int           has_range = 0;
219   int           has_qual = 0;
220   int           n;
221   int           i;
222
223   /* Collect stats */
224   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
225   wrq.u.data.pointer = (caddr_t) buffer;
226   wrq.u.data.length = 0;
227   wrq.u.data.flags = 0;
228   if(ioctl(skfd, SIOCGIWAPLIST, &wrq) < 0)
229     {
230       fprintf(stderr, "%-8.8s  Interface doesn't have a list of Access Points\n\n", ifname);
231       return;
232     }
233
234   /* Number of addresses */
235   n = wrq.u.data.length;
236   has_qual = wrq.u.data.flags;
237
238   /* The two lists */
239   hwa = (struct sockaddr *) buffer;
240   qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n));
241
242   /* Check if we have valid address types */
243   if(check_addr_type(skfd, ifname) < 0)
244     {
245       fprintf(stderr, "%-8.8s  Interface doesn't support MAC & IP addresses\n\n", ifname);
246       return;
247     }
248
249   /* Get range info if we can */
250   if(get_range_info(skfd, ifname, &(range)) >= 0)
251     has_range = 1;
252
253   /* Display it */
254   if(n == 0)
255     printf("%-8.8s  No Access Point in range\n", ifname);
256   else
257     printf("%-8.8s  Access Points in range:\n", ifname);
258   for(i = 0; i < n; i++)
259     {
260       if(has_qual)
261         if(has_range)
262           /* If the statistics are in dBm */
263           if(qual[i].level > range.max_qual.level)
264             printf("    %s : Quality %d/%d ; Signal %d dBm ; Noise %d dBm %s\n",
265                    pr_ether(hwa[i].sa_data),
266                    qual[i].qual, range.max_qual.qual,
267                    qual[i].level - 0x100, qual[i].noise - 0x100,
268                    qual[i].updated & 0x7 ? "(updated)" : "");
269           else
270             printf("    %s : Quality %d/%d ; Signal %d/%d ; Noise %d/%d %s\n",
271                    pr_ether(hwa[i].sa_data),
272                    qual[i].qual, range.max_qual.qual,
273                    qual[i].level, range.max_qual.level,
274                    qual[i].noise, range.max_qual.noise,
275                    qual[i].updated & 0x7 ? "(updated)" : "");
276         else
277           printf("    %s : Quality %d ; Signal %d ; Noise %d %s\n",
278                  pr_ether(hwa[i].sa_data),
279                  qual[i].qual, qual[i].level, qual[i].noise,
280                  qual[i].updated & 0x7 ? "(updated)" : "");
281       else
282         printf("    %s\n", pr_ether(hwa[i].sa_data));
283     }
284   printf("\n");
285 }
286
287 /*------------------------------------------------------------------*/
288 /*
289  * Get list of AP on all devices and print it on the screen
290  */
291 static void
292 print_ap_devices(int            skfd)
293 {
294   char          buff[1024];
295   struct ifconf ifc;
296   struct ifreq *ifr;
297   int i;
298
299   /* Get list of active devices */
300   ifc.ifc_len = sizeof(buff);
301   ifc.ifc_buf = buff;
302   if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
303     {
304       fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
305       return;
306     }
307   ifr = ifc.ifc_req;
308
309   /* Print them */
310   for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
311     print_ap_info(skfd, ifr->ifr_name);
312 }
313 #endif  /* WIRELESS_EXT > 5 */
314
315 #if WIRELESS_EXT > 7
316 /*------------------------------------------------------------------*/
317 /*
318  * Print the number of available bitrates for the device
319  */
320 static void
321 print_bitrate_info(int          skfd,
322                    char *       ifname)
323 {
324   struct iwreq          wrq;
325   float                 bitrate;
326   struct iw_range       range;
327   int                   k;
328
329   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
330   wrq.u.data.pointer = (caddr_t) &range;
331   wrq.u.data.length = 0;
332   wrq.u.data.flags = 0;
333   if(ioctl(skfd, SIOCGIWRANGE, &wrq) < 0)
334       fprintf(stderr, "%-8.8s  no bit-rate information.\n\n",
335                       ifname);
336   else
337     {
338       if((range.num_bitrates > 0) && (range.num_bitrates < IW_MAX_BITRATES))
339         {
340           printf("%-8.8s  %d available bit-rates :\n",
341                  ifname, range.num_bitrates);
342           /* Print them all */
343           for(k = 0; k < range.num_bitrates; k++)
344             {
345               printf("\t  ");
346               bitrate = range.bitrate[k];
347               if(bitrate >= GIGA)
348                 printf("%g Gb/s\n", bitrate / GIGA);
349               else
350                 if(bitrate >= MEGA)
351                   printf("%g Mb/s\n", bitrate / MEGA);
352                 else
353                   printf("%g kb/s\n", bitrate / KILO);
354             }
355           printf("\n\n");
356         }
357       else
358         printf("%-8.8s  No bit-rates ? Please update driver...\n\n", ifname);
359     }
360 }
361
362 /*------------------------------------------------------------------*/
363 /*
364  * Get bit-rate info on all devices and print it on the screen
365  */
366 static void
367 print_bitrate_devices(int               skfd)
368 {
369   char          buff[1024];
370   struct ifconf ifc;
371   struct ifreq *ifr;
372   int i;
373
374   /* Get list of active devices */
375   ifc.ifc_len = sizeof(buff);
376   ifc.ifc_buf = buff;
377   if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
378     {
379       fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
380       return;
381     }
382   ifr = ifc.ifc_req;
383
384   /* Print them */
385   for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
386     print_bitrate_info(skfd, ifr->ifr_name);
387 }
388 #endif  /* WIRELESS_EXT > 7 */
389
390 /************************* SETTING ROUTINES **************************/
391
392 /*------------------------------------------------------------------*/
393 /*
394  * Set list of addresses specified on command line in the driver.
395  */
396 static int
397 set_spy_info(int                skfd,           /* The socket */
398              char *             args[],         /* Command line args */
399              int                count,          /* Args count */
400              char *             ifname)         /* Dev name */
401 {
402   struct iwreq          wrq;
403   int                   i;
404   int                   nbr;            /* Number of valid addresses */
405   struct sockaddr       hw_address[IW_MAX_SPY];
406
407   /* Read command line */
408   i = 0;        /* first arg to read */
409   nbr = 0;      /* Number of args readen so far */
410
411   /* Check if we have valid address types */
412   if(check_addr_type(skfd, ifname) < 0)
413     {
414       fprintf(stderr, "%-8.8s  Interface doesn't support MAC & IP addresses\n", ifname);
415       return(-1);
416     }
417
418   /* "off" : disable functionality (set 0 addresses) */
419   if(!strcmp(args[0], "off"))
420     i = count;  /* hack */
421
422   /* "+" : add all addresses already in the driver */
423   if(!strcmp(args[0], "+"))
424     {
425       char      buffer[(sizeof(struct iw_quality) +
426                         sizeof(struct sockaddr)) * IW_MAX_SPY];
427
428       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
429       wrq.u.data.pointer = (caddr_t) buffer;
430       wrq.u.data.length = 0;
431       wrq.u.data.flags = 0;
432       if(ioctl(skfd, SIOCGIWSPY, &wrq) < 0)
433         {
434           fprintf(stderr, "Interface doesn't accept reading addresses...\n");
435           fprintf(stderr, "SIOCGIWSPY: %s\n", strerror(errno));
436           return(-1);
437         }
438
439       /* Copy old addresses */
440       nbr = wrq.u.data.length;
441       memcpy(hw_address, buffer, nbr * sizeof(struct sockaddr));
442
443       i = 1;    /* skip the "+" */
444     }
445
446   /* Read other args on command line */
447   while((i < count) && (nbr < IW_MAX_SPY))
448     {
449       if(in_addr(skfd, ifname, args[i++], &(hw_address[nbr])) < 0)
450         continue;
451       nbr++;
452     }
453
454   /* Check the number of addresses */
455   if((nbr == 0) && strcmp(args[0], "off"))
456     {
457       fprintf(stderr, "No valid addresses found : exiting...\n");
458       exit(0);
459     }
460
461   /* Check if there is some remaining arguments */
462   if(i < count)
463     {
464       fprintf(stderr, "Got only the first %d addresses, remaining discarded\n", IW_MAX_SPY);
465     }
466
467   /* Time to do send addresses to the driver */
468   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
469   wrq.u.data.pointer = (caddr_t) hw_address;
470   wrq.u.data.length = nbr;
471   wrq.u.data.flags = 0;
472   if(ioctl(skfd, SIOCSIWSPY, &wrq) < 0)
473     {
474       fprintf(stderr, "Interface doesn't accept addresses...\n");
475       fprintf(stderr, "SIOCSIWSPY: %s\n", strerror(errno));
476       return(-1);
477     }
478
479   return(0);
480 }
481
482 /******************************* MAIN ********************************/
483
484 /*------------------------------------------------------------------*/
485 /*
486  * The main !
487  */
488 int
489 main(int        argc,
490      char **    argv)
491 {
492   int skfd = -1;                /* generic raw socket desc.     */
493   int goterr = 0;
494
495   /* Create a channel to the NET kernel. */
496   if((skfd = sockets_open()) < 0)
497     {
498       perror("socket");
499       exit(-1);
500     }
501
502   /* No argument : show the list of all device + info */
503   if(argc == 1)
504     {
505       print_spy_devices(skfd);
506       close(skfd);
507       exit(0);
508     }
509
510   /* Special cases take one... */
511   /* Help */
512   if((!strncmp(argv[1], "-h", 9)) ||
513      (!strcmp(argv[1], "--help")))
514     {
515       fprintf(stderr, "Usage: iwspy interface [+] [MAC address] [IP address]\n");
516       fprintf(stderr, "             interface [freq]\n");
517       fprintf(stderr, "             interface [ap]\n");
518       close(skfd);
519       exit(0);
520     }
521
522   /* Frequency list */
523   if((!strncmp(argv[1], "freq", 4)) ||
524      (!strncmp(argv[1], "channel", 7)))
525     {
526       print_freq_devices(skfd);
527       close(skfd);
528       exit(0);
529     }
530
531 #if WIRELESS_EXT > 5
532   /* Access Point list */
533   if(!strcasecmp(argv[1], "ap"))
534     {
535       print_ap_devices(skfd);
536       close(skfd);
537       exit(0);
538     }
539 #endif  /* WIRELESS_EXT > 5 */
540
541 #if WIRELESS_EXT > 7
542   /* Bit-rate list */
543   if((!strncmp(argv[1], "bit", 3)) ||
544      (!strcmp(argv[1], "rate")))
545     {
546       print_bitrate_devices(skfd);
547       close(skfd);
548       exit(0);
549     }
550 #endif  /* WIRELESS_EXT > 7 */
551
552   /* The device name must be the first argument */
553   /* Name only : show spy list for that device only */
554   if(argc == 2)
555     {
556       print_spy_info(skfd, argv[1]);
557       close(skfd);
558       exit(0);
559     }
560
561   /* Special cases take two... */
562   /* Frequency list */
563   if((!strncmp(argv[2], "freq", 4)) ||
564      (!strncmp(argv[2], "channel", 7)))
565     {
566       print_freq_info(skfd, argv[1]);
567       close(skfd);
568       exit(0);
569     }
570
571 #if WIRELESS_EXT > 5
572   /* Access Point  list */
573   if(!strcasecmp(argv[2], "ap"))
574     {
575       print_ap_info(skfd, argv[1]);
576       close(skfd);
577       exit(0);
578     }
579 #endif  /* WIRELESS_EXT > 5 */
580
581 #if WIRELESS_EXT > 7
582   /* Access Point  list */
583   if((!strncmp(argv[2], "bit", 3)) ||
584      (!strcmp(argv[2], "rate")))
585     {
586       print_bitrate_info(skfd, argv[1]);
587       close(skfd);
588       exit(0);
589     }
590 #endif  /* WIRELESS_EXT > 7 */
591
592   /* Otherwise, it's a list of address to set in the spy list */
593   goterr = set_spy_info(skfd, argv + 2, argc - 2, argv[1]);
594
595   /* Close the socket. */
596   close(skfd);
597
598   return(1);
599 }