wpa_supplicant子系统分析 android 5.1

看在android5.1平台上看了将近半个月的wpa_supplicant子系统,还是希望能将最近的一些所学整理成文档发表到博客(在学博客过程其实也是对自己的思路的一个在整理),有误地方欢迎指正交流。

wpa_supplicant是一个开源的软件项目,它实现了Station对无线网络进行管理和控制的功能。wpa_supplicant是Android用户空间中无线网络的核心模块,所有Framework中和Wifi相关的操作最终都将有wpa_supplicant来完成。另外,wpa_supplicant对802.11、802.1X以及android Alliance定义的一些规范都有极好的支持。

其内部模块构成如下图:

wpa_supplicant子系统分析 android 5.1_第1张图片

             WPA_supplicant中所有工作都围绕事件(event loop模块)展开。WPA_supplicant的运行机制比较简单,它是基于事件驱动,所有事件都是由主线程完成。

event loop模块下方的driver i/f接口模块用于隔离和底层驱动直接交互的driver控制模块,也正式这种隔离作用是WPA_supplicant中的其他模块能最大程度的保持平台以及驱动的无关性。

           EAPEAOOL为状态机,除此之外WPA_supplicant还定义了自己的状态机WPA/WPA2WPA_ supplicant中实现了多种EAP方法。如EAP method模块。另外还包含了cryptoTLS模块用于支持EAP方法。

          EAP以及EAPOL的消息都属于LLC层数据,所以I2_packet用于接收EAPEAPOL消息。

         WPA_supplicant支持较多的配置参数,这些参数的处理主要在configuration模块中完成。

         WPA_supplicantC/S架构中的服务端,它通过ctrl i/f端口向客户端提供通信接口。


WPA_Supplicant的初始化过程

        WPA_Supplicant入口函数位于main.c文件中,路径见3.1章节。

        先来看其入口函数main函数:

        在这个函数中主要做了做了四件工作:

       1)调用os_program_init()函数给wpa_supplicant进程分配权限以及结构体的初始化,解析命令行参数。

       2)通过wpa_supplicant_init()函数,初始化struct wpa_global *global局部结构体(结构体详解见后文)同时传递给static struct eloop_data eloop全局结构体初始化事件循环机制。

       3)for循环中调用wpa_supplicant_add_iface()函数注册一个或者多个网络接口。

       4)调用wpa_supplicant_run()函数启动wpa_supplicant主事件循环机制,如果失败跳转到out或者通过goto跳转到out

main函数中出现了几个重要的结构体和两个关键函数,先来看下main函数主要的数据

wpa_supplicant子系统分析 android 5.1_第2张图片

如图2所示:

             wpa_interface用于描述一个无线网路设备,参数在wpa_supplicant_add_iface()函数调用

        wpa_global是一个全局性质的上下文信息。它通过ifaces变量指向一个wpa_supplicant结构体,该结构体的初始化主要通过调用wpa_supplicant_init()函数实现。

       wpa_supplicant结构体是WPA_Supplicant的核心数据结构,一个interface对应一个结构体wap_supplicant

        ctrl_iface_global_priv是全局控制接口的信息,内部包含一个socket句柄。

下面来分析下wpa_supplicant_init()函数和wpa_supplicant_add_iface()函数。


wpa_supplicant_init()函数

     wpa_supplicant_init()函数流程如下图3

wpa_supplicant子系统分析 android 5.1_第3张图片

           wpa_supplicant_init()函数实现的功能是:先分配struct wpa_global *global这个局部指向结构体的内存空间;然后通过main函数传递进来的params参数填充global指向的内嵌结构体对象struct wpa_params;然后调用eloop_init()函数初始化eloop事件循环机制;最后设置消息全局回调函数(共2个)。

比较重要的函数:

           wpa_msg_register_ifname_cb()函数:该函数为回调函数,用于获取有需要输出打印网卡接口名的网卡接口名。

           wpa_supplicant_global_ctrl_iface_init()函数:初始化全局接口对象。

          eap_register_methods()函数:主要将根据编译配置选项来注册锁需要的EAP metholdEAP methold方法见图1所示。

          eloop_init()函数:见下文分析。

 

          eloop_init()函数:的主要功能是初始化了WPA_Supplicant中事件驱动的核心数据结构体eloop_dataWPA_Supplicant事件驱动主要支持5中类型的event:

          1)read event:读事件

          2)write event:写事件

          3)exception event:异常事件,如果socket操作发生异常,则由错误事件处理

          4)timeout event:定时事件

          5)signal:信号事件

