wpa_supplicant軟件架構分析

1.系統架構

Android WiFi系統引入了wpa_supplicant,它的整個WiFi系統以wpa_supplicant爲核心來定義上層用戶接口和下層驅動接口。整個WiFi系統架構如下圖所示: 
這裏寫圖片描述

1.1 WifiService

由SystemServer啓動的時候生成的ConnecttivityService創建,負責啓動關閉wpa_supplicant,啓動和關閉WifiMonitor線程,把命令下發給wpa_supplicant以及更新WIFI的狀態。 
處理其它模塊通過IWifiManager接口發送過來的遠端WiFi操作。

1.2 WifiMonitor

負責從wpa_supplicant接收事件通知。

1.3 wpa_supplicant

1) 讀取配置文件 
2) 初始化配置參數,驅動函數 
3) 讓驅動scan當前所有的bssid 
4) 檢查掃描的參數是否和用戶設置的相符 
5) 如果相符,通知驅動進行權限和認證操作 
6) 連上AP

1.4 Wifi驅動模塊

廠商提供的source,主要進行load firware和kernel的wireless進行通信

1.5 Wifi電源管理模塊

主要控制硬件的GPIO和上下電,讓CPU和Wifi模組之間通過sdio接口或USB接口通信

1.6 Wifi工作步驟

1) Wifi啓動 
2) 開始掃描 
3) 顯示掃描的AP 
4) 配置AP 
5) 連接AP 
6) 獲取IP地址 
7) 上網

1.7 Wifi模塊代碼

1) Wifi Settings應用程序 
packages/apps/Settings/src/com/android/settings/wifi 
frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi

2) Wifi Framework 
frameworks/base/wifi/Java/android/net/wifi(WifiManager) 
frameworks/base/core/java/android/net 
frameworks/base/core/java/android/app(SystemServiceRegistry) 
frameworks/base/services/java/com/android/server(SystemServer) 
frameworks/base/services/core/java/com/android/server(SystemServiceManager) frameworks/opt/net/wifi/service/java/com/android/server/wifi(WifiService/WifiServiceImpl/WifiMonitor/WifiStateMachine/WifiNative)

3) Wifi JNI 
frameworks/opt/net/wifi/service/jni/com_android_server_wifi_WifiNative.cpp

4) Wifi Hardware (wifi管理庫) 
hardware/libhardware_legacy/wifi/wifi.c

5) wpa_supplicant(wifi tool) 
external/wpa_supplicant8 
(1) wpa_client (生成庫libwpaclient.so) 
external/wpa_supplicant_8/wpa_supplicant/src/common/wpa_ctrl.c 
(2) wpa_server (生成守護進程wpa_supplicant) 
external/wpa_supplicant_8/wpa_supplicant/main.c

6) Wifi kernel 
net/wireless drivers/wlan_xxx arch/arm/mach-xxx/wlan_pm.c

2. wpa_supplicant 初始化流程

2.1. main()函數:

在這個函數中,主要做了四件事。 
a. 解析命令行傳進的參數。 
b. 調用wpa_supplicant_init()函數,做wpa_supplicant的初始化工作。 
c. 調用wpa_supplicant_add_iface()函數,增加網絡接口。 
d. 調用wpa_supplicant_run()函數,讓wpa_supplicant真正的run起來。

2.2. wpa_supplicant_init()函數:

a. 打開debug 文件。 
b. 註冊EAP peer方法。 
c. 申請wpa_global內存,該數據結構作爲統領其他數據結構的一個核心, 主要包括四個部分:

wpa_supplicant *ifaces   /* 每個網絡接口都有一個對應的wpa_supplicant數據結構,該指針指向最近加入的一個,在wpa_supplicant數據結構中有指針指向next */
wpa_params params   /* 啓動命令行中帶的通用的參數 */
ctrl_iface_global_priv *ctrl_iface  /* global的控制接口 */
ctrl_iface_dbus_priv *dbus_ctrl_iface  /* dbus 的控制接口 */
  • 1
  • 2
  • 3
  • 4

d. 設置wpa_global中的wpa_params中的參數。 
e. 調用eloop_init函數將全局變量eloop中的user_data指針指向wpa_global。 
f. 調用wpa_supplicant_global_ctrl_iface_init函數初始化global 控制接口。 
g. 調用wpa_supplicant_dbus_ctrl_iface_init函數初始化dbus 控制接口。 
h. 將該daemon的pid寫入pid_file中。

