浅析rtnetlink接收wireless网卡信息的源码实例【转】

 

浅析rtnetlink接收wireless网卡信息的源码实例【转】

作者:飞镖 luther (gliethttp)

http://blog.chinaunix.net/u1/38994/showart_1353632.html

 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/wireless.h>
#include <linux/sockios.h>

#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
#define luther_printf(msg...) printf("===luther:=== "msg)
struct luther_context {
    int ioctl_sock;
    int event_sock;
    char ifname[IFNAMSIZ + 1];
    int ifindex;
    int ifindex2;
    int has_capability;
    int we_version_compiled;
} luther_context = {
        .ifname = "eth0",
        .ifindex = -1,
        .ifindex2 = -1,
    };

static void luther_event_rtm_newlink(struct luther_context *ctx,
             struct nlmsghdr *h, size_t len);
static void luther_event_rtm_dellink(struct luther_context *ctx,
            struct nlmsghdr *h, size_t len);
static void luther_wext_event_wireless(struct luther_context *ctx,
             char *data, int len);
static void luther_wext_event_link(struct luther_context *ctx, char *buf, size_t len,
                 int del);
static int luther_wext_get_range(struct luther_context *ctx);
static unsigned int if_nametoindex(const char *ifname);

int main(int argc, char *argv[])
{
    struct sockaddr_nl local;

    luther_context.ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
    if (luther_context.ioctl_sock < 0) {
        perror("socket(PF_INET,SOCK_DGRAM)");
        return 0;
    }

    luther_context.event_sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if (luther_context.event_sock < 0) {
        perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
        close(luther_context.ioctl_sock);
        return 0;
    }
    
    memset(&local, 0, sizeof(local));
    local.nl_family = AF_NETLINK;
    local.nl_groups = RTMGRP_LINK;

    if (bind(luther_context.event_sock, (struct sockaddr *) &local, sizeof(local)) < 0) {
        perror("bind(netlink)");
        close(luther_context.ioctl_sock);
        close(luther_context.event_sock);
        return 0;
    }

    if (argc == 2) {
        strcpy(luther_context.ifname, argv[1]);
    }

    if( luther_wext_get_range(&luther_context) < 0) {
        close(luther_context.ioctl_sock);
        close(luther_context.event_sock);
        return 0;
    }
    luther_context.ifindex = luther_context.ifname[0] ? if_nametoindex(luther_context.ifname) : -1;

    do {
        char buf[8192];
        int left;
        struct sockaddr_nl from;
        socklen_t fromlen;
        struct nlmsghdr *h;
        int sock = luther_context.event_sock;
        struct luther_context *ctx = &luther_context;
        int max_events = 10;
try_again:
        fromlen = sizeof(from);
        left = recvfrom(sock, buf, sizeof(buf), 0/* MSG_DONTWAIT */,
                (struct sockaddr *) &from, &fromlen);
        if (left < 0) {
            if (errno != EINTR && errno != EAGAIN)
                perror("recvfrom(netlink)");
            return 0;
        }

        h = (struct nlmsghdr *) buf;
        while (left >= (int) sizeof(*h)) {
            int len, plen;

            len = h->nlmsg_len;
            plen = len - sizeof(*h);
            if (len > left || plen < 0) {
                luther_printf("Malformed netlink message: "
rtnetlin
                       "len=%d left=%d plen=%d/n",
                       len, left, plen);
                break;
            }

            switch (h->nlmsg_type) {
            case RTM_NEWLINK:
                luther_event_rtm_newlink(ctx, h, plen);
                break;
            case RTM_DELLINK:
                luther_event_rtm_dellink(ctx, h, plen);
                break;
            }

            len = NLMSG_ALIGN(len);
            left -= len;
            h = (struct nlmsghdr *) ((char *) h + len);
        }

        if (left > 0) {
            luther_printf("%d extra bytes in the end of netlink "
             "message/n", left);
        }

        if (--max_events > 0) {
            /*
             * Try to receive all events in one eloop call in order to
             * limit race condition on cases where AssocInfo event, Assoc
             * event, and EAPOL frames are received more or less at the
             * same time. We want to process the event messages first
             * before starting EAPOL processing.
             */

            goto try_again;
        }
        goto try_again;
    } while (0) ;
}

static void luther_event_rtm_newlink(struct luther_context *ctx,
             struct nlmsghdr *h, size_t len)
{
    struct ifinfomsg *ifi;
    int attrlen, nlmsg_len, rta_len;
    struct rtattr * attr;

    if (len < sizeof(*ifi))
        return;

    ifi = NLMSG_DATA(h);

