Android wpa_supplicant源码分析--启动之网络接口初始化

1 wpa_supplicant结构体与网络接口

在手机adb中运行 netcfg或者ifconfig可以看到相关的网络接口的ip,掩码,mac地址等信息

这里写图片描述 
Wpa_supplicant为每个网络接口都分配了一个struct wpa_supplicant, 该结构体存储了一些必要信息例如 struct dl_list bss(扫描结果); struct wpa_config *conf(配置文件)等等。 
每一个网络接口的扫描,连接等操作都是通过struct wpa_supplicant中定义的相关函数和数据来实现的。下面是结构体中一些重要的元素介绍

struct wpa_supplicant{
    //接口的名字和mac地址
    unsigned char own_addr[ETH_ALEN];
    char ifname[100];

    /**************************************/    

    //外部控制wpa_s的socket
    struct ctrl_iface_priv *ctrl_iface;

    //网络接口当前的状态,断开/关联/连接的bssid ssid等
    enum wpa_states wpa_state;
    u8 bssid[ETH_ALEN];
    u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
                     * field contains the target BSSID. */
    int reassociate; /* reassociation requested */
    int disconnected; /* all connections disabled; i.e., do no reassociate
               * before this has been cleared */
    struct wpa_ssid *current_ssid;
    struct wpa_bss *current_bss;
    int ap_ies_from_associnfo;
    unsigned int assoc_freq;

    //是否支持2.4G/5G
    enum { WPA_SETBAND_AUTO, WPA_SETBAND_5G, WPA_SETBAND_2G } setband;

    /**************************************/

    //配置文件
    struct wpa_config *conf;
    //配置文件中的ESS网络的信息
    /* Selected configuration (based on Beacon/ProbeResp WPA IE) */
    int pairwise_cipher;
    int group_cipher;
    int key_mgmt;
    int wpa_proto;
    int mgmt_group_cipher;

    /**************************************/

    //扫描结果的处理,每次扫描后的结果都会做相应的更新
    void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
                 struct wpa_scan_results *scan_res);
    struct dl_list bss; /* struct wpa_bss::list */
    struct dl_list bss_id; /* struct wpa_bss::list_id */
    size_t num_bss;
    unsigned int bss_update_idx;
    unsigned int bss_next_id;
    //黑名单
    struct wpa_blacklist *blacklist;

    /**************************************/

    //底层相关,驱动的操作函数
    struct wpa_driver_ops *driver;
    int interface_removed; /* whether the network interface has been removed */
    void *drv_priv; /* private data used by driver_ops */
    void *global_drv_priv;

    //用来处理密钥相关netlink socket和处理方法
    struct l2_packet_data *l2;
    struct l2_packet_data *l2_br;

    /**************************************/

    //扫描相关的一些信息
    struct wpa_radio_work *scan_work;
    int scanning;
    int sched_scanning;
    struct os_reltime scan_trigger_time, scan_start_time;
    int scan_runs; /* number of scan runs since WPS was started */
    int *next_scan_freqs;
    int scan_interval; /* time in sec between scans to find suitable AP */
    int normal_scans; /* normal scans run before sched_scan */
    int scan_for_connection; /* whether the scan request was triggered for
                  * finding a connection */

    //sched_scan
    struct wpa_ssid *prev_sched_ssid; /* last SSID used in sched scan */
    int sched_scan_timeout;
    int sched_scan_interval;
    int first_sched_scan;
    int sched_scan_timed_out;

    //pno扫描
    int pno;
    int pno_sched_pending;
}

2初始化网络接口配置

在wpa_s的main()函数中,进行完全局初始化后,会调用 wpa_supplicant_add_iface(),为wpa_s运行时传入的每个网络接口分配wpa_supplicant结构体,并进行相应的初始化

struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
                         struct wpa_interface *iface)
{
    struct wpa_supplicant *wpa_s = wpa_supplicant_alloc();
    wpa_s->global = global;