2.3. wpa_supplicant_add_iface()函數:

該函數根據啓動命令行中帶有的參數增加網絡接口, 有幾個就增加幾個。 
a. 因爲wpa_supplicant是與網絡接口對應的重要的數據結構,所以,首先分配一個wpa_supplicant數據結構的內存。 
b. 調用wpa_supplicant_init_iface() 函數來做網絡接口的初始工作,主要包括: 
設置驅動類型,現常用nl80211; 
讀取配置文件,並將其中的信息設置到wpa_supplicant數據結構中的conf 指針指向的數據結構,它是一個wpa_config類型; 
命令行設置的控制接口ctrl_interface和驅動參數driver_param覆蓋配置文件裏設置,命令行中的優先; 
拷貝網絡接口名稱和橋接口名稱到wpa_config數據結構; 
對於網絡配置塊有兩個鏈表描述它,一個是 config->ssid,它按照配置文件中的順序依次掛載在這個鏈表上,還有一個是pssid,它是一個二級指針,指向一個指針數組,該指針數組按照優先級從高到底的順序依次保存wpa_ssid指針,相同優先級的在同一鏈表中掛載。 
c. 調用wpa_supplicant_init_iface2() 函數,主要包括: 
調用wpa_supplicant_init_eapol()函數來初始化eapol; 
調用相應類型的driver的init()函數; 
設置driver的param參數; 
調用wpa_drv_get_ifname()函數獲得網絡接口的名稱,對於wext類型的driver,沒有這個接口函數; 
調用wpa_supplicant_init_wpa()函數來初始化wpa,並做相應的初始化工作; 
調用wpa_supplicant_driver_init()函數,來初始化driver接口參數;在該函數的最後,會設置

wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN;
wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
  • 1
  • 2

來主動發起scan; 
調用wpa_supplicant_ctrl_iface_init()函數,來初始化控制接口;對於UNIX SOCKET這種方式,其本地socket文件是由配置文件裏的ctrl_interface參數指定的路徑加上網絡接口名稱;

2.4. wpa_supplicant_run()函數:

初始化完成之後,讓wpa_supplicant的main event loop run起來。 
在wpa_supplicant中,有許多與外界通信的socket,它們都是需要註冊到eloop event模塊中的,具體地說,就是在eloop_sock_table中增加一項記錄,其中包括了sock_fd, handle, eloop_data, user_data。 
eloop event模塊就是將這些socket組織起來,統一管理,然後在eloop_run中利用select機制來管理socket的通信。

3. Wpa_supplicant提供的接口

從通信層次上劃分,wpa_supplicant提供向上的控制接口 control interface,用於與其他模塊(如UI)進行通信,其他模塊可以通過control interface 來獲取信息或下發命令。Wpa_supplicant通過socket通信機制實現下行接口,與內核進行通信,獲取信息或下發命令。

3.1 上行接口

Wpa_supplicant提供兩種方式的上行接口。一種基於傳統dbus機制實現與其他進程間的IPC通信;另一種通過Unix domain socket機制實現進程間的IPC通信。

3.1.1 Dbus接口

該接口主要在文件“ctrl_iface_dbus.h”,“ctrl_iface_dbus.c”,“ctrl_iface_dbus_handler.h”和“ctrl_iface_dbus_handler.c”中實現,提供一些基本的控制方法。

3.1.2 Unix domain socket 接口

該接口主要在文件“wpa_ctrl.h”,“wpa_ctrl.c”,“ctrl_iface_unix.c”,“ctrl_iface.h”和“ctrl_iface.c”實現。

(1)“wpa_ctrl.h”,“wpa_ctrl.c”完成對control interface的封裝,對外提供統一的接口。其主要的工作是通過Unix domain socket建立一個control interface 的client結點,與作爲server的wpa_supplicant結點通信。

主要功能函數:

struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
/* 建立並初始化一個Unix domain socket的client結點,並與作爲server的wpa_supplicant結點綁定 */
  • 1
  • 2