    if ((ctx->ifindex != ifi->ifi_index && ctx->ifindex2 != ifi->ifi_index) && (ctx->ifindex != -1)) {
        luther_printf("Ignore event for foreign ifindex %d/n",
             ifi->ifi_index);
        return;
    }
    
    /*
    luther_printf("RTM_NEWLINK: ifi_flags=0x%x "
         "(%s%s)/n",
         ifi->ifi_flags,
         (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
         (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "");
    */


    nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));

    attrlen = h->nlmsg_len - nlmsg_len;
    if (attrlen < 0)
        return;

    attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);

    rta_len = RTA_ALIGN(sizeof(struct rtattr));
    while (RTA_OK(attr, attrlen)) {
        if (attr->rta_type == IFLA_WIRELESS) {
            luther_wext_event_wireless(
                ctx, ((char *) attr) + rta_len,
                attr->rta_len - rta_len);
        } else if (attr->rta_type == IFLA_IFNAME) {
            luther_wext_event_link(ctx,
                         ((char *) attr) + rta_len,
                         attr->rta_len - rta_len, 0);
        }
        attr = RTA_NEXT(attr, attrlen);
    }
}

static void luther_event_rtm_dellink(struct luther_context *ctx,
        struct nlmsghdr *h, size_t len)
{
    struct ifinfomsg *ifi;
    int attrlen, nlmsg_len, rta_len;
    struct rtattr * attr;

    if (len < sizeof(*ifi))
        return;

    ifi = NLMSG_DATA(h);

    nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));

    attrlen = h->nlmsg_len - nlmsg_len;
    if (attrlen < 0)
        return;

    attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);

    rta_len = RTA_ALIGN(sizeof(struct rtattr));
    while (RTA_OK(attr, attrlen)) {
        if (attr->rta_type == IFLA_IFNAME) {
            luther_wext_event_link(ctx,
                         ((char *) attr) + rta_len,
                         attr->rta_len - rta_len, 1);
        }
        attr = RTA_NEXT(attr, attrlen);
    }
}

static void luther_wext_event_wireless(struct luther_context *ctx,
             char *data, int len)
{
    struct iw_event iwe_buf, *iwe = &iwe_buf;
    char *pos, *end, *custom, *buf;

    pos = data;
    end = data + len;

    while (pos + IW_EV_LCP_LEN <= end) {
        /* Event data may be unaligned, so make a local, aligned copy
         * before processing. */

        memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
        luther_printf("event: cmd=0x%x len=%d/n",
             iwe->cmd, iwe->len);
        if (iwe->len <= IW_EV_LCP_LEN)
            return;

        custom = pos + IW_EV_POINT_LEN;
        if (ctx->we_version_compiled > 18 &&
         (iwe->cmd == IWEVMICHAELMICFAILURE ||
         iwe->cmd == IWEVCUSTOM ||
         iwe->cmd == IWEVASSOCREQIE ||
         iwe->cmd == IWEVASSOCRESPIE ||
         iwe->cmd == IWEVPMKIDCAND)) {
            /* WE-19 removed the pointer from struct iw_point */
            char *dpos = (char *) &iwe_buf.u.data.length;
            int dlen = dpos - (char *) &iwe_buf;
            memcpy(dpos, pos + IW_EV_LCP_LEN,
                 sizeof(struct iw_event) - dlen);
        } else {
            memcpy(&iwe_buf, pos, sizeof(struct iw_event));
            custom += IW_EV_POINT_OFF;
        }

        switch (iwe->cmd) {
        case SIOCGIWAP:
            luther_printf("event: new AP: "
                 MACSTR,
                 MAC2STR((unsigned char *) iwe->u.ap_addr.sa_data));
            if (memcmp(iwe->u.ap_addr.sa_data,
                 "/x00/x00/x00/x00/x00/x00", ETH_ALEN) ==
             0 ||
             memcmp(iwe->u.ap_addr.sa_data,
                 "/x44/x44/x44/x44/x44/x44", ETH_ALEN) ==
             0) {
             luther_printf("event : Disconnect/n");
            } else {
                luther_printf("event : Associated to a new BSS/n");
            }
            break;
        case IWEVMICHAELMICFAILURE:
            luther_printf("event : Michael MIC failure wireless/n");
            break;
        case IWEVCUSTOM:
            if (custom + iwe->u.data.length > end)
                return;
            buf = malloc(iwe->u.data.length + 1);
            if (buf == NULL)
                return;
            memcpy(buf, custom, iwe->u.data.length);
            buf[iwe->u.data.length] = '/0';
            luther_printf("event : custom -> %s/n", buf);
            free(buf);
            break;
        case SIOCGIWSCAN:
            luther_printf("event : scan_results/n");
            break;
        case IWEVASSOCREQIE:
            luther_printf("event : AssocReq IE wireless/n");
            break;
        case IWEVASSOCRESPIE:
            luther_printf("event : AssocResp IE wireless/n");
            break;
        case IWEVPMKIDCAND:
            luther_printf("event : PMKID candidate wireless/n");
            break;
        }

        pos += iwe->len;
    }
}