这些事件都保存在eloop_data结构体中,如下图4

          另外一个需要注意的地方是wpa_supplicant_init()函数中定义了全局数组变量wpa_driverwpa_driver数组成员指向一个wpa_driver_ops类型对象,wpa_driver_opsdriver i/f模块的核心数据结构,其内部定义很多的函数指针,正是通过这些函数指针的方法,WPA_Supplicant能够是上层的使用者和底层驱动隔离。

const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
.get_bssid = wpa_driver_nl80211_get_bssid,
.get_ssid = wpa_driver_nl80211_get_ssid,
.set_key = driver_nl80211_set_key,
.scan2 = driver_nl80211_scan2,
.sched_scan = wpa_driver_nl80211_sched_scan,
.stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
.deauthenticate = driver_nl80211_deauthenticate,
.......
.set_wowlan = nl80211_set_wowlan,
.roaming = nl80211_roaming,
.set_mac_addr = nl80211_set_mac_addr,
}

wpa_supplicant_add_iface()函数

         wpa_supplicant_add_iface()这个函数实现的功能是被用于向WPA_Supplicant添加网络接口设备,这一操作将会在主线程启动之前被调用(也就是在wpa_supplicant_run()函数被调用之前被被调用)。wpa_supplicant_add_iface()函数主要涉及到两个重要的数据结构(wpa_supplicantwpa_ssid)以及一个关键函数wpa_supplicant_init_iface

进入wpa_supplicant_add_iface()函数:wpa_supplicant子系统分析 android 5.1_第4张图片

上图6wpa_supplicant_add_iface函数的时序图:

wpa_supplicant_add_iface()函数主要功能是被用于向WPA_Supplicant添加一个网络接口。主要做了两件工作:

1)调用wpa_supplicant_alloc()函数分配一个struct wpa_supplicant *wpa_s局部指针空间(该结构体在上文分析)并初始化。

2)将struct wpa_supplicant对象以及struct wpa_interface对象传递给wpa_supplicant_init_iface函数(wpa_supplicant_add_iface函数主要工作在wpa_supplicant_init_iface函数中完成)

下面分别来分析下这两个方面。


重要的数据结构

如上图5wpa_supplicant结构体和wpa_ssid结构体定义的主要成员变量。


        先来看看wpa_supplicant结构体:
        pairwise_ciphergroup_cipherkey_mgmtwpa_protomgmt_group_cipher:这几个变量表示该WPA_Supplicant选择的安全策略。其中,mgmt_group_cipherIEEE 802.11W有关。

         current_bss:该变量的类型为wpa_bsswpa_bss是无线网络在wpa_supplicant的代表,wpa_bss的主要成员表述无线网络中的ssidbssidfreq(频率)、caps(性能)、qual(信号强度)、level(信号等级)等。

         drv_privglobal_drv_priv:这两给变量主要用于存储两个初始化函数的返回值,WPA_Supplicantdriver_wrapper以供定义了两个上下文信息(主要与driver i/f接口定义的两个初始化函数global _initinit2相对应)。global_init以及init2返回值为driver_wrapper对象对应的上下文信息,分别存储在drv_priv以及global_drv_priv中,那个WPA_Supplicant都对应有一个driver_wrapper对象。

         sched_scan_timeout:该变量与定时扫描功能有关。启用该功能时,需要为驱动设置定时扫描的间隔。

bgscan:这个变量主要与后台扫描功能以及漫游技术有关。漫游技术是指一个STAESS中移动时选择连接与自己较近的AP连接的过程。

wpa_supplicant结构体内部还定义了一个枚举变量如下:

enum wpa_states {
WPA_DISCONNECTED,
    WPA_INTERFACE_DISABLED,
WPA_INACTIVE,
WPA_SCANNING,
WPA_AUTHENTICATING,
WPA_ASSOCIATING,
WPA_ASSOCIATED,
WPA_4WAY_HANDSHAKE,
WPA_GROUP_HANDSHAKE,
WPA_COMPLETED
}

WPA_DISCONNECTED:表示当前没有连接任何客户端无线网络。

WPA_INTERFACE_DISABLED:表示当前wpa_supplicant使用的所有接口被禁用。

