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 /************************ RTNETLINK HELPERS ************************/
31 * The following code is extracted from :
32 * ----------------------------------------------
33 * libnetlink.c RTnetlink service routines.
35 * This program is free software; you can redistribute it and/or
36 * modify it under the terms of the GNU General Public License
37 * as published by the Free Software Foundation; either version
38 * 2 of the License, or (at your option) any later version.
40 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
41 * -----------------------------------------------
47 struct sockaddr_nl local;
48 struct sockaddr_nl peer;
53 static inline void rtnl_close(struct rtnl_handle *rth)
58 static inline int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
62 memset(rth, 0, sizeof(rth));
64 rth->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
66 perror("Cannot open netlink socket");
70 memset(&rth->local, 0, sizeof(rth->local));
71 rth->local.nl_family = AF_NETLINK;
72 rth->local.nl_groups = subscriptions;
74 if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
75 perror("Cannot bind netlink socket");
78 addr_len = sizeof(rth->local);
79 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
80 perror("Cannot getsockname");
83 if (addr_len != sizeof(rth->local)) {
84 fprintf(stderr, "Wrong address length %d\n", addr_len);
87 if (rth->local.nl_family != AF_NETLINK) {
88 fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
91 rth->seq = time(NULL);
95 /********************* WIRELESS EVENT DECODING *********************/
97 * This is the bit I wrote...
100 #if WIRELESS_EXT > 13
101 /*------------------------------------------------------------------*/
103 * Print one element from the scanning results
106 print_event_token(struct iw_event * event, /* Extracted token */
107 struct iw_range * iwrange, /* Range info */
110 char buffer[128]; /* Temporary buffer */
112 /* Now, let's decode the event */
115 /* ----- set events ----- */
116 /* Events that result from a "SET XXX" operation by the user */
118 if(event->u.nwid.disabled)
119 printf("NWID:off/any\n");
121 printf("NWID:%X\n", event->u.nwid.value);
125 float freq; /* Frequency/channel */
126 freq = iw_freq2float(&(event->u.freq));
127 iw_print_freq(buffer, freq);
128 printf("%s\n", buffer);
133 iw_operation_mode[event->u.mode]);
137 char essid[IW_ESSID_MAX_SIZE+1];
138 if((event->u.essid.pointer) && (event->u.essid.length))
139 memcpy(essid, event->u.essid.pointer, event->u.essid.length);
140 essid[event->u.essid.length] = '\0';
141 if(event->u.essid.flags)
143 /* Does it have an ESSID index ? */
144 if((event->u.essid.flags & IW_ENCODE_INDEX) > 1)
145 printf("ESSID:\"%s\" [%d]\n", essid,
146 (event->u.essid.flags & IW_ENCODE_INDEX));
148 printf("ESSID:\"%s\"\n", essid);
151 printf("ESSID:off/any\n");
156 unsigned char key[IW_ENCODING_TOKEN_MAX];
157 if(event->u.data.pointer)
158 memcpy(key, event->u.essid.pointer, event->u.data.length);
160 event->u.data.flags |= IW_ENCODE_NOKEY;
161 printf("Encryption key:");
162 if(event->u.data.flags & IW_ENCODE_DISABLED)
166 /* Display the key */
167 iw_print_key(buffer, key, event->u.data.length,
168 event->u.data.flags);
169 printf("%s", buffer);
172 if((event->u.data.flags & IW_ENCODE_INDEX) > 1)
173 printf(" [%d]", event->u.data.flags & IW_ENCODE_INDEX);
174 if(event->u.data.flags & IW_ENCODE_RESTRICTED)
175 printf(" Encryption mode:restricted");
176 if(event->u.data.flags & IW_ENCODE_OPEN)
177 printf(" Encryption mode:open");
182 /* ----- driver events ----- */
183 /* Events generated by the driver when something important happens */
185 printf("New Access Point/Cell address:%s\n",
186 iw_pr_ether(buffer, event->u.ap_addr.sa_data));
189 printf("Scan request completed\n");
192 printf("Tx packet dropped:%s\n",
193 iw_pr_ether(buffer, event->u.ap_addr.sa_data));
195 /* ----- junk ----- */
196 /* other junk not currently in use */
198 iw_print_bitrate(buffer, event->u.bitrate.value);
199 printf("Bit Rate:%s\n", buffer);
203 event->u.qual.updated = 0x0; /* Not that reliable, disable */
204 iw_print_stats(buffer, &event->u.qual, iwrange, has_range);
205 printf("Link %s\n", buffer);
209 printf("(Unknown Wireless event 0x%04X)\n", event->cmd);
210 } /* switch(event->cmd) */
215 /*------------------------------------------------------------------*/
217 * Print out all Wireless Events part of the RTNetlink message
218 * Most often, there will be only one event per message, but
219 * just make sure we read everything...
222 print_event_stream(char * ifname,
227 struct stream_descr stream;
231 struct timeval recv_time;
233 struct iw_range range;
238 has_range = (iw_get_range_info(skfd, ifname, &range) < 0);
241 /* In readable form */
242 gettimeofday(&recv_time, NULL);
243 iw_print_timeval(buffer, &recv_time);
245 iw_init_event_stream(&stream, data, len);
248 /* Extract an event and print it */
249 ret = iw_extract_event_stream(&stream, &iwe);
253 printf("%s %-8.8s ", buffer, ifname);
257 print_event_token(&iwe, NULL, 0);
259 printf("(Invalid event)\n");
266 #endif /* WIRELESS_EXT > 13 */
268 /*********************** RTNETLINK EVENT DUMP***********************/
270 * Dump the events we receive from rtnetlink
271 * This code is mostly from Casey
274 /*------------------------------------------------------------------*/
276 * Respond to a single RTM_NEWLINK event from the rtnetlink socket.
279 index2name(int index, char *name)
281 int skfd = -1; /* generic raw socket desc. */
285 memset(name, 0, IFNAMSIZ + 1);
287 /* Create a channel to the NET kernel. */
288 if((skfd = iw_sockets_open()) < 0)
294 /* Get interface name */
295 irq.ifr_ifindex = index;
296 if(ioctl(skfd, SIOCGIFNAME, &irq) < 0)
299 strncpy(name, irq.ifr_name, IFNAMSIZ);
306 /*------------------------------------------------------------------*/
308 * Respond to a single RTM_NEWLINK event from the rtnetlink socket.
311 LinkCatcher(struct nlmsghdr *nlh)
313 struct ifinfomsg* ifi;
314 char ifname[IFNAMSIZ + 1];
317 fprintf(stderr, "nlmsg_type = %d.\n", nlh->nlmsg_type);
320 if(nlh->nlmsg_type != RTM_NEWLINK)
323 ifi = NLMSG_DATA(nlh);
326 index2name(ifi->ifi_index, ifname);
328 #if WIRELESS_EXT > 13
329 /* Code is ugly, but sort of works - Jean II */
331 /* Check for attributes */
332 if (nlh->nlmsg_len > NLMSG_ALIGN(sizeof(struct ifinfomsg))) {
333 int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct ifinfomsg));
334 struct rtattr *attr = (void*)ifi + NLMSG_ALIGN(sizeof(struct ifinfomsg));
336 while (RTA_OK(attr, attrlen)) {
337 /* Check if the Wireless kind */
338 if(attr->rta_type == IFLA_WIRELESS) {
339 /* Go to display it */
340 print_event_stream(ifname,
341 (void *)attr + RTA_ALIGN(sizeof(struct rtattr)),
342 attr->rta_len - RTA_ALIGN(sizeof(struct rtattr)));
344 attr = RTA_NEXT(attr, attrlen);
347 #endif /* WIRELESS_EXT > 13 */
352 /* ---------------------------------------------------------------- */
354 * We must watch the rtnelink socket for events.
355 * This routine handles those events (i.e., call this when rth.fd
359 handle_netlink_events(struct rtnl_handle * rth)
363 struct sockaddr_nl sanl;
370 amt = recvfrom(rth->fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sanl, &sanllen);
373 if(errno != EINTR && errno != EAGAIN)
375 fprintf(stderr, "%s: error reading netlink: %s.\n",
376 __PRETTY_FUNCTION__, strerror(errno));
383 fprintf(stderr, "%s: EOF on netlink??\n", __PRETTY_FUNCTION__);
387 h = (struct nlmsghdr*)buf;
388 while(amt >= (int)sizeof(*h))
390 int len = h->nlmsg_len;
391 int l = len - sizeof(*h);
393 if(l < 0 || len > amt)
395 fprintf(stderr, "%s: malformed netlink message: len=%d\n", __PRETTY_FUNCTION__, len);
399 switch(h->nlmsg_type)
406 fprintf(stderr, "%s: got nlmsg of type %#x.\n", __PRETTY_FUNCTION__, h->nlmsg_type);
411 len = NLMSG_ALIGN(len);
413 h = (struct nlmsghdr*)((char*)h + len);
417 fprintf(stderr, "%s: remnant of size %d on netlink\n", __PRETTY_FUNCTION__, amt);
421 /**************************** MAIN LOOP ****************************/
423 /* ---------------------------------------------------------------- */
425 * Wait until we get an event
428 wait_for_event(struct rtnl_handle * rth)
431 struct timeval tv; /* Select timeout */
437 fd_set rfds; /* File descriptors for select */
438 int last_fd; /* Last fd */
441 /* Guess what ? We must re-generate rfds each time */
443 FD_SET(rth->fd, &rfds);
446 /* Wait until something happens */
447 ret = select(last_fd + 1, &rfds, NULL, NULL, NULL);
449 /* Check if there was an error */
452 if(errno == EAGAIN || errno == EINTR)
454 fprintf(stderr, "Unhandled signal - exiting...\n");
458 /* Check if there was a timeout */
464 /* Check for interface discovery events. */
465 if(FD_ISSET(rth->fd, &rfds))
466 handle_netlink_events(rth);
472 /******************************* MAIN *******************************/
474 /* ---------------------------------------------------------------- */
481 fputs("Usage: iwevent [OPTIONS]\n"
482 " Monitors and displays Wireless Events.\n"
484 " -h,--help Print this message.\n",
485 status ? stderr : stdout);
488 /* Command line options */
489 static const struct option long_opts[] = {
490 { "help", no_argument, NULL, 'h' },
494 /* ---------------------------------------------------------------- */
496 * main body of the program
502 struct rtnl_handle rth;
505 /* Check command line options */
506 while((opt = getopt_long(argc, argv, "h", long_opts, NULL)) > 0)
521 fputs("Too many arguments.\n", stderr);
525 /* Open netlink channel */
526 if(rtnl_open(&rth, RTMGRP_LINK) < 0)
528 perror("Can't initialize rtnetlink socket");
532 /* Do what we have to do */
533 wait_for_event(&rth);
535 /* Cleanup - only if you are pedantic */