深入理解 wpa_supplicant(二)

来源:互联网 发布:排序算法 Python实现 编辑:程序博客网 时间:2024/06/06 02:03

本文为《深入理解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_POLL    int num_poll_fds;    int timeout_ms = 0;#endif /* CONFIG_ELOOP_POLL */#ifdef CONFIG_ELOOP_SELECT    fd_set *rfds, *wfds, *efds;    //fd_set 是 select 中用到的一种参数类型    struct timeval _tv;#endif /* CONFIG_ELOOP_SELECT */#ifdef CONFIG_ELOOP_EPOLL    int timeout_ms = -1;#endif /* CONFIG_ELOOP_EPOLL */    int res;    struct os_reltime tv, now;#ifdef CONFIG_ELOOP_SELECT    rfds = 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);            else                tv.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_POLL        num_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_EPOLL        if (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_POLL        eloop_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_EPOLL        eloop_sock_table_dispatch(eloop.epoll_events, res);#endif /* CONFIG_ELOOP_EPOLL */    }    eloop.terminate = 0;out:#ifdef CONFIG_ELOOP_SELECT    os_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,};

0 0
原创粉丝点击