WPA_INACTIVE:表示当前没有可连接的无线网络。

WPA_SCANNINGWPA_AUTHENTICATINGWPA_ASSOCIATING:表示当前wpa_supplicant分别处于扫描无线网络、身份验证以及关联的过程。

WPA_4WAY_HANDSHAKE:表示WPA_Supplicant处于四次握手处理过程中。当使用PSK策略时,STA收到第一个EAPOL-Key数据包进入此状态。

WPA_GROUP_HANDSHAKE:表示WPA_Supplicant处于组密钥握手协议处理过程。当STA完成四次握手协议并收到组播密钥交换第一帧编进入此状态。

WPA_COMPLETED:表示所有认证已经完成。

 

对于wpa_ssid结构体:

          wpa_ssid结构体是用于存储某个无线网络的配置信息,主要的数据成员如图5所示。

       passphrase:该变量只和WPA/WPA-PSK模式有关。主要用于存储用户输入的字符串密码。WPAS将根据它和ssid进行计算得到最终使用的PSK

       pairwise_ciphergroup_cipher:这两个主要和规范中的cipher suite定义有关。cipher suite用于指明数据收发双方使用的加密方法,pairwise_ciphergroup_cipher分别表示该无线网络设置的单播以及组播的数据加密方法。

       key_mgmt:该变量主要与802.11AKM suite相关。

       proto:表示该无线网络支持的安全协议类型。

       auth_alg:表示无线网络支持的身份验证算法。

       disabled:该变量为0代表当前无线网络可用;为1代表该变量被禁止使用;为2代表该变量和p2p有关。

       mode:wpa_ssid结构体内部也定义了的枚举型变量


wpa_supplicant_init_iface()函数分析

wpa_supplicant_init_iface()函数功能如下:

1)调用wpa_config_read()函数读取配置文件信息并将它转换成对应的数据结构。

2)调用wpa_supplicant_set_driver()函数初始化一个driver wrapper全局上下文信息(详细分析见下文)。

3)调用wpa_drv_init()函数初始化单个driver wrapper相关资源(详细分析见下文)。

4)初始化其他资源(wpa_sm状态机等)

重要函数分析如下:

         wpa_supplicant_init_iface()函数的第一个工作是调用wpa_config_read()函数解析运行时的配置文件。其中,wpa_s->confname的值为/data/wifi/wpa_supplicant.conf

         wpa_config_read()函数仅是把配置文件中的信息转换成对应的数据结构。这边涉及到的数据结构wpa_config(wpa_supplicant配置参数)wpa_ssid(Network的配置参数),每个配置项可参考wpa_supplicant.conf配置文件具体含义。wpa__config_read()函数最终的结果就是设置wpa_config结构体中的对应项的值。

          wpa_supplicant_init_iface()函数的第二个工作是调用wpas_init_driver()函数初始化接口驱动以及注册驱动相关的处理事件,这些功能实现主要通过wpas_init_driver()调用wpa_supplicant_set_driver以及wpa_drv_init()函数实现。

         wpa_supplicant_set_driver()函数将根据driver wrapper名找到nl80211指定的结构体(详细节3.2.1节)wpa_driver_nl80211_ops,然后调用nl80211_global_init()函数完成如下功能:(1)调用netlink_init创建一个netlink socket来接收来之内核的网卡状态的变化事件,然后通过eloop_register_read_sock()函数注册一个netlink_recv()函数用于处理接收到的socket消息。netlink_recv()函数内部将根据消息的类别来调用回调函数newlink_cb()dellink_cb()处理网卡状态变化事件(这部分代码比较简单自行分析);(2)调用wpa_driver_nl80211_init_nl_global()函数创建了两个nl_handle对象,分别global_nlglobal_event并将对应的socket注册到eloop读写事件队列中。其中,global_event用于接收wlan driver发送的netlink消息;global_nl用于向wlan driver发送netlink消息。

上面涉及到一个比较重要的数据结构体nl80211_global,如下:

struct nl80211_global {
struct dl_list interfaces;
int if_add_ifindex;
u64 if_add_wdevid;
int if_add_wdevid_set;
struct netlink_data *netlink;
struct nl_cb *nl_cb;
struct nl_handle *nl;
int nl80211_id;
int ioctl_sock; /* socket for ioctl() use */
struct nl_handle *nl_event;
}


      主要初始化是在wpa_driver_nl80211_init_nl_global()函数中完成,包含两个上面(2)介绍的两个nl_handle对象,详细介绍见上。

