linux --- iwevent事件上报机制

来源:互联网 发布:xp添加网络win7打印机 编辑:程序博客网 时间:2024/04/30 09:48

最近工作涉及到了对linux下面的iwevent命令的使用,主要是:通过linux下面的netlink机制将内核的信息发送给用户态程序,这里的用户态程序就是iwevent。

linux 对iwevent命令的帮助信息如下:



IWEVENT(8)                                              Linux Programmer's Manual                                              IWEVENT(8)


NAME
       iwevent - Display Wireless Events generated by drivers and setting changes


SYNOPSIS
       iwevent

DESCRIPTION
       iwevent  displays  Wireless  Events  received  through  the RTNetlink socket. Each line displays the specific Wireless Event which
       describes what has happened on the specified wireless interface.
       This command doesn't take any arguments.


DISPLAY
       There are two classes of Wireless Events.


       The first class is events related to a change of wireless settings on the interface (typically done through iwconfig or  a  script
       calling  iwconfig).   Only  settings that could result in a disruption of connectivity are reported. The events currently reported
       are changing one of the following setting :
            Network ID
            ESSID
            Frequency
            Mode
            Encryption
       All those events will be generated on all wireless interfaces by the kernel wireless subsystem (but only if the  driver  has  been
       converted to the new driver API).


       The  second class of events are events generated by the hardware, when something happens or a task has been finished. Those events
       include :


       New Access Point/Cell address
              The interface has joined a new Access Point or Ad-Hoc Cell, or lost its association with it. This is the same address  that
              is reported by iwconfig.


       Scan request completed
              A scanning request has been completed, results of the scan are available (see iwlist).


       Tx packet dropped
              A packet directed at this address has been dropped because the interface believes this node doesn't answer anymore (usually
              maximum of MAC level retry exceeded). This is usually an early indication that the node may have left the cell or gone  out
              of range, but it may be due to fading or excessive contention.


       Custom driver event
              Event specific to the driver. Please check the driver documentation.


       Registered node
              The  interface  has successfully registered a new wireless client/peer. Will be generated mostly when the interface acts as
              an Access Point (mode Master).


       Expired node
              The registration of the client/peer on this interface has expired. Will be generated mostly when the interface acts  as  an
              Access Point (mode Master).


       Spy threshold crossed
              The signal strength for one of the addresses in the spy list went under the low threshold or went above the high threshold.


       Most  wireless  drivers  generate  only  a  subset  of those events, not all of them, the exact list depends on the specific hard?
       ware/driver combination. Please refer to driver documentation for details on when they are generated, and use iwlist(8)  to  check
       what the driver supports.


AUTHOR
       Jean Tourrilhes - jt@hpl.hp.com


SEE ALSO
       iwconfig(8), iwlist(8), iwspy(8), iwpriv(8), wireless(7).

二:iwevent代码分析

iwevent命令的源代码存在于:wireless_tools.29中,代码重要是通过socket从内核获取信息。

int
main(int argc,
     char * argv[])
{
  struct rtnl_handle rth;
  int opt;

  /* Check command line options */
  while((opt = getopt_long(argc, argv, "hv", long_opts, NULL)) > 0)
    {
      switch(opt)
{
case 'h':
 iw_usage(0);
 break;
case 'v':
 return(iw_print_version_info("iwevent"));
 break;
default:
 iw_usage(1);
 break;
}
    }
  if(optind < argc)
    {
      fputs("Too many arguments.\n", stderr);
      iw_usage(1);
    }
  /* Open netlink channel */
  if(rtnl_open(&rth, RTMGRP_LINK) < 0)
    {
      perror("Can't initialize rtnetlink socket");
      return(1);
    }

  fprintf(stderr, "Waiting for Wireless Events from interfaces...\n");

  /* Do what we have to do */
  wait_for_event(&rth);

  /* Cleanup - only if you are pedantic */
  rtnl_close(&rth);


  return(0);
}

下面看一下这三个函数:

static inline int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
{
int addr_len;
memset(rth, 0, sizeof(rth));
rth->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (rth->fd < 0) {
perror("Cannot open netlink socket");
return -1;
}
memset(&rth->local, 0, sizeof(rth->local));
rth->local.nl_family = AF_NETLINK;
rth->local.nl_groups = subscriptions;


if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {

perror("Cannot bind netlink socket");
return -1;
}
addr_len = sizeof(rth->local);
if (getsockname(rth->fd, (struct sockaddr*)&rth->local,(socklen_t *) &addr_len) < 0) {
perror("Cannot getsockname");
return -1;
}
if (addr_len != sizeof(rth->local)) {
fprintf(stderr, "Wrong address length %d\n", addr_len);
return -1;
}
if (rth->local.nl_family != AF_NETLINK) {
fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
return -1;
}
rth->seq = time(NULL);
return 0;
}

