现在的位置: 首页 > 综合 > 正文

android_wifi读书笔记之5-WPA_SUPPLICANT分析

2018年08月23日 ⁄ 综合 ⁄ 共 7583字 ⁄ 字号 评论关闭

本文为读书笔记,整理自网络文献和源码

5 WPA_SUPPLICANT分析

5.1、WPA_SUPPLICANT 分析1:

参考文献:

http://www.cnblogs.com/chenbin7/p/3266032.html

http://blog.chinaunix.net/uid-26585427-id-4051479.html

wpa_supplicant软件架构分析http://blog.csdn.net/fxfzz/article/details/6176414

wpa_supplicant本是开源项目源码,被谷歌修改后加入android移动平台,它主要是用来支持WEP,WPA/WPA2和WAPI无线协议和加密认证的,而实际上的工作内容是通过socket(不管是wpa_supplicant与上层还是wpa_supplicant与驱动都采用socket通讯)与驱动交互上报数据给用户,而用户可以通过socket发送命令给wpa_supplicant调动驱动来对WiFi芯片操作。简单的说,wpa_supplicant就是WiFi驱动和用户的中转站外加对协议和加密认证的支持。

wpa_supplicant.c

首先定义一个驱动操作数组externstructwpa_driver_ops*wpa_supplicant_drivers[],然后是系列wpa_supplicant_XXX()方法,很多方法里面调用 wpa_drv_XXX()方法,这些方法是wpa_supplicant_i.h中实现的方法。几乎每个方法都需要一个wpa_supplicant结构,对其进行所有的控制和通信操作。

Wpa_supplicant_i.h

其中定义了一个重要数据结构wpa_supplicant,其中有一个重要的driver成 员,它是wpa_driver_ops类型,可以被用来调用抽象层的接口。接下来是系列方法声明,这些方法声明在wpa_supplicant.c中实现,然后就是wpa_drv_XXX方法,这些方法就是在 wpa_supplicant.c中被wpa_supplicant_xxx方法调用的,而这些wpa_drv_xxx方法也都有一个wpa_supplicant结构的变量指针,用来调用封装的抽象接口,而这些抽象接口的实现在driver_wext.c中(如果使用的汉斯WEXT驱动)。

这里要注意的是:在wpa_suppliant.c文件中定义的很多方法是在该头文件中声明的,而不是在wpa_supplicant.h中声明的。

 

上行接口:

wpa_supplicant提供两种方式的上行接口。一种基于传统dbus机制实现与其他进程间的IPC通信;另一种通过Unix domain socket机制实现进程间的IPC通信。

(1)  Dbus

(2)  Socket

该接口主要在文件”wpa_ctrl.h”,“wpa_ctrl.c”,“ctrl_iface_unix.c”,“ctrl_iface.h”和“ctrl_iface.c”实现。

        1. “wpa_ctrl.h”,“wpa_ctrl.c”完成对controlinterface的封装,对外提供统一的接口。其主要的工作是通过Unix domainsocket建立一个controlinterface 的client结点,与作为server的wpa_supplicant结点通信。

wpa_supplicant 提供两种由外部模块获取信息的方式:一种是外部模块通过发送request 命令然后获取response的问答模式,另一种是wpa_supplicant主动向外部发送event事件,由外部模块监听接收。

一般的常用做法是外部模块通过调用wpa_ctrl_open()两次,分别建立两个controlinterface接口。一个为ctrl interface,用于发送命令,获取信息。然后,将另外一个接口作为参数,调用wpa_ctrl_attach,成为 monitor interface,用于监听接收来自于wpa_supplicant的event事件。此举可以降低通信的耦合性,避免response和event的相互干扰。

2. “ctrl_iface_unix.c”实现wpa_supplicant的Unix domainsocket通信机制中server结点,完成对client结点的响应。

3. “ctrl_iface.h”和“ctrl_iface.c”主要实现了各种request命令的底层处理方法。

 

下行接口:

wpa_supplicant提供的下行接口主要用于和kernel(driver)进行通信,下发命令和获取信息。

wpa_supplicant下行接口主要包括三种重要的接口:

1.    PF_INET socket接口,主要用于向kernel发送ioctl命令,控制并获取相应信息。

2.    PF_NETLINK socket接口,主要用于接收kernel发送上来的event 事件。

3.    PF_PACKET socket接口,主要用于向driver传递802.1X报文。

 

(1)“driver.h”,“drivers.c”主要用于封装底层差异对外显示一个相同的wpa_driver_ops接口。wpa_supplicant可支持atheros, broadcom, madwifi, ndis,nl80211, wext等多种驱动。

 (2)“driver_nl80211.c”实现了nl80211形式的wpa_driver_ops,并创建了PF_INETsocket接口和PF_NETLINK socket接口,然后通过这两个接口完成与kernel的信息交互。

wpa_driver_nl80211_event_receive方法:处理kernel主动发送的event事件的 callback 方法。

(3)“l2_packet.h”和“l2_packet_linux.c”主要用于实现PF_PACKET socket接口,通过该接口,wpa_supplicant可以直接将802.1X packet发送到L2层,而不经过TCP/IP协议栈。

WEXT(WirelessExtension):使用WEXT的工具通过ioctl和驱动通信,典型工具ifconfig等;NL80211(Netlink 80211):使用NL80211的工具通过一个特殊的socket( Netlink技术)和驱动打通信,典型工具包括IW、iwconfig等。

        nl80211接口逐渐替代wext接口的原因主要是使用netlink技术在应用层和内核层数据交换上相比ioctl方式具有优势。 Netlink 是一种在内核与用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的 socket API 就可以使用 netlink 提供的强大功能,内核态需要使用专门的内核 API 来使用 netlink。

wpa_supplocant服务开启:

service wpa_supplicant/system/bin/wpa_supplicant -Dnl80211 -iwlan0-c/data/misc/wifi/wpa_supplicant.conf

   socket wpa_wlan0 dgram 660 wifi wifi

   group wifi inet

   disabled

   oneshot

 

 

5.2 WPA_SUPPLICANT分析2,主要涉及下行接口

在drivers.h中定义了一个wpa_driver_ops结构体,结构体成员是一个个方法指针。在driviers.c里面都是不同驱动操作接口的集合wpa_driver_XXX_ops变量;然后就是定义一个驱

动操作接口集合的数组,根据宏定义添加对应的驱动操作接口集合的变量。不同的驱动接口采用不同的文件来实现,如果wpa_supplicant使用的是wext接口与驱动进行通信,那么

就在external/wpa_supplicant_8/src/drivers/driver_nl80211.c文件里面对wpa_driver_ops结构体里面的成员赋值,这些成员指针指向的方法也在这个文件里面实现。代码如下:

const struct wpa_driver_opswpa_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= wpa_driver_nl80211_set_key,

         .scan2= wpa_driver_nl80211_scan,

         .get_scan_results2= wpa_driver_nl80211_get_scan_results,

         .deauthenticate= wpa_driver_nl80211_deauthenticate,

         .disassociate= wpa_driver_nl80211_disassociate,

         .authenticate= wpa_driver_nl80211_authenticate,

         .associate= wpa_driver_nl80211_associate,

         .global_init= nl80211_global_init,

         .global_deinit= nl80211_global_deinit,

         .init2= wpa_driver_nl80211_init,

         .deinit= wpa_driver_nl80211_deinit,

         .get_capa= wpa_driver_nl80211_get_capa,

         .set_operstate= wpa_driver_nl80211_set_operstate,

         .set_supp_port= wpa_driver_nl80211_set_supp_port,

         .set_country= wpa_driver_nl80211_set_country,

         .set_beacon= wpa_driver_nl80211_set_beacon,

         .if_add= wpa_driver_nl80211_if_add,

         .if_remove= wpa_driver_nl80211_if_remove,

         .send_mlme= wpa_driver_nl80211_send_mlme,

         .get_hw_feature_data= wpa_driver_nl80211_get_hw_feature_data,

         .sta_add= wpa_driver_nl80211_sta_add,

         .sta_remove= wpa_driver_nl80211_sta_remove,

         .hapd_send_eapol= wpa_driver_nl80211_hapd_send_eapol,

         .sta_set_flags= wpa_driver_nl80211_sta_set_flags,

