1. 程式人生 > >Android wpa_supplicant原始碼分析--啟動之全域性初始化

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

[email protected]:wpa_wlan0     class main     socket wpa_wlan0 dgram 660 wifi wifi     disabled     oneshot 其中 socket wpa_wlan0 dgram 660 wifi wifi建立了一個socket,wpa_s使用該socket接收framework的命令和向上傳遞event。framework同樣會呼叫連線該socket,後面會講到

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  版權宣告:本文為博主原創文章,轉載請附上博文連結!