Radix cross Linux

The main Radix cross Linux repository contains the build scripts of packages, which have the most complete and common functionality for desktop machines

452 Commits   2 Branches   1 Tag
     5         kx /*
     5         kx  *	Wireless Tools
     5         kx  *
     5         kx  *		Jean II - HPL 99->04
     5         kx  *
     5         kx  * Main code for "iwevent". This listent for wireless events on rtnetlink.
     5         kx  * You need to link this code against "iwcommon.c" and "-lm".
     5         kx  *
     5         kx  * Part of this code is from Alexey Kuznetsov, part is from Casey Carter,
     5         kx  * I've just put the pieces together...
     5         kx  * By the way, if you know a way to remove the root restrictions, tell me
     5         kx  * about it...
     5         kx  *
     5         kx  * This file is released under the GPL license.
     5         kx  *     Copyright (c) 1997-2004 Jean Tourrilhes <jt@hpl.hp.com>
     5         kx  */
     5         kx 
     5         kx /***************************** INCLUDES *****************************/
     5         kx 
     5         kx #include "iwlib-private.h"		/* Private header */
     5         kx 
     5         kx #include <linux/netlink.h>
     5         kx #include <linux/rtnetlink.h>
     5         kx 
     5         kx #include <getopt.h>
     5         kx #include <time.h>
     5         kx #include <sys/time.h>
     5         kx 
     5         kx /* Ugly backward compatibility :-( */
     5         kx #ifndef IFLA_WIRELESS
     5         kx #define IFLA_WIRELESS	(IFLA_MASTER + 1)
     5         kx #endif /* IFLA_WIRELESS */
     5         kx 
     5         kx /****************************** TYPES ******************************/
     5         kx 
     5         kx /*
     5         kx  * Static information about wireless interface.
     5         kx  * We cache this info for performance reason.
     5         kx  */
     5         kx typedef struct wireless_iface
     5         kx {
     5         kx   /* Linked list */
     5         kx   struct wireless_iface *	next;
     5         kx 
     5         kx   /* Interface identification */
     5         kx   int		ifindex;		/* Interface index == black magic */
     5         kx 
     5         kx   /* Interface data */
     5         kx   char			ifname[IFNAMSIZ + 1];	/* Interface name */
     5         kx   struct iw_range	range;			/* Wireless static data */
     5         kx   int			has_range;
     5         kx } wireless_iface;
     5         kx 
     5         kx /**************************** VARIABLES ****************************/
     5         kx 
     5         kx /* Cache of wireless interfaces */
     5         kx struct wireless_iface *	interface_cache = NULL;
     5         kx 
     5         kx /************************ RTNETLINK HELPERS ************************/
     5         kx /*
     5         kx  * The following code is extracted from :
     5         kx  * ----------------------------------------------
     5         kx  * libnetlink.c	RTnetlink service routines.
     5         kx  *
     5         kx  *		This program is free software; you can redistribute it and/or
     5         kx  *		modify it under the terms of the GNU General Public License
     5         kx  *		as published by the Free Software Foundation; either version
     5         kx  *		2 of the License, or (at your option) any later version.
     5         kx  *
     5         kx  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
     5         kx  * -----------------------------------------------
     5         kx  */
     5         kx 
     5         kx struct rtnl_handle
     5         kx {
     5         kx 	int			fd;
     5         kx 	struct sockaddr_nl	local;
     5         kx 	struct sockaddr_nl	peer;
     5         kx 	__u32			seq;
     5         kx 	__u32			dump;
     5         kx };
     5         kx 
     5         kx static inline void rtnl_close(struct rtnl_handle *rth)
     5         kx {
     5         kx 	close(rth->fd);
     5         kx }
     5         kx 
     5         kx static inline int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
     5         kx {
     5         kx 	int addr_len;
     5         kx 
     5         kx 	addr_len = sizeof(rth);
     5         kx 	memset(rth, 0, addr_len);
     5         kx 
     5         kx 	rth->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
     5         kx 	if (rth->fd < 0) {
     5         kx 		perror("Cannot open netlink socket");
     5         kx 		return -1;
     5         kx 	}
     5         kx 
     5         kx 	memset(&rth->local, 0, sizeof(rth->local));
     5         kx 	rth->local.nl_family = AF_NETLINK;
     5         kx 	rth->local.nl_groups = subscriptions;
     5         kx 
     5         kx 	if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
     5         kx 		perror("Cannot bind netlink socket");
     5         kx 		return -1;
     5         kx 	}
     5         kx 	addr_len = sizeof(rth->local);
     5         kx 	if (getsockname(rth->fd, (struct sockaddr*)&rth->local,
     5         kx 			(socklen_t *) &addr_len) < 0) {
     5         kx 		perror("Cannot getsockname");
     5         kx 		return -1;
     5         kx 	}
     5         kx 	if (addr_len != sizeof(rth->local)) {
     5         kx 		fprintf(stderr, "Wrong address length %d\n", addr_len);
     5         kx 		return -1;
     5         kx 	}
     5         kx 	if (rth->local.nl_family != AF_NETLINK) {
     5         kx 		fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
     5         kx 		return -1;
     5         kx 	}
     5         kx 	rth->seq = time(NULL);
     5         kx 	return 0;
     5         kx }
     5         kx 
     5         kx /******************* WIRELESS INTERFACE DATABASE *******************/
     5         kx /*
     5         kx  * We keep a few information about each wireless interface on the
     5         kx  * system. This avoid to query this info at each event, therefore
     5         kx  * reducing overhead.
     5         kx  *
     5         kx  * Each interface is indexed by the 'ifindex'. As opposed to interface
     5         kx  * names, 'ifindex' are never reused (even if you reactivate the same
     5         kx  * hardware), so the data we cache will never apply to the wrong
     5         kx  * interface.
     5         kx  * Because of that, we are pretty lazy when it come to purging the
     5         kx  * cache...
     5         kx  */
     5         kx 
     5         kx /*------------------------------------------------------------------*/
     5         kx /*
     5         kx  * Get name of interface based on interface index...
     5         kx  */
     5         kx static inline int
     5         kx index2name(int		skfd,
     5         kx 	   int		ifindex,
     5         kx 	   char *	name)
     5         kx {
     5         kx   struct ifreq	irq;
     5         kx   int		ret = 0;
     5         kx 
     5         kx   memset(name, 0, IFNAMSIZ + 1);
     5         kx 
     5         kx   /* Get interface name */
     5         kx   irq.ifr_ifindex = ifindex;
     5         kx   if(ioctl(skfd, SIOCGIFNAME, &irq) < 0)
     5         kx     ret = -1;
     5         kx   else
     5         kx     strncpy(name, irq.ifr_name, IFNAMSIZ);
     5         kx 
     5         kx   return(ret);
     5         kx }
     5         kx 
     5         kx /*------------------------------------------------------------------*/
     5         kx /*
     5         kx  * Get interface data from cache or live interface
     5         kx  */
     5         kx static struct wireless_iface *
     5         kx iw_get_interface_data(int	ifindex)
     5         kx {
     5         kx   struct wireless_iface *	curr;
     5         kx   int				skfd = -1;	/* ioctl socket */
     5         kx 
     5         kx   /* Search for it in the database */
     5         kx   curr = interface_cache;
     5         kx   while(curr != NULL)
     5         kx     {
     5         kx       /* Match ? */
     5         kx       if(curr->ifindex == ifindex)
     5         kx 	{
     5         kx 	  //printf("Cache : found %d-%s\n", curr->ifindex, curr->ifname);
     5         kx 
     5         kx 	  /* Return */
     5         kx 	  return(curr);
     5         kx 	}
     5         kx       /* Next entry */
     5         kx       curr = curr->next;
     5         kx     }
     5         kx 
     5         kx   /* Create a channel to the NET kernel. Doesn't happen too often, so
     5         kx    * socket creation overhead is minimal... */
     5         kx   if((skfd = iw_sockets_open()) < 0)
     5         kx     {
     5         kx       perror("iw_sockets_open");
     5         kx       return(NULL);
     5         kx     }
     5         kx 
     5         kx   /* Create new entry, zero, init */
     5         kx   curr = calloc(1, sizeof(struct wireless_iface));
     5         kx   if(!curr)
     5         kx     {
     5         kx       fprintf(stderr, "Malloc failed\n");
     5         kx       return(NULL);
     5         kx     }
     5         kx   curr->ifindex = ifindex;
     5         kx 
     5         kx   /* Extract static data */
     5         kx   if(index2name(skfd, ifindex, curr->ifname) < 0)
     5         kx     {
     5         kx       perror("index2name");
     5         kx       free(curr);
     5         kx       return(NULL);
     5         kx     }
     5         kx   curr->has_range = (iw_get_range_info(skfd, curr->ifname, &curr->range) >= 0);
     5         kx   //printf("Cache : create %d-%s\n", curr->ifindex, curr->ifname);
     5         kx 
     5         kx   /* Done */
     5         kx   iw_sockets_close(skfd);
     5         kx 
     5         kx   /* Link it */
     5         kx   curr->next = interface_cache;
     5         kx   interface_cache = curr;
     5         kx 
     5         kx   return(curr);
     5         kx }
     5         kx 
     5         kx /*------------------------------------------------------------------*/
     5         kx /*
     5         kx  * Remove interface data from cache (if it exist)
     5         kx  */
     5         kx static void
     5         kx iw_del_interface_data(int	ifindex)
     5         kx {
     5         kx   struct wireless_iface *	curr;
     5         kx   struct wireless_iface *	prev = NULL;
     5         kx   struct wireless_iface *	next;
     5         kx 
     5         kx   /* Go through the list, find the interface, kills it */
     5         kx   curr = interface_cache;
     5         kx   while(curr)
     5         kx     {
     5         kx       next = curr->next;
     5         kx 
     5         kx       /* Got a match ? */
     5         kx       if(curr->ifindex == ifindex)
     5         kx 	{
     5         kx 	  /* Unlink. Root ? */
     5         kx 	  if(!prev)
     5         kx 	    interface_cache = next;
     5         kx 	  else
     5         kx 	    prev->next = next;
     5         kx 	  //printf("Cache : purge %d-%s\n", curr->ifindex, curr->ifname);
     5         kx 
     5         kx 	  /* Destroy */
     5         kx 	  free(curr);
     5         kx 	}
     5         kx       else
     5         kx 	{
     5         kx 	  /* Keep as previous */
     5         kx 	  prev = curr;
     5         kx 	}
     5         kx 
     5         kx       /* Next entry */
     5         kx       curr = next;
     5         kx     }
     5         kx }
     5         kx 
     5         kx /********************* WIRELESS EVENT DECODING *********************/
     5         kx /*
     5         kx  * Parse the Wireless Event and print it out
     5         kx  */
     5         kx 
     5         kx /*------------------------------------------------------------------*/
     5         kx /*
     5         kx  * Dump a buffer as a serie of hex
     5         kx  * Maybe should go in iwlib...
     5         kx  * Maybe we should have better formatting like iw_print_key...
     5         kx  */
     5         kx static char *
     5         kx iw_hexdump(char *		buf,
     5         kx 	   size_t		buflen,
     5         kx 	   const unsigned char *data,
     5         kx 	   size_t		datalen)
     5         kx {
     5         kx   size_t	i;
     5         kx   char *	pos = buf;
     5         kx 
     5         kx   for(i = 0; i < datalen; i++)
     5         kx     pos += snprintf(pos, buf + buflen - pos, "%02X", data[i]);
     5         kx   return buf;
     5         kx }
     5         kx 
     5         kx /*------------------------------------------------------------------*/
     5         kx /*
     5         kx  * Print one element from the scanning results
     5         kx  */
     5         kx static inline int
     5         kx print_event_token(struct iw_event *	event,		/* Extracted token */
     5         kx 		  struct iw_range *	iw_range,	/* Range info */
     5         kx 		  int			has_range)
     5         kx {
     5         kx   char		buffer[128];	/* Temporary buffer */
     5         kx   char		buffer2[30];	/* Temporary buffer */
     5         kx   char *	prefix = (IW_IS_GET(event->cmd) ? "New" : "Set");
     5         kx 
     5         kx   /* Now, let's decode the event */
     5         kx   switch(event->cmd)
     5         kx     {
     5         kx       /* ----- set events ----- */
     5         kx       /* Events that result from a "SET XXX" operation by the user */
     5         kx     case SIOCSIWNWID:
     5         kx       if(event->u.nwid.disabled)
     5         kx 	printf("Set NWID:off/any\n");
     5         kx       else
     5         kx 	printf("Set NWID:%X\n", event->u.nwid.value);
     5         kx       break;
     5         kx     case SIOCSIWFREQ:
     5         kx     case SIOCGIWFREQ:
     5         kx       {
     5         kx 	double		freq;			/* Frequency/channel */
     5         kx 	int		channel = -1;		/* Converted to channel */
     5         kx 	freq = iw_freq2float(&(event->u.freq));
     5         kx 	if(has_range)
     5         kx 	  {
     5         kx 	    if(freq < KILO)
     5         kx 	      /* Convert channel to frequency if possible */
     5         kx 	      channel = iw_channel_to_freq((int) freq, &freq, iw_range);
     5         kx 	    else
     5         kx 	      /* Convert frequency to channel if possible */
     5         kx 	      channel = iw_freq_to_channel(freq, iw_range);
     5         kx 	  }
     5         kx 	iw_print_freq(buffer, sizeof(buffer),
     5         kx 		      freq, channel, event->u.freq.flags);
     5         kx 	printf("%s %s\n", prefix, buffer);
     5         kx       }
     5         kx       break;
     5         kx     case SIOCSIWMODE:
     5         kx       printf("Set Mode:%s\n",
     5         kx 	     iw_operation_mode[event->u.mode]);
     5         kx       break;
     5         kx     case SIOCSIWESSID:
     5         kx     case SIOCGIWESSID:
     5         kx       {
     5         kx 	char essid[4*IW_ESSID_MAX_SIZE + 1];
     5         kx 	memset(essid, '\0', sizeof(essid));
     5         kx 	if((event->u.essid.pointer) && (event->u.essid.length))
     5         kx 	  iw_essid_escape(essid,
     5         kx 			  event->u.essid.pointer, event->u.essid.length);
     5         kx 	if(event->u.essid.flags)
     5         kx 	  {
     5         kx 	    /* Does it have an ESSID index ? */
     5         kx 	    if((event->u.essid.flags & IW_ENCODE_INDEX) > 1)
     5         kx 	      printf("%s ESSID:\"%s\" [%d]\n", prefix, essid,
     5         kx 		     (event->u.essid.flags & IW_ENCODE_INDEX));
     5         kx 	    else
     5         kx 	      printf("%s ESSID:\"%s\"\n", prefix, essid);
     5         kx 	  }
     5         kx 	else
     5         kx 	  printf("%s ESSID:off/any\n", prefix);
     5         kx       }
     5         kx       break;
     5         kx     case SIOCSIWENCODE:
     5         kx       {
     5         kx 	unsigned char	key[IW_ENCODING_TOKEN_MAX];
     5         kx 	if(event->u.data.pointer)
     5         kx 	  memcpy(key, event->u.data.pointer, event->u.data.length);
     5         kx 	else
     5         kx 	  event->u.data.flags |= IW_ENCODE_NOKEY;
     5         kx 	printf("Set Encryption key:{%X}", event->u.data.flags);
     5         kx 	if(event->u.data.flags & IW_ENCODE_DISABLED)
     5         kx 	  printf("off\n");
     5         kx 	else
     5         kx 	  {
     5         kx 	    /* Display the key */
     5         kx 	    iw_print_key(buffer, sizeof(buffer), key, event->u.data.length,
     5         kx 			 event->u.data.flags);
     5         kx 	    printf("%s", buffer);
     5         kx 
     5         kx 	    /* Other info... */
     5         kx 	    if((event->u.data.flags & IW_ENCODE_INDEX) > 1)
     5         kx 	      printf(" [%d]", event->u.data.flags & IW_ENCODE_INDEX);
     5         kx 	    if(event->u.data.flags & IW_ENCODE_RESTRICTED)
     5         kx 	      printf("   Security mode:restricted");
     5         kx 	    if(event->u.data.flags & IW_ENCODE_OPEN)
     5         kx 	      printf("   Security mode:open");
     5         kx 	    printf("\n");
     5         kx 	  }
     5         kx       }
     5         kx       break;
     5         kx       /* ----- driver events ----- */
     5         kx       /* Events generated by the driver when something important happens */
     5         kx     case SIOCGIWAP:
     5         kx       printf("New Access Point/Cell address:%s\n",
     5         kx 	     iw_sawap_ntop(&event->u.ap_addr, buffer));
     5         kx       break;
     5         kx     case SIOCGIWSCAN:
     5         kx       printf("Scan request completed\n");
     5         kx       break;
     5         kx     case IWEVTXDROP:
     5         kx       printf("Tx packet dropped:%s\n",
     5         kx 	     iw_saether_ntop(&event->u.addr, buffer));
     5         kx       break;
     5         kx     case IWEVCUSTOM:
     5         kx       {
     5         kx 	char custom[IW_CUSTOM_MAX+1];
     5         kx 	memset(custom, '\0', sizeof(custom));
     5         kx 	if((event->u.data.pointer) && (event->u.data.length))
     5         kx 	  memcpy(custom, event->u.data.pointer, event->u.data.length);
     5         kx 	printf("Custom driver event:%s\n", custom);
     5         kx       }
     5         kx       break;
     5         kx     case IWEVREGISTERED:
     5         kx       printf("Registered node:%s\n",
     5         kx 	     iw_saether_ntop(&event->u.addr, buffer));
     5         kx       break;
     5         kx     case IWEVEXPIRED:
     5         kx       printf("Expired node:%s\n",
     5         kx 	     iw_saether_ntop(&event->u.addr, buffer));
     5         kx       break;
     5         kx     case SIOCGIWTHRSPY:
     5         kx       {
     5         kx 	struct iw_thrspy	threshold;
     5         kx 	if((event->u.data.pointer) && (event->u.data.length))
     5         kx 	  {
     5         kx 	    memcpy(&threshold, event->u.data.pointer,
     5         kx 		   sizeof(struct iw_thrspy));
     5         kx 	    printf("Spy threshold crossed on address:%s\n",
     5         kx 		   iw_saether_ntop(&threshold.addr, buffer));
     5         kx 	    iw_print_stats(buffer, sizeof(buffer),
     5         kx 			   &threshold.qual, iw_range, has_range);
     5         kx 	    printf("                            Link %s\n", buffer);
     5         kx 	  }
     5         kx 	else
     5         kx 	  printf("Invalid Spy Threshold event\n");
     5         kx       }
     5         kx       break;
     5         kx       /* ----- driver WPA events ----- */
     5         kx       /* Events generated by the driver, used for WPA operation */
     5         kx     case IWEVMICHAELMICFAILURE:
     5         kx       if(event->u.data.length >= sizeof(struct iw_michaelmicfailure))
     5         kx 	{
     5         kx 	  struct iw_michaelmicfailure mf;
     5         kx 	  memcpy(&mf, event->u.data.pointer, sizeof(mf));
     5         kx 	  printf("Michael MIC failure flags:0x%X src_addr:%s tsc:%s\n",
     5         kx 		 mf.flags,
     5         kx 		 iw_saether_ntop(&mf.src_addr, buffer2),
     5         kx 		 iw_hexdump(buffer, sizeof(buffer),
     5         kx 			    mf.tsc, IW_ENCODE_SEQ_MAX_SIZE));
     5         kx 	}
     5         kx       break;
     5         kx     case IWEVASSOCREQIE:
     5         kx       printf("Association Request IEs:%s\n",
     5         kx 	     iw_hexdump(buffer, sizeof(buffer),
     5         kx 			event->u.data.pointer, event->u.data.length));
     5         kx       break;
     5         kx     case IWEVASSOCRESPIE:
     5         kx       printf("Association Response IEs:%s\n",
     5         kx 	     iw_hexdump(buffer, sizeof(buffer),
     5         kx 			event->u.data.pointer, event->u.data.length));
     5         kx       break;
     5         kx     case IWEVPMKIDCAND:
     5         kx       if(event->u.data.length >= sizeof(struct iw_pmkid_cand))
     5         kx 	{
     5         kx 	  struct iw_pmkid_cand cand;
     5         kx 	  memcpy(&cand, event->u.data.pointer, sizeof(cand));
     5         kx 	  printf("PMKID candidate flags:0x%X index:%d bssid:%s\n",
     5         kx 		 cand.flags, cand.index,
     5         kx 		 iw_saether_ntop(&cand.bssid, buffer));
     5         kx 	}
     5         kx       break;
     5         kx       /* ----- junk ----- */
     5         kx       /* other junk not currently in use */
     5         kx     case SIOCGIWRATE:
     5         kx       iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
     5         kx       printf("New Bit Rate:%s\n", buffer);
     5         kx       break;
     5         kx     case SIOCGIWNAME:
     5         kx       printf("Protocol:%-1.16s\n", event->u.name);
     5         kx       break;
     5         kx     case IWEVQUAL:
     5         kx       {
     5         kx 	event->u.qual.updated = 0x0;	/* Not that reliable, disable */
     5         kx 	iw_print_stats(buffer, sizeof(buffer),
     5         kx 		       &event->u.qual, iw_range, has_range);
     5         kx 	printf("Link %s\n", buffer);
     5         kx 	break;
     5         kx       }
     5         kx     default:
     5         kx       printf("(Unknown Wireless event 0x%04X)\n", event->cmd);
     5         kx     }	/* switch(event->cmd) */
     5         kx 
     5         kx   return(0);
     5         kx }
     5         kx 
     5         kx /*------------------------------------------------------------------*/
     5         kx /*
     5         kx  * Print out all Wireless Events part of the RTNetlink message
     5         kx  * Most often, there will be only one event per message, but
     5         kx  * just make sure we read everything...
     5         kx  */
     5         kx static inline int
     5         kx print_event_stream(int		ifindex,
     5         kx 		   char *	data,
     5         kx 		   int		len)
     5         kx {
     5         kx   struct iw_event	iwe;
     5         kx   struct stream_descr	stream;
     5         kx   int			i = 0;
     5         kx   int			ret;
     5         kx   char			buffer[64];
     5         kx   struct timeval	recv_time;
     5         kx   struct timezone	tz;
     5         kx   struct wireless_iface *	wireless_data;
     5         kx 
     5         kx   /* Get data from cache */
     5         kx   wireless_data = iw_get_interface_data(ifindex);
     5         kx   if(wireless_data == NULL)
     5         kx     return(-1);
     5         kx 
     5         kx   /* Print received time in readable form */
     5         kx   gettimeofday(&recv_time, &tz);
     5         kx   iw_print_timeval(buffer, sizeof(buffer), &recv_time, &tz);
     5         kx 
     5         kx   iw_init_event_stream(&stream, data, len);
     5         kx   do
     5         kx     {
     5         kx       /* Extract an event and print it */
     5         kx       ret = iw_extract_event_stream(&stream, &iwe,
     5         kx 				    wireless_data->range.we_version_compiled);
     5         kx       if(ret != 0)
     5         kx 	{
     5         kx 	  if(i++ == 0)
     5         kx 	    printf("%s   %-8.16s ", buffer, wireless_data->ifname);
     5         kx 	  else
     5         kx 	    printf("                           ");
     5         kx 	  if(ret > 0)
     5         kx 	    print_event_token(&iwe,
     5         kx 			      &wireless_data->range, wireless_data->has_range);
     5         kx 	  else
     5         kx 	    printf("(Invalid event)\n");
     5         kx 	  /* Push data out *now*, in case we are redirected to a pipe */
     5         kx 	  fflush(stdout);
     5         kx 	}
     5         kx     }
     5         kx   while(ret > 0);
     5         kx 
     5         kx   return(0);
     5         kx }
     5         kx 
     5         kx /*********************** RTNETLINK EVENT DUMP***********************/
     5         kx /*
     5         kx  * Dump the events we receive from rtnetlink
     5         kx  * This code is mostly from Casey
     5         kx  */
     5         kx 
     5         kx /*------------------------------------------------------------------*/
     5         kx /*
     5         kx  * Respond to a single RTM_NEWLINK event from the rtnetlink socket.
     5         kx  */
     5         kx static int
     5         kx LinkCatcher(struct nlmsghdr *nlh)
     5         kx {
     5         kx   struct ifinfomsg* ifi;
     5         kx 
     5         kx #if 0
     5         kx   fprintf(stderr, "nlmsg_type = %d.\n", nlh->nlmsg_type);
     5         kx #endif
     5         kx 
     5         kx   ifi = NLMSG_DATA(nlh);
     5         kx 
     5         kx   /* Code is ugly, but sort of works - Jean II */
     5         kx 
     5         kx   /* If interface is getting destoyed */
     5         kx   if(nlh->nlmsg_type == RTM_DELLINK)
     5         kx     {
     5         kx       /* Remove from cache (if in cache) */
     5         kx       iw_del_interface_data(ifi->ifi_index);
     5         kx       return 0;
     5         kx     }
     5         kx 
     5         kx   /* Only keep add/change events */
     5         kx   if(nlh->nlmsg_type != RTM_NEWLINK)
     5         kx     return 0;
     5         kx 
     5         kx   /* Check for attributes */
     5         kx   if (nlh->nlmsg_len > NLMSG_ALIGN(sizeof(struct ifinfomsg)))
     5         kx     {
     5         kx       int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct ifinfomsg));
     5         kx       struct rtattr *attr = (void *) ((char *) ifi +
     5         kx 				      NLMSG_ALIGN(sizeof(struct ifinfomsg)));
     5         kx 
     5         kx       while (RTA_OK(attr, attrlen))
     5         kx 	{
     5         kx 	  /* Check if the Wireless kind */
     5         kx 	  if(attr->rta_type == IFLA_WIRELESS)
     5         kx 	    {
     5         kx 	      /* Go to display it */
     5         kx 	      print_event_stream(ifi->ifi_index,
     5         kx 				 (char *) attr + RTA_ALIGN(sizeof(struct rtattr)),
     5         kx 				 attr->rta_len - RTA_ALIGN(sizeof(struct rtattr)));
     5         kx 	    }
     5         kx 	  attr = RTA_NEXT(attr, attrlen);
     5         kx 	}
     5         kx     }
     5         kx 
     5         kx   return 0;
     5         kx }
     5         kx 
     5         kx /* ---------------------------------------------------------------- */
     5         kx /*
     5         kx  * We must watch the rtnelink socket for events.
     5         kx  * This routine handles those events (i.e., call this when rth.fd
     5         kx  * is ready to read).
     5         kx  */
     5         kx static inline void
     5         kx handle_netlink_events(struct rtnl_handle *	rth)
     5         kx {
     5         kx   while(1)
     5         kx     {
     5         kx       struct sockaddr_nl sanl;
     5         kx       socklen_t sanllen = sizeof(struct sockaddr_nl);
     5         kx 
     5         kx       struct nlmsghdr *h;
     5         kx       int amt;
     5         kx       char buf[8192];
     5         kx 
     5         kx       amt = recvfrom(rth->fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sanl, &sanllen);
     5         kx       if(amt < 0)
     5         kx 	{
     5         kx 	  if(errno != EINTR && errno != EAGAIN)
     5         kx 	    {
     5         kx 	      fprintf(stderr, "%s: error reading netlink: %s.\n",
     5         kx 		      __PRETTY_FUNCTION__, strerror(errno));
     5         kx 	    }
     5         kx 	  return;
     5         kx 	}
     5         kx 
     5         kx       if(amt == 0)
     5         kx 	{
     5         kx 	  fprintf(stderr, "%s: EOF on netlink??\n", __PRETTY_FUNCTION__);
     5         kx 	  return;
     5         kx 	}
     5         kx 
     5         kx       h = (struct nlmsghdr*)buf;
     5         kx       while(amt >= (int)sizeof(*h))
     5         kx 	{
     5         kx 	  int len = h->nlmsg_len;
     5         kx 	  int l = len - sizeof(*h);
     5         kx 
     5         kx 	  if(l < 0 || len > amt)
     5         kx 	    {
     5         kx 	      fprintf(stderr, "%s: malformed netlink message: len=%d\n", __PRETTY_FUNCTION__, len);
     5         kx 	      break;
     5         kx 	    }
     5         kx 
     5         kx 	  switch(h->nlmsg_type)
     5         kx 	    {
     5         kx 	    case RTM_NEWLINK:
     5         kx 	    case RTM_DELLINK:
     5         kx 	      LinkCatcher(h);
     5         kx 	      break;
     5         kx 	    default:
     5         kx #if 0
     5         kx 	      fprintf(stderr, "%s: got nlmsg of type %#x.\n", __PRETTY_FUNCTION__, h->nlmsg_type);
     5         kx #endif
     5         kx 	      break;
     5         kx 	    }
     5         kx 
     5         kx 	  len = NLMSG_ALIGN(len);
     5         kx 	  amt -= len;
     5         kx 	  h = (struct nlmsghdr*)((char*)h + len);
     5         kx 	}
     5         kx 
     5         kx       if(amt > 0)
     5         kx 	fprintf(stderr, "%s: remnant of size %d on netlink\n", __PRETTY_FUNCTION__, amt);
     5         kx     }
     5         kx }
     5         kx 
     5         kx /**************************** MAIN LOOP ****************************/
     5         kx 
     5         kx /* ---------------------------------------------------------------- */
     5         kx /*
     5         kx  * Wait until we get an event
     5         kx  */
     5         kx static inline int
     5         kx wait_for_event(struct rtnl_handle *	rth)
     5         kx {
     5         kx #if 0
     5         kx   struct timeval	tv;	/* Select timeout */
     5         kx #endif
     5         kx 
     5         kx   /* Forever */
     5         kx   while(1)
     5         kx     {
     5         kx       fd_set		rfds;		/* File descriptors for select */
     5         kx       int		last_fd;	/* Last fd */
     5         kx       int		ret;
     5         kx 
     5         kx       /* Guess what ? We must re-generate rfds each time */
     5         kx       FD_ZERO(&rfds);
     5         kx       FD_SET(rth->fd, &rfds);
     5         kx       last_fd = rth->fd;
     5         kx 
     5         kx       /* Wait until something happens */
     5         kx       ret = select(last_fd + 1, &rfds, NULL, NULL, NULL);
     5         kx 
     5         kx       /* Check if there was an error */
     5         kx       if(ret < 0)
     5         kx 	{
     5         kx 	  if(errno == EAGAIN || errno == EINTR)
     5         kx 	    continue;
     5         kx 	  fprintf(stderr, "Unhandled signal - exiting...\n");
     5         kx 	  break;
     5         kx 	}
     5         kx 
     5         kx       /* Check if there was a timeout */
     5         kx       if(ret == 0)
     5         kx 	{
     5         kx 	  continue;
     5         kx 	}
     5         kx 
     5         kx       /* Check for interface discovery events. */
     5         kx       if(FD_ISSET(rth->fd, &rfds))
     5         kx 	handle_netlink_events(rth);
     5         kx     }
     5         kx 
     5         kx   return(0);
     5         kx }
     5         kx 
     5         kx /******************************* MAIN *******************************/
     5         kx 
     5         kx /* ---------------------------------------------------------------- */
     5         kx /*
     5         kx  * helper ;-)
     5         kx  */
     5         kx static void
     5         kx iw_usage(int status)
     5         kx {
     5         kx   fputs("Usage: iwevent [OPTIONS]\n"
     5         kx 	"   Monitors and displays Wireless Events.\n"
     5         kx 	"   Options are:\n"
     5         kx 	"     -h,--help     Print this message.\n"
     5         kx 	"     -v,--version  Show version of this program.\n",
     5         kx 	status ? stderr : stdout);
     5         kx   exit(status);
     5         kx }
     5         kx /* Command line options */
     5         kx static const struct option long_opts[] = {
     5         kx   { "help", no_argument, NULL, 'h' },
     5         kx   { "version", no_argument, NULL, 'v' },
     5         kx   { NULL, 0, NULL, 0 }
     5         kx };
     5         kx 
     5         kx /* ---------------------------------------------------------------- */
     5         kx /*
     5         kx  * main body of the program
     5         kx  */
     5         kx int
     5         kx main(int	argc,
     5         kx      char *	argv[])
     5         kx {
     5         kx   struct rtnl_handle	rth;
     5         kx   int opt;
     5         kx 
     5         kx   /* Check command line options */
     5         kx   while((opt = getopt_long(argc, argv, "hv", long_opts, NULL)) > 0)
     5         kx     {
     5         kx       switch(opt)
     5         kx 	{
     5         kx 	case 'h':
     5         kx 	  iw_usage(0);
     5         kx 	  break;
     5         kx 
     5         kx 	case 'v':
     5         kx 	  return(iw_print_version_info("iwevent"));
     5         kx 	  break;
     5         kx 
     5         kx 	default:
     5         kx 	  iw_usage(1);
     5         kx 	  break;
     5         kx 	}
     5         kx     }
     5         kx   if(optind < argc)
     5         kx     {
     5         kx       fputs("Too many arguments.\n", stderr);
     5         kx       iw_usage(1);
     5         kx     }
     5         kx 
     5         kx   /* Open netlink channel */
     5         kx   if(rtnl_open(&rth, RTMGRP_LINK) < 0)
     5         kx     {
     5         kx       perror("Can't initialize rtnetlink socket");
     5         kx       return(1);
     5         kx     }
     5         kx 
     5         kx   fprintf(stderr, "Waiting for Wireless Events from interfaces...\n");
     5         kx 
     5         kx   /* Do what we have to do */
     5         kx   wait_for_event(&rth);
     5         kx 
     5         kx   /* Cleanup - only if you are pedantic */
     5         kx   rtnl_close(&rth);
     5         kx 
     5         kx   return(0);
     5         kx }