    //网络接口的初始化,与底层通信的socket,密钥数据包的socket,wpa_s的初始状态等 
    if (wpa_supplicant_init_iface(wpa_s, &t_iface)) 
    {


        //读取两个conf配置文件
        //wpa_s允许提供两个配置文件,一个是原始的一个overlay,在overlay中的文件可以重新一些参数的值
        wpa_s->conf = wpa_config_read(wpa_s->confname, NULL);
        wpa_config_read(wpa_s->confanother, wpa_s->conf);

        //初始化驱动接口,并注册接收驱动event的函数 nl80211
        if (wpas_init_driver(wpa_s, iface) < 0)
        {
            //根据传进来的-inl80211选定对应的wpa_driver_ops(driver_nl80211.c),里面定义了驱动的操作方法,同时调用对应的global_init()进行初始化
            if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
            ...

3nl80211操作列表内容

驱动初始化 
下一步是初始化相关驱动的操作参数和与驱动通信的socket 
wpa_supplicant支持多种架构的驱动,Android中多使用的是nl80211架构,相关操作函数在文件drivers_ml80211.c中

//根据名称选择网络ops,创建于driver通信的socket
select_driver(wpa_s, i)
{
    //调用对应的global_init(),void * nl80211_global_init(void)
    global->drv_priv[i] = wpa_drivers[i]->global_init();
    {
        //初始化netlink socket,设置两个消息处理函数,netlink_receive中使用
        cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
        cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
        //创建一个接收kernel中 route 子系统的消息socket
        global->netlink = netlink_init(cfg);
        {
            //*****该socket用于接收 kernel中
            netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
            bind(netlink->sock, (struct sockaddr *) &local, sizeof(local));
            //注册内核消息接收函数, 根据接收到的消息type选择以下两个处理函数
            eloop_register_read_sock(netlink->sock, netlink_receive, netlink, NULL);
            static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx)
            {
                char buf[8192]; //接收消息的字节数, 
                left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr *) &from, &fromlen);
                //buf中是一个netlink消息,符合netlink规范,根据消息type选在相应的处理函数 newlink 和 dellink          
            }
        }

        //创建 global结构体中的 nl_cb(接收消息处理)和nl(发送消息)
        if (wpa_driver_nl80211_init_nl_global(global) < 0)
        {
            //创建连接到 GENERIC_NETLINK 的socket
            global->nl = nl_create_handle(global->nl_cb, "nl");
            //将nl连接到 内核中的nl80211模块
            global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");

            //创建接收消息的event socket, 并分别加入到组播组scan mlme regulatory vendor 中
            global->nl_event = nl_create_handle(global->nl_cb, "event");
            ret = nl_get_multicast_id(global, "nl80211", "scan");
            ret = nl_socket_add_membership(global->nl_event, ret);

            //设置nl_cb的回调函数 process_global_event(), 该函数又会调用 wpa_supplicant_event() 做进一步处理
            nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_global_event, global);
            //为nl_event注册接收函数, 通过nl_recvmsgs()调用 process_global_event()
            nl80211_register_eloop_read(&global->nl_event, wpa_driver_nl80211_event_receive, global->nl_cb);
        }

        //创建一个 ioctl_sock, 还不知道干啥用,该sock用于通过ioctl方式向底层发送命令
        global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
    }
}

4网络接口初始配置

例如up对应的接口

//调用对应的初始化函数wpa_driver_nl80211_drv_init(),传入的ifname名称为 wlan0
wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname, void *global_priv, int hostapd, const u8 *set_addr)
{
    //挺重要的一个结构体
    struct wpa_driver_nl80211_data *drv;

    //添加了回调函数drv->nl_cb process_drv_event(),最终会调用 wpa_supplicant_event()
    if (wpa_driver_nl80211_init_nl(drv))
    //添加bss回调函数bss->nl_cb,看着没啥用,最终处理 wpa_supplicant_event(),这两个回调函数没有和socket绑定,目前不清楚调用地方
    if (nl80211_init_bss(bss))

    //RF射频省电相关,读取节点“/dev/rfkill”只是接受消息打印log,不做任何操作
    rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
    rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
    drv->rfkill = rfkill_init(rcfg);

    //检查当前接口是否为UP状态
    linux_iface_up(drv->global->ioctl_sock, ifname)

    //主要为操作网卡wlan0
    wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1)
    {
        //得知网卡地址和设置网口为UP
        if (set_addr && (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) || linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, set_addr)))
        //获取网口能力,具体能力请查阅struct wpa_driver_capa
        if (wpa_driver_nl80211_capa(drv))
        //设置网口信息 IF_OPER_DORMANT
        netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 1, IF_OPER_DORMANT);
        //获取网口地址
        if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, bss->addr))
    }

    //创建一个socket,并注册接收函数wpa_driver_nl80211_handle_eapol_tx_status
    drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
    eloop_register_read_sock(drv->eapol_tx_sock, wpa_driver_nl80211_handle_eapol_tx_status, drv, NULL);
}

