linux --- iwevent事件上报机制
最近工作涉及到了对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的源代码。
更多推荐
所有评论(0)