static void luther_wext_event_link(struct luther_context *ctx, char *buf, size_t len,
                 int del)
{
    luther_printf("RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s/n",
         del ? "DEL" : "NEW",
         buf,
rtnetlin
         del ? "removed" : "added");
}

static int luther_wext_get_range(struct luther_context *ctx)
{
    struct iw_range *range;
    struct iwreq iwr;
    int minlen;
    size_t buflen;

    /*
     * Use larger buffer than struct iw_range in order to allow the
     * structure to grow in the future.
     */

    buflen = sizeof(struct iw_range) + 500;
    range = calloc(buflen, 1);
    if (range == NULL)
        return -1;

    memset(&iwr, 0, sizeof(iwr));
    strncpy(iwr.ifr_name, ctx->ifname, IFNAMSIZ);
    iwr.u.data.pointer = (caddr_t) range;
    iwr.u.data.length = buflen;

    minlen = ((char *) &range->enc_capa) - (char *) range +
        sizeof(range->enc_capa);

    if (ioctl(ctx->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
        perror("ioctl[SIOCGIWRANGE]");
        free(range);
        return -1;
    } else if (iwr.u.data.length >= minlen &&
         range->we_version_compiled >= 18) {
        /*
        luther_printf("SIOCGIWRANGE: WE(compiled)=%d "
             "WE(source)=%d enc_capa=0x%x/n",
             range->we_version_compiled,
             range->we_version_source,
             range->enc_capa);
        */

        ctx->has_capability = 1;
        ctx->we_version_compiled = range->we_version_compiled;
    } else {
        luther_printf("SIOCGIWRANGE: too old (short) data - "
             "assuming WPA is not supported/n");
    }

    free(range);

    return 0;
}

static unsigned int if_nametoindex(const char *ifname)
{
    struct ifreq ifr;
    int fd = socket(AF_INET, SOCK_DGRAM, 0);

    if (fd < 0)
        return 0;

    strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
    ifr.ifr_ifindex = 0;
    if (ioctl (fd, SIOCGIFINDEX, &ifr) < 0) {
        return 0;
    }
    return ifr.ifr_ifindex;
}


luther@gliethttp:~$ arm-linux-gcc -o rtnetlink rtnetlink.c ;arm-linux-strip -s rtnetlink
/telephony/modules # tftp -r rtnetlink -g 192.168.100.1
/telephony/modules # ./rtnetlink &
===luther:=== event: cmd=0x8b06 len=8
===luther:=== RTM_NEWLINK, IFLA_IFNAME: Interface 'eth0' added
===luther:=== RTM_NEWLINK, IFLA_IFNAME: Interface 'eth0' added
===luther:=== event: cmd=0x8b19 len=8
===luther:=== event : scan_results
===luther:=== event: cmd=0x8b06 len=8
===luther:=== event: cmd=0x8b04 len=12
===luther:=== event: cmd=0x8b15 len=20
===luther:=== event: new AP: 00:1d:7e:a0:0e:81
===luther:=== event : Associated to a new BSS
===luther:=== event: cmd=0x8b1a len=22
===luther:=== RTM_NEWLINK, IFLA_IFNAME: Interface 'eth0' added
===luther:=== RTM_NEWLINK, IFLA_IFNAME: Interface 'eth0' added
===luther:=== event: cmd=0x8b06 len=8
===luther:=== RTM_NEWLINK, IFLA_IFNAME: Interface 'eth0' added
===luther:=== RTM_NEWLINK, IFLA_IFNAME: Interface 'eth0' added
===luther:=== event: cmd=0x8b19 len=8
===luther:=== event : scan_results
===luther:=== event: cmd=0x8b06 len=8
===luther:=== event: cmd=0x8b04 len=12
===luther:=== event: cmd=0x8b15 len=20
===luther:=== event: new AP: 00:1d:7e:a0:0e:81
===luther:=== event : Associated to a new BSS
===luther:=== event: cmd=0x8b1a len=22
===luther:=== RTM_NEWLINK, IFLA_IFNAME: Interface 'eth0' added
===luther:=== RTM_NEWLINK, IFLA_IFNAME: Interface 'eth0' added
===luther:=== event: cmd=0x8c02 len=28
===luther:=== event : custom -> HS_DEACTIVATED
===luther:=== event: cmd=0x8c02 len=26
===luther:=== event : custom -> HS_ACTIVATED

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值