<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                wpa_supplicant_init代碼如下所示。 **wpa_supplicant.c::wpa_supplicant_init** ~~~ struct wpa_global * wpa_supplicant_init(struct wpa_params *params) { struct wpa_global *global; int ret, i; ...... #ifdef CONFIG_DRIVER_NDIS ......// windows driver支持 #endif #ifndef CONFIG_NO_WPA_MSG // 設置全局回調函數,詳情見下文解釋 wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb); #endif /* CONFIG_NO_WPA_MSG */ // 輸出日志文件設置,本例未設置該文件 wpa_debug_open_file(params->wpa_debug_file_path); ...... ret = eap_register_methods();// ①注冊EAP方法 ...... global = os_zalloc(sizeof(*global)); // 創建一個wpa_global對象 ...... // 初始化global中的其他參數 wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR); // ②初始化事件循環機制 if (eloop_init()) {......} // 初始化隨機數相關資源,用于提升后續隨機數生成的隨機性 // 這部分內容不是本書的重點,感興趣的讀者請自行研究 random_init(params->entropy_file); // 初始化全局控制接口對象。由于本例中未設置全局控制接口,故該函數的處理非常簡單,請讀者自行閱讀該函數 global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global); ...... // 初始化通知機制相關資源,它和dbus有關。本例沒有包括dbus相關內容,略 if (wpas_notify_supplicant_initialized(global)) {......} // ③wpa_driver是一個全局變量,其作用見下文解釋 for (i = 0; wpa_drivers[i]; i++) global->drv_count++; ...... // 分配全局driver wrapper上下文信息數組 global->drv_priv = os_zalloc(global->drv_count * sizeof(void *)); ...... return global; } ~~~ wpa_supplicant_init函數的主要功能是初始化wpa_global以及一些與整個程序相關的資源,包括隨機數資源、eloop事件循環機制以及設置消息全局回調函數。 此處先簡單介紹消息全局回調函數,一共有兩個。 * **wpa_msg_get_ifname_func**:有些輸出信息中需要打印出網卡接口名。該回調函數用于獲取網卡接口名。 * **wpa_msg_cb_func**:除了打印輸出信息外,還可通過該回調函數進行一些特殊處理,如把輸出信息發送給客戶端進行處理。 上述兩個回調函數相關的代碼如下所示。 **wpa_debug.c** ~~~ // wpa_msg_ifname_cb用于獲取無線網卡接口名 // WPAS為其設置的實現函數為wpa_supplicant_msg_ifname_cb // 讀者可自行閱讀此函數 static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL; void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func){ wpa_msg_ifname_cb = func; } // WPAS中,wpa_msg_cb的實現函數是wpa_supplicant_ctrl_iface_msg_cb,它將輸出信息發送給客戶端 // 圖4-2最后兩行的信息就是由此函數發送給客戶端的。而且前面的"<3>"也是由它添加的 static wpa_msg_cb_func wpa_msg_cb = NULL; void wpa_msg_register_cb(wpa_msg_cb_func func){ wpa_msg_cb = func; } ~~~ 現在來看wpa_supplicant_init中列出的三個關鍵點,首先是eap_register_method函數。 1. eap_register_methods函數 該函數本身非常簡單,它主要根據編譯時的配置項來初始化不同的eap方法。其代碼如下所示。 **eap_register.c::eap_register_methods** ~~~ int eap_register_methods(void) { int ret = 0; #ifdef EAP_MD5 // 作為supplicant端,編譯時將定義EAP_MD5 if (ret == 0) ret = eap_peer_md5_register(); #endif /* EAP_MD5 */ ...... #ifdef EAP_SERVER_MD5 // 作為Authenticator端,編譯時將定義EAP_SERVER_MD5 if (ret == 0) ret = eap_server_md5_register(); #endif /* EAP_SERVER_MD5 */ ...... return ret; } ~~~ 如上述代碼所示,eap_register_methods函數將根據編譯配置項來注冊所需的eap method。例如,MD5身份驗證方法對應的注冊函數是eap_peer_md5_register,該函數內部將填充一個名為eap_method的數據結構,其定義如圖4-8所示。 圖4-8所示的struct eap_method結構體聲明于eap_i.h中,其內部一些變量及函數指針的定義和RFC4137有較大關系。此處,我們暫時列出其中一些簡單的成員變量。4.4節將詳細介紹RFC4137相關的知識。 來看第二個關鍵函數eloop_init,它和圖4-1所示WPAS軟件架構中的event loop模塊有關。 2. eloop_init函數及event loop模塊 eloop_init函數本身特別簡單,它僅初始化了WPAS中事件驅動的核心數據結構體eloop_data。WPAS事件驅動機制的實現非常簡單,它就是利用epoll(如果編譯時設置了CONFIG_ELOOP_POLL選項)或select實現了I/O復用。 **提醒** select(或epoll)是I/O復用的重要函數,屬于基礎知識范疇。請不熟悉的讀者自行學習相關內容。 從事件角度來看,WPAS的事件驅動機制支持5種類型的event。 * read event:讀事件,例如來自socket的可讀事件。 * write event:寫事件,例如socket的可寫事件。 * exception event:異常事件,如果socket操作發生錯誤,則由錯誤事件處理。 * timeout event:定時事件,通過select的等待超時機制來實現定時事件。 * signal:信號事件,信號事件來源于Kernel。WPAS允許為一些特定信號設置處理函數。 以上這些事件相關的信息都保存在eloop_data結構體中,如圖4-9所示。 :-: ![](https://box.kancloud.cn/104717da8e12a7982fe107be7c532729_991x526.jpg) 圖4-8 eap_method數據結構 :-: ![](https://box.kancloud.cn/9c60fec0a04f1c1418fd3c3e9e700b11_741x363.jpg) 圖4-9 eloop_data結構體 簡單介紹一下eloop提供的事件注冊API及eloop事件循環核心處理函數eloop_run。首先是事件注冊API函數,相關代碼如下所示。 **eloop.h** ~~~ // 注冊socket讀事件處理函數,參數sock代表一個socket句柄。一旦該句柄上有讀事件發生,則handler函數 // 將被事件處理循環(見下文eloop_run函數)調用 int eloop_register_read_sock(int sock, eloop_sock_handler handler, void *eloop_data, void *user_data); // 注冊socket事件處理函數,具體是哪種事件(只能是讀、寫或異常)由type參數決定 int eloop_register_sock(int sock, eloop_event_type type, eloop_sock_handler handler,void *eloop_data, void *user_data); // 注冊超時事件處理函數 int eloop_register_timeout(unsigned int secs, unsigned int usecs, eloop_timeout_handler handler, void *eloop_data, void *user_data); // 注冊信號事件處理函數,具體要處理的信號由sig參數指定 int eloop_register_signal(int sig, eloop_signal_handler handler, void *user_data); ~~~ 最后,向讀者展示一下WPAS事件驅動機制的運行原理,其代碼在eloop_run函數中,如下所示。 **eloop.c::eloop_run** ~~~ void eloop_run(void) { fd_set *rfds, *wfds, *efds; // fd_set是select中用到的一種參數類型 struct timeval _tv; int res; struct os_time tv, now; // 事件驅動循環 while (!eloop.terminate && (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 || eloop.writers.count > 0 || eloop.exceptions.count > 0)) { struct eloop_timeout *timeout; // 判斷是否有超時事件需要等待 timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,list); if (timeout) { os_get_time(&now); if (os_time_before(&now, &timeout->time)) os_time_sub(&timeout->time, &now, &tv); else tv.sec = tv.usec = 0; _tv.tv_sec = tv.sec; _tv.tv_usec = tv.usec; } // 將外界設置的讀事件添加到對應的fd_set中 eloop_sock_table_set_fds(&eloop.readers, rfds); ......// 設置寫、異常事件到fd_set中 // 調用select函數 res = select(eloop.max_sock + 1, rfds, wfds, efds,timeout ? &_tv : NULL); if(res &lt; 0) { ......// 錯誤處理 } // 先處理信號事件 eloop_process_pending_signals(); // 判斷是否有超時事件發生 timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,list); if (timeout) { os_get_time(&now); if (!os_time_before(&now, &timeout->time)) { void *eloop_data = timeout->eloop_data; void *user_data = timeout->user_data; eloop_timeout_handler handler = timeout->handler; eloop_remove_timeout(timeout); // 注意,超時事件只執行一次 handler(eloop_data, user_data); // 處理超時事件 } } ......// 處理讀/寫/異常事件。方法和下面這個函數類似 eloop_sock_table_dispatch(&eloop.readers, rfds); ......// 處理wfds和efds } out: return; } ~~~ eloop_run中的while循環是WPAS進程的運行中樞。不過其難度也不大。 下面來看wpa_supplicant_init代碼中的第三個關鍵點,即wpa_drivers變量。 3. wpa_drivers數組和driver i/f模塊 wpa_drivers是一個全局數組變量,它通過extern方式聲明于main.c中,其定義卻在drivers.c中,如下所示。 **drivers.c::wpa_drivers定義** ~~~ struct wpa_driver_ops *wpa_drivers[] = { #ifdef CONFIG_DRIVER_WEXT &wpa_driver_wext_ops, #endif /* CONFIG_DRIVER_WEXT */ #ifdef CONFIG_DRIVER_NL80211 &wpa_driver_nl80211_ops, #endif /* CONFIG_DRIVER_NL80211 */ ......// 其他driver接口 } ~~~ wpa_drivers數組成員指向一個wpa_driver_ops類型的對象。wpa_driver_ops是driver i/f模塊的核心數據結構,其內部定義了很多函數指針。而正是通過定義函數指針的方法,WPAS能夠隔離上層使用者和具體的driver。 **注意** 此處的driver并非通常意義所指的那些運行于Kernel層的驅動。讀者可認為它們是Kernel層wlan驅動在用戶空間的代理模塊。上層使用者通過它們來和Kernel層的驅動交互。為了避免混淆,本書后續將用driver wrapper一詞來表示WPAS中的driver。而driver一詞將專指Kernel里對應的wlan驅動。 **另外**,wpa_drivers數組包含多少個driver wrapper對象也由編譯選項來控制(如代碼中所示的CONFIG_DRIVER_WEXT宏,它們可在android.cfg中被修改)。 此處先列出wpa_driver_nl80211_ops的定義。 **driver_nl80211.c::wpa_driver_nl80211_ops** ~~~ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", // driver wrapper的名稱 .desc = "Linux nl80211/cfg80211", // 描述信息 .get_bssid = wpa_driver_nl80211_get_bssid, // 用于獲取bssid ...... .scan2 = wpa_driver_nl80211_scan, // 掃描函數 ...... .get_scan_results2 = wpa_driver_nl80211_get_scan_results, // 獲取掃描結果 ...... .disassociate = wpa_driver_nl80211_disassociate, // 觸發disassociation操作 .authenticate = wpa_driver_nl80211_authenticate, // 觸發authentication操作 .associate = wpa_driver_nl80211_associate, // 觸發association操作 // driver wrapper全局初始化函數,該函數的返回值保存在wpa_global成員變量drv_pri數組中 .global_init = nl80211_global_init, ...... .init2 = wpa_driver_nl80211_init, // driver wrapper初始化函數 ...... #ifdef ANDROID // Android平臺定義了該宏 .driver_cmd = wpa_driver_nl80211_driver_cmd,// 該函數用于處理和具體驅動相關的命令 #endif }; ~~~ 本節介紹了main函數中第一個的關鍵點wpa_supplicant_init,其中涉及的知識有:幾個重要數據結構,如wpa_global、wpa_interface、eap_method、wpa_driver_ops等;event loop的工作原理;消息全局回調函數和wpa_drivers等內容。 下面來分析main中第二個關鍵函數wpa_supplicant_add_iface。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看