5 密钥处理数据包(L2_packet)收发socekt

创建了PF_PACKET的socket,可以直接收发链路层的包,网页 
http://www.cnblogs.com/cdwodm/archive/2012/09/22/2698163.html 对PF_PACKET有详细的介绍

//初始化驱动,主要完成了l2_paket回掉函数的初始化,与4次握手相关
if (wpa_supplicant_driver_init(wpa_s) < 0)
{
    //主要函数,该函数会初始化l2_packet,并注册回掉函数,与4次握手相关
    if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
    {
        //wpa_supplicant_rx_eapol()就是4次握手的处理函数了
        wpa_s->l2 = l2_packet_init(wpa_s->ifname, wpa_drv_get_mac_addr(wpa_s), ETH_P_EAPOL,  wpa_supplicant_rx_eapol, wpa_s, 0);
        {
            //新建socket 
            struct l2_packet_data *l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM, htons(protocol));
            //bind
            if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0)
            //将socket与回掉函数l2_packet_receive相关联,内部实际会调用 wpa_supplicant_rx_eapol()
            eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
            {   
                //相关步骤请看eloop_data结构体,所有的回掉函数和回掉所用的数据都在保存在该结构体中
                res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll, &fromlen);
                l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
            }
        }
    }
}

6wap_cli控制socket

在linux中可以通过wpa_supplicant提供的wpa_cli工具控制wpa_supplicant,在android中也可以通过wpa_cli在没有framework的情况下实现扫描连接工作 
下述代码就是创建需要的socket和接收发送函数。 
在android手机中打开wifi后再 /data/misc/wifi/sockets下的wlan0 和p2p0 就是该段代码生成的

wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
{
    //分配空间,然后执行真正的初始化工作
    struct ctrl_iface_priv *priv;
    if (wpas_ctrl_iface_open_sock(wpa_s, priv) < 0)
    {
        //android上运行不会执行以下两行代码
        //os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s", wpa_s->conf->ctrl_interface);
        //priv->sock = android_get_control_socket(addr.sun_path);

        //新建sock
        priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
        //bind,地址为,/data/misc/wifi/sockets/wlan0,这个地址是新生成的                
        bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr))
        //注册接收socket的函数wpa_supplicant_ctrl_iface_receive, 其核心调用函数是 wpa_supplicant_ctrl_iface_process
        eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, wpa_s, priv);
        //向socket上传event的函数
        wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
    }
}

通过wpa_cli工具使用连接网络的步骤:

  • 加载wlan驱动
  • 启动wpa_supplicant,参照init rc中的启动参数
  • 使用wpa_cli连接wpa_supplicant 
    wpa_cli -p /data/misc/wifi/sockets -i wlan0
  • 添加并使能一个网络 
    add_network ———会返回一个值,假设为n 
    set_network n ssid “ssid” 
    set_network n key_mgmt NONE ————无密码 
    set_network n psk “密码” ————–有密码 
    select_network n
  • 使用dhcpcd动态获取IP地址 
    dhcpcd <网络接口名> 一般为wlan0

7添加接口过程中的全部代码

struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
                         struct wpa_interface *iface)
{
    struct wpa_supplicant *wpa_s;
    struct wpa_interface t_iface;
    struct wpa_ssid *ssid;


    struct wpa_supplicant *wpa_s = wpa_supplicant_alloc();
    wpa_s->global = global;

