linux基于802.11的wifi扫描流程

wifi scan

netlink协议

Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口

不同于ioctl的是,ioctl只能由应用将消息单向发往内核,netlink则完全支持双工通信

netlink是一种异步通信机制,在内核与用户态应用之间传递的消息保存在socket缓存队列中,发送消息只是把消息保存在接收者的socket的接收队列,而不需要等待接收者收到消息

基于socket的通信

Netlink的通道是通过Family来组织的,但随着使用越来越多,Family ID已经不够分配了,所以才有了Generic Netlink

Generic Netlink其实是对Netlink报文中的数据进行了再次封装

依赖库

libnl-3.so //netlink

libnl-genl-3.so //Generic Netlink

结构

消息回调函数的类型

enum  nl_cb_kind {
  NL_CB_DEFAULT,  //默认回调处理函数
  NL_CB_VERBOSE,  //默认处理函数,在default的基础上会将错误信息、无效信息等打印到stderr,且nl_cb_set()或者nl_cl_err()中的arg参数提供FILE*替代stderr
  NL_CB_DEBUG,    //默认处理函数,在VERBOSE的基础上打印所有信息到终端
  NL_CB_CUSTOM,   //用户自定义处理函数
  __NL_CB_KIND_MAX
};

回调函数通常返回值

enum nl_cb_action {
  NL_OK,   //表示处理正常。
  NL_SKIP,  //表示停止当前netlink消息分析,转而去分析接收buffer中下一条netlink消息(消息分 片的情况)。
  NL_STOP, //表示停止此次接收buffer中的消息分析。
};

type类型:处理底层不同netlink消息的情况

enum  nl_cb_type {
  NL_CB_VALID,  //有效消息
  NL_CB_FINISH, //multipart消息结尾
  NL_CB_OVERRUN, //数据丢失报告
  NL_CB_SKIPPED, //跳过处理消息
  NL_CB_ACK,      //确认消息
  NL_CB_MSG_IN,   //所有接收到的消息
  NL_CB_MSG_OUT,   //所有发出的消息,除nl_sendto()外
  NL_CB_INVALID,   //无效消息
  NL_CB_SEQ_CHECK,  
  NL_CB_SEND_ACK,
  NL_CB_DUMP_INTR,
  __NL_CB_TYPE_MAX
};

流程说明

对于从user to kernel的通讯,driver必须先向内核注册一个struct genl_family,并且注册一些cmd的处理函数。这些cmd是跟某个family关联起来的。注册family的时候我们可以让内核自动为这个family分配一个ID。每个family都有一个唯一的ID,其中ID号0x10是被内核的nlctrl family所使用。当注册成功以后,如果user program向某个family发送cmd,那么内核就会回调对应cmd的处理函数。对于user program,使用前,除了要创建一个socket并绑定地址以外,还需要先通过family的名字获取family的ID。有了family的ID以后,才能向该family发送cmd

对于从kernel to user的通讯,采用的是广播的形式,只要user program监听了,都能收到。但是同样的,user program在监听前,也必须先查询到family的ID

流程

init:

wifiscan->ifname  = strdup(IFNAME);
wifiscan->ifindex = if_nametoindex(wifiscan->ifname);

nl80211_init_nl_global()
    -->nl_cb_alloc()
    /*
    申请回调函数
    wifiscan->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); //NL_CB_DEFAULT:默认处理handler类型
    calloc空间,最终调用nl_cb_set()将回调函数及其参数按顺序放入nl_recvmsg_msg_cb_t cb_set[]中
    */
    -->nl_create_handle() //创建nl_cb对应的nl_handle
    /* wifiscan->nl = nl_create_handle(wifiscan->nl_cb, "nl"); */
        -->nl80211_handle_alloc(cb)
        /* struct nl_handle *handle = nl80211_handle_alloc(cb); */

            -->__alloc_socket(cb);
            /*
            struct nl_sock *sk;
            申请空间并初始化sk的参数,诸如s_local.nl_family=AF_NETLINK,s_peer,s_local.nl_pid,s_cb等信息

            ps:nl_handle即为nl_sockc
            */

        -->genl_connect(handle)
            -->nl_connect(handle, NETLINK_GENERIC);
            /*
            sk即handle,protocol即NETLINK_GENERIC

            sk->s_fd = socket(AF_NETLINK, SOCK_RAW | flags, protocol);
            bind(sk->s_fd, (struct sockaddr*) &sk->s_local,sizeof(sk->s_local)) //绑定本地信息
            */

    -->genl_ctrl_resolve() //向内核发命令,根据family name "nl80211" 获得family id (将nl连接到 内核中的nl80211模块)
    /* wifiscan->nl80211_id = genl_ctrl_resolve(wifiscan->nl, "nl80211"); */

    -->nl_create_handle() //创建接收消息的event socket
    /* wifiscan->nl_event = nl_create_handle(wifiscan->nl_cb, "event"); */

    -->nl_socket_set_nonblocking(wifiscan->nl_event); //设置该handle为非阻塞模式(fcntl)
    -->nl_get_multicast_id() //将nl_event加入到组播组scan
    /* ret = nl_get_multicast_id(wifiscan, "nl80211", "scan"); */

        -->struct nl_msg *msg = nlmsg_alloc() //申请一个nl_msg结构用于向内核发送控制消息
        -->genlmsg_put() //Add Generic Netlink headers to Netlink message
        /*
        void *genlmsg_put(struct nl_msg *msg, uint32_t port, uint32_t seq, int family, int hdrlen, int flags, uint8_t cmd, uint8_t version)

        genlmsg_put(msg, 0, 0, genl_ctrl_resolve(wifiscan->nl, "nlctrl"), 0, 0, CTRL_CMD_GETFAMILY, 0);
        //port:0,表示发非内核;family为"nlctrl",表示该消息为控制消息;cmd:CTRL_CMD_GETFAMILY,消息索引;
        */

        -->send_and_recv_msgs() //发送消息并接收返回
        /* ret = send_and_recv_msgs(wifiscan, msg, family_handler, &res); */

            -->struct nl_cb *cb = nl_cb_clone(wifiscan->nl_cb); //克隆一个nl_cb
            -->nl_send_auto_complete(wifiscan->nl, msg)
            /* 发送生成的帧到内核,内核收到后会执行该消息帧中填充的命令索引和参数,如wifi扫描*/

            -->nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); //注册出错回调
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值