Android wpa_supplicant原始碼分析--啟動之全域性初始化
1. wpa_supplicant簡介 wpa_supplicant是用來用來支援無線中各種加密方式的,包括WEP、WPA/WPA2和WAPI(中國特有)、EAP(8021x)。wpa_s通過socket與上層(framework)和底層(driver)通訊,向上接收命令和傳遞當前狀態,向下傳送命令到驅動並接收驅動上傳的各種event,嚴格來講wap_s和driver中還有一層cfg80211,cfg80211可以理解為linux定義的80211管理控制層的框架,例如掃描、連線這些通用的過程,各個廠商按照cfg80211提供的框架編寫各自的驅動,實現具體的幀傳送與接收。wpa_s是如何處理各個socket中資料的請看 eloop sun章節。 下圖是網頁(http://zwz94.blog.163.com/blog/static/3206039520120149580531/)上的一張圖片,可以清晰的看到wpa_s早整個wifi架構中的位置
2. wpa_supplicant的啟動 在Android手機中,wpa_supplicant的啟動是由framework控制的,frameowork設定property來啟動寫在init rc檔案的中service, 同時會生成兩條socket,一條向wpa_s傳送命令,一條接收wpa_s上傳的event
service p2p_supplicant /system/bin/wpa_supplicant \
-ip2p0 -Dnl80211 -c/data/misc/wifi/p2p_supplicant.conf \
-I/system/etc/wifi/p2p_supplicant_overlay.conf -N \
-iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf \
-I/system/etc/wifi/wpa_supplicant_overlay.conf \
-O/data/misc/wifi/sockets -puse_p2p_group_interface=1 -dd \
-e/data/misc/wifi/entropy.bin
3. wpa_supplicant啟動引數 wpa_s允許傳入很多引數, 引數區分大小寫 引數一共有3中型別,
3.1 不帶後續內容的引數 有 –BdhKLqstuvW -h:幫助檔案 -L:輸出license -q:提升wpa_s除錯級別(輸出log減少),與-d相反 -v:輸出wpa_s版本號 -W:等到control interface monitor再執行 -N:當需要設定兩個network interface時,需要在兩個網口引數中間插入 –N, 例如 一個網口為p2p0,需要插入-N後,再新新增另一個wlan0 wpa_supplicant通過為每一個網路介面設定不同的引數的方式,來實現對多網絡卡的支援。
3.2 帶後續內容的全域性引數 結構體 wpa_params在呼叫 wpa_supplicant_init() 初始化wpa_s使用,控制wpa_s執行
struct wpa_params { //-B:當做守護程序執行在後臺 int daemonize; //-W:等到control interface monitor再執行 int wait_for_monitor; //-P: pid_file - Path to a PID (process ID) file char *pid_file;
//-d:輸出log的級別,-d為預設級別,-dd級別降低一級(輸出log會增加一級),依次類推,設定程式碼為params.wpa_debug_level int wpa_debug_level; //-K:在log中列印key int wpa_debug_show_keys; //-t:除錯資訊中增加時間戳 int wpa_debug_timestamp;
//ctrl_interface - Global ctrl_iface path/parameter //-g:global ctrl_interface(字串為@android+SOCK_NAME, SOCK_NAME是由init.rc) char *ctrl_interface; //ctrl_interface_group - Global ctrl_iface group //-G:global ctrl_interface group char *ctrl_interface_group;
//-u:支援dbus控制介面 int dbus_ctrl_interface; //-f:將log輸出到file中 const char *wpa_debug_file_path; //-s:輸出log到 syslog, 預設輸出到stdout int wpa_debug_syslog;
//-T:log增加linux trace int wpa_debug_tracing; //-o:設定linux網口的目錄 char *override_driver; //-O:設定wpa_s控制sockets的目錄 char *override_ctrl_interface; //-e:entropy_file - Optional entropy file char *entropy_file; }; 3.3 帶後續內容的網路介面引數 存放到結構體 struct wpa_interface 中,執行wpa_supplicant_add_iface()需要傳入該結構體
struct wpa_interface { //-c:conf配置檔案,裡面定義了一些引數和一些network節點,一般為wpa_supplicant.conf const char *confname; //-I:conf配置檔案的補充選項,一般為wpa_supplicant_overlay.conf/ const char *confanother; //-m:p2p網口的配置檔案 const char *conf_p2p_dev; //-C:控制埠socket的引數 //功能等同conf 檔案 const char *ctrl_interface; //-D:driver的型別,可以設定多個,例如 nl80211,wext const char *driver;
//driver_param - Driver interface parameters const char *driver_param; //-i:linux的網口,可以定義多個,例如wlan0 const char *ifname; //-b:橋接的interface const char *bridge_ifname;
//p2p_mgmt - Interface used for P2P management (P2P Device operations) int p2p_mgmt; }; 4. wpa_supplicant全域性初始化 主要包括 EAP各種方法的註冊,eloop(wpa_s執行的主體)引數,與framework通訊socket的初始化
struct wpa_global * wpa_supplicant_init(struct wpa_params *params) { //全域性資訊,params中的內容都會拷貝到該結構體中 struct wpa_global *global;
//初始化eap方法,每種eap方式都有對應的方法 ret = eap_register_methods();
//將params中的資訊複製到global中 global = os_zalloc(sizeof(*global));
//初始化 struct eloop_data,該結構體是個全域性變數 if (eloop_init())
random_init(params->entropy_file);
//連線與FWKS通訊socket(init.rc中定義的),並註冊接收cmd的函式 global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global); { //初始化控制socket wpas_global_ctrl_iface_open_sock(global, priv) < 0) { //獲取-g傳進來的socket名稱,與init.rc中相對應 os_strncmp(ctrl, "@android:", 9) == 0) { priv->sock = android_get_control_socket(ctrl + 9); //註冊接收socket資料的函式,分發處理傳入的命令 eloop_register_read_sock(priv->sock, wpa_supplicant_global_ctrl_iface_receive, global, priv); //註冊傳送event到FWKS的函式wpa_supplicant_ctrl_iface_send wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); } } return global; } 下圖是簡易的全域性初始化過程
wpa_supplicant_global_ctrl_iface_receive()可以接受兩類命令,介面命令和全域性命令。一類命令前面有“IFNAME= ”指明處理該命令的介面,然後呼叫每個介面對應的 wpa_supplicant_ctrl_iface_process()來進行相應處理。另一類未指定介面,由wpa_supplicant_global_ctrl_iface_process()直接處理。
5 Framework與wpa_supplicant通訊 framework新建了兩條socket,並與init rc中的socket相關聯,一條用於傳送CMD,一條用接收event 程式碼在wifi.c中。
//path 內容為"@android:wpa_wlan0", wpa_wlan0是由init.rc啟動的socket int wifi_connect_on_socket_path(const char *path) { ctrl_conn = wpa_ctrl_open(path); monitor_conn = wpa_ctrl_open(path); } 在該函式中會呼叫wpa_ctrl_open()在wpa_s中,具體操作如下
static struct wpa_ctrl *ctrl_conn = wpa_ctrl_open(path); { //新建一個UNIX域的socket struct wpa_ctrl *ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
//經socket與檔案系統的地址繫結,就是手機目錄下的 /data/misc/wifi/sockets os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path), CONFIG_CTRL_IFACE_CLIENT_DIR "/" CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d", (int) getpid(), counter);
bind(ctrl->s, (struct sockaddr *) &ctrl->local, sizeof(ctrl->local))
//將新建立的socket和init.rc啟動的socket連線起來 socket_local_client_connect( ctrl->s, ctrl_path + 9, NDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM) } wifi_send_command()用於向wpa_s傳送命令 wifi_wait_on_socket()接收wpa_s向上傳遞的event
--------------------- 作者:cuijiyue 來源:CSDN 原文:https://blog.csdn.net/cuijiyue/article/details/51357263 版權宣告:本文為博主原創文章,轉載請附上博文連結!