    //网络接口的初始化,与底层通信的socket,密钥数据包的socket,wpa_s的初始状态等 
    if (wpa_supplicant_init_iface(wpa_s, &t_iface)) 
    {
        //读取两个conf配置文件
        wpa_s->conf = wpa_config_read(wpa_s->confname, NULL);
        wpa_config_read(wpa_s->confanother, wpa_s->conf);

        //初始化驱动接口,并注册接收驱动event的函数 nl80211
        if (wpas_init_driver(wpa_s, iface) < 0)
        {
            //根据传进来的-inl80211选定对应的wpa_driver_ops(driver_nl80211.c),里面定义了驱动的操作方法(),同时调用对应的global_init()进行初始化
            if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
            {
                //根据名称选择网络ops
                select_driver(wpa_s, i)
                {
                    //调用对应的global_init(),void * nl80211_global_init(void)
                    global->drv_priv[i] = wpa_drivers[i]->global_init();
                    {
                        //初始化netlink socket,设置两个消息处理函数,netlink_receive中使用
                        cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
                        cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
                        //创建一个接收kernel中 route 子系统的消息socket
                        global->netlink = netlink_init(cfg);
                        {
                            //*****该socket用于接收 kernel中
                            netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
                            bind(netlink->sock, (struct sockaddr *) &local, sizeof(local));
                            //注册内核消息接收函数, 根据接收到的消息type选择以下两个处理函数
                            eloop_register_read_sock(netlink->sock, netlink_receive, netlink, NULL);
                            static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx)
                            {
                                char buf[8192]; //接收消息的字节数, 
                                left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr *) &from, &fromlen);
                                //buf中是一个netlink消息,符合netlink规范,根据消息type选在相应的处理函数 newlink 和 dellink          
                            }
                        }

                        //创建 global结构体中的 nl_cb(接收消息处理)和nl(发送消息)
                        if (wpa_driver_nl80211_init_nl_global(global) < 0)
                        {
                            //创建连接到 GENERIC_NETLINK 的socket
                            global->nl = nl_create_handle(global->nl_cb, "nl");
                            //将nl连接到 内核中的nl80211模块
                            global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");

                            //创建接收消息的event socket, 并分别加入到组播组scan mlme regulatory vendor 中
                            global->nl_event = nl_create_handle(global->nl_cb, "event");
                            ret = nl_get_multicast_id(global, "nl80211", "scan");
                            ret = nl_socket_add_membership(global->nl_event, ret);

                            //设置nl_cb的回调函数 process_global_event(), 该函数又会调用 wpa_supplicant_event() 做进一步处理
                            nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_global_event, global);
                            //为nl_event注册接收函数, 通过nl_recvmsgs()调用 process_global_event()
                            nl80211_register_eloop_read(&global->nl_event, wpa_driver_nl80211_event_receive, global->nl_cb);
                        }

                        //创建一个 ioctl_sock, 还不知道干啥用,该sock用于通过ioctl方式向底层发送命令
                        global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
                    }
                }               
            }

            //调用对应的初始化函数wpa_driver_nl80211_drv_init(),传入的ifname名称为 wlan0
            wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
                static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname, void *global_priv, int hostapd, const u8 *set_addr)
                {
                    //挺重要的一个结构体
                    struct wpa_driver_nl80211_data *drv;

                    //添加了回调函数drv->nl_cb process_drv_event(),最终会调用 wpa_supplicant_event()
                    if (wpa_driver_nl80211_init_nl(drv))
                    //添加bss回调函数bss->nl_cb,看着没啥用,最终处理 wpa_supplicant_event(),这两个回调函数没有和socket绑定,目前不清楚调用地方
                    if (nl80211_init_bss(bss))

                    //RF射频省电相关,读取节点“/dev/rfkill”只是接受消息打印log,不做任何操作
                    rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
                    rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
                    drv->rfkill = rfkill_init(rcfg);

                    //检查当前接口是否为UP状态
                    linux_iface_up(drv->global->ioctl_sock, ifname)

                    //主要为操作网卡wlan0
                    wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1)
                    {
                        //得知网卡地址和设置网口为UP
                        if (set_addr && (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) || linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, set_addr)))
                        //获取网口能力,具体能力请查阅struct wpa_driver_capa
                        if (wpa_driver_nl80211_capa(drv))
                        //设置网口信息 IF_OPER_DORMANT
                        netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 1, IF_OPER_DORMANT);
                        //获取网口地址
                        if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, bss->addr))
                    }

                    。。创建一个socket,并注册接收函数wpa_driver_nl80211_handle_eapol_tx_status
                    drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
                    eloop_register_read_sock(drv->eapol_tx_sock, wpa_driver_nl80211_handle_eapol_tx_status, drv, NULL);
                }


        }

        //初始化wpa_s,主要设置 wpa 状态机
        if (wpa_supplicant_init_wpa(wpa_s) < 0)
        {
            //设置一些操作函数,请查看结构体 struct wpa_sm_ctx
            。。。
            //
            struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
            {
                //主要是3个变量值
                sm->dot11RSNAConfigPMKLifetime = 43200; //PMK的生存时间(秒)(12小时),超时后要重新计算
                sm->dot11RSNAConfigPMKReauthThreshold = 70;  //PMK超时多少(70%)后,需要重新身份认证
                sm->dot11RSNAConfigSATimeout = 60;      //进行身份验证的最长时间(秒)
            }
        }

        //初始化驱动,主要完成了l2_paket回掉函数的初始化,与4次握手相关
        if (wpa_supplicant_driver_init(wpa_s) < 0)
        {
            //主要函数,该函数会初始化l2_packet,并注册回掉函数,与4次握手相关
            if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
            {
                //wpa_supplicant_rx_eapol()就是4次握手的处理函数了
                wpa_s->l2 = l2_packet_init(wpa_s->ifname, wpa_drv_get_mac_addr(wpa_s), ETH_P_EAPOL,  wpa_supplicant_rx_eapol, wpa_s, 0);
                {
                    //新建socket 
                    struct l2_packet_data *l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM, htons(protocol));
                    //bind
                    if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0)
                    //将socket与回掉函数l2_packet_receive相关联,内部实际会调用 wpa_supplicant_rx_eapol()
                    eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
                    {   
                        //相关步骤请看eloop_data结构体,所有的回掉函数和回掉所用的数据都在保存在该结构体中
                        res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll, &fromlen);
                        l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
                    }
                }
            }
        }

        //设置国家码到驱动中
        wpa_drv_set_country(wpa_s, wpa_s->conf->country))

        //wpa_s中的 struct wps_context *wps 节点
        if (wpas_wps_init(wpa_s))
        {
            //wps_context *wps中定义了一些方法,具体请查看注释,没什么逻辑处理的问题
        }

        //初始化 EAPOOL,参考eapol模块信息
        wpa_supplicant_init_eapol(wpa_s)
        {
            //设置一些方法
            。。。
            ctx->eapol_send = wpa_supplicant_eapol_send;
            。。。
            //初始化eapol状态机
            wpa_s->eapol = eapol_sm_init(ctx);
        }


        //初始化与FWKS的通信的socket???
        wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
        {
            //分配空间,然后执行真正的初始化工作
            struct ctrl_iface_priv *priv;
            if (wpas_ctrl_iface_open_sock(wpa_s, priv) < 0)
            {
                //参数通过启动参数传入wlan0的名称,然后获取init.rc中wpa_wlan0的socket
                //android上运行不会执行以下两行代码
                //os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s", wpa_s->conf->ctrl_interface);
                //priv->sock = android_get_control_socket(addr.sun_path);

                //新建sock
                priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
                //bind,地址为,/data/misc/wifi/sockets/wlan0,这个地址是新生成的                
                bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr))
                //注册接收socket 命令的函数wpa_supplicant_ctrl_iface_receive, 其核心调用函数是 wpa_supplicant_ctrl_iface_process
                eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, wpa_s, priv);
                //向socket上传event的函数
                wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
            }
        }

        //初始化bss相关,主要是wpa_s中的两个链表
        if (wpa_bss_init(wpa_s) < 0)
        {
            //初始化wpa_s中bss和bssid链表
            dl_list_init(&wpa_s->bss);
            dl_list_init(&wpa_s->bss_id);
            //注册超时函数 ,每隔10秒刷新下bss,去掉无用的bss
            eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD=10, wpa_bss_timeout, wpa_s, NULL);
        }

        //sim卡 sd卡相关
        if (pcsc_reader_init(wpa_s) < 0)

        //不知道做什么用的
        if (wpas_init_ext_pw(wpa_s) < 0)            
    }

    /* Notify the control interfaces about new iface */
    if (wpas_notify_iface_added(wpa_s)) {
        wpa_supplicant_deinit_iface(wpa_s, 1, 0);
        return NULL;
    }

    for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
        wpas_notify_network_added(wpa_s, ssid);

    //设置wpas状态
    wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
    return wpa_s;
}

流程图

其中虚线表示数据的传递,深棕色部分表示创建的socket以及收发函数 
添加接口流程图

8总结

在接口初始化的过程中,共创建了以下几个socket,下表是socket和其相应的handler 
这里写图片描述

猜你喜欢

转载自blog.csdn.net/weichanghu_/article/details/79376380