6 * Main code for "iwevent". This listent for wireless events on rtnetlink.
7 * You need to link this code against "iwcommon.c" and "-lm".
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
14 * This file is released under the GPL license.
15 * Copyright (c) 1997-2004 Jean Tourrilhes <jt@hpl.hp.com>
18 /***************************** INCLUDES *****************************/
20 #include "iwlib-private.h" /* Private header */
22 #include <linux/netlink.h>
23 #include <linux/rtnetlink.h>
29 /* Ugly backward compatibility :-( */
31 #define IFLA_WIRELESS (IFLA_MASTER + 1)
32 #endif /* IFLA_WIRELESS */
34 /****************************** TYPES ******************************/
37 * Static information about wireless interface.
38 * We cache this info for performance reason.
40 typedef struct wireless_iface
43 struct wireless_iface * next;
45 /* Interface identification */
46 int ifindex; /* Interface index == black magic */
49 char ifname[IFNAMSIZ + 1]; /* Interface name */
50 struct iw_range range; /* Wireless static data */
54 /**************************** VARIABLES ****************************/
56 /* Cache of wireless interfaces */
57 struct wireless_iface * interface_cache = NULL;
59 /************************ RTNETLINK HELPERS ************************/
61 * The following code is extracted from :
62 * ----------------------------------------------
63 * libnetlink.c RTnetlink service routines.
65 * This program is free software; you can redistribute it and/or
66 * modify it under the terms of the GNU General Public License
67 * as published by the Free Software Foundation; either version
68 * 2 of the License, or (at your option) any later version.
70 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
71 * -----------------------------------------------
77 struct sockaddr_nl local;
78 struct sockaddr_nl peer;
83 static inline void rtnl_close(struct rtnl_handle *rth)
88 static inline int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
92 memset(rth, 0, sizeof(rth));
94 rth->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
96 perror("Cannot open netlink socket");
100 memset(&rth->local, 0, sizeof(rth->local));
101 rth->local.nl_family = AF_NETLINK;
102 rth->local.nl_groups = subscriptions;
104 if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
105 perror("Cannot bind netlink socket");
108 addr_len = sizeof(rth->local);
109 if (getsockname(rth->fd, (struct sockaddr*)&rth->local,
110 (socklen_t *) &addr_len) < 0) {
111 perror("Cannot getsockname");
114 if (addr_len != sizeof(rth->local)) {
115 fprintf(stderr, "Wrong address length %d\n", addr_len);
118 if (rth->local.nl_family != AF_NETLINK) {
119 fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
122 rth->seq = time(NULL);
126 /******************* WIRELESS INTERFACE DATABASE *******************/
128 * We keep a few information about each wireless interface on the
129 * system. This avoid to query this info at each event, therefore
132 * Each interface is indexed by the 'ifindex'. As opposed to interface
133 * names, 'ifindex' are never reused (even if you reactivate the same
134 * hardware), so the data we cache will never apply to the wrong
136 * Because of that, we are pretty lazy when it come to purging the
140 /*------------------------------------------------------------------*/
142 * Get name of interface based on interface index...
152 memset(name, 0, IFNAMSIZ + 1);
154 /* Get interface name */
155 irq.ifr_ifindex = ifindex;
156 if(ioctl(skfd, SIOCGIFNAME, &irq) < 0)
159 strncpy(name, irq.ifr_name, IFNAMSIZ);
164 /*------------------------------------------------------------------*/
166 * Get interface data from cache or live interface
168 static struct wireless_iface *
169 iw_get_interface_data(int ifindex)
171 struct wireless_iface * curr;
172 int skfd = -1; /* ioctl socket */
174 /* Search for it in the database */
175 curr = interface_cache;
179 if(curr->ifindex == ifindex)
181 //printf("Cache : found %d-%s\n", curr->ifindex, curr->ifname);
190 /* Create a channel to the NET kernel. Doesn't happen too often, so
191 * socket creation overhead is minimal... */
192 if((skfd = iw_sockets_open()) < 0)
194 perror("iw_sockets_open");
198 /* Create new entry, zero, init */
199 curr = calloc(1, sizeof(struct wireless_iface));
202 fprintf(stderr, "Malloc failed\n");
205 curr->ifindex = ifindex;
207 /* Extract static data */
208 if(index2name(skfd, ifindex, curr->ifname) < 0)
210 perror("index2name");
214 curr->has_range = (iw_get_range_info(skfd, curr->ifname, &curr->range) >= 0);
215 //printf("Cache : create %d-%s\n", curr->ifindex, curr->ifname);
218 iw_sockets_close(skfd);
221 curr->next = interface_cache;
222 interface_cache = curr;
227 /*------------------------------------------------------------------*/
229 * Remove interface data from cache (if it exist)
232 iw_del_interface_data(int ifindex)
234 struct wireless_iface * curr;
235 struct wireless_iface * prev = NULL;
236 struct wireless_iface * next;
238 /* Go through the list, find the interface, kills it */
239 curr = interface_cache;
245 if(curr->ifindex == ifindex)
249 interface_cache = next;
252 //printf("Cache : purge %d-%s\n", curr->ifindex, curr->ifname);
259 /* Keep as previous */
268 /********************* WIRELESS EVENT DECODING *********************/
270 * Parse the Wireless Event and print it out
273 /*------------------------------------------------------------------*/
275 * Dump a buffer as a serie of hex
276 * Maybe should go in iwlib...
277 * Maybe we should have better formatting like iw_print_key...
280 iw_hexdump(char * buf,
282 const unsigned char *data,
288 for(i = 0; i < datalen; i++)
289 pos += snprintf(pos, buf + buflen - pos, "%02X", data[i]);
293 /*------------------------------------------------------------------*/
295 * Print one element from the scanning results
298 print_event_token(struct iw_event * event, /* Extracted token */
299 struct iw_range * iw_range, /* Range info */
302 char buffer[128]; /* Temporary buffer */
303 char buffer2[30]; /* Temporary buffer */
304 char * prefix = (IW_IS_GET(event->cmd) ? "New" : "Set");
306 /* Now, let's decode the event */
309 /* ----- set events ----- */
310 /* Events that result from a "SET XXX" operation by the user */
312 if(event->u.nwid.disabled)
313 printf("Set NWID:off/any\n");
315 printf("Set NWID:%X\n", event->u.nwid.value);
320 double freq; /* Frequency/channel */
321 int channel = -1; /* Converted to channel */
322 freq = iw_freq2float(&(event->u.freq));
326 /* Convert channel to frequency if possible */
327 channel = iw_channel_to_freq((int) freq, &freq, iw_range);
329 /* Convert frequency to channel if possible */
330 channel = iw_freq_to_channel(freq, iw_range);
332 iw_print_freq(buffer, sizeof(buffer),
333 freq, channel, event->u.freq.flags);
334 printf("%s %s\n", prefix, buffer);
338 printf("Set Mode:%s\n",
339 iw_operation_mode[event->u.mode]);
344 char essid[4*IW_ESSID_MAX_SIZE + 1];
345 memset(essid, '\0', sizeof(essid));
346 if((event->u.essid.pointer) && (event->u.essid.length))
347 iw_essid_escape(essid,
348 event->u.essid.pointer, event->u.essid.length);
349 if(event->u.essid.flags)
351 /* Does it have an ESSID index ? */
352 if((event->u.essid.flags & IW_ENCODE_INDEX) > 1)
353 printf("%s ESSID:\"%s\" [%d]\n", prefix, essid,
354 (event->u.essid.flags & IW_ENCODE_INDEX));
356 printf("%s ESSID:\"%s\"\n", prefix, essid);
359 printf("%s ESSID:off/any\n", prefix);
364 unsigned char key[IW_ENCODING_TOKEN_MAX];
365 if(event->u.data.pointer)
366 memcpy(key, event->u.data.pointer, event->u.data.length);
368 event->u.data.flags |= IW_ENCODE_NOKEY;
369 printf("Set Encryption key:{%X}", event->u.data.flags);
370 if(event->u.data.flags & IW_ENCODE_DISABLED)
374 /* Display the key */
375 iw_print_key(buffer, sizeof(buffer), key, event->u.data.length,
376 event->u.data.flags);
377 printf("%s", buffer);
380 if((event->u.data.flags & IW_ENCODE_INDEX) > 1)
381 printf(" [%d]", event->u.data.flags & IW_ENCODE_INDEX);
382 if(event->u.data.flags & IW_ENCODE_RESTRICTED)
383 printf(" Security mode:restricted");
384 if(event->u.data.flags & IW_ENCODE_OPEN)
385 printf(" Security mode:open");
390 /* ----- driver events ----- */
391 /* Events generated by the driver when something important happens */
393 printf("New Access Point/Cell address:%s\n",
394 iw_sawap_ntop(&event->u.ap_addr, buffer));
397 printf("Scan request completed\n");
400 printf("Tx packet dropped:%s\n",
401 iw_saether_ntop(&event->u.addr, buffer));
405 char custom[IW_CUSTOM_MAX+1];
406 memset(custom, '\0', sizeof(custom));
407 if((event->u.data.pointer) && (event->u.data.length))
408 memcpy(custom, event->u.data.pointer, event->u.data.length);
409 printf("Custom driver event:%s\n", custom);
413 printf("Registered node:%s\n",
414 iw_saether_ntop(&event->u.addr, buffer));
417 printf("Expired node:%s\n",
418 iw_saether_ntop(&event->u.addr, buffer));
422 struct iw_thrspy threshold;
423 if((event->u.data.pointer) && (event->u.data.length))
425 memcpy(&threshold, event->u.data.pointer,
426 sizeof(struct iw_thrspy));
427 printf("Spy threshold crossed on address:%s\n",
428 iw_saether_ntop(&threshold.addr, buffer));
429 iw_print_stats(buffer, sizeof(buffer),
430 &threshold.qual, iw_range, has_range);
431 printf(" Link %s\n", buffer);
434 printf("Invalid Spy Threshold event\n");
437 /* ----- driver WPA events ----- */
438 /* Events generated by the driver, used for WPA operation */
439 case IWEVMICHAELMICFAILURE:
440 if(event->u.data.length >= sizeof(struct iw_michaelmicfailure))
442 struct iw_michaelmicfailure mf;
443 memcpy(&mf, event->u.data.pointer, sizeof(mf));
444 printf("Michael MIC failure flags:0x%X src_addr:%s tsc:%s\n",
446 iw_saether_ntop(&mf.src_addr, buffer2),
447 iw_hexdump(buffer, sizeof(buffer),
448 mf.tsc, IW_ENCODE_SEQ_MAX_SIZE));
452 printf("Association Request IEs:%s\n",
453 iw_hexdump(buffer, sizeof(buffer),
454 event->u.data.pointer, event->u.data.length));
456 case IWEVASSOCRESPIE:
457 printf("Association Response IEs:%s\n",
458 iw_hexdump(buffer, sizeof(buffer),
459 event->u.data.pointer, event->u.data.length));
462 if(event->u.data.length >= sizeof(struct iw_pmkid_cand))
464 struct iw_pmkid_cand cand;
465 memcpy(&cand, event->u.data.pointer, sizeof(cand));
466 printf("PMKID candidate flags:0x%X index:%d bssid:%s\n",
467 cand.flags, cand.index,
468 iw_saether_ntop(&cand.bssid, buffer));
471 /* ----- junk ----- */
472 /* other junk not currently in use */
474 iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
475 printf("New Bit Rate:%s\n", buffer);
478 printf("Protocol:%-1.16s\n", event->u.name);
482 event->u.qual.updated = 0x0; /* Not that reliable, disable */
483 iw_print_stats(buffer, sizeof(buffer),
484 &event->u.qual, iw_range, has_range);
485 printf("Link %s\n", buffer);
489 printf("(Unknown Wireless event 0x%04X)\n", event->cmd);
490 } /* switch(event->cmd) */
495 /*------------------------------------------------------------------*/
497 * Print out all Wireless Events part of the RTNetlink message
498 * Most often, there will be only one event per message, but
499 * just make sure we read everything...
502 print_event_stream(int ifindex,
507 struct stream_descr stream;
511 struct timeval recv_time;
513 struct wireless_iface * wireless_data;
515 /* Get data from cache */
516 wireless_data = iw_get_interface_data(ifindex);
517 if(wireless_data == NULL)
520 /* Print received time in readable form */
521 gettimeofday(&recv_time, &tz);
522 iw_print_timeval(buffer, sizeof(buffer), &recv_time, &tz);
524 iw_init_event_stream(&stream, data, len);
527 /* Extract an event and print it */
528 ret = iw_extract_event_stream(&stream, &iwe,
529 wireless_data->range.we_version_compiled);
533 printf("%s %-8.16s ", buffer, wireless_data->ifname);
537 print_event_token(&iwe,
538 &wireless_data->range, wireless_data->has_range);
540 printf("(Invalid event)\n");
541 /* Push data out *now*, in case we are redirected to a pipe */
550 /*********************** RTNETLINK EVENT DUMP***********************/
552 * Dump the events we receive from rtnetlink
553 * This code is mostly from Casey
556 /*------------------------------------------------------------------*/
558 * Respond to a single RTM_NEWLINK event from the rtnetlink socket.
561 LinkCatcher(struct nlmsghdr *nlh)
563 struct ifinfomsg* ifi;
566 fprintf(stderr, "nlmsg_type = %d.\n", nlh->nlmsg_type);
569 ifi = NLMSG_DATA(nlh);
571 /* Code is ugly, but sort of works - Jean II */
573 /* If interface is getting destoyed */
574 if(nlh->nlmsg_type == RTM_DELLINK)
576 /* Remove from cache (if in cache) */
577 iw_del_interface_data(ifi->ifi_index);
581 /* Only keep add/change events */
582 if(nlh->nlmsg_type != RTM_NEWLINK)
585 /* Check for attributes */
586 if (nlh->nlmsg_len > NLMSG_ALIGN(sizeof(struct ifinfomsg)))
588 int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct ifinfomsg));
589 struct rtattr *attr = (void *) ((char *) ifi +
590 NLMSG_ALIGN(sizeof(struct ifinfomsg)));
592 while (RTA_OK(attr, attrlen))
594 /* Check if the Wireless kind */
595 if(attr->rta_type == IFLA_WIRELESS)
597 /* Go to display it */
598 print_event_stream(ifi->ifi_index,
599 (char *) attr + RTA_ALIGN(sizeof(struct rtattr)),
600 attr->rta_len - RTA_ALIGN(sizeof(struct rtattr)));
602 attr = RTA_NEXT(attr, attrlen);
609 /* ---------------------------------------------------------------- */
611 * We must watch the rtnelink socket for events.
612 * This routine handles those events (i.e., call this when rth.fd
616 handle_netlink_events(struct rtnl_handle * rth)
620 struct sockaddr_nl sanl;
621 socklen_t sanllen = sizeof(struct sockaddr_nl);
627 amt = recvfrom(rth->fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sanl, &sanllen);
630 if(errno != EINTR && errno != EAGAIN)
632 fprintf(stderr, "%s: error reading netlink: %s.\n",
633 __PRETTY_FUNCTION__, strerror(errno));
640 fprintf(stderr, "%s: EOF on netlink??\n", __PRETTY_FUNCTION__);
644 h = (struct nlmsghdr*)buf;
645 while(amt >= (int)sizeof(*h))
647 int len = h->nlmsg_len;
648 int l = len - sizeof(*h);
650 if(l < 0 || len > amt)
652 fprintf(stderr, "%s: malformed netlink message: len=%d\n", __PRETTY_FUNCTION__, len);
656 switch(h->nlmsg_type)
664 fprintf(stderr, "%s: got nlmsg of type %#x.\n", __PRETTY_FUNCTION__, h->nlmsg_type);
669 len = NLMSG_ALIGN(len);
671 h = (struct nlmsghdr*)((char*)h + len);
675 fprintf(stderr, "%s: remnant of size %d on netlink\n", __PRETTY_FUNCTION__, amt);
679 /**************************** MAIN LOOP ****************************/
681 /* ---------------------------------------------------------------- */
683 * Wait until we get an event
686 wait_for_event(struct rtnl_handle * rth)
689 struct timeval tv; /* Select timeout */
695 fd_set rfds; /* File descriptors for select */
696 int last_fd; /* Last fd */
699 /* Guess what ? We must re-generate rfds each time */
701 FD_SET(rth->fd, &rfds);
704 /* Wait until something happens */
705 ret = select(last_fd + 1, &rfds, NULL, NULL, NULL);
707 /* Check if there was an error */
710 if(errno == EAGAIN || errno == EINTR)
712 fprintf(stderr, "Unhandled signal - exiting...\n");
716 /* Check if there was a timeout */
722 /* Check for interface discovery events. */
723 if(FD_ISSET(rth->fd, &rfds))
724 handle_netlink_events(rth);
730 /******************************* MAIN *******************************/
732 /* ---------------------------------------------------------------- */
739 fputs("Usage: iwevent [OPTIONS]\n"
740 " Monitors and displays Wireless Events.\n"
742 " -h,--help Print this message.\n"
743 " -v,--version Show version of this program.\n",
744 status ? stderr : stdout);
747 /* Command line options */
748 static const struct option long_opts[] = {
749 { "help", no_argument, NULL, 'h' },
750 { "version", no_argument, NULL, 'v' },
754 /* ---------------------------------------------------------------- */
756 * main body of the program
762 struct rtnl_handle rth;
765 /* Check command line options */
766 while((opt = getopt_long(argc, argv, "hv", long_opts, NULL)) > 0)
775 return(iw_print_version_info("iwevent"));
785 fputs("Too many arguments.\n", stderr);
789 /* Open netlink channel */
790 if(rtnl_open(&rth, RTMGRP_LINK) < 0)
792 perror("Can't initialize rtnetlink socket");
796 fprintf(stderr, "Waiting for Wireless Events from interfaces...\n");
798 /* Do what we have to do */
799 wait_for_event(&rth);
801 /* Cleanup - only if you are pedantic */