OSDN Git Service

v10
[android-x86/external-wireless-tools.git] / wireless_tools / iwconfig.c
1 /*
2  * Hack my way... Jean II
3  */
4 #include <sys/types.h>
5 #include <sys/socket.h>
6 #include <sys/ioctl.h>
7 #include <linux/netdevice.h>
8 #include <linux/if.h>
9 #include <linux/if_arp.h>
10 #include <linux/if_ether.h>
11 #include <linux/ipx.h>
12 #include <linux/wireless.h>
13 #include <stdio.h>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <ctype.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20
21 /* Some usefull constants */
22 #define KILO    1e3
23 #define MEGA    1e6
24 #define GIGA    1e9
25
26 typedef struct iw_statistics    iwstats;
27 typedef struct iw_range         iwrange;
28
29 /* Structure for storing all wireless information for each device */
30 struct wireless_info
31 {
32   char          dev[IFNAMSIZ];          /* Interface name (device) */
33   char          name[12];               /* Wireless name */
34   int           has_nwid;
35   int           nwid_on;
36   u_long        nwid;                   /* Network ID */
37   int           has_freq;
38   u_long        freq;                   /* Frequency/channel */
39
40   /* Stats */
41   iwstats       stats;
42   int           has_stats;
43   iwrange       range;
44   int           has_range;
45 };
46
47 int skfd = -1;                          /* generic raw socket desc.     */
48 int ipx_sock = -1;                      /* IPX socket                   */
49 int ax25_sock = -1;                     /* AX.25 socket                 */
50 int inet_sock = -1;                     /* INET socket                  */
51 int ddp_sock = -1;                      /* Appletalk DDP socket         */
52
53
54 static void
55 usage(void)
56 {
57   fprintf(stderr, "Usage: iwconfig interface\n");
58   fprintf(stderr, "                [nwid NN]\n");
59   fprintf(stderr, "                [freq N.NN (add k, M or G) ]\n");
60   fprintf(stderr, "                [channel N]\n");
61   exit(1);
62 }
63
64
65 static void
66 print_info(struct wireless_info *       info)
67 {
68   /* Display device name */
69   printf("%-8.8s  ", info->dev);
70
71   /* Display wireless name */
72   printf("%s  ", info->name);
73
74   /* Display Network ID */
75   if(info->has_nwid)
76     if(info->nwid_on)
77       printf("NWID:%lX  ", info->nwid);
78     else
79       printf("NWID:off  ");
80
81   /* Display frequency / channel */
82   if(info->has_freq)
83     if(info->freq < KILO)
84       printf("Channel:%g  ", (double) info->freq);
85     else
86       if(info->freq > GIGA)
87         printf("Frequency:%gGHz  ", info->freq / GIGA);
88       else
89         if(info->freq > MEGA)
90           printf("Frequency:%gMHz  ", info->freq / MEGA);
91         else
92           printf("Frequency:%gkHz  ", info->freq / KILO);
93
94   printf("\n");
95
96   if(info->has_stats)
97     {
98       if(info->has_range)
99         printf("          Link quality:%d/%d  Signal level:%d/%d  Noise level:%d/%d\n",
100                info->stats.qual.qual, info->range.max_qual.qual,
101                info->stats.qual.level, info->range.max_qual.level,
102                info->stats.qual.noise, info->range.max_qual.noise);
103       else
104         printf("          Link quality:%d  Signal level:%d  Noise level:%d\n",
105                info->stats.qual.qual,
106                info->stats.qual.level,
107                info->stats.qual.noise);
108
109       printf("          Rx invalid nwid:%d  invalid crypt:%d  invalid misc:%d\n",
110              info->stats.discard.nwid,
111              info->stats.discard.crypt,
112              info->stats.discard.misc);
113     }
114
115   printf("\n");
116 }
117
118 static int if_getstats(char *ifname, iwstats *  stats)
119 {
120   FILE *f=fopen("/proc/net/wireless","r");
121   char buf[256];
122   char *bp;
123   if(f==NULL)
124         return -1;
125   while(fgets(buf,255,f))
126   {
127         bp=buf;
128         while(*bp&&isspace(*bp))
129                 bp++;
130         if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':')
131         {
132                 bp=strchr(bp,':');
133                 bp++;
134                 bp = strtok(bp, " .");
135                 sscanf(bp, "%X", &stats->status);
136                 bp = strtok(NULL, " .");
137                 sscanf(bp, "%d", &stats->qual.qual);
138                 bp = strtok(NULL, " .");
139                 sscanf(bp, "%d", &stats->qual.level);
140                 bp = strtok(NULL, " .");
141                 sscanf(bp, "%d", &stats->qual.noise);
142                 bp = strtok(NULL, " .");
143                 sscanf(bp, "%d", &stats->discard.nwid);
144                 bp = strtok(NULL, " .");
145                 sscanf(bp, "%d", &stats->discard.crypt);
146                 bp = strtok(NULL, " .");
147                 sscanf(bp, "%d", &stats->discard.misc);
148                 fclose(f);
149                 return;
150         }
151   }
152   fclose(f);
153   return 0;
154 }
155
156 /* Get wireless informations & config from the device driver */
157 static int
158 get_info(char *                 ifname,
159          struct wireless_info * info)
160 {
161   struct iwreq          wrq;
162
163   memset((char *) info, 0, sizeof(struct wireless_info));
164
165   /* Get device name */
166   strcpy(info->dev, ifname);
167
168   /* Get wireless name */
169   strcpy(wrq.ifr_name, ifname);
170   if(ioctl(skfd, SIOCGIWNAME, &wrq) < 0)
171     /* If no wireless name : no wireless extensions */
172     return(-1);
173   else
174     strcpy(info->name, wrq.u.name);
175
176   /* Get network ID */
177   strcpy(wrq.ifr_name, ifname);
178   if(ioctl(skfd, SIOCGIWNWID, &wrq) >= 0)
179     {
180       info->has_nwid = 1;
181       info->nwid_on = wrq.u.nwid.on;
182       info->nwid = wrq.u.nwid.nwid;
183     }
184
185   /* Get frequency / channel */
186   strcpy(wrq.ifr_name, ifname);
187   if(ioctl(skfd, SIOCGIWFREQ, &wrq) >= 0)
188     {
189       info->has_freq = 1;
190       info->freq = wrq.u.freq;
191     }
192
193   /* Get stats */
194   if(if_getstats(ifname, &(info->stats)) == 0)
195     {
196       info->has_stats = 1;
197     }
198
199   /* Get ranges */
200   strcpy(wrq.ifr_name, ifname);
201   wrq.u.data.pointer = (caddr_t) &(info->range);
202   wrq.u.data.length = 0;
203   wrq.u.data.flags = 0;
204   if(ioctl(skfd, SIOCGIWRANGE, &wrq) >= 0)
205     {
206       info->has_range = 1;
207     }
208
209   return(0);
210 }
211
212
213 static int
214 set_info(char *         args[],         /* Command line args */
215          int            count,          /* Args count */
216          char *         ifname)         /* Dev name */
217 {
218   struct iwreq          wrq;
219   int                   i;
220
221   /* Set dev name */
222   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
223
224   /* The other args on the line specify options to be set... */
225   for(i = 0; i < count; i++)
226     {
227       /* Set network ID */
228       if(!strcmp(args[i], "nwid"))
229         {
230           if(++i >= count)
231             usage();
232           if(!strcasecmp(args[i], "off"))
233             wrq.u.nwid.on = 0;
234           else
235             if(sscanf(args[i], "%lX", &(wrq.u.nwid.nwid)) != 1)
236               usage();
237             else
238               wrq.u.nwid.on = 1;
239
240           if(ioctl(skfd, SIOCSIWNWID, &wrq) < 0)
241             {
242               fprintf(stderr, "SIOCSIWNWID: %s\n", strerror(errno));
243               return(-1);
244             }
245           continue;
246         }
247
248       /* Set frequency / channel */
249       if((!strncmp(args[i], "freq", 4)) ||
250          (!strcmp(args[i], "channel")))
251         {
252           if(++i >= count)
253             {
254               struct iw_range   range;
255               int               k;
256
257               wrq.u.data.pointer = (caddr_t) &range;
258               wrq.u.data.length = 0;
259               wrq.u.data.flags = 0;
260               if(ioctl(skfd, SIOCGIWRANGE, &wrq) < 0)
261                 {
262                   fprintf(stderr, "SIOCGIWRANGE: %s\n", strerror(errno));
263                   return(-1);
264                 }
265
266               printf("%d channels ; available frequencies :",
267                      range.num_channels);
268               for(k = 0; k < range.num_frequency; k++)
269                 if(range.freq[k] > GIGA)
270                   printf(" %gGHz ", range.freq[k] / GIGA);
271                 else
272                   if(range.freq[k] > MEGA)
273                     printf(" %gMHz ", range.freq[k] / MEGA);
274                   else
275                     printf(" %gkHz ", range.freq[k] / KILO);
276               printf("\n");
277               return;   /* no more arg */
278             }
279
280           if(sscanf(args[i], "%g", &(wrq.u.freq)) != 1)
281             usage();
282           if(index(args[i], 'G')) wrq.u.freq *= GIGA;
283           if(index(args[i], 'M')) wrq.u.freq *= MEGA;
284           if(index(args[i], 'k')) wrq.u.freq *= KILO;
285
286           if(ioctl(skfd, SIOCSIWFREQ, &wrq) < 0)
287             {
288               fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
289               return(-1);
290             }
291           continue;
292         }
293
294       /* Here we have an unrecognised arg... */
295       fprintf(stderr, "Invalid argument : %s\n", args[i]);
296       usage();
297       return(-1);
298     }           /* for(index ... */
299   return(0);
300 }
301
302 static void
303 print_devices(char *ifname)
304 {
305   char buff[1024];
306   struct wireless_info  info;
307   struct ifconf ifc;
308   struct ifreq *ifr;
309   int i;
310
311   if(ifname == (char *)NULL)
312     {
313       ifc.ifc_len = sizeof(buff);
314       ifc.ifc_buf = buff;
315       if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
316         {
317           fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
318           return;
319         }
320
321       ifr = ifc.ifc_req;
322       for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
323         {
324           if(get_info(ifr->ifr_name, &info) < 0)
325             {
326               /* Could skip this message ? */
327               fprintf(stderr, "%-8.8s  no wireless extensions.\n\n",
328                       ifr->ifr_name);
329               continue;
330             }
331
332           print_info(&info);
333         }
334     }
335   else
336     {
337       if(get_info(ifname, &info) < 0)
338         {
339           fprintf(stderr, "%s: no wireless extensions.\n",
340                   ifname);
341           usage();
342         }
343       else
344         print_info(&info);
345     }
346 }
347
348
349 static int sockets_open()
350 {
351         inet_sock=socket(AF_INET, SOCK_DGRAM, 0);
352         ipx_sock=socket(AF_IPX, SOCK_DGRAM, 0);
353         ax25_sock=socket(AF_AX25, SOCK_DGRAM, 0);
354         ddp_sock=socket(AF_APPLETALK, SOCK_DGRAM, 0);
355         /*
356          *      Now pick any (exisiting) useful socket family for generic queries
357          */
358         if(inet_sock!=-1)
359                 return inet_sock;
360         if(ipx_sock!=-1)
361                 return ipx_sock;
362         if(ax25_sock!=-1)
363                 return ax25_sock;
364         /*
365          *      If this is -1 we have no known network layers and its time to jump.
366          */
367          
368         return ddp_sock;
369 }
370         
371 int
372 main(int        argc,
373      char **    argv)
374 {
375   int goterr = 0;
376
377   /* Create a channel to the NET kernel. */
378   if((skfd = sockets_open()) < 0)
379     {
380       perror("socket");
381       exit(-1);
382     }
383
384   /* No argument : show the list of all device + info */
385   if(argc == 1)
386     {
387       print_devices((char *)NULL);
388       close(skfd);
389       exit(0);
390     }
391
392   /* The device name must be the first argument */
393   if(argc == 2)
394     {
395       print_devices(argv[1]);
396       close(skfd);
397       exit(0);
398     }
399
400   /* The other args on the line specify options to be set... */
401   goterr = set_info(argv + 2, argc - 2, argv[1]);
402
403   /* Close the socket. */
404   close(skfd);
405
406   return(goterr);
407 }