7wpa_drv_init()函数时序图:wpa_supplicant子系统分析 android 5.1_第5张图片

        wpa_drv_init()函数:前面以及介绍通过wpa_supplicant_set_driver()函数调用global_init()函数初始化一个driver wrapper全局上下文信息。wpa_drv_init()函数实现的功能是初始化单个driver wrapper,内部将调用

         wpa_driver_nl80211_init()函数从而调用到wpa_driver_nl80211_drv_init()函数。

         wpa_driver_nl80211_drv_init()函数主要实现了四个功能:

1)分配struct wpa_driver_nl80211_data *drv以及对其进行初始化。

2)调用wpa_driver_nl80211_init_nl()nl80211_init_bss()函数创建了两个nl_cb对象以及设置相对应回调函数process_drv_event()以及process_bss_event()函数。

3)调用rfkill_init()函数初始化rfkill用户空间相关的资源。

4)通过wpa_driver_nl80211_finish_drv_init()函数对工作模式、设备启用状态、ifopenStatus等进行相关设定,同时获取wifi驱动的capability信息以及接口对应的Mac地址等。

 

         重点来分析下重点函数wpa_driver_nl80211_finish_drv_init(),同样先简单介绍下它的主要工作流程:

1)调用nl80211_get_ifmode()函数获取驱动的接口模式。

2)调用wpa_driver_nl80211_capa()函数获取wifi设备的处理能力(capability)。

3)调用linux_set_iface_flags()函数通过netdevices API启用wifi设备。如果失败,需要判断该设备是否被rfkill block

4)调用wpa_driver_nl80211_set_mode()函数设置wifi设备类型为NL_80211_IFTYPE_STATION

5)调用netlink_send_oper_ifla()函数设置网卡的工作状态为IF_OPER_DORMANT

6)最后,调用linux_get_ifhwaddr()函数获取wifi设备的MAC地址,并判断是否需要设置超时函数。

需要注意方面如下:

         对于wifi设备而言,一块网络接口设备对应一个MAC地址。引入虚拟接口(virtual interface)主要考虑到设备在多功能方面的需求,也就是个虚拟接口对应一个MAC地址。NL80211定义了众多的虚拟接口类型,如下所示:

enum nl80211_iftype {
NL80211_IFTYPE_UNSPECIFIED,
NL80211_IFTYPE_ADHOC,
NL80211_IFTYPE_STATION,
NL80211_IFTYPE_AP,
NL80211_IFTYPE_AP_VLAN,
NL80211_IFTYPE_WDS,
NL80211_IFTYPE_MONITOR,
NL80211_IFTYPE_MESH_POINT,
NL80211_IFTYPE_P2P_CLIENT,
NL80211_IFTYPE_P2P_GO,
NL80211_IFTYPE_P2P_DEVICE,
/* keep last */
NUM_NL80211_IFTYPES,
NL80211_IFTYPE_MAX = NUM_NL80211_IFTYPES - 1
};

该枚举成员详细定义见NL80211_copy.h

 

继续分析wpa_supplicant_add_iface()代码:

.......

(1)初始化wpa上下文信息

if (wpa_supplicant_init_wpa(wpa_s) < 0)
{
wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname,
  wpa_s->bridge_ifname[0] ? wpa_s->bridge_ifname : NULL);
wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
if (wpa_s->conf->dot11RSNAConfigPMKLifetime &&
    wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
     wpa_s->conf->dot11RSNAConfigPMKLifetime)) {
........
(2)获取wifi设备的hardware特性
wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
                    &wpa_s->hw.num_modes,&wpa_s->hw.flags);
(3)capability信息
if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
wpa_s->drv_capa_known = 1;
......
wpa_s->num_multichan_concurrent =capa.num_multichan_concurrent;
}
if (wpa_s->max_remain_on_chan == 0)wpa_s->max_remain_on_chan = 1000;


wpa_supplicant_add_iface()函数的第三个工作主要如下:

1)wpa_supplicant_init_wpa()函数用于初始化wpa_sm状态相关的资源。

2)wpa_drv_get_hw_feature_data()函数用于获取hw特性。

3)wpa_drv_get_capa()函数获取一些新的特性。

