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-2002 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 /************************ RTNETLINK HELPERS ************************/
36 * The following code is extracted from :
37 * ----------------------------------------------
38 * libnetlink.c RTnetlink service routines.
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.
45 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
46 * -----------------------------------------------
52 struct sockaddr_nl local;
53 struct sockaddr_nl peer;
58 static inline void rtnl_close(struct rtnl_handle *rth)
63 static inline int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
67 memset(rth, 0, sizeof(rth));
69 rth->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
71 perror("Cannot open netlink socket");
75 memset(&rth->local, 0, sizeof(rth->local));
76 rth->local.nl_family = AF_NETLINK;
77 rth->local.nl_groups = subscriptions;
79 if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
80 perror("Cannot bind netlink socket");
83 addr_len = sizeof(rth->local);
84 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
85 perror("Cannot getsockname");
88 if (addr_len != sizeof(rth->local)) {
89 fprintf(stderr, "Wrong address length %d\n", addr_len);
92 if (rth->local.nl_family != AF_NETLINK) {
93 fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
96 rth->seq = time(NULL);
100 /********************* WIRELESS EVENT DECODING *********************/
102 * This is the bit I wrote...
105 #if WIRELESS_EXT > 13
106 /*------------------------------------------------------------------*/
108 * Print one element from the scanning results
111 print_event_token(struct iw_event * event, /* Extracted token */
113 struct iw_range * iwrange, /* Range info */
116 char buffer[128]; /* Temporary buffer */
118 /* Now, let's decode the event */
121 /* ----- set events ----- */
122 /* Events that result from a "SET XXX" operation by the user */
124 if(event->u.nwid.disabled)
125 printf("NWID:off/any\n");
127 printf("NWID:%X\n", event->u.nwid.value);
131 float freq; /* Frequency/channel */
132 freq = iw_freq2float(&(event->u.freq));
133 iw_print_freq(buffer, freq);
134 printf("%s\n", buffer);
139 iw_operation_mode[event->u.mode]);
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)
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));
154 printf("ESSID:\"%s\"\n", essid);
157 printf("ESSID:off/any\n");
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);
166 event->u.data.flags |= IW_ENCODE_NOKEY;
167 printf("Encryption key:");
168 if(event->u.data.flags & IW_ENCODE_DISABLED)
172 /* Display the key */
173 iw_print_key(buffer, key, event->u.data.length,
174 event->u.data.flags);
175 printf("%s", buffer);
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");
188 /* ----- driver events ----- */
189 /* Events generated by the driver when something important happens */
191 printf("New Access Point/Cell address:%s\n",
192 iw_pr_ether(buffer, event->u.ap_addr.sa_data));
195 printf("Scan request completed\n");
198 printf("Tx packet dropped:%s\n",
199 iw_pr_ether(buffer, event->u.addr.sa_data));
201 #if WIRELESS_EXT > 14
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);
212 printf("Registered node:%s\n",
213 iw_pr_ether(buffer, event->u.addr.sa_data));
216 printf("Expired node:%s\n",
217 iw_pr_ether(buffer, event->u.addr.sa_data));
219 #endif /* WIRELESS_EXT > 14 */
220 #if WIRELESS_EXT > 15
223 struct iw_thrspy threshold;
225 struct iw_range range;
227 if((event->u.data.pointer) && (event->u.data.length))
229 memcpy(&threshold, event->u.data.pointer,
230 sizeof(struct iw_thrspy));
231 if((skfd = iw_sockets_open()) >= 0)
233 has_range = (iw_get_range_info(skfd, ifname, &range) >= 0);
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);
243 printf("Invalid Spy Threshold event\n");
247 /* Avoid "Unused parameter" warning */
249 #endif /* WIRELESS_EXT > 15 */
250 /* ----- junk ----- */
251 /* other junk not currently in use */
253 iw_print_bitrate(buffer, event->u.bitrate.value);
254 printf("Bit Rate:%s\n", buffer);
257 printf("Protocol:%-1.16s\n", event->u.name);
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);
267 printf("(Unknown Wireless event 0x%04X)\n", event->cmd);
268 } /* switch(event->cmd) */
273 /*------------------------------------------------------------------*/
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...
280 print_event_stream(char * ifname,
285 struct stream_descr stream;
289 struct timeval recv_time;
291 struct iw_range range;
296 has_range = (iw_get_range_info(skfd, ifname, &range) < 0);
299 /* In readable form */
300 gettimeofday(&recv_time, NULL);
301 iw_print_timeval(buffer, &recv_time);
303 iw_init_event_stream(&stream, data, len);
306 /* Extract an event and print it */
307 ret = iw_extract_event_stream(&stream, &iwe);
311 printf("%s %-8.8s ", buffer, ifname);
315 print_event_token(&iwe, ifname, NULL, 0);
317 printf("(Invalid event)\n");
324 #endif /* WIRELESS_EXT > 13 */
326 /*********************** RTNETLINK EVENT DUMP***********************/
328 * Dump the events we receive from rtnetlink
329 * This code is mostly from Casey
332 /*------------------------------------------------------------------*/
334 * Respond to a single RTM_NEWLINK event from the rtnetlink socket.
337 index2name(int index, char *name)
339 int skfd = -1; /* generic raw socket desc. */
343 memset(name, 0, IFNAMSIZ + 1);
345 /* Create a channel to the NET kernel. */
346 if((skfd = iw_sockets_open()) < 0)
352 /* Get interface name */
353 irq.ifr_ifindex = index;
354 if(ioctl(skfd, SIOCGIFNAME, &irq) < 0)
357 strncpy(name, irq.ifr_name, IFNAMSIZ);
364 /*------------------------------------------------------------------*/
366 * Respond to a single RTM_NEWLINK event from the rtnetlink socket.
369 LinkCatcher(struct nlmsghdr *nlh)
371 struct ifinfomsg* ifi;
372 char ifname[IFNAMSIZ + 1];
375 fprintf(stderr, "nlmsg_type = %d.\n", nlh->nlmsg_type);
378 if(nlh->nlmsg_type != RTM_NEWLINK)
381 ifi = NLMSG_DATA(nlh);
384 index2name(ifi->ifi_index, ifname);
386 #if WIRELESS_EXT > 13
387 /* Code is ugly, but sort of works - Jean II */
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));
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)));
402 attr = RTA_NEXT(attr, attrlen);
405 #endif /* WIRELESS_EXT > 13 */
410 /* ---------------------------------------------------------------- */
412 * We must watch the rtnelink socket for events.
413 * This routine handles those events (i.e., call this when rth.fd
417 handle_netlink_events(struct rtnl_handle * rth)
421 struct sockaddr_nl sanl;
428 amt = recvfrom(rth->fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sanl, &sanllen);
431 if(errno != EINTR && errno != EAGAIN)
433 fprintf(stderr, "%s: error reading netlink: %s.\n",
434 __PRETTY_FUNCTION__, strerror(errno));
441 fprintf(stderr, "%s: EOF on netlink??\n", __PRETTY_FUNCTION__);
445 h = (struct nlmsghdr*)buf;
446 while(amt >= (int)sizeof(*h))
448 int len = h->nlmsg_len;
449 int l = len - sizeof(*h);
451 if(l < 0 || len > amt)
453 fprintf(stderr, "%s: malformed netlink message: len=%d\n", __PRETTY_FUNCTION__, len);
457 switch(h->nlmsg_type)
464 fprintf(stderr, "%s: got nlmsg of type %#x.\n", __PRETTY_FUNCTION__, h->nlmsg_type);
469 len = NLMSG_ALIGN(len);
471 h = (struct nlmsghdr*)((char*)h + len);
475 fprintf(stderr, "%s: remnant of size %d on netlink\n", __PRETTY_FUNCTION__, amt);
479 /**************************** MAIN LOOP ****************************/
481 /* ---------------------------------------------------------------- */
483 * Wait until we get an event
486 wait_for_event(struct rtnl_handle * rth)
489 struct timeval tv; /* Select timeout */
495 fd_set rfds; /* File descriptors for select */
496 int last_fd; /* Last fd */
499 /* Guess what ? We must re-generate rfds each time */
501 FD_SET(rth->fd, &rfds);
504 /* Wait until something happens */
505 ret = select(last_fd + 1, &rfds, NULL, NULL, NULL);
507 /* Check if there was an error */
510 if(errno == EAGAIN || errno == EINTR)
512 fprintf(stderr, "Unhandled signal - exiting...\n");
516 /* Check if there was a timeout */
522 /* Check for interface discovery events. */
523 if(FD_ISSET(rth->fd, &rfds))
524 handle_netlink_events(rth);
530 /******************************* MAIN *******************************/
532 /* ---------------------------------------------------------------- */
539 fputs("Usage: iwevent [OPTIONS]\n"
540 " Monitors and displays Wireless Events.\n"
542 " -h,--help Print this message.\n"
543 " -v,--version Show version of this program.\n",
544 status ? stderr : stdout);
547 /* Command line options */
548 static const struct option long_opts[] = {
549 { "help", no_argument, NULL, 'h' },
550 { "version", no_argument, NULL, 'v' },
554 /* ---------------------------------------------------------------- */
556 * main body of the program
562 struct rtnl_handle rth;
565 /* Check command line options */
566 while((opt = getopt_long(argc, argv, "hv", long_opts, NULL)) > 0)
575 return(iw_print_version_info("iwevent"));
585 fputs("Too many arguments.\n", stderr);
589 /* Open netlink channel */
590 if(rtnl_open(&rth, RTMGRP_LINK) < 0)
592 perror("Can't initialize rtnetlink socket");
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");
601 #endif /* WIRELESS_EXT > 13 */
603 /* Do what we have to do */
604 wait_for_event(&rth);
606 /* Cleanup - only if you are pedantic */