1. 程式人生 > >android_wifi讀書筆記之5-WPA_SUPPLICANT分析

android_wifi讀書筆記之5-WPA_SUPPLICANT分析

本文為讀書筆記,整理自網路文獻和原始碼

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初始化。