static inline int wait_for_event(struct rtnl_handle *rth)
{
#if 0
  struct timeval tv;/* Select timeout */
#endif

  /* Forever */
  while(1)
    {
      fd_set rfds;/* File descriptors for select */
      int last_fd;/* Last fd */
      int ret;
      /* Guess what ? We must re-generate rfds each time */
      FD_ZERO(&rfds);
      FD_SET(rth->fd, &rfds);

      last_fd = rth->fd;
      /* Wait until something happens */
      ret = select(last_fd + 1, &rfds, NULL, NULL, NULL);
      /* Check if there was an error */
      if(ret < 0)
{
 if(errno == EAGAIN || errno == EINTR)
   continue;
 fprintf(stderr, "Unhandled signal - exiting...\n");
 break;
}
      /* Check if there was a timeout */
      if(ret == 0)
{
 continue;
}
      /* Check for interface discovery events. */
      if(FD_ISSET(rth->fd, &rfds))
handle_netlink_events(rth);
    }
  return(0);
}


/*
 * We must watch the rtnelink socket for events.
 * This routine handles those events (i.e., call this when rth.fd
 * is ready to read).
 */
static inline void handle_netlink_events(struct rtnl_handle *rth)
{
  while(1)
    {
      struct sockaddr_nl sanl;
      socklen_t sanllen = sizeof(struct sockaddr_nl);
      struct nlmsghdr *h;
      int amt;
      char buf[8192];
      amt = recvfrom(rth->fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sanl, &sanllen);
      if(amt < 0)
{
 if(errno != EINTR && errno != EAGAIN)
   {
     fprintf(stderr, "%s: error reading netlink: %s.\n",
     __PRETTY_FUNCTION__, strerror(errno));
   }
 return;
}
      if(amt == 0)
{
 fprintf(stderr, "%s: EOF on netlink??\n", __PRETTY_FUNCTION__);
 return;
}
      h = (struct nlmsghdr*)buf;
      while(amt >= (int)sizeof(*h))
{
 int len = h->nlmsg_len;
 int l = len - sizeof(*h);
 if(l < 0 || len > amt)
   {
     fprintf(stderr, "%s: malformed netlink message: len=%d\n", __PRETTY_FUNCTION__, len);
     break;
   }
 switch(h->nlmsg_type)
   {
   case RTM_NEWLINK:
   case RTM_DELLINK:
     LinkCatcher(h);
     break;
   default:
#if 0
     fprintf(stderr, "%s: got nlmsg of type %#x.\n", __PRETTY_FUNCTION__, h->nlmsg_type);
#endif
     break;
   }
 len = NLMSG_ALIGN(len);
 amt -= len;
 h = (struct nlmsghdr*)((char*)h + len);
}
      if(amt > 0)
fprintf(stderr, "%s: remnant of size %d on netlink\n", __PRETTY_FUNCTION__, amt);
    }
}

/*------------------------------------------------------------------*/
/*
 * Respond to a single RTM_NEWLINK event from the rtnetlink socket.
 */
static int LinkCatcher(struct nlmsghdr *nlh)
{
  struct ifinfomsg* ifi;

#if 0
  fprintf(stderr, "nlmsg_type = %d.\n", nlh->nlmsg_type);
#endif
  ifi = NLMSG_DATA(nlh);
  /* 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)))
    {
      int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct ifinfomsg));
      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);
}
    }
  return 0;
}

 

----------------------------------------------------------------------------------------------

二:对iwevent的测试

~ # iwevent
Waiting for Wireless Events from interfaces...
00:01:30.492550   ath0     Custom driver event:STA ASSOC.indication sta=40:16:9f:01:2f:80   ,sig_strength=31, association time is -52390

00:01:30.510397   ath0     Registered node:40:16:9F:01:2F:80
00:01:30.808654   ath0     Custom driver event:STA ASSOC.indication sta=40:16:9f:01:2f:80   ,sig_strength=31, association time is -52298

00:01:30.808800   ath0     Registered node:40:16:9F:01:2F:80

上面的信息是当无线网卡连接上ap时的打印信息。根据这些打印信息可以分析linux和iwevent的源代码。


原创粉丝点击