學習android wifi開發已經一周了,今天開始立帖,將每天的學習成果貼出來,以備以後查閱,從framework到wpa_supplicant的適配層(wifi.c)網上介紹的文章很多,而且本身也並不複雜,其中framework部分需要注意的是wifiService和wifiMoniter兩部分,這兩快一個是轉寄AP的CMD另一個是接收來自wpa_supplicant的CMD。他們與本地庫的串連都是通過JNI方法,具體實現方法在android_net_wifi_Wifi.cpp中。在這個檔案中可以大致看出AP會給wpa_supplicant下哪些命令。這些命令通過wifi.c的wifi_command發送給wpa_supplicant,在發送命令的過程中實際是調用wpa_ctrl_request來完成命令發送的,wpa_ctrl_request是通過socket的方式與wpa_supplicant進行通訊的,然後通過wpa_ctrl_recv來接收來自wpa_supplicant的命令,並返回標識給wifi_wait_for_event。
但是命令發到wpa_supplicant後的流程網上提到的資料就非常少了,不過由於wpa_supplicant是一個標準的開源項目,已經被移植到很多平台上,它中間的過程我暫時還沒有去細看。比較關心的是wpa_supplicant在接收到上層的命令後是怎麼將命令發給DRIVER的,DRIVER在接收到命令後的解析的動作以及之後調用驅動功能函數的流程以及驅動對寄存器控制的細節。由於需要注意代碼保密,之後不會提及具體使用了哪塊WIFI晶片也不會提及此WIFI DRIVER是在什麼平台什麼產品。
先貼一張wpa_supplicant的標準結構框圖:
重點關注框圖的下半部分,即wpa_supplicant是如何與DRIVER進行聯絡的。整個過程暫以AP發出SCAN命令為主線。由於現在大部分WIFI DRIVER都支援wext,所以就假設我們的裝置走的是wext這條線,其實用ndis也一樣,流程感覺差不多。
首先要說的是,在Driver.h檔案中有個結構體wpa_driver_ops:
/**
* struct wpa_driver_ops - Driver interface API definition
*
* This structure defines the API that each driver interface needs to implement
* for core wpa_supplicant code. All driver specific functionality is captured
* in this wrapper.
*/
struct wpa_driver_ops
這個結構體在Driver.c中被聲明為:
#ifdef CONFIG_DRIVER_WEXT
extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
然後在driver_wext.c填寫了結構體的成員,
const struct wpa_driver_ops wpa_driver_wext_ops = {
.name = "wext",
.desc = "Linux wireless extensions (generic)",
.get_bssid = wpa_driver_wext_get_bssid,
.get_ssid = wpa_driver_wext_get_ssid,
.set_wpa = wpa_driver_wext_set_wpa,
.set_key = wpa_driver_wext_set_key,
.set_countermeasures = wpa_driver_wext_set_countermeasures,
.set_drop_unencrypted = wpa_driver_wext_set_drop_unencrypted,
.scan = wpa_driver_wext_scan,
.combo_scan = wpa_driver_wext_combo_scan,
.get_scan_results2 = wpa_driver_wext_get_scan_results,
.deauthenticate = wpa_driver_wext_deauthenticate,
.disassociate = wpa_driver_wext_disassociate,
.set_mode = wpa_driver_wext_set_mode,
.associate = wpa_driver_wext_associate,
.set_auth_alg = wpa_driver_wext_set_auth_alg,
.init = wpa_driver_wext_init,
.deinit = wpa_driver_wext_deinit,
.add_pmkid = wpa_driver_wext_add_pmkid,
.remove_pmkid = wpa_driver_wext_remove_pmkid,
.flush_pmkid = wpa_driver_wext_flush_pmkid,
.get_capa = wpa_driver_wext_get_capa,
.set_operstate = wpa_driver_wext_set_operstate,
#ifdef ANDROID
.driver_cmd = wpa_driver_priv_driver_cmd,
#endif
};
這些成員其實都是驅動和wpa_supplicant的介面,以SCAN為例:
int wpa_driver_wext_scan(void *priv, const u8 *ssid, size_t ssid_len)
中的LINE1174:if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0)從這裡可以看出wpa_cupplicant是通過IOCTL來調用SOCKET與DRIVER進行通訊的,並給DRIVER下達SIOCSIWSCAN這個命令。
這樣,一個命令從AP到FRAMEWORK到C++本地庫再到wpa_supplicant適配層,再由wpa_supplicant下CMD給DRIVER的路線就打通了,寫起來雖然不多但也是一點小成果。
時間過得很快,畢業已經三周了,後悔當初在實驗室沒有去學習關於WIFI的知識,現在只好從頭看起。好在公司環境比較輕鬆,可以有時間抓抓細節,後面就要開始將DRIVER部分的結構和流程理理清楚了。