这里面涉及到一个比较重要的结构体wpa_sm(也叫wpa_sm状态机)如下图8

         如图6 wpa_supplicant_add_iface时序图2124调用流程主要完成EAPOL模块、ctrl i/f模块相应的初始化工作以及向wpa_supplicant注册一个定时任务用于定时更新保存在wpa_bss中的信息。(相关代码较简单可自行分析)。


WPA_Supplicant的命令处理过程

       WPA_Supplicant的相关流程分析主要从扫描流程、关联流程以及EAPOL-Key交换流程三方面分析。

WPA_Supplicant的扫描流程

        图9为无线网络扫描过程以及扫描结果的处理过程时序图。其中,19为扫描过程;1023为扫描结果的处理过程。若WPA_Supplicant接收到ENABLE_NETWORK命令触发一个无线网络使能并开始扫描过程,ENABLE_NETWORK命令由wpa_supplicant_ctrl_iface_enable_network()函数进行处理。


1.WPA_Supplicant的扫描过程分析

        Wpa_Supplicant扫描过程的关键函数是wpa_supplicant_scan()函数,wpa_supplicant_scan()函数功能:

        1)调用wpa_supplicant_enabled_networks()函数判断周围是否存在使能的无线网络设备并通过struct wpa_supplicant结构体中ap_scan参数判定扫描及选择绝大部分工作是由WPAS还是驱动完成(0表示由WPAS完成)。

         2)调用wpa_supplicant_set_state()函数设置WPASWPA_SCANNING状态然后通过调用wpa_supplicant_associate()函数关联到无线网络设备。如果设置了struct wpa_supplicant结构体的成员connect_without_scan(连接已知无线网络),跳过扫描阶段。

         3)搜索无线网络的所有配置项存储于struct wpa_ssid结构体,同时设置频率参数优化扫描过程、过滤不符合的无线网络wpa_supplicant_build_filter_ssids()等存储在sturct wpa_driver_scan_param

         4)通过wpa_supplicant_trigger_scan()直接调用driver_nl80211scan2函数直接向驱动发起scan,并将扫描参数(存储于sturct wpa_driver_scan_param)传递给driver wrapper

struct wpa_driver_scan_params {

struct wpa_driver_scan_ssid //用于扫描的ssid

size_t num_ssids;//无线网络个数

const u8 *extra_ies;//

int *freqs;//扫描频率

struct wpa_driver_scan_filter//需要过滤的ssid

size_t num_filter_ssids;//过滤的ssid个数

unsigned int only_new_results:1;//要求驱动广播最新结果

unsigned int low_priority:1;//优先级设定

该结构体对配置driver wrapper至关重要!


2.WPA_Supplicant的扫描结果处理

         driver_nl80211发送NL80211_CMD_TRIGGER_SCAN命令给wlan driver以通知wlan driver开始扫描周围的无线网络,若底层wlan driver完成扫描工作driver_nl80211会收到NL80211_CMD_NEW_

SCAN_RESULTS netlink消息,这个netlink消息处理主要在process_global_event()回调函数中处理。

       driver wrapper主要完成两项工作:

1)获取来之wlan drivernetlink消息信息(NL_80211_ATTR_SCAN_SSIDSfreqs等)并将这些信息存储在一个联合体union wpa_event_data event中。

2)调用wpa_supplicant_event()函数通知driver event。其中,wpa_supplicant_event()函数driver wrapperWPAS的接口函数。

       比较重要的函数如下:

wpa_supplicant_pick_network():在扫描结果中找到一个最佳的无线网络。

wpa_supplicant_need_to_roam():判断是否需要切换无线网络。

wpa_supplicant_rsn_preauth_scan_results():更新PMKSA信息。

wpa_supplicant_connect():向目标AP发起关联等请求以加入无线网络。

       其中,wpa_supplicant_connect()开启WPA_Supplicant的第二个流程关联无线网络相关流程。下面分析关联流程。


WPA_Supplicant的关联流程

           如图10 WPA_Supplicant无线网络关联流程时序图,主要分为无线网络关联过程(图10中时序111);无线网络关联结果处理过程(图10中时序1221)。

简要分析下这两个流程:

wpa_supplicant子系统分析 android 5.1_第6张图片