void wpa_ctrl_close(struct wpa_ctrl *ctrl);
/* 撤銷並銷燬已建立的Unix domain socket的client結點 */
  • 1
  • 2
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
                   char *reply, size_t *reply_len,
                   void (*msg_cb)(char *msg, size_t len));

/* 用戶模塊直接調用該函數對wpa_supplicant發送命令並獲取所需信息 */
  • 1
  • 2
  • 3
  • 4
  • 5

Note: 
Wpa_supplicant 提供兩種由外部模塊獲取信息的方式:一種是外部模塊通過發送request命令然後獲取response的問答模式,另一種是wpa_supplicant主動向外部發送event事件,由外部模塊監聽接收。 
一般的常用做法是外部模塊通過調用wpa_ctrl_open()兩次,建立兩個control interface接口,一個爲ctrl interface,用於發送命令,獲取信息,另一個爲monitor interface,用於監聽接收來自於wpa_supplicant的event時間。此舉可以降低通信的耦合性,避免response和event的相互干擾。

int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
/* 註冊 某個 control interface 作爲 monitor interface */
  • 1
  • 2
int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
/* 撤銷某個 monitor interface 爲 普通的 control interface  */
  • 1
  • 2
int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
/* 判斷是否有掛起的event 事件 */
  • 1
  • 2
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);
/* 獲取掛起的event 事件 */
  • 1
  • 2

(2)“ctrl_iface_unix.c”實現wpa_supplicant的Unix domain socket通信機制中server結點,完成對client結點的響應。 
其中最主要的兩個函數爲:

static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
                                         void *sock_ctx)
/* 接收並解析client發送request命令,然後根據不同的命令調用底層不同的處理函數;
 * 然後將獲得response結果回饋到 client 結點。
 */
  • 1
  • 2
  • 3
  • 4
  • 5
static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
                                      int level, const char *buf,
                                      size_t len)
/* 向註冊的monitor interfaces 主動發送event事件 */
  • 1
  • 2
  • 3
  • 4

(3)“ctrl_iface.h”和“ctrl_iface.c”主要實現了各種request命令的底層處理函數。

3.2 下行接口

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報文。

主要涉及到的文件包括:“driver.h”,“drivers.c”,“driver_nl80211.h”,“driver_nl80211.c”,“l2_packet.h”和“l2_packet_linux.c”。 
其中“driver.h”,“drivers.c”,“driver_wext.h”和“driver_wext.c”實現PF_INETsocket接口和PF_NETLINK socket接口;“l2_packet.h”和“l2_packet_linux.c”實現PF_PACKET socket接口。

(1)“driver.h”,“drivers.c”主要用於封裝底層差異對外顯示一個相同的wpa_driver_ops接口。Wpa_supplicant可支持atmel, Broadcom, ipw, madwifi, ndis, nl80211, wext等多種驅動。 
其中一個最主要的數據結構爲wpa_driver_ops, 其定義了driver相關的各種操作接口。

(2)“driver_nl80211.h”,“driver_nl80211.c”實現了netlink形式的wpa_driver_ops,通過netlink完成與kernel的信息交互。

(3)“l2_packet.h”和“l2_packet_linux.c”主要用於實現PF_PACKET socket接口,通過該接口,wpa_supplicant可以直接將802.1X packet發送到L2層,而不經過TCP/IP協議棧。

其中主要的功能函數爲:

struct l2_packet_data * l2_packet_init(
       const char *ifname, const u8 *own_addr, unsigned short protocol,
       void (*rx_callback)(void *ctx, const u8 *src_addr,
                         const u8 *buf, size_t len),
       void *rx_callback_ctx, int l2_hdr);
/* 創建並初始化PF_PACKET socket接口,其中rx_callback 爲從L2接收到的packet 處理callback函數 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
void l2_packet_deinit(struct l2_packet_data *l2);
/* 銷燬 PF_PACKET socket接口 */
  • 1
  • 2
int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
                 const u8 *buf, size_t len);
/* L2層packet發送函數,wpa_supplicant用此發送L2層 802.1X packet  */
  • 1
  • 2
  • 3
static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx);
/*  L2層packet接收函數,接收來自L2層數據後,將其發送到上層  */
  • 1
  • 2

參考資料:http://blog.csdn.net/hatchuel/article/details/50779546 
參考資料:http://blog.csdn.net/fxfzz/article/details/6176414

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章