OSDN Git Service

v26
[android-x86/external-wireless-tools.git] / wireless_tools / iwevent.c
1 /*
2  *      Wireless Tools
3  *
4  *              Jean II - HPL 99->01
5  *
6  * Main code for "iwevent". This listent for wireless events on rtnetlink.
7  * You need to link this code against "iwcommon.c" and "-lm".
8  *
9  * Part of this code is from Alexey Kuznetsov, part is from Casey Carter,
10  * I've just put the pieces together...
11  * By the way, if you know a way to remove the root restrictions, tell me
12  * about it...
13  *
14  * This file is released under the GPL license.
15  *     Copyright (c) 1997-2002 Jean Tourrilhes <jt@hpl.hp.com>
16  */
17
18 /***************************** INCLUDES *****************************/
19
20 #include "iwlib.h"              /* Header */
21
22 #include <linux/netlink.h>
23 #include <linux/rtnetlink.h>
24
25 #include <getopt.h>
26 #include <time.h>
27 #include <sys/time.h>
28
29 /* Ugly backward compatibility :-( */
30 #ifndef IFLA_WIRELESS
31 #define IFLA_WIRELESS   (IFLA_MASTER + 1)
32 #endif /* IFLA_WIRELESS */
33
34 /************************ RTNETLINK HELPERS ************************/
35 /*
36  * The following code is extracted from :
37  * ----------------------------------------------
38  * libnetlink.c RTnetlink service routines.
39  *
40  *              This program is free software; you can redistribute it and/or
41  *              modify it under the terms of the GNU General Public License
42  *              as published by the Free Software Foundation; either version
43  *              2 of the License, or (at your option) any later version.
44  *
45  * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
46  * -----------------------------------------------
47  */
48
49 struct rtnl_handle
50 {
51         int                     fd;
52         struct sockaddr_nl      local;
53         struct sockaddr_nl      peer;
54         __u32                   seq;
55         __u32                   dump;
56 };
57
58 static inline void rtnl_close(struct rtnl_handle *rth)
59 {
60         close(rth->fd);
61 }
62
63 static inline int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
64 {
65         int addr_len;
66
67         memset(rth, 0, sizeof(rth));
68
69         rth->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
70         if (rth->fd < 0) {
71                 perror("Cannot open netlink socket");
72                 return -1;
73         }
74
75         memset(&rth->local, 0, sizeof(rth->local));
76         rth->local.nl_family = AF_NETLINK;
77         rth->local.nl_groups = subscriptions;
78
79         if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
80                 perror("Cannot bind netlink socket");
81                 return -1;
82         }
83         addr_len = sizeof(rth->local);
84         if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
85                 perror("Cannot getsockname");
86                 return -1;
87         }
88         if (addr_len != sizeof(rth->local)) {
89                 fprintf(stderr, "Wrong address length %d\n", addr_len);
90                 return -1;
91         }
92         if (rth->local.nl_family != AF_NETLINK) {
93                 fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
94                 return -1;
95         }
96         rth->seq = time(NULL);
97         return 0;
98 }
99
100 /********************* WIRELESS EVENT DECODING *********************/
101 /*
102  * This is the bit I wrote...
103  */
104
105 #if WIRELESS_EXT > 13
106 /*------------------------------------------------------------------*/
107 /*
108  * Print one element from the scanning results
109  */
110 static inline int
111 print_event_token(struct iw_event *     event,  /* Extracted token */
112                   char *                ifname,
113                   struct iw_range *     iwrange,        /* Range info */
114                   int                   has_iwrange)
115 {
116   char          buffer[128];    /* Temporary buffer */
117
118   /* Now, let's decode the event */
119   switch(event->cmd)
120     {
121       /* ----- set events ----- */
122       /* Events that result from a "SET XXX" operation by the user */
123     case SIOCSIWNWID:
124       if(event->u.nwid.disabled)
125         printf("NWID:off/any\n");
126       else
127         printf("NWID:%X\n", event->u.nwid.value);
128       break;
129     case SIOCSIWFREQ:
130       {
131         float           freq;                   /* Frequency/channel */
132         freq = iw_freq2float(&(event->u.freq));
133         iw_print_freq(buffer, freq);
134         printf("%s\n", buffer);
135       }
136       break;
137     case SIOCSIWMODE:
138       printf("Mode:%s\n",
139              iw_operation_mode[event->u.mode]);
140       break;
141     case SIOCSIWESSID:
142       {
143         char essid[IW_ESSID_MAX_SIZE+1];
144         if((event->u.essid.pointer) && (event->u.essid.length))
145           memcpy(essid, event->u.essid.pointer, event->u.essid.length);
146         essid[event->u.essid.length] = '\0';
147         if(event->u.essid.flags)
148           {
149             /* Does it have an ESSID index ? */
150             if((event->u.essid.flags & IW_ENCODE_INDEX) > 1)
151               printf("ESSID:\"%s\" [%d]\n", essid,
152                      (event->u.essid.flags & IW_ENCODE_INDEX));
153             else
154               printf("ESSID:\"%s\"\n", essid);
155           }
156         else
157           printf("ESSID:off/any\n");
158       }
159       break;
160     case SIOCSIWENCODE:
161       {
162         unsigned char   key[IW_ENCODING_TOKEN_MAX];
163         if(event->u.data.pointer)
164           memcpy(key, event->u.essid.pointer, event->u.data.length);
165         else
166           event->u.data.flags |= IW_ENCODE_NOKEY;
167         printf("Encryption key:");
168         if(event->u.data.flags & IW_ENCODE_DISABLED)
169           printf("off\n");
170         else
171           {
172             /* Display the key */
173             iw_print_key(buffer, key, event->u.data.length,
174                          event->u.data.flags);
175             printf("%s", buffer);
176
177             /* Other info... */
178             if((event->u.data.flags & IW_ENCODE_INDEX) > 1)
179               printf(" [%d]", event->u.data.flags & IW_ENCODE_INDEX);
180             if(event->u.data.flags & IW_ENCODE_RESTRICTED)
181               printf("   Security mode:restricted");
182             if(event->u.data.flags & IW_ENCODE_OPEN)
183               printf("   Security mode:open");
184             printf("\n");
185           }
186       }
187       break;
188       /* ----- driver events ----- */
189       /* Events generated by the driver when something important happens */
190     case SIOCGIWAP:
191       printf("New Access Point/Cell address:%s\n",
192              iw_pr_ether(buffer, event->u.ap_addr.sa_data));
193       break;
194     case SIOCGIWSCAN:
195       printf("Scan request completed\n");
196       break;
197     case IWEVTXDROP:
198       printf("Tx packet dropped:%s\n",
199              iw_pr_ether(buffer, event->u.addr.sa_data));
200       break;
201 #if WIRELESS_EXT > 14
202     case IWEVCUSTOM:
203       {
204         char custom[IW_CUSTOM_MAX+1];
205         if((event->u.data.pointer) && (event->u.data.length))
206           memcpy(custom, event->u.data.pointer, event->u.data.length);
207         custom[event->u.data.length] = '\0';
208         printf("Custom driver event:%s\n", custom);
209       }
210       break;
211     case IWEVREGISTERED:
212       printf("Registered node:%s\n",
213              iw_pr_ether(buffer, event->u.addr.sa_data));
214       break;
215     case IWEVEXPIRED:
216       printf("Expired node:%s\n",
217              iw_pr_ether(buffer, event->u.addr.sa_data));
218       break;
219 #endif /* WIRELESS_EXT > 14 */
220 #if WIRELESS_EXT > 15
221     case SIOCGIWTHRSPY:
222       {
223         struct iw_thrspy        threshold;
224         int                     skfd;
225         struct iw_range         range;
226         int                     has_range = 0;
227         if((event->u.data.pointer) && (event->u.data.length))
228           {
229             memcpy(&threshold, event->u.data.pointer,
230                    sizeof(struct iw_thrspy));
231             if((skfd = iw_sockets_open()) >= 0)
232               {
233                 has_range = (iw_get_range_info(skfd, ifname, &range) >= 0);
234                 close(skfd);
235               }
236             printf("Spy threshold crossed on address:%s\n",
237                    iw_pr_ether(buffer, threshold.addr.sa_data));
238             threshold.qual.updated = 0x0;       /* Not that reliable, disable */
239             iw_print_stats(buffer, &threshold.qual, &range, has_range);
240             printf("                            Link %s\n", buffer);
241           }
242         else
243           printf("Invalid Spy Threshold event\n");
244       }
245       break;
246 #else
247       /* Avoid "Unused parameter" warning */
248       ifname = ifname;
249 #endif /* WIRELESS_EXT > 15 */
250       /* ----- junk ----- */
251       /* other junk not currently in use */
252     case SIOCGIWRATE:
253       iw_print_bitrate(buffer, event->u.bitrate.value);
254       printf("Bit Rate:%s\n", buffer);
255       break;
256     case SIOCGIWNAME:
257       printf("Protocol:%-1.16s\n", event->u.name);
258       break;
259     case IWEVQUAL:
260       {
261         event->u.qual.updated = 0x0;    /* Not that reliable, disable */
262         iw_print_stats(buffer, &event->u.qual, iwrange, has_iwrange);
263         printf("Link %s\n", buffer);
264         break;
265       }
266     default:
267       printf("(Unknown Wireless event 0x%04X)\n", event->cmd);
268     }   /* switch(event->cmd) */
269
270   return(0);
271 }
272
273 /*------------------------------------------------------------------*/
274 /*
275  * Print out all Wireless Events part of the RTNetlink message
276  * Most often, there will be only one event per message, but
277  * just make sure we read everything...
278  */
279 static inline int
280 print_event_stream(char *       ifname,
281                    char *       data,
282                    int          len)
283 {
284   struct iw_event       iwe;
285   struct stream_descr   stream;
286   int                   i = 0;
287   int                   ret;
288   char                  buffer[64];
289   struct timeval        recv_time;
290 #if 0
291   struct iw_range       range;
292   int                   has_range;
293 #endif
294
295 #if 0
296   has_range = (iw_get_range_info(skfd, ifname, &range) < 0);
297 #endif
298
299   /* In readable form */
300   gettimeofday(&recv_time, NULL);
301   iw_print_timeval(buffer, &recv_time);
302
303   iw_init_event_stream(&stream, data, len);
304   do
305     {
306       /* Extract an event and print it */
307       ret = iw_extract_event_stream(&stream, &iwe);
308       if(ret != 0)
309         {
310           if(i++ == 0)
311             printf("%s   %-8.8s ", buffer, ifname);
312           else
313             printf("                           ");
314           if(ret > 0)
315             print_event_token(&iwe, ifname, NULL, 0);
316           else
317             printf("(Invalid event)\n");
318         }
319     }
320   while(ret > 0);
321
322   return(0);
323 }
324 #endif  /* WIRELESS_EXT > 13 */
325
326 /*********************** RTNETLINK EVENT DUMP***********************/
327 /*
328  * Dump the events we receive from rtnetlink
329  * This code is mostly from Casey
330  */
331
332 /*------------------------------------------------------------------*/
333 /*
334  * Respond to a single RTM_NEWLINK event from the rtnetlink socket.
335  */
336 static inline int
337 index2name(int  index, char *name)
338 {
339   int           skfd = -1;      /* generic raw socket desc.     */
340   struct ifreq  irq;
341   int           ret = 0;
342
343   memset(name, 0, IFNAMSIZ + 1);
344
345   /* Create a channel to the NET kernel. */
346   if((skfd = iw_sockets_open()) < 0)
347     {
348       perror("socket");
349       exit(-1);
350     }
351
352   /* Get interface name */
353   irq.ifr_ifindex = index;
354   if(ioctl(skfd, SIOCGIFNAME, &irq) < 0)
355     ret = -1;
356   else
357     strncpy(name, irq.ifr_name, IFNAMSIZ);
358
359   close(skfd);
360   return(ret);
361 }
362
363
364 /*------------------------------------------------------------------*/
365 /*
366  * Respond to a single RTM_NEWLINK event from the rtnetlink socket.
367  */
368 static int
369 LinkCatcher(struct nlmsghdr *nlh)
370 {
371   struct ifinfomsg* ifi;
372   char ifname[IFNAMSIZ + 1];
373
374 #if 0
375   fprintf(stderr, "nlmsg_type = %d.\n", nlh->nlmsg_type);
376 #endif
377
378   if(nlh->nlmsg_type != RTM_NEWLINK)
379     return 0;
380
381   ifi = NLMSG_DATA(nlh);
382
383   /* Get a name... */
384   index2name(ifi->ifi_index, ifname);
385
386 #if WIRELESS_EXT > 13
387   /* Code is ugly, but sort of works - Jean II */
388
389   /* Check for attributes */
390   if (nlh->nlmsg_len > NLMSG_ALIGN(sizeof(struct ifinfomsg))) {
391       int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct ifinfomsg));
392       struct rtattr *attr = (void*)ifi + NLMSG_ALIGN(sizeof(struct ifinfomsg));
393
394       while (RTA_OK(attr, attrlen)) {
395         /* Check if the Wireless kind */
396         if(attr->rta_type == IFLA_WIRELESS) {
397           /* Go to display it */
398           print_event_stream(ifname,
399                              (void *)attr + RTA_ALIGN(sizeof(struct rtattr)),
400                              attr->rta_len - RTA_ALIGN(sizeof(struct rtattr)));
401         }
402         attr = RTA_NEXT(attr, attrlen);
403       }
404   }
405 #endif  /* WIRELESS_EXT > 13 */
406
407   return 0;
408 }
409
410 /* ---------------------------------------------------------------- */
411 /*
412  * We must watch the rtnelink socket for events.
413  * This routine handles those events (i.e., call this when rth.fd
414  * is ready to read).
415  */
416 static inline void
417 handle_netlink_events(struct rtnl_handle *      rth)
418 {
419   while(1)
420     {
421       struct sockaddr_nl sanl;
422       socklen_t sanllen;
423
424       struct nlmsghdr *h;
425       int amt;
426       char buf[8192];
427
428       amt = recvfrom(rth->fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sanl, &sanllen);
429       if(amt < 0)
430         {
431           if(errno != EINTR && errno != EAGAIN)
432             {
433               fprintf(stderr, "%s: error reading netlink: %s.\n",
434                       __PRETTY_FUNCTION__, strerror(errno));
435             }
436           return;
437         }
438
439       if(amt == 0)
440         {
441           fprintf(stderr, "%s: EOF on netlink??\n", __PRETTY_FUNCTION__);
442           return;
443         }
444
445       h = (struct nlmsghdr*)buf;
446       while(amt >= (int)sizeof(*h))
447         {
448           int len = h->nlmsg_len;
449           int l = len - sizeof(*h);
450
451           if(l < 0 || len > amt)
452             {
453               fprintf(stderr, "%s: malformed netlink message: len=%d\n", __PRETTY_FUNCTION__, len);
454               break;
455             }
456
457           switch(h->nlmsg_type)
458             {
459             case RTM_NEWLINK:
460               LinkCatcher(h);
461               break;
462             default:
463 #if 0
464               fprintf(stderr, "%s: got nlmsg of type %#x.\n", __PRETTY_FUNCTION__, h->nlmsg_type);
465 #endif
466               break;
467             }
468
469           len = NLMSG_ALIGN(len);
470           amt -= len;
471           h = (struct nlmsghdr*)((char*)h + len);
472         }
473
474       if(amt > 0)
475         fprintf(stderr, "%s: remnant of size %d on netlink\n", __PRETTY_FUNCTION__, amt);
476     }
477 }
478
479 /**************************** MAIN LOOP ****************************/
480
481 /* ---------------------------------------------------------------- */
482 /*
483  * Wait until we get an event
484  */
485 static inline int
486 wait_for_event(struct rtnl_handle *     rth)
487 {
488 #if 0
489   struct timeval        tv;     /* Select timeout */
490 #endif
491
492   /* Forever */
493   while(1)
494     {
495       fd_set            rfds;           /* File descriptors for select */
496       int               last_fd;        /* Last fd */
497       int               ret;
498
499       /* Guess what ? We must re-generate rfds each time */
500       FD_ZERO(&rfds);
501       FD_SET(rth->fd, &rfds);
502       last_fd = rth->fd;
503
504       /* Wait until something happens */
505       ret = select(last_fd + 1, &rfds, NULL, NULL, NULL);
506
507       /* Check if there was an error */
508       if(ret < 0)
509         {
510           if(errno == EAGAIN || errno == EINTR)
511             continue;
512           fprintf(stderr, "Unhandled signal - exiting...\n");
513           break;
514         }
515
516       /* Check if there was a timeout */
517       if(ret == 0)
518         {
519           continue;
520         }
521
522       /* Check for interface discovery events. */
523       if(FD_ISSET(rth->fd, &rfds))
524         handle_netlink_events(rth);
525     }
526
527   return(0);
528 }
529
530 /******************************* MAIN *******************************/
531
532 /* ---------------------------------------------------------------- */
533 /*
534  * helper ;-)
535  */
536 static void
537 iw_usage(int status)
538 {
539   fputs("Usage: iwevent [OPTIONS]\n"
540         "   Monitors and displays Wireless Events.\n"
541         "   Options are:\n"
542         "     -h,--help     Print this message.\n"
543         "     -v,--version  Show version of this program.\n",
544         status ? stderr : stdout);
545   exit(status);
546 }
547 /* Command line options */
548 static const struct option long_opts[] = {
549   { "help", no_argument, NULL, 'h' },
550   { "version", no_argument, NULL, 'v' },
551   { NULL, 0, NULL, 0 }
552 };
553
554 /* ---------------------------------------------------------------- */
555 /*
556  * main body of the program
557  */
558 int
559 main(int        argc,
560      char *     argv[])
561 {
562   struct rtnl_handle    rth;
563   int opt;
564
565   /* Check command line options */
566   while((opt = getopt_long(argc, argv, "hv", long_opts, NULL)) > 0)
567     {
568       switch(opt)
569         {
570         case 'h':
571           iw_usage(0);
572           break;
573
574         case 'v':
575           return(iw_print_version_info("iwevent"));
576           break;
577
578         default:
579           iw_usage(1);
580           break;
581         }
582     }
583   if(optind < argc)
584     {
585       fputs("Too many arguments.\n", stderr);
586       iw_usage(1);
587     }
588
589   /* Open netlink channel */
590   if(rtnl_open(&rth, RTMGRP_LINK) < 0)
591     {
592       perror("Can't initialize rtnetlink socket");
593       return(1);
594     }
595
596 #if WIRELESS_EXT > 13
597   fprintf(stderr, "Waiting for Wireless Events...\n");
598 #else   /* WIRELESS_EXT > 13 */
599   fprintf(stderr, "Unsupported in Wireless Extensions <= 14 :-(\n");
600   return(-1);
601 #endif  /* WIRELESS_EXT > 13 */
602
603   /* Do what we have to do */
604   wait_for_event(&rth);
605
606   /* Cleanup - only if you are pedantic */
607   rtnl_close(&rth);
608
609   return(0);
610 }