1.WPA_Supplicant的关联无线网络过程

            Wpa_Supplicant关联无线网络最重要的工作就是触发STA发起关联操作。关联无线网络的流程从wpa_supplicant_connect()函数开始。Wpa_Supplicant关联无线网络过程的关键函数是wpas_start_assoc_cb()函数,wpas_start_assoc_cb()函数主要功能:

1)和scan请求类似,关联无线网络过程也需要初始化struct wpa_driver_associate_params结构体的对象。

2)调用wpa_drv_associate()函数并通过wpa_drv_associate()函数将结构体对象传递给底层wlan driverstruct wpa_driver_associate_params结构体)。wpa_drv_associate()函熟内部将调用到driver_ nl80211.c中的wpa_driver_nl80211_associate()函数与wlan driver交互。

           类似scan流程,这里面有一个非常重要的结构体:struct wpa_driver_associate_params,该结构体主要为关联过程配置相关参数,参数成员的具体分析请自行分析代码。

struct wpa_driver_associate_params {
const u8 *bssid;
const u8 *bssid_hint;
const u8 *ssid;
size_t ssid_len;
struct hostapd_freq_params freq;
int freq_hint;
int bg_scan_period;
const u8 *wpa_ie;
size_t wpa_ie_len;
unsigned int wpa_proto;
unsigned int key_mgmt_suite;
int auth_alg;
const char *passphrase;
...
const struct ieee80211_vht_capabilities *vhtcaps;
const struct ieee80211_vht_capabilities *vhtcaps_mask;
}


比较重要的函数:

      wpa_supplicant_scard_init()函数:和EAP-SIM/AKA认证方法有关,主要初始化了SIM/USIM相关资源。这个函数在开始无线网络认证时被调用。

      wpa_supplicant_associate()函数:初始化一个struct wpa_connect_work *cwork结构体对象并将该结构体对象传递给wpas_start_assoc_cb()函数。

      wpa_supplicant_cancel_sched_scan()/wpa_supplicant_cancel_scan()函数:这两个函数的任务是取消扫描任务和取消普通扫描任务。

      wpa_sm_set_assoc_wpa_ie()函数:设置WPA/RSN IE信息并通知WPA状态机,这些信息主要用在关联请求帧的过程。

      wpa_bss_get_vendor_ie()函数:用于获取wpa_bss中的和vendor相关的IE

      wpa_bss_get_ie()函数:用于获取RSN_IE

      wpa_key_mgmt_wpa()函数:用于判断无线网络配置时设置的key_mgmn是否和WPA相关。

      wpa_supplicant_set_suites()函数:目的是生成一个用于关联请求的IE信息(如group_cipherpairwise_cipherkey_mgmt等)。

       wpa_driver_nl80211_connect()函数:构造一个NL80211_CMD_CONNECT命令,并将它发给wlan driver。通过NL80211_CMD_CONNECT命令与驱动交互,驱动接收到该命令将完成AuthenticationAssociation帧处理以及返回NL80211_CMD_CONNECT类型的消息处理结果。

 

2.WPA_Supplicant的关联结果处理

        如上节所示,WPAS中的driver wrapper将收到来之wlan driverNL80211_CMD_CONNECT类型的消息。这个消息处理同样在process_global_event()回调函数中处理,收到这个消息driver wrapper主要做两件处理工作:

        1)获取来之wlan driverNL80211_CMD_CONNECT类型的结果处理相关的消息(bssid消息、Association Request ie消息、Association Response ie消息、freqs等)并将这些信息存储在一个联合体union wpa_event_data event中。

         2)通过wpa_supplicant_event()函数调用wpa_supplicant_event_assoc()函数通知driver eventwpa_supplicant_event_assoc()函数功能主要通过下面主要函数功能分析来了解。

比较重要的函数如下:

          wpa_supplicant_event_associnfo():上节中wpa_supplicant对象的assoc_wpa_iewpa_sm_set _assoc_wpa_ie()清空,wpa_supplicant_event_associnfo()函数的功能是更新以及保存RSN/WPAIE信息。

          wpa_supplicant_scard_init():上一节已经介绍过。

          wpa_sm_notify_assoc():通知WPA状态机无线网络状态被建立

         eapol_sm_notify_portEnabled()/eapol_sm_notify_portValid():设置EAPOL相关的外部变量。

         wpa_key_mgmt_wpa_psk():采用wpa_psk认证算法。

 




你可能感兴趣的:(wpa_supplicant子系统分析 android 5.1)