深入理解 wpa_supplicant(二)
生活随笔
收集整理的這篇文章主要介紹了
深入理解 wpa_supplicant(二)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
本文為《深入理解Android Wi-Fi、NFC和GPS卷》讀書筆記,Android源碼為Android 5.1
struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
{struct wpa_global *global;int ret, i;if (params == NULL)return NULL;#ifdef CONFIG_DRIVER_NDIS{void driver_ndis_init_ops(void);driver_ndis_init_ops();}
#endif /* CONFIG_DRIVER_NDIS */#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);if (params->wpa_debug_syslog)wpa_debug_open_syslog();if (params->wpa_debug_tracing) {ret = wpa_debug_open_linux_tracing();if (ret) {wpa_printf(MSG_ERROR,"Failed to enable trace logging");return NULL;}}ret = eap_register_methods(); //注冊 EAP 方法if (ret) {wpa_printf(MSG_ERROR, "Failed to register EAP methods");if (ret == -2)wpa_printf(MSG_ERROR, "Two or more EAP methods used ""the same EAP type.");return NULL;}global = os_zalloc(sizeof(*global)); //創建一個 wpa_global 對象,后面是初始化if (global == NULL)return NULL;dl_list_init(&global->p2p_srv_bonjour);dl_list_init(&global->p2p_srv_upnp);global->params.daemonize = params->daemonize;global->params.wait_for_monitor = params->wait_for_monitor;global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;if (params->pid_file)global->params.pid_file = os_strdup(params->pid_file);if (params->ctrl_interface)global->params.ctrl_interface =os_strdup(params->ctrl_interface);if (params->override_driver)global->params.override_driver =os_strdup(params->override_driver);if (params->override_ctrl_interface)global->params.override_ctrl_interface =os_strdup(params->override_ctrl_interface);wpa_debug_level = global->params.wpa_debug_level =params->wpa_debug_level;wpa_debug_show_keys = global->params.wpa_debug_show_keys =params->wpa_debug_show_keys;wpa_debug_timestamp = global->params.wpa_debug_timestamp =params->wpa_debug_timestamp;wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR);if (eloop_init()) {wpa_printf(MSG_ERROR, "Failed to initialize event loop");wpa_supplicant_deinit(global);return NULL;}//初始化隨機數相關資源,用于提升后續隨機數生成的隨機性random_init(params->entropy_file);//初始化全局控制接口對象global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);if (global->ctrl_iface == NULL) {wpa_supplicant_deinit(global);return NULL;}//初始化通知機制相關資源if (wpas_notify_supplicant_initialized(global)) {wpa_supplicant_deinit(global);return NULL;}//wpa_drivers 是一個全局變量for (i = 0; wpa_drivers[i]; i++)global->drv_count++;if (global->drv_count == 0) {wpa_printf(MSG_ERROR, "No drivers enabled");wpa_supplicant_deinit(global);return NULL;}//分配全局 driver wrapper 上下文信息數組global->drv_priv = os_zalloc(global->drv_count * sizeof(void *));if (global->drv_priv == NULL) {wpa_supplicant_deinit(global);return NULL;}#ifdef CONFIG_WIFI_DISPLAYif (wifi_display_init(global) < 0) {wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display");wpa_supplicant_deinit(global);return NULL;}
#endif /* CONFIG_WIFI_DISPLAY */return global;
}wpa_supplicant_init 函數的主要功能是初始化 wpa_global 以及一些與整個程序相關的資源,包括隨機數資源、 eloop 時間循環機制以及設置消息全局回調函數。
wpa_msg_get_ifname_func: 獲取網卡接口名
wpa_msg_cb_func: 通過該回調函數進行一些特殊處理
android-5.1/external/wpa_supplicant_8/wpa_supplicant/src/utils/wpa_debug.c
static wpa_msg_cb_func wpa_msg_cb = NULL;void wpa_msg_register_cb(wpa_msg_cb_func func)
{wpa_msg_cb = func;
}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;
}該文件只有這一個函數,該函數主要根據編譯時的配置項來初始化不同的 eap 方法
android-5.1/external/wpa_supplicant_8/wpa_supplicant/eap_register.c
int eap_register_methods(void)
{int ret = 0;#ifdef EAP_MD5if (ret == 0)ret = eap_peer_md5_register();
#endif /* EAP_MD5 */#ifdef EAP_TLSif (ret == 0)ret = eap_peer_tls_register();
#endif /* EAP_TLS */#ifdef EAP_UNAUTH_TLSif (ret == 0)ret = eap_peer_unauth_tls_register();
#endif /* EAP_UNAUTH_TLS */#ifdef EAP_MSCHAPv2if (ret == 0)ret = eap_peer_mschapv2_register();
#endif /* EAP_MSCHAPv2 */#ifdef EAP_PEAPif (ret == 0)ret = eap_peer_peap_register();
#endif /* EAP_PEAP */#ifdef EAP_TTLSif (ret == 0)ret = eap_peer_ttls_register();
#endif /* EAP_TTLS */#ifdef EAP_GTCif (ret == 0)ret = eap_peer_gtc_register();
#endif /* EAP_GTC */#ifdef EAP_OTPif (ret == 0)ret = eap_peer_otp_register();
#endif /* EAP_OTP */#ifdef EAP_SIMif (ret == 0)ret = eap_peer_sim_register();
#endif /* EAP_SIM */#ifdef EAP_LEAPif (ret == 0)ret = eap_peer_leap_register();
#endif /* EAP_LEAP */#ifdef EAP_PSKif (ret == 0)ret = eap_peer_psk_register();
#endif /* EAP_PSK */#ifdef EAP_AKAif (ret == 0)ret = eap_peer_aka_register();
#endif /* EAP_AKA */#ifdef EAP_AKA_PRIMEif (ret == 0)ret = eap_peer_aka_prime_register();
#endif /* EAP_AKA_PRIME */#ifdef EAP_FASTif (ret == 0)ret = eap_peer_fast_register();
#endif /* EAP_FAST */#ifdef EAP_PAXif (ret == 0)ret = eap_peer_pax_register();
#endif /* EAP_PAX */#ifdef EAP_SAKEif (ret == 0)ret = eap_peer_sake_register();
#endif /* EAP_SAKE */#ifdef EAP_GPSKif (ret == 0)ret = eap_peer_gpsk_register();
#endif /* EAP_GPSK */#ifdef EAP_WSCif (ret == 0)ret = eap_peer_wsc_register();
#endif /* EAP_WSC */#ifdef EAP_IKEV2if (ret == 0)ret = eap_peer_ikev2_register();
#endif /* EAP_IKEV2 */#ifdef EAP_VENDOR_TESTif (ret == 0)ret = eap_peer_vendor_test_register();
#endif /* EAP_VENDOR_TEST */#ifdef EAP_TNCif (ret == 0)ret = eap_peer_tnc_register();
#endif /* EAP_TNC */#ifdef EAP_PWDif (ret == 0)ret = eap_peer_pwd_register();
#endif /* EAP_PWD */#ifdef EAP_SERVER_IDENTITYif (ret == 0)ret = eap_server_identity_register();
#endif /* EAP_SERVER_IDENTITY */#ifdef EAP_SERVER_MD5if (ret == 0)ret = eap_server_md5_register();
#endif /* EAP_SERVER_MD5 */#ifdef EAP_SERVER_TLSif (ret == 0)ret = eap_server_tls_register();
#endif /* EAP_SERVER_TLS */#ifdef EAP_SERVER_UNAUTH_TLSif (ret == 0)ret = eap_server_unauth_tls_register();
#endif /* EAP_SERVER_UNAUTH_TLS */#ifdef EAP_SERVER_MSCHAPV2if (ret == 0)ret = eap_server_mschapv2_register();
#endif /* EAP_SERVER_MSCHAPV2 */#ifdef EAP_SERVER_PEAPif (ret == 0)ret = eap_server_peap_register();
#endif /* EAP_SERVER_PEAP */#ifdef EAP_SERVER_TLVif (ret == 0)ret = eap_server_tlv_register();
#endif /* EAP_SERVER_TLV */#ifdef EAP_SERVER_GTCif (ret == 0)ret = eap_server_gtc_register();
#endif /* EAP_SERVER_GTC */#ifdef EAP_SERVER_TTLSif (ret == 0)ret = eap_server_ttls_register();
#endif /* EAP_SERVER_TTLS */#ifdef EAP_SERVER_SIMif (ret == 0)ret = eap_server_sim_register();
#endif /* EAP_SERVER_SIM */#ifdef EAP_SERVER_AKAif (ret == 0)ret = eap_server_aka_register();
#endif /* EAP_SERVER_AKA */#ifdef EAP_SERVER_AKA_PRIMEif (ret == 0)ret = eap_server_aka_prime_register();
#endif /* EAP_SERVER_AKA_PRIME */#ifdef EAP_SERVER_PAXif (ret == 0)ret = eap_server_pax_register();
#endif /* EAP_SERVER_PAX */#ifdef EAP_SERVER_PSKif (ret == 0)ret = eap_server_psk_register();
#endif /* EAP_SERVER_PSK */#ifdef EAP_SERVER_SAKEif (ret == 0)ret = eap_server_sake_register();
#endif /* EAP_SERVER_SAKE */#ifdef EAP_SERVER_GPSKif (ret == 0)ret = eap_server_gpsk_register();
#endif /* EAP_SERVER_GPSK */#ifdef EAP_SERVER_VENDOR_TESTif (ret == 0)ret = eap_server_vendor_test_register();
#endif /* EAP_SERVER_VENDOR_TEST */#ifdef EAP_SERVER_FASTif (ret == 0)ret = eap_server_fast_register();
#endif /* EAP_SERVER_FAST */#ifdef EAP_SERVER_WSCif (ret == 0)ret = eap_server_wsc_register();
#endif /* EAP_SERVER_WSC */#ifdef EAP_SERVER_IKEV2if (ret == 0)ret = eap_server_ikev2_register();
#endif /* EAP_SERVER_IKEV2 */#ifdef EAP_SERVER_TNCif (ret == 0)ret = eap_server_tnc_register();
#endif /* EAP_SERVER_TNC */#ifdef EAP_SERVER_PWDif (ret == 0)ret = eap_server_pwd_register();
#endif /* EAP_SERVER_PWD */return ret;
}
eap_register_methods 將根據編譯配置項來注冊所需的 eap method。 例如 MD5 身份驗證方法對應的注冊函數是 eap_peer_md5_register,該函數內部將填充一個名為 eap_method 的數據結構。
struct eap_method 結構體內部一些變量及函數指針的定義和 RFC4137 有較大關系。
android-5.1/external/wpa_supplicant_8/src/eap_peer/eap_i.h
struct eap_method {/*** vendor - EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)*/int vendor; //EAP方法的廠商ID/*** method - EAP type number (EAP_TYPE_*)*/EapType method; //EAP方法枚舉定義/*** name - Name of the method (e.g., "TLS")*/const char *name; //EAP 方法名/*** init - Initialize an EAP method* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()* Returns: Pointer to allocated private data, or %NULL on failure** This function is used to initialize the EAP method explicitly* instead of using METHOD_INIT state as specific in RFC 4137. The* method is expected to initialize it method-specific state and return* a pointer that will be used as the priv argument to other calls.*/void * (*init)(struct eap_sm *sm); //該 eap_method 對象的初始化函數/*** deinit - Deinitialize an EAP method* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()* @priv: Pointer to private EAP method data from eap_method::init()** Deinitialize the EAP method and free any allocated private data.*/void (*deinit)(struct eap_sm *sm, void *priv); //資源釋放函數/*** process - Process an EAP request* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()* @priv: Pointer to private EAP method data from eap_method::init()* @ret: Return values from EAP request validation and processing* @reqData: EAP request to be processed (eapReqData)* Returns: Pointer to allocated EAP response packet (eapRespData)** This function is a combination of m.check(), m.process(), and* m.buildResp() procedures defined in section 4.4 of RFC 4137 In other* words, this function validates the incoming request, processes it,* and build a response packet. m.check() and m.process() return values* are returned through struct eap_method_ret *ret variable. Caller is* responsible for freeing the returned EAP response packet.*/struct wpabuf * (*process)(struct eap_sm *sm, void *priv,struct eap_method_ret *ret,const struct wpabuf *reqData); //EAP request消息的處理函數/*** isKeyAvailable - Find out whether EAP method has keying material* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()* @priv: Pointer to private EAP method data from eap_method::init()* Returns: %TRUE if key material (eapKeyData) is available*/Boolean (*isKeyAvailable)(struct eap_sm *sm, void *priv);/*** getKey - Get EAP method specific keying material (eapKeyData)* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()* @priv: Pointer to private EAP method data from eap_method::init()* @len: Pointer to variable to store key length (eapKeyDataLen)* Returns: Keying material (eapKeyData) or %NULL if not available** This function can be used to get the keying material from the EAP* method. The key may already be stored in the method-specific private* data or this function may derive the key.*/u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);/*** get_status - Get EAP method status* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()* @priv: Pointer to private EAP method data from eap_method::init()* @buf: Buffer for status information* @buflen: Maximum buffer length* @verbose: Whether to include verbose status information* Returns: Number of bytes written to buf** Query EAP method for status information. This function fills in a* text area with current status information from the EAP method. If* the buffer (buf) is not large enough, status information will be* truncated to fit the buffer.*/int (*get_status)(struct eap_sm *sm, void *priv, char *buf,size_t buflen, int verbose);/*** has_reauth_data - Whether method is ready for fast reauthentication* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()* @priv: Pointer to private EAP method data from eap_method::init()* Returns: %TRUE or %FALSE based on whether fast reauthentication is* possible** This function is an optional handler that only EAP methods* supporting fast re-authentication need to implement.*/Boolean (*has_reauth_data)(struct eap_sm *sm, void *priv);/*** deinit_for_reauth - Release data that is not needed for fast re-auth* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()* @priv: Pointer to private EAP method data from eap_method::init()** This function is an optional handler that only EAP methods* supporting fast re-authentication need to implement. This is called* when authentication has been completed and EAP state machine is* requesting that enough state information is maintained for fast* re-authentication*/void (*deinit_for_reauth)(struct eap_sm *sm, void *priv);/*** init_for_reauth - Prepare for start of fast re-authentication* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()* @priv: Pointer to private EAP method data from eap_method::init()** This function is an optional handler that only EAP methods* supporting fast re-authentication need to implement. This is called* when EAP authentication is started and EAP state machine is* requesting fast re-authentication to be used.*/void * (*init_for_reauth)(struct eap_sm *sm, void *priv);/*** get_identity - Get method specific identity for re-authentication* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()* @priv: Pointer to private EAP method data from eap_method::init()* @len: Length of the returned identity* Returns: Pointer to the method specific identity or %NULL if default* identity is to be used** This function is an optional handler that only EAP methods* that use method specific identity need to implement.*/const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);/*** free - Free EAP method data* @method: Pointer to the method data registered with* eap_peer_method_register().** This function will be called when the EAP method is being* unregistered. If the EAP method allocated resources during* registration (e.g., allocated struct eap_method), they should be* freed in this function. No other method functions will be called* after this call. If this function is not defined (i.e., function* pointer is %NULL), a default handler is used to release the method* data with free(method). This is suitable for most cases.*/void (*free)(struct eap_method *method); //釋放 eap_method 對象內部資源#define EAP_PEER_METHOD_INTERFACE_VERSION 1/*** version - Version of the EAP peer method interface** The EAP peer method implementation should set this variable to* EAP_PEER_METHOD_INTERFACE_VERSION. This is used to verify that the* EAP method is using supported API version when using dynamically* loadable EAP methods.*/int version; //EAP版本號/*** next - Pointer to the next EAP method** This variable is used internally in the EAP method registration code* to create a linked list of registered EAP methods.*/struct eap_method *next; //所有注冊的 eap_method 對象都存儲在一個單向鏈表中#ifdef CONFIG_DYNAMIC_EAP_METHODS/*** dl_handle - Handle for the dynamic library** This variable is used internally in the EAP method registration code* to store a handle for the dynamic library. If the method is linked* in statically, this is %NULL.*/void *dl_handle;
#endif /* CONFIG_DYNAMIC_EAP_METHODS *//*** get_emsk - Get EAP method specific keying extended material (EMSK)* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()* @priv: Pointer to private EAP method data from eap_method::init()* @len: Pointer to a variable to store EMSK length* Returns: EMSK or %NULL if not available** This function can be used to get the extended keying material from* the EAP method. The key may already be stored in the method-specific* private data or this function may derive the key.*/u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len);/*** getSessionId - Get EAP method specific Session-Id* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()* @priv: Pointer to private EAP method data from eap_method::init()* @len: Pointer to a variable to store Session-Id length* Returns: Session-Id or %NULL if not available** This function can be used to get the Session-Id from the EAP method.* The Session-Id may already be stored in the method-specific private* data or this function may derive the Session-Id.*/u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len);
};android-5.1/external/wpa_supplicant_8/src/utils/eloop.c
int eloop_init(void)
{os_memset(&eloop, 0, sizeof(eloop));dl_list_init(&eloop.timeout);
#ifdef CONFIG_ELOOP_EPOLLeloop.epollfd = epoll_create1(0);if (eloop.epollfd < 0) {wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s\n",__func__, strerror(errno));return -1;}eloop.readers.type = EVENT_TYPE_READ;eloop.writers.type = EVENT_TYPE_WRITE;eloop.exceptions.type = EVENT_TYPE_EXCEPTION;
#endif /* CONFIG_ELOOP_EPOLL */
#ifdef WPA_TRACEsignal(SIGSEGV, eloop_sigsegv_handler);
#endif /* WPA_TRACE */return 0;
}eloop_init 初始化了 WPAS 中事件驅動的核心數據結構體 eloop_data。 WPAS 事件驅動機制就是利用 epoll(如果編譯時設置了 CONFIG_ELOOP_POOL 選項)或 select 實現了 I/O 復用。
android-5.1/external/wpa_supplicant_8/src/utils/eloop.c
struct eloop_data {int max_sock; //供select使用int count; /* sum of all table counts 所有事件表中事件的個數*/
#ifdef CONFIG_ELOOP_POLLint max_pollfd_map; /* number of pollfds_map currently allocated */int max_poll_fds; /* number of pollfds currently allocated */struct pollfd *pollfds;struct pollfd **pollfds_map;
#endif /* CONFIG_ELOOP_POLL */
#ifdef CONFIG_ELOOP_EPOLLint epollfd;int epoll_max_event_num;int epoll_max_fd;struct eloop_sock *epoll_table;struct epoll_event *epoll_events;
#endif /* CONFIG_ELOOP_EPOLL */struct eloop_sock_table readers; //讀事件表struct eloop_sock_table writers; //寫事件表struct eloop_sock_table exceptions; //異常事件表struct dl_list timeout; //超時事件鏈表int signal_count; //信號事件個數struct eloop_signal *signals; //信號事件表int signaled;int pending_terminate;int terminate;
};從事件角度來看, WPAS 的事件驅動機制支持5中類型的event。
read event: 讀事件,例如來自 socket 的可讀時間
write event:寫事件,例如 socket 的可寫事件
exception event: 異常事件, 如果socket 操作發生錯誤,則由錯誤事件處理
timeout event:定時事件,通過 select 的等待超時機制來實現定時事件
signal: 信號事件,信號事件來源于 Kernel。 WPAS 允許為一些特定信號設置處理函數
以上這些事件相關的信息都保存在 eloop_data 結構體中。
android-5.1/external/wpa_supplicant_8/src/utils/eloop.h
/*** eloop_register_read_sock - Register handler for read events* @sock: File descriptor number for the socket* @handler: Callback function to be called when data is available for reading* @eloop_data: Callback context data (eloop_ctx)* @user_data: Callback context data (sock_ctx)* Returns: 0 on success, -1 on failure** Register a read socket notifier for the given file descriptor. The handler* function will be called whenever data is available for reading from the* socket. The handler function is responsible for clearing the event after* having processed it in order to avoid eloop from calling the handler again* for the same event.*///注冊 socket 讀事件處理函數,參數sock代表一個socket句柄。一旦該句柄上有讀事件發生,則 handler 函數將被事件處理循環調用
int eloop_register_read_sock(int sock, eloop_sock_handler handler,void *eloop_data, void *user_data);
/*** eloop_register_sock - Register handler for socket events* @sock: File descriptor number for the socket* @type: Type of event to wait for* @handler: Callback function to be called when the event is triggered* @eloop_data: Callback context data (eloop_ctx)* @user_data: Callback context data (sock_ctx)* Returns: 0 on success, -1 on failure** Register an event notifier for the given socket's file descriptor. The* handler function will be called whenever the that event is triggered for the* socket. The handler function is responsible for clearing the event after* having processed it in order to avoid eloop from calling the handler again* for the same event.*///注冊 socket 事件處理函數,具體是哪種事件(只能是讀、寫或異常)由type參數決定
int eloop_register_sock(int sock, eloop_event_type type,eloop_sock_handler handler,void *eloop_data, void *user_data);
/*** eloop_register_timeout - Register timeout* @secs: Number of seconds to the timeout* @usecs: Number of microseconds to the timeout* @handler: Callback function to be called when timeout occurs* @eloop_data: Callback context data (eloop_ctx)* @user_data: Callback context data (sock_ctx)* Returns: 0 on success, -1 on failure** Register a timeout that will cause the handler function to be called after* given time.*///注冊超時事件處理函數
int eloop_register_timeout(unsigned int secs, unsigned int usecs,eloop_timeout_handler handler,void *eloop_data, void *user_data);
/*** eloop_register_signal - Register handler for signals* @sig: Signal number (e.g., SIGHUP)* @handler: Callback function to be called when the signal is received* @user_data: Callback context data (signal_ctx)* Returns: 0 on success, -1 on failure** Register a callback function that will be called when a signal is received.* The callback function is actually called only after the system signal* handler has returned. This means that the normal limits for sighandlers* (i.e., only "safe functions" allowed) do not apply for the registered* callback.*///注冊信號事件處理函數,具體要處理的信號由 sig 參數指定
int eloop_register_signal(int sig, eloop_signal_handler handler,void *user_data);
WPAS 事件驅動機制的運行原理:
android-5.1/external/wpa_supplicant_8/src/utils/eloop.c
void eloop_run(void)
{
#ifdef CONFIG_ELOOP_POLLint num_poll_fds;int timeout_ms = 0;
#endif /* CONFIG_ELOOP_POLL */
#ifdef CONFIG_ELOOP_SELECTfd_set *rfds, *wfds, *efds; //fd_set 是 select 中用到的一種參數類型struct timeval _tv;
#endif /* CONFIG_ELOOP_SELECT */
#ifdef CONFIG_ELOOP_EPOLLint timeout_ms = -1;
#endif /* CONFIG_ELOOP_EPOLL */int res;struct os_reltime tv, now;#ifdef CONFIG_ELOOP_SELECTrfds = os_malloc(sizeof(*rfds));wfds = os_malloc(sizeof(*wfds));efds = os_malloc(sizeof(*efds));if (rfds == NULL || wfds == NULL || efds == NULL)goto out;
#endif /* CONFIG_ELOOP_SELECT *///事件驅動循環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_reltime(&now);if (os_reltime_before(&now, &timeout->time))os_reltime_sub(&timeout->time, &now, &tv);elsetv.sec = tv.usec = 0;
#if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)timeout_ms = tv.sec * 1000 + tv.usec / 1000;
#endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
#ifdef CONFIG_ELOOP_SELECT_tv.tv_sec = tv.sec;_tv.tv_usec = tv.usec;
#endif /* CONFIG_ELOOP_SELECT */}#ifdef CONFIG_ELOOP_POLLnum_poll_fds = eloop_sock_table_set_fds(&eloop.readers, &eloop.writers, &eloop.exceptions,eloop.pollfds, eloop.pollfds_map,eloop.max_pollfd_map);res = poll(eloop.pollfds, num_poll_fds,timeout ? timeout_ms : -1);
#endif /* CONFIG_ELOOP_POLL */
#ifdef CONFIG_ELOOP_SELECT//將外界設置的讀、寫、異常事件添加到對應的 fd_set 中eloop_sock_table_set_fds(&eloop.readers, rfds);eloop_sock_table_set_fds(&eloop.writers, wfds);eloop_sock_table_set_fds(&eloop.exceptions, efds);//調用select函數res = select(eloop.max_sock + 1, rfds, wfds, efds,timeout ? &_tv : NULL);
#endif /* CONFIG_ELOOP_SELECT */
#ifdef CONFIG_ELOOP_EPOLLif (eloop.count == 0) {res = 0;} else {res = epoll_wait(eloop.epollfd, eloop.epoll_events,eloop.count, timeout_ms);}
#endif /* CONFIG_ELOOP_EPOLL */if (res < 0 && errno != EINTR && errno != 0) {wpa_printf(MSG_ERROR, "eloop: %s: %s",
#ifdef CONFIG_ELOOP_POLL"poll"
#endif /* CONFIG_ELOOP_POLL */
#ifdef CONFIG_ELOOP_SELECT"select"
#endif /* CONFIG_ELOOP_SELECT */
#ifdef CONFIG_ELOOP_EPOLL"epoll"
#endif /* CONFIG_ELOOP_EPOLL */, strerror(errno));goto out;}//先處理信號事件eloop_process_pending_signals();/* check if some registered timeouts have occurred *///判斷是否有超時事件發生timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,list);if (timeout) {os_get_reltime(&now);if (!os_reltime_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); //處理超時事件}}if (res <= 0)continue;#ifdef CONFIG_ELOOP_POLLeloop_sock_table_dispatch(&eloop.readers, &eloop.writers,&eloop.exceptions, eloop.pollfds_map,eloop.max_pollfd_map);
#endif /* CONFIG_ELOOP_POLL */
#ifdef CONFIG_ELOOP_SELECT//處理讀、寫、異常事件eloop_sock_table_dispatch(&eloop.readers, rfds);eloop_sock_table_dispatch(&eloop.writers, wfds);eloop_sock_table_dispatch(&eloop.exceptions, efds);
#endif /* CONFIG_ELOOP_SELECT */
#ifdef CONFIG_ELOOP_EPOLLeloop_sock_table_dispatch(eloop.epoll_events, res);
#endif /* CONFIG_ELOOP_EPOLL */}eloop.terminate = 0;
out:
#ifdef CONFIG_ELOOP_SELECTos_free(rfds);os_free(wfds);os_free(efds);
#endif /* CONFIG_ELOOP_SELECT */return;
}wpa_drivers 是一個全局數組變量
android-5.1/external/wpa_supplicant_8/src/drivers/drivers.c
struct wpa_driver_ops *wpa_drivers[] =
{
#ifdef CONFIG_DRIVER_NL80211&wpa_driver_nl80211_ops,
#endif /* CONFIG_DRIVER_NL80211 */
#ifdef CONFIG_DRIVER_WEXT&wpa_driver_wext_ops,
#endif /* CONFIG_DRIVER_WEXT */
#ifdef CONFIG_DRIVER_HOSTAP&wpa_driver_hostap_ops,
#endif /* CONFIG_DRIVER_HOSTAP */
#ifdef CONFIG_DRIVER_MADWIFI&wpa_driver_madwifi_ops,
#endif /* CONFIG_DRIVER_MADWIFI */
#ifdef CONFIG_DRIVER_BSD&wpa_driver_bsd_ops,
#endif /* CONFIG_DRIVER_BSD */
#ifdef CONFIG_DRIVER_OPENBSD&wpa_driver_openbsd_ops,
#endif /* CONFIG_DRIVER_OPENBSD */
#ifdef CONFIG_DRIVER_NDIS&wpa_driver_ndis_ops,
#endif /* CONFIG_DRIVER_NDIS */
#ifdef CONFIG_DRIVER_WIRED&wpa_driver_wired_ops,
#endif /* CONFIG_DRIVER_WIRED */
#ifdef CONFIG_DRIVER_MACSEC_QCA&wpa_driver_macsec_qca_ops,
#endif /* CONFIG_DRIVER_MACSEC_QCA */
#ifdef CONFIG_DRIVER_TEST&wpa_driver_test_ops,
#endif /* CONFIG_DRIVER_TEST */
#ifdef CONFIG_DRIVER_ROBOSWITCH&wpa_driver_roboswitch_ops,
#endif /* CONFIG_DRIVER_ROBOSWITCH */
#ifdef CONFIG_DRIVER_ATHEROS&wpa_driver_atheros_ops,
#endif /* CONFIG_DRIVER_ATHEROS */
#ifdef CONFIG_DRIVER_NONE&wpa_driver_none_ops,
#endif /* CONFIG_DRIVER_NONE */NULL
};wpa_driver_ops內部定義很多函數指針,通過這些定義的函數指針,WPAS能隔離上層使用者和具體的driver。
android-5.1/external/wpa_supplicant_8/src/drivers/driver_nl80211.c
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.get_ssid = wpa_driver_nl80211_get_ssid,.set_key = driver_nl80211_set_key,.scan2 = driver_nl80211_scan2, //掃描函數.sched_scan = wpa_driver_nl80211_sched_scan,.stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,.get_scan_results2 = wpa_driver_nl80211_get_scan_results, //獲取掃描結果.deauthenticate = driver_nl80211_deauthenticate,.authenticate = driver_nl80211_authenticate, //觸發 authentication 操作.associate = wpa_driver_nl80211_associate, //觸發 association 操作.global_init = nl80211_global_init, //driver wrapper 全局初始化函數,該函數的返回值保存在 wpa_global 成員變量 drv_pri 數組中.global_deinit = nl80211_global_deinit,.init2 = wpa_driver_nl80211_init, //driver wrapper 初始化函數.deinit = driver_nl80211_deinit,.get_capa = wpa_driver_nl80211_get_capa,.set_operstate = wpa_driver_nl80211_set_operstate,.set_supp_port = wpa_driver_nl80211_set_supp_port,.set_country = wpa_driver_nl80211_set_country,.get_country = wpa_driver_nl80211_get_country,.set_ap = wpa_driver_nl80211_set_ap,.set_acl = wpa_driver_nl80211_set_acl,.if_add = wpa_driver_nl80211_if_add,.if_remove = driver_nl80211_if_remove,.send_mlme = driver_nl80211_send_mlme,.get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,.sta_add = wpa_driver_nl80211_sta_add,.sta_remove = driver_nl80211_sta_remove,.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,.sta_set_flags = wpa_driver_nl80211_sta_set_flags,.hapd_init = i802_init,.hapd_deinit = i802_deinit,.set_wds_sta = i802_set_wds_sta,.get_seqnum = i802_get_seqnum,.flush = i802_flush,.get_inact_sec = i802_get_inact_sec,.sta_clear_stats = i802_sta_clear_stats,.set_rts = i802_set_rts,.set_frag = i802_set_frag,.set_tx_queue_params = i802_set_tx_queue_params,.set_sta_vlan = driver_nl80211_set_sta_vlan,.sta_deauth = i802_sta_deauth,.sta_disassoc = i802_sta_disassoc,.read_sta_data = driver_nl80211_read_sta_data,.set_freq = i802_set_freq,.send_action = driver_nl80211_send_action,.send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,.remain_on_channel = wpa_driver_nl80211_remain_on_channel,.cancel_remain_on_channel = wpa_driver_nl80211_cancel_remain_on_channel,.probe_req_report = driver_nl80211_probe_req_report,.deinit_ap = wpa_driver_nl80211_deinit_ap,.deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,.resume = wpa_driver_nl80211_resume,.send_ft_action = nl80211_send_ft_action,.signal_monitor = nl80211_signal_monitor,.signal_poll = nl80211_signal_poll,.send_frame = nl80211_send_frame,.shared_freq = wpa_driver_nl80211_shared_freq,.set_param = nl80211_set_param,.get_radio_name = nl80211_get_radio_name,.add_pmkid = nl80211_add_pmkid,.remove_pmkid = nl80211_remove_pmkid,.flush_pmkid = nl80211_flush_pmkid,.set_rekey_info = nl80211_set_rekey_info,.poll_client = nl80211_poll_client,.set_p2p_powersave = nl80211_set_p2p_powersave,.start_dfs_cac = nl80211_start_radar_detection,.stop_ap = wpa_driver_nl80211_stop_ap,
#ifdef CONFIG_TDLS.send_tdls_mgmt = nl80211_send_tdls_mgmt,.tdls_oper = nl80211_tdls_oper,
#endif /* CONFIG_TDLS */.update_ft_ies = wpa_driver_nl80211_update_ft_ies,.get_mac_addr = wpa_driver_nl80211_get_macaddr,.get_survey = wpa_driver_nl80211_get_survey,.status = wpa_driver_nl80211_status,.switch_channel = nl80211_switch_channel,
#ifdef ANDROID_P2P.set_noa = wpa_driver_set_p2p_noa,.get_noa = wpa_driver_get_p2p_noa,.set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
#endif /* ANDROID_P2P */
#ifdef ANDROID.driver_cmd = wpa_driver_nl80211_driver_cmd, //用于處理和具體驅動相關的命令
#endif /* ANDROID */.vendor_cmd = nl80211_vendor_cmd,.set_qos_map = nl80211_set_qos_map,.set_wowlan = nl80211_set_wowlan,.roaming = nl80211_roaming,.set_mac_addr = nl80211_set_mac_addr,
};
總結
以上是生活随笔為你收集整理的深入理解 wpa_supplicant(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入理解 wpa_supplicant(
- 下一篇: 深入理解 wpa_supplicant(