OSDN Git Service

v27
[android-x86/external-wireless-tools.git] / wireless_tools / iwevent.c
index 54bf96b..525cb68 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     Wireless Tools
  *
- *             Jean II - HPL 99->01
+ *             Jean II - HPL 99->04
  *
  * Main code for "iwevent". This listent for wireless events on rtnetlink.
  * You need to link this code against "iwcommon.c" and "-lm".
@@ -12,7 +12,7 @@
  * about it...
  *
  * This file is released under the GPL license.
- *     Copyright (c) 1997-2002 Jean Tourrilhes <jt@hpl.hp.com>
+ *     Copyright (c) 1997-2004 Jean Tourrilhes <jt@hpl.hp.com>
  */
 
 /***************************** INCLUDES *****************************/
 #include <time.h>
 #include <sys/time.h>
 
+/* Ugly backward compatibility :-( */
+#ifndef IFLA_WIRELESS
+#define IFLA_WIRELESS  (IFLA_MASTER + 1)
+#endif /* IFLA_WIRELESS */
+
+/****************************** TYPES ******************************/
+
+/*
+ * Static information about wireless interface.
+ * We cache this info for performance reason.
+ */
+typedef struct wireless_iface
+{
+  /* Linked list */
+  struct wireless_iface *      next;
+
+  /* Interface identification */
+  int          ifindex;                /* Interface index == black magic */
+
+  /* Interface data */
+  char                 ifname[IFNAMSIZ + 1];   /* Interface name */
+  struct iw_range      range;                  /* Wireless static data */
+  int                  has_range;
+} wireless_iface;
+
+/**************************** VARIABLES ****************************/
+
+/* Cache of wireless interfaces */
+struct wireless_iface *        interface_cache = NULL;
+
 /************************ RTNETLINK HELPERS ************************/
 /*
  * The following code is extracted from :
@@ -92,22 +122,164 @@ static inline int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
        return 0;
 }
 
+/******************* WIRELESS INTERFACE DATABASE *******************/
+/*
+ * We keep a few information about each wireless interface on the
+ * system. This avoid to query this info at each event, therefore
+ * reducing overhead.
+ *
+ * Each interface is indexed by the 'ifindex'. As opposed to interface
+ * names, 'ifindex' are never reused (even if you reactivate the same
+ * hardware), so the data we cache will never apply to the wrong
+ * interface.
+ * Because of that, we are pretty lazy when it come to purging the
+ * cache...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Get name of interface based on interface index...
+ */
+static inline int
+index2name(int         skfd,
+          int          ifindex,
+          char *       name)
+{
+  struct ifreq irq;
+  int          ret = 0;
+
+  memset(name, 0, IFNAMSIZ + 1);
+
+  /* Get interface name */
+  irq.ifr_ifindex = ifindex;
+  if(ioctl(skfd, SIOCGIFNAME, &irq) < 0)
+    ret = -1;
+  else
+    strncpy(name, irq.ifr_name, IFNAMSIZ);
+
+  return(ret);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Get interface data from cache or live interface
+ */
+static struct wireless_iface *
+iw_get_interface_data(int      ifindex)
+{
+  struct wireless_iface *      curr;
+  int                          skfd = -1;      /* ioctl socket */
+
+  /* Search for it in the database */
+  curr = interface_cache;
+  while(curr != NULL)
+    {
+      /* Match ? */
+      if(curr->ifindex == ifindex)
+       {
+         //printf("Cache : found %d-%s\n", curr->ifindex, curr->ifname);
+
+         /* Return */
+         return(curr);
+       }
+      /* Next entry */
+      curr = curr->next;
+    }
+
+  /* Create a channel to the NET kernel. Doesn't happen too often, so
+   * socket creation overhead is minimal... */
+  if((skfd = iw_sockets_open()) < 0)
+    {
+      perror("iw_sockets_open");
+      return(NULL);
+    }
+
+  /* Create new entry, zero, init */
+  curr = calloc(1, sizeof(struct wireless_iface));
+  if(!curr)
+    {
+      fprintf(stderr, "Malloc failed\n");
+      return(NULL);
+    }
+  curr->ifindex = ifindex;
+
+  /* Extract static data */
+  if(index2name(skfd, ifindex, curr->ifname) < 0)
+    {
+      perror("index2name");
+      free(curr);
+      return(NULL);
+    }
+  curr->has_range = (iw_get_range_info(skfd, curr->ifname, &curr->range) >= 0);
+  //printf("Cache : create %d-%s\n", curr->ifindex, curr->ifname);
+
+  /* Done */
+  iw_sockets_close(skfd);
+
+  /* Link it */
+  curr->next = interface_cache;
+  interface_cache = curr;
+
+  return(curr);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Remove interface data from cache (if it exist)
+ */
+static void
+iw_del_interface_data(int      ifindex)
+{
+  struct wireless_iface *      curr;
+  struct wireless_iface *      prev = NULL;
+  struct wireless_iface *      next;
+
+  /* Go through the list, find the interface, kills it */
+  curr = interface_cache;
+  while(curr)
+    {
+      next = curr->next;
+
+      /* Got a match ? */
+      if(curr->ifindex == ifindex)
+       {
+         /* Unlink. Root ? */
+         if(!prev)
+           interface_cache = next;
+         else
+           prev->next = next;
+         //printf("Cache : purge %d-%s\n", curr->ifindex, curr->ifname);
+
+         /* Destroy */
+         free(curr);
+       }
+      else
+       {
+         /* Keep as previous */
+         prev = curr;
+       }
+
+      /* Next entry */
+      curr = next;
+    }
+}
+
 /********************* WIRELESS EVENT DECODING *********************/
 /*
- * This is the bit I wrote...
+ * Parse the Wireless Event and print it out
  */
 
-#if WIRELESS_EXT > 13
 /*------------------------------------------------------------------*/
 /*
  * Print one element from the scanning results
  */
 static inline int
-print_event_token(struct iw_event *    event,  /* Extracted token */
-                 struct iw_range *     iwrange,        /* Range info */
+print_event_token(struct iw_event *    event,          /* Extracted token */
+                 struct iw_range *     iw_range,       /* Range info */
                  int                   has_range)
 {
   char         buffer[128];    /* Temporary buffer */
+  char *       prefix = (IW_IS_GET(event->cmd) ? "New" : "Set");
 
   /* Now, let's decode the event */
   switch(event->cmd)
@@ -116,23 +288,36 @@ print_event_token(struct iw_event *       event,  /* Extracted token */
       /* Events that result from a "SET XXX" operation by the user */
     case SIOCSIWNWID:
       if(event->u.nwid.disabled)
-       printf("NWID:off/any\n");
+       printf("Set NWID:off/any\n");
       else
-       printf("NWID:%X\n", event->u.nwid.value);
+       printf("Set NWID:%X\n", event->u.nwid.value);
       break;
     case SIOCSIWFREQ:
+    case SIOCGIWFREQ:
       {
-       float           freq;                   /* Frequency/channel */
+       double          freq;                   /* Frequency/channel */
+       int             channel = -1;           /* Converted to channel */
        freq = iw_freq2float(&(event->u.freq));
-       iw_print_freq(buffer, freq);
-       printf("%s\n", buffer);
+       if(has_range)
+         {
+           if(freq < KILO)
+             /* Convert channel to frequency if possible */
+             channel = iw_channel_to_freq((int) freq, &freq, iw_range);
+           else
+             /* Convert frequency to channel if possible */
+             channel = iw_freq_to_channel(freq, iw_range);
+         }
+       iw_print_freq(buffer, sizeof(buffer),
+                     freq, channel, event->u.freq.flags);
+       printf("%s %s\n", prefix, buffer);
       }
       break;
     case SIOCSIWMODE:
-      printf("Mode:%s\n",
+      printf("Set Mode:%s\n",
             iw_operation_mode[event->u.mode]);
       break;
     case SIOCSIWESSID:
+    case SIOCGIWESSID:
       {
        char essid[IW_ESSID_MAX_SIZE+1];
        if((event->u.essid.pointer) && (event->u.essid.length))
@@ -142,13 +327,13 @@ print_event_token(struct iw_event *       event,  /* Extracted token */
          {
            /* Does it have an ESSID index ? */
            if((event->u.essid.flags & IW_ENCODE_INDEX) > 1)
-             printf("ESSID:\"%s\" [%d]\n", essid,
+             printf("%s ESSID:\"%s\" [%d]\n", prefix, essid,
                     (event->u.essid.flags & IW_ENCODE_INDEX));
            else
-             printf("ESSID:\"%s\"\n", essid);
+             printf("%s ESSID:\"%s\"\n", prefix, essid);
          }
        else
-         printf("ESSID:off/any\n");
+         printf("%s ESSID:off/any\n", prefix);
       }
       break;
     case SIOCSIWENCODE:
@@ -158,13 +343,13 @@ print_event_token(struct iw_event *       event,  /* Extracted token */
          memcpy(key, event->u.essid.pointer, event->u.data.length);
        else
          event->u.data.flags |= IW_ENCODE_NOKEY;
-       printf("Encryption key:");
+       printf("Set Encryption key:");
        if(event->u.data.flags & IW_ENCODE_DISABLED)
          printf("off\n");
        else
          {
            /* Display the key */
-           iw_print_key(buffer, key, event->u.data.length,
+           iw_print_key(buffer, sizeof(buffer), key, event->u.data.length,
                         event->u.data.flags);
            printf("%s", buffer);
 
@@ -172,9 +357,9 @@ print_event_token(struct iw_event * event,  /* Extracted token */
            if((event->u.data.flags & IW_ENCODE_INDEX) > 1)
              printf(" [%d]", event->u.data.flags & IW_ENCODE_INDEX);
            if(event->u.data.flags & IW_ENCODE_RESTRICTED)
-             printf("   Encryption mode:restricted");
+             printf("   Security mode:restricted");
            if(event->u.data.flags & IW_ENCODE_OPEN)
-             printf("   Encryption mode:open");
+             printf("   Security mode:open");
            printf("\n");
          }
       }
@@ -192,7 +377,6 @@ print_event_token(struct iw_event * event,  /* Extracted token */
       printf("Tx packet dropped:%s\n",
             iw_pr_ether(buffer, event->u.addr.sa_data));
       break;
-#if WIRELESS_EXT > 14
     case IWEVCUSTOM:
       {
        char custom[IW_CUSTOM_MAX+1];
@@ -210,17 +394,37 @@ print_event_token(struct iw_event *       event,  /* Extracted token */
       printf("Expired node:%s\n",
             iw_pr_ether(buffer, event->u.addr.sa_data));
       break;
-#endif /* WIRELESS_EXT > 14 */
+    case SIOCGIWTHRSPY:
+      {
+       struct iw_thrspy        threshold;
+       if((event->u.data.pointer) && (event->u.data.length))
+         {
+           memcpy(&threshold, event->u.data.pointer,
+                  sizeof(struct iw_thrspy));
+           printf("Spy threshold crossed on address:%s\n",
+                  iw_pr_ether(buffer, threshold.addr.sa_data));
+           iw_print_stats(buffer, sizeof(buffer),
+                          &threshold.qual, iw_range, has_range);
+           printf("                            Link %s\n", buffer);
+         }
+       else
+         printf("Invalid Spy Threshold event\n");
+      }
+      break;
       /* ----- junk ----- */
       /* other junk not currently in use */
     case SIOCGIWRATE:
-      iw_print_bitrate(buffer, event->u.bitrate.value);
-      printf("Bit Rate:%s\n", buffer);
+      iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
+      printf("New Bit Rate:%s\n", buffer);
+      break;
+    case SIOCGIWNAME:
+      printf("Protocol:%-1.16s\n", event->u.name);
       break;
     case IWEVQUAL:
       {
        event->u.qual.updated = 0x0;    /* Not that reliable, disable */
-       iw_print_stats(buffer, &event->u.qual, iwrange, has_range);
+       iw_print_stats(buffer, sizeof(buffer),
+                      &event->u.qual, iw_range, has_range);
        printf("Link %s\n", buffer);
        break;
       }
@@ -238,7 +442,7 @@ print_event_token(struct iw_event * event,  /* Extracted token */
  * just make sure we read everything...
  */
 static inline int
-print_event_stream(char *      ifname,
+print_event_stream(int         ifindex,
                   char *       data,
                   int          len)
 {
@@ -248,41 +452,42 @@ print_event_stream(char * ifname,
   int                  ret;
   char                 buffer[64];
   struct timeval       recv_time;
-#if 0
-  struct iw_range      range;
-  int                  has_range;
-#endif
+  struct wireless_iface *      wireless_data;
 
-#if 0
-  has_range = (iw_get_range_info(skfd, ifname, &range) < 0);
-#endif
+  /* Get data from cache */
+  wireless_data = iw_get_interface_data(ifindex);
+  if(wireless_data == NULL)
+    return(-1);
 
-  /* In readable form */
+  /* Print received time in readable form */
   gettimeofday(&recv_time, NULL);
-  iw_print_timeval(buffer, &recv_time);
+  iw_print_timeval(buffer, sizeof(buffer), &recv_time);
 
   iw_init_event_stream(&stream, data, len);
   do
     {
       /* Extract an event and print it */
-      ret = iw_extract_event_stream(&stream, &iwe);
+      ret = iw_extract_event_stream(&stream, &iwe,
+                                   wireless_data->range.we_version_compiled);
       if(ret != 0)
        {
          if(i++ == 0)
-           printf("%s   %-8.8s ", buffer, ifname);
+           printf("%s   %-8.16s ", buffer, wireless_data->ifname);
          else
            printf("                           ");
          if(ret > 0)
-           print_event_token(&iwe, NULL, 0);
+           print_event_token(&iwe,
+                             &wireless_data->range, wireless_data->has_range);
          else
            printf("(Invalid event)\n");
+         /* Push data out *now*, in case we are redirected to a pipe */
+         fflush(stdout);
        }
     }
   while(ret > 0);
 
   return(0);
 }
-#endif /* WIRELESS_EXT > 13 */
 
 /*********************** RTNETLINK EVENT DUMP***********************/
 /*
@@ -294,76 +499,51 @@ print_event_stream(char * ifname,
 /*
  * Respond to a single RTM_NEWLINK event from the rtnetlink socket.
  */
-static inline int
-index2name(int index, char *name)
-{
-  int          skfd = -1;      /* generic raw socket desc.     */
-  struct ifreq irq;
-  int          ret = 0;
-
-  memset(name, 0, IFNAMSIZ + 1);
-
-  /* Create a channel to the NET kernel. */
-  if((skfd = iw_sockets_open()) < 0)
-    {
-      perror("socket");
-      exit(-1);
-    }
-
-  /* Get interface name */
-  irq.ifr_ifindex = index;
-  if(ioctl(skfd, SIOCGIFNAME, &irq) < 0)
-    ret = -1;
-  else
-    strncpy(name, irq.ifr_name, IFNAMSIZ);
-
-  close(skfd);
-  return(ret);
-}
-
-
-/*------------------------------------------------------------------*/
-/*
- * Respond to a single RTM_NEWLINK event from the rtnetlink socket.
- */
 static int
 LinkCatcher(struct nlmsghdr *nlh)
 {
   struct ifinfomsg* ifi;
-  char ifname[IFNAMSIZ + 1];
 
 #if 0
   fprintf(stderr, "nlmsg_type = %d.\n", nlh->nlmsg_type);
 #endif
 
-  if(nlh->nlmsg_type != RTM_NEWLINK)
-    return 0;
-
   ifi = NLMSG_DATA(nlh);
 
-  /* Get a name... */
-  index2name(ifi->ifi_index, ifname);
-
-#if WIRELESS_EXT > 13
   /* Code is ugly, but sort of works - Jean II */
 
+  /* If interface is getting destoyed */
+  if(nlh->nlmsg_type == RTM_DELLINK)
+    {
+      /* Remove from cache (if in cache) */
+      iw_del_interface_data(ifi->ifi_index);
+      return 0;
+    }
+
+  /* Only keep add/change events */
+  if(nlh->nlmsg_type != RTM_NEWLINK)
+    return 0;
+
   /* Check for attributes */
-  if (nlh->nlmsg_len > NLMSG_ALIGN(sizeof(struct ifinfomsg))) {
+  if (nlh->nlmsg_len > NLMSG_ALIGN(sizeof(struct ifinfomsg)))
+    {
       int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct ifinfomsg));
-      struct rtattr *attr = (void*)ifi + NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
-      while (RTA_OK(attr, attrlen)) {
-       /* Check if the Wireless kind */
-       if(attr->rta_type == IFLA_WIRELESS) {
-         /* Go to display it */
-         print_event_stream(ifname,
-                            (void *)attr + RTA_ALIGN(sizeof(struct rtattr)),
-                            attr->rta_len - RTA_ALIGN(sizeof(struct rtattr)));
+      struct rtattr *attr = (void *) ((char *) ifi +
+                                     NLMSG_ALIGN(sizeof(struct ifinfomsg)));
+
+      while (RTA_OK(attr, attrlen))
+       {
+         /* Check if the Wireless kind */
+         if(attr->rta_type == IFLA_WIRELESS)
+           {
+             /* Go to display it */
+             print_event_stream(ifi->ifi_index,
+                                (char *) attr + RTA_ALIGN(sizeof(struct rtattr)),
+                                attr->rta_len - RTA_ALIGN(sizeof(struct rtattr)));
+           }
+         attr = RTA_NEXT(attr, attrlen);
        }
-       attr = RTA_NEXT(attr, attrlen);
-      }
-  }
-#endif /* WIRELESS_EXT > 13 */
+    }
 
   return 0;
 }
@@ -380,7 +560,7 @@ handle_netlink_events(struct rtnl_handle *  rth)
   while(1)
     {
       struct sockaddr_nl sanl;
-      socklen_t sanllen;
+      socklen_t sanllen = sizeof(struct sockaddr_nl);
 
       struct nlmsghdr *h;
       int amt;
@@ -418,6 +598,7 @@ handle_netlink_events(struct rtnl_handle *  rth)
          switch(h->nlmsg_type)
            {
            case RTM_NEWLINK:
+           case RTM_DELLINK:
              LinkCatcher(h);
              break;
            default:
@@ -554,12 +735,7 @@ main(int   argc,
       return(1);
     }
 
-#if WIRELESS_EXT > 13
-  fprintf(stderr, "Waiting for Wireless Events...\n");
-#else  /* WIRELESS_EXT > 13 */
-  fprintf(stderr, "Unsupported in Wireless Extensions <= 14 :-(\n");
-  return(-1);
-#endif /* WIRELESS_EXT > 13 */
+  fprintf(stderr, "Waiting for Wireless Events from interfaces...\n");
 
   /* Do what we have to do */
   wait_for_event(&rth);