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.h" /* 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, &addr_len) < 0) {
110 perror("Cannot getsockname");
113 if (addr_len != sizeof(rth->local)) {
114 fprintf(stderr, "Wrong address length %d\n", addr_len);
117 if (rth->local.nl_family != AF_NETLINK) {
118 fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
121 rth->seq = time(NULL);
125 /******************* WIRELESS INTERFACE DATABASE *******************/
127 * We keep a few information about each wireless interface on the
128 * system. This avoid to query this info at each event, therefore
131 * Each interface is indexed by the 'ifindex'. As opposed to interface
132 * names, 'ifindex' are never reused (even if you reactivate the same
133 * hardware), so the data we cache will never apply to the wrong
135 * Because of that, we are pretty lazy when it come to purging the
139 /*------------------------------------------------------------------*/
141 * Get name of interface based on interface index...
151 memset(name, 0, IFNAMSIZ + 1);
153 /* Get interface name */
154 irq.ifr_ifindex = ifindex;
155 if(ioctl(skfd, SIOCGIFNAME, &irq) < 0)
158 strncpy(name, irq.ifr_name, IFNAMSIZ);
163 /*------------------------------------------------------------------*/
165 * Get interface data from cache or live interface
167 static struct wireless_iface *
168 iw_get_interface_data(int ifindex)
170 struct wireless_iface * curr;
171 int skfd = -1; /* ioctl socket */
173 /* Search for it in the database */
174 curr = interface_cache;
178 if(curr->ifindex == ifindex)
180 //printf("Cache : found %d-%s\n", curr->ifindex, curr->ifname);
189 /* Create a channel to the NET kernel. Doesn't happen too often, so
190 * socket creation overhead is minimal... */
191 if((skfd = iw_sockets_open()) < 0)
193 perror("iw_sockets_open");
197 /* Create new entry, zero, init */
198 curr = calloc(1, sizeof(struct wireless_iface));
201 fprintf(stderr, "Malloc failed\n");
204 curr->ifindex = ifindex;
206 /* Extract static data */
207 if(index2name(skfd, ifindex, curr->ifname) < 0)
209 perror("index2name");
213 curr->has_range = (iw_get_range_info(skfd, curr->ifname, &curr->range) >= 0);
214 //printf("Cache : create %d-%s\n", curr->ifindex, curr->ifname);
217 iw_sockets_close(skfd);
220 curr->next = interface_cache;
221 interface_cache = curr;
226 /*------------------------------------------------------------------*/
228 * Remove interface data from cache (if it exist)
231 iw_del_interface_data(int ifindex)
233 struct wireless_iface * curr;
234 struct wireless_iface * prev = NULL;
235 struct wireless_iface * next;
237 /* Go through the list, find the interface, kills it */
238 curr = interface_cache;
244 if(curr->ifindex == ifindex)
248 interface_cache = next;
251 //printf("Cache : purge %d-%s\n", curr->ifindex, curr->ifname);
258 /* Keep as previous */
267 /********************* WIRELESS EVENT DECODING *********************/
269 * Parse the Wireless Event and print it out
272 /*------------------------------------------------------------------*/
274 * Print one element from the scanning results
277 print_event_token(struct iw_event * event, /* Extracted token */
278 struct iw_range * iw_range, /* Range info */
281 char buffer[128]; /* Temporary buffer */
282 char * prefix = (IW_IS_GET(event->cmd) ? "New" : "Set");
284 /* Now, let's decode the event */
287 /* ----- set events ----- */
288 /* Events that result from a "SET XXX" operation by the user */
290 if(event->u.nwid.disabled)
291 printf("Set NWID:off/any\n");
293 printf("Set NWID:%X\n", event->u.nwid.value);
298 double freq; /* Frequency/channel */
299 int channel = -1; /* Converted to channel */
300 freq = iw_freq2float(&(event->u.freq));
304 /* Convert channel to frequency if possible */
305 channel = iw_channel_to_freq((int) freq, &freq, iw_range);
307 /* Convert frequency to channel if possible */
308 channel = iw_freq_to_channel(freq, iw_range);
310 iw_print_freq(buffer, sizeof(buffer),
311 freq, channel, event->u.freq.flags);
312 printf("%s %s\n", prefix, buffer);
316 printf("Set Mode:%s\n",
317 iw_operation_mode[event->u.mode]);
322 char essid[IW_ESSID_MAX_SIZE+1];
323 if((event->u.essid.pointer) && (event->u.essid.length))
324 memcpy(essid, event->u.essid.pointer, event->u.essid.length);
325 essid[event->u.essid.length] = '\0';
326 if(event->u.essid.flags)
328 /* Does it have an ESSID index ? */
329 if((event->u.essid.flags & IW_ENCODE_INDEX) > 1)
330 printf("%s ESSID:\"%s\" [%d]\n", prefix, essid,
331 (event->u.essid.flags & IW_ENCODE_INDEX));
333 printf("%s ESSID:\"%s\"\n", prefix, essid);
336 printf("%s ESSID:off/any\n", prefix);
341 unsigned char key[IW_ENCODING_TOKEN_MAX];
342 if(event->u.data.pointer)
343 memcpy(key, event->u.essid.pointer, event->u.data.length);
345 event->u.data.flags |= IW_ENCODE_NOKEY;
346 printf("Set Encryption key:");
347 if(event->u.data.flags & IW_ENCODE_DISABLED)
351 /* Display the key */
352 iw_print_key(buffer, sizeof(buffer), key, event->u.data.length,
353 event->u.data.flags);
354 printf("%s", buffer);
357 if((event->u.data.flags & IW_ENCODE_INDEX) > 1)
358 printf(" [%d]", event->u.data.flags & IW_ENCODE_INDEX);
359 if(event->u.data.flags & IW_ENCODE_RESTRICTED)
360 printf(" Security mode:restricted");
361 if(event->u.data.flags & IW_ENCODE_OPEN)
362 printf(" Security mode:open");
367 /* ----- driver events ----- */
368 /* Events generated by the driver when something important happens */
370 printf("New Access Point/Cell address:%s\n",
371 iw_pr_ether(buffer, event->u.ap_addr.sa_data));
374 printf("Scan request completed\n");
377 printf("Tx packet dropped:%s\n",
378 iw_pr_ether(buffer, event->u.addr.sa_data));
382 char custom[IW_CUSTOM_MAX+1];
383 if((event->u.data.pointer) && (event->u.data.length))
384 memcpy(custom, event->u.data.pointer, event->u.data.length);
385 custom[event->u.data.length] = '\0';
386 printf("Custom driver event:%s\n", custom);
390 printf("Registered node:%s\n",
391 iw_pr_ether(buffer, event->u.addr.sa_data));
394 printf("Expired node:%s\n",
395 iw_pr_ether(buffer, event->u.addr.sa_data));
399 struct iw_thrspy threshold;
400 if((event->u.data.pointer) && (event->u.data.length))
402 memcpy(&threshold, event->u.data.pointer,
403 sizeof(struct iw_thrspy));
404 printf("Spy threshold crossed on address:%s\n",
405 iw_pr_ether(buffer, threshold.addr.sa_data));
406 iw_print_stats(buffer, sizeof(buffer),
407 &threshold.qual, iw_range, has_range);
408 printf(" Link %s\n", buffer);
411 printf("Invalid Spy Threshold event\n");
414 /* ----- junk ----- */
415 /* other junk not currently in use */
417 iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
418 printf("New Bit Rate:%s\n", buffer);
421 printf("Protocol:%-1.16s\n", event->u.name);
425 event->u.qual.updated = 0x0; /* Not that reliable, disable */
426 iw_print_stats(buffer, sizeof(buffer),
427 &event->u.qual, iw_range, has_range);
428 printf("Link %s\n", buffer);
432 printf("(Unknown Wireless event 0x%04X)\n", event->cmd);
433 } /* switch(event->cmd) */
438 /*------------------------------------------------------------------*/
440 * Print out all Wireless Events part of the RTNetlink message
441 * Most often, there will be only one event per message, but
442 * just make sure we read everything...
445 print_event_stream(int ifindex,
450 struct stream_descr stream;
454 struct timeval recv_time;
455 struct wireless_iface * wireless_data;
457 /* Get data from cache */
458 wireless_data = iw_get_interface_data(ifindex);
459 if(wireless_data == NULL)
462 /* Print received time in readable form */
463 gettimeofday(&recv_time, NULL);
464 iw_print_timeval(buffer, sizeof(buffer), &recv_time);
466 iw_init_event_stream(&stream, data, len);
469 /* Extract an event and print it */
470 ret = iw_extract_event_stream(&stream, &iwe,
471 wireless_data->range.we_version_compiled);
475 printf("%s %-8.16s ", buffer, wireless_data->ifname);
479 print_event_token(&iwe,
480 &wireless_data->range, wireless_data->has_range);
482 printf("(Invalid event)\n");
483 /* Push data out *now*, in case we are redirected to a pipe */
492 /*********************** RTNETLINK EVENT DUMP***********************/
494 * Dump the events we receive from rtnetlink
495 * This code is mostly from Casey
498 /*------------------------------------------------------------------*/
500 * Respond to a single RTM_NEWLINK event from the rtnetlink socket.
503 LinkCatcher(struct nlmsghdr *nlh)
505 struct ifinfomsg* ifi;
508 fprintf(stderr, "nlmsg_type = %d.\n", nlh->nlmsg_type);
511 ifi = NLMSG_DATA(nlh);
513 /* Code is ugly, but sort of works - Jean II */
515 /* If interface is getting destoyed */
516 if(nlh->nlmsg_type == RTM_DELLINK)
518 /* Remove from cache (if in cache) */
519 iw_del_interface_data(ifi->ifi_index);
523 /* Only keep add/change events */
524 if(nlh->nlmsg_type != RTM_NEWLINK)
527 /* Check for attributes */
528 if (nlh->nlmsg_len > NLMSG_ALIGN(sizeof(struct ifinfomsg)))
530 int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct ifinfomsg));
531 struct rtattr *attr = (void *) ((char *) ifi +
532 NLMSG_ALIGN(sizeof(struct ifinfomsg)));
534 while (RTA_OK(attr, attrlen))
536 /* Check if the Wireless kind */
537 if(attr->rta_type == IFLA_WIRELESS)
539 /* Go to display it */
540 print_event_stream(ifi->ifi_index,
541 (char *) attr + RTA_ALIGN(sizeof(struct rtattr)),
542 attr->rta_len - RTA_ALIGN(sizeof(struct rtattr)));
544 attr = RTA_NEXT(attr, attrlen);
551 /* ---------------------------------------------------------------- */
553 * We must watch the rtnelink socket for events.
554 * This routine handles those events (i.e., call this when rth.fd
558 handle_netlink_events(struct rtnl_handle * rth)
562 struct sockaddr_nl sanl;
563 socklen_t sanllen = sizeof(struct sockaddr_nl);
569 amt = recvfrom(rth->fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sanl, &sanllen);
572 if(errno != EINTR && errno != EAGAIN)
574 fprintf(stderr, "%s: error reading netlink: %s.\n",
575 __PRETTY_FUNCTION__, strerror(errno));
582 fprintf(stderr, "%s: EOF on netlink??\n", __PRETTY_FUNCTION__);
586 h = (struct nlmsghdr*)buf;
587 while(amt >= (int)sizeof(*h))
589 int len = h->nlmsg_len;
590 int l = len - sizeof(*h);
592 if(l < 0 || len > amt)
594 fprintf(stderr, "%s: malformed netlink message: len=%d\n", __PRETTY_FUNCTION__, len);
598 switch(h->nlmsg_type)
606 fprintf(stderr, "%s: got nlmsg of type %#x.\n", __PRETTY_FUNCTION__, h->nlmsg_type);
611 len = NLMSG_ALIGN(len);
613 h = (struct nlmsghdr*)((char*)h + len);
617 fprintf(stderr, "%s: remnant of size %d on netlink\n", __PRETTY_FUNCTION__, amt);
621 /**************************** MAIN LOOP ****************************/
623 /* ---------------------------------------------------------------- */
625 * Wait until we get an event
628 wait_for_event(struct rtnl_handle * rth)
631 struct timeval tv; /* Select timeout */
637 fd_set rfds; /* File descriptors for select */
638 int last_fd; /* Last fd */
641 /* Guess what ? We must re-generate rfds each time */
643 FD_SET(rth->fd, &rfds);
646 /* Wait until something happens */
647 ret = select(last_fd + 1, &rfds, NULL, NULL, NULL);
649 /* Check if there was an error */
652 if(errno == EAGAIN || errno == EINTR)
654 fprintf(stderr, "Unhandled signal - exiting...\n");
658 /* Check if there was a timeout */
664 /* Check for interface discovery events. */
665 if(FD_ISSET(rth->fd, &rfds))
666 handle_netlink_events(rth);
672 /******************************* MAIN *******************************/
674 /* ---------------------------------------------------------------- */
681 fputs("Usage: iwevent [OPTIONS]\n"
682 " Monitors and displays Wireless Events.\n"
684 " -h,--help Print this message.\n"
685 " -v,--version Show version of this program.\n",
686 status ? stderr : stdout);
689 /* Command line options */
690 static const struct option long_opts[] = {
691 { "help", no_argument, NULL, 'h' },
692 { "version", no_argument, NULL, 'v' },
696 /* ---------------------------------------------------------------- */
698 * main body of the program
704 struct rtnl_handle rth;
707 /* Check command line options */
708 while((opt = getopt_long(argc, argv, "hv", long_opts, NULL)) > 0)
717 return(iw_print_version_info("iwevent"));
727 fputs("Too many arguments.\n", stderr);
731 /* Open netlink channel */
732 if(rtnl_open(&rth, RTMGRP_LINK) < 0)
734 perror("Can't initialize rtnetlink socket");
738 fprintf(stderr, "Waiting for Wireless Events from interfaces...\n");
740 /* Do what we have to do */
741 wait_for_event(&rth);
743 /* Cleanup - only if you are pedantic */