#ifdef HOSTAPD

         .hapd_init= i802_init,

         .hapd_deinit= i802_deinit,

         .set_wds_sta= i802_set_wds_sta,

#endif /* HOSTAPD */

#if defined(HOSTAPD) || defined(CONFIG_AP)

         .get_seqnum= i802_get_seqnum,

         .flush= i802_flush,

         .read_sta_data= i802_read_sta_data,

         .get_inact_sec= i802_get_inact_sec,

         .sta_clear_stats= i802_sta_clear_stats,

         .set_rts= i802_set_rts,

         .set_frag= i802_set_frag,

         .set_cts_protect= i802_set_cts_protect,

         .set_preamble= i802_set_preamble,

         .set_short_slot_time= i802_set_short_slot_time,

         .set_tx_queue_params= i802_set_tx_queue_params,

         .set_sta_vlan= i802_set_sta_vlan,

         .set_ht_params= i802_set_ht_params,

         .set_rate_sets= i802_set_rate_sets,

         .sta_deauth= i802_sta_deauth,

         .sta_disassoc= i802_sta_disassoc,

#endif /* HOSTAPD || CONFIG_AP */

         .set_freq= i802_set_freq,

         .send_action= wpa_driver_nl80211_send_action,

         .send_action_cancel_wait= wpa_driver_nl80211_send_action_cancel_wait,

         .remain_on_channel= wpa_driver_nl80211_remain_on_channel,

         .cancel_remain_on_channel=

         wpa_driver_nl80211_cancel_remain_on_channel,

         .probe_req_report= wpa_driver_nl80211_probe_req_report,

         .disable_11b_rates= wpa_driver_nl80211_disable_11b_rates,

         .deinit_ap= wpa_driver_nl80211_deinit_ap,

         .resume= wpa_driver_nl80211_resume,

         .send_ft_action= nl80211_send_ft_action,

         .signal_monitor= nl80211_signal_monitor,

         .signal_poll= nl80211_signal_poll,

         .send_frame= nl80211_send_frame,

         .set_intra_bss= nl80211_set_intra_bss,

         .set_param= nl80211_set_param,

         .get_radio_name= nl80211_get_radio_name,

         .add_pmkid= nl80211_add_pmkid,

         .remove_pmkid= nl80211_remove_pmkid,

         .flush_pmkid= nl80211_flush_pmkid,

#ifdef ANDROID_BRCM_P2P_PATCH

         .get_noa= wpa_driver_get_p2p_noa,

         .set_noa= wpa_driver_set_p2p_noa,

         .set_p2p_powersave= wpa_driver_set_p2p_ps,

         .set_ap_wps_ie= wpa_driver_set_ap_wps_p2p_ie,

#endif

#ifdef ANDROID

         .driver_cmd= wpa_driver_nl80211_driver_cmd,  //处理DRIVER开头的命令

 

#endif

};

 

在启动wpa_supplicant服务时,带了很多参数

Service wpa_supplicant/system/bin/wpa_supplicant -Dnl80211 -iwlan0-c/data/misc/wifi/wpa_supplicant.conf

其中-D<driver>: 驱动类型代表的是驱动类型。也就是-Dnl80211

wpa_supplicant的主方法main中会将驱动类型参数赋给iface->driver

         case'D':

                            iface->driver= optarg;

之后调用wpa_supplicant_add_iface(global,&ifaces[i]),wpa_supplicant_add_iface调用的是wpa_supplicant_init_iface。在wpa_supplicant_init_iface(struct

wpa_supplicant *wpa_s,struct wpa_interface*iface)方法里面

driver = iface->driver;

之后调用wpa_supplicant_set_driver(wpa_s,driver)来设置wpa_supplicant使用哪个接口与驱动进行通信:

                   wpa_s->driver= wpa_drivers[i];

                   wpa_s->global_drv_priv= wpa_s->global->drv_priv[i];

之后调用wpa_supplicant_driver_init初始化。

 

抱歉!评论已关闭.