位置: 编程技术 - 正文

Android4.4 wpa_supplicant深入分析之wpa_supplicant初始化流程

编辑:rootadmin

推荐整理分享Android4.4 wpa_supplicant深入分析之wpa_supplicant初始化流程,希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:,内容如对您有帮助,希望把文章链接给更多的朋友!

Android系统中,wpa_supplicant启动是通过“setprop ctrl.start wpa_supplicant”来触发init进程去fork一个子进程来完成的。wpa_supplicant在init配置文件中被定义为一个service。

[cpp] view plaincopyservice wpa_supplicant /system/bin/wpa_supplicant -iwlan0 -Dnl -c/data/misc/wifi/wpa_supplicant.conf -I/system/etc/wifi/wpa_supplicant_overlay.conf -O/data/misc/wifi/sockets -e/data/misc/wifi/entropy.bin -g@android:wpa_wlan0 # we will start as root and wpa_supplicant will switch to user wifi # after setting up the capabilities required for WEXT # user wifi # group wifi inet keystore class main socket wpa_wlan0 dgram wifi wifi disabled oneshot 以上众多启动参数中,最重要的是通过“-c“参数制定的wpa_supplicant启动配置文件。[cpp] view plaincopyctrl_interface=/data/misc/wifi/sockets driver_param=use_p2p_group_interface=1p2p_device=1 update_config=1 device_name=******** manufacturer=BROADCOM model_name=********* model_number=********* serial_number= device_type=-F-5 config_methods=physical_display virtual_push_button p2p_listen_reg_class= p2p_listen_channel= p2p_oper_reg_class= p2p_oper_channel= p2p_ssid_postfix=-Android_ persistent_reconnect=1 network={ ssid="AP_5DE3" psk="" key_mgmt=WPA-PSK priority=1 } network={ ssid="Android-" psk="android.com" key_mgmt=WPA-PSK priority=2 }

(1)ctrl_interface知名控制接口Unix域socket的文件名。

(2)update_config表示如果wpa_supplicant运行过程中修改了配置信息,则需要把它们保存到此wpa_supplicant文件中。

(3)从device_name到config_methods都和wpa_supplicant设置有关。

(4)p2p等选项和WiFi P2P有关。

(5)wpa_supplicant运行过程中得到的无线网络信息都会通过”network“配置项保存到配置文件中。如果该信息完整,一旦wpa_supplicant找到该无线网络就会尝试用保存的信息去加入它。(这也是手机能自动加入周围某个曾经的路过的无线网络的原因)。

(6)network项包括的内容比较多。network项展示了该无线网络的ssid、密钥管理方法(key management)、身份认证方法及密码等信息。network中的priority表示无线网络的优先级。其作用是,如果同时存在多个可用的无线网络,wpa_supplicant有限选择priority搞得那一个。

main函数分析[-->main.c::main]

[cpp] view plaincopyint main(int argc, char *argv[]) { int c, i; struct wpa_interface *ifaces, *iface; int iface_count, exitcode = -1; struct wpa_params params; struct wpa_global *global; if (os_program_init()) return -1; os_memset(¶ms, 0, sizeof(params)); params.wpa_debug_level = MSG_INFO; iface = ifaces = os_zalloc(sizeof(struct wpa_interface)); if (ifaces == NULL) return -1; iface_count = 1; wpa_supplicant_fd_workaround(1); //输入输出重定向到/dev/null设备 for (;;) { c = getopt(argc, argv, "b:Bc:C:D:de:f:g:G:hi:I:KLNo:O:p:P:qsTtuvW"); if (c < 0) break; switch (c) { case 'b': iface->bridge_ifname = optarg; break; case 'B': params.daemonize&#;&#;; break; case 'c': iface->confname = optarg; //指定配置文件名。注意,该参数赋&#;给了wpa_interface中的变量 break; case 'C': iface->ctrl_interface = optarg; break; case 'D': iface->driver = optarg; //指定driver名称。注意,该参数赋&#;给了wpa_interface中的变量 break; case 'd': #ifdef CONFIG_NO_STDOUT_DEBUG printf("Debugging disabled with " "CONFIG_NO_STDOUT_DEBUG=y build time " "option.n"); goto out; #else /* CONFIG_NO_STDOUT_DEBUG */ params.wpa_debug_level--; break; #endif /* CONFIG_NO_STDOUT_DEBUG */ case 'e': params.entropy_file = optarg; //制定初始随机数文件,用于后续随机数的生成 break; #ifdef CONFIG_DEBUG_FILE case 'f': params.wpa_debug_file_path = optarg; break; #endif /* CONFIG_DEBUG_FILE */ case 'g': params.ctrl_interface = optarg; break; case 'G': params.ctrl_interface_group = optarg; break; case 'h': usage(); exitcode = 0; goto out; case 'i': iface->ifname = optarg; //指定网络设备接口名,本例是"wlan0" break; case 'I': iface->confanother = optarg; break; case 'K': params.wpa_debug_show_keys&#;&#;; break; case 'L': license(); exitcode = 0; goto out; case 'o': params.override_driver = optarg; break; case 'O': params.override_ctrl_interface = optarg; break; case 'p': iface->driver_param = optarg; break; case 'P': os_free(params.pid_file); params.pid_file = os_rel2abs_path(optarg); break; case 'q': params.wpa_debug_level&#;&#;; break; #ifdef CONFIG_DEBUG_SYSLOG case 's': params.wpa_debug_syslog&#;&#;; break; #endif /* CONFIG_DEBUG_SYSLOG */ #ifdef CONFIG_DEBUG_LINUX_TRACING case 'T': params.wpa_debug_tracing&#;&#;; break; #endif /* CONFIG_DEBUG_LINUX_TRACING */ case 't': params.wpa_debug_timestamp&#;&#;; break; #ifdef CONFIG_DBUS case 'u': params.dbus_ctrl_interface = 1; break; #endif /* CONFIG_DBUS */ case 'v': printf("%sn", wpa_supplicant_version); exitcode = 0; goto out; case 'W': params.wait_for_monitor&#;&#;; break; case 'N': iface_count&#;&#;; iface = os_realloc_array(ifaces, iface_count, sizeof(struct wpa_interface)); if (iface == NULL) goto out; ifaces = iface; iface = &ifaces[iface_count - 1]; os_memset(iface, 0, sizeof(*iface)); break; default: usage(); exitcode = 0; goto out; } } exitcode = 0; global = wpa_supplicant_init(&params); //关键函数,根据传入的参数,创建并初始化一个wpa_global对象 if (global == NULL) { wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant"); exitcode = -1; goto out; } else { wpa_printf(MSG_INFO, "Successfully initialized " "wpa_supplicant"); } for (i = 0; exitcode == 0 && i < iface_count; i&#;&#;) { struct wpa_supplicant *wpa_s; if ((ifaces[i].confname == NULL && ifaces[i].ctrl_interface == NULL) || ifaces[i].ifname == NULL) { if (iface_count == 1 && (params.ctrl_interface || params.dbus_ctrl_interface)) break; usage(); exitcode = -1; break; } wpa_s = wpa_supplicant_add_iface(global, &ifaces[i]); //关键函数,wpa_supplicant支持操作多个无线网络设备,此处需将它们一一添加到wpa_supplicant中,wpa_supplicant内部将初始化这些设备。 if (wpa_s == NULL) { exitcode = -1; break; } #ifdef CONFIG_P2P if (wpa_s->global->p2p == NULL && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) && wpas_p2p_add_p2pdev_interface(wpa_s) < 0) exitcode = -1; #endif /* CONFIG_P2P */ } if (exitcode == 0) exitcode = wpa_supplicant_run(global); //android平台中,wpa_supplicant通过select或epoll或方式实现多路I/O复用。 wpa_supplicant_deinit(global); out: wpa_supplicant_fd_workaround(0); os_free(ifaces); os_free(params.pid_file); os_program_deinit(); return exitcode; } main函数中重要的数据结构struct wpa_interface&#;confname:const char* //该接口对应的配置文件名&#;ctrl_interface: const char* //控制接口unix域socket地址&#;driver:const char* //该接口对应的驱动名&#;driver_param:const char* //该接口对应驱动的参数&#;ifname:const char* //指定网络接口设备名&#;bridge_ifname:const char* //当接口用作桥接设备时,其桥接设备名本例中:confname = "/data/misc/wifi/wpa_supplicant.conf"ifname = "wlan0"driver = "nl"

struct wpa_global&#;ifaces:struct wpa_supplicant* //见下文解释&#;params:struct wpa_params //运行参数&#;ctrl_ifaces:struct ctrl_iface_global_priv* //全局控制接口&#;drv_priv:void** //driver wrapper对应的全局上下文信息&#;drv_count:size_t //driver wrapper的个数

struct ctrl_iface_global_privstruct wpa_supplicant&#;global:struct wpa_global*&#;socket:int&#;global:struct wpa_global*&#;next:struct wpa_supplicant*

(1)wpa_interface用于描述一个无线设备。该参数在初始化时用到。

Android4.4 wpa_supplicant深入分析之wpa_supplicant初始化流程

(2)wpa_global是一个全局性质的上下文信息。它通过ifaces变量指向一个wpa_supplicant对象。

(3)wpa_supplicant是wpa_supplicant的核心数据结构。一个interface对应一个wpa_supplicant对象,其内部包含非常多的成员变量。

(4)ctrl_iface_global_priv是全局控制接口的信息,内部包含一个用于通信的socket句柄。

wpa_supplicant_init函数分析

[-->wpa_supplicant.c::wpa_supplicant_init]

[cpp] view plaincopystruct 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 [cpp] view plaincopy<span style="white-space:pre"> </span>//设置全局回调函数 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();<span style="white-space:pre"> </span>//注册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)); 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->ctrl_interface_group) global->params.ctrl_interface_group = os_strdup(params->ctrl_interface_group); 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); <span style="white-space:pre"> </span>//初始化事件循环机制 if (eloop_init()) { wpa_printf(MSG_ERROR, "Failed to initialize event loop"); wpa_supplicant_deinit(global); return NULL; } <span style="white-space:pre"> </span>//初始化随机数相关资源,用于提升后续随机数生成的随机性 random_init(params->entropy_file); <span style="white-space:pre"> </span>//初始化全局控制接口对象 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; } <span style="white-space:pre"> </span>//wpa_driver是一个全局变量。 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; } [cpp] view plaincopy<span style="white-space:pre"> </span>//分配全局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_DISPLAY if (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事件循环机制以及设置消息全局回调函数。

(1)wpa_msg_get_ifname_func:有些输出信息中需要打印出网卡接口名。该回调函数用于获取网卡接口名。

(2)wpa_msg_cb_func:除了打印输出信息外,还可通过该回调函数进行一些特殊处理,如把输出信息发送给客户端进行处理。

[-->wpa_debug.c]

[cpp] view plaincopyvoid wpa_msg_register_cb(wpa_msg_cb_func func) { wpa_msg_cb = func; } static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL; [cpp] view plaincopystatic 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函数、eloop_init函数及event loop模块、wpa_drivers数组和driver i/f模块

1、eap_register_method函数

主要根据编译时的配置项来初始化不同的eap方法。

[-->eap-register.c::eap_register_methods]

[cpp] view plaincopyint eap_register_methods(void) { int ret = 0; #ifdef EAP_MD5<span style="white-space:pre"> </span>//作为supplicant端,编译时将定义EAP_MD5 if (ret == 0) ret = eap_peer_md5_register(); #endif /* EAP_MD5 */ #ifdef EAP_TLS if (ret == 0) ret = eap_peer_tls_register(); #endif /* EAP_TLS */ #ifdef EAP_UNAUTH_TLS if (ret == 0) ret = eap_peer_unauth_tls_register(); #endif /* EAP_UNAUTH_TLS */ #ifdef EAP_MSCHAPv2 if (ret == 0) ret = eap_peer_mschapv2_register(); #endif /* EAP_MSCHAPv2 */ #ifdef EAP_PEAP if (ret == 0) ret = eap_peer_peap_register(); #endif /* EAP_PEAP */ #ifdef EAP_TTLS if (ret == 0) ret = eap_peer_ttls_register(); #endif /* EAP_TTLS */ #ifdef EAP_GTC if (ret == 0) ret = eap_peer_gtc_register(); #endif /* EAP_GTC */ #ifdef EAP_OTP if (ret == 0) ret = eap_peer_otp_register(); #endif /* EAP_OTP */ #ifdef EAP_SIM if (ret == 0) ret = eap_peer_sim_register(); #endif /* EAP_SIM */ #ifdef EAP_LEAP if (ret == 0) ret = eap_peer_leap_register(); #endif /* EAP_LEAP */ #ifdef EAP_PSK if (ret == 0) ret = eap_peer_psk_register(); #endif /* EAP_PSK */ #ifdef EAP_AKA if (ret == 0) ret = eap_peer_aka_register(); #endif /* EAP_AKA */ #ifdef EAP_AKA_PRIME if (ret == 0) ret = eap_peer_aka_prime_register(); #endif /* EAP_AKA_PRIME */ #ifdef EAP_FAST if (ret == 0) ret = eap_peer_fast_register(); #endif /* EAP_FAST */ #ifdef EAP_PAX if (ret == 0) ret = eap_peer_pax_register(); #endif /* EAP_PAX */ #ifdef EAP_SAKE if (ret == 0) ret = eap_peer_sake_register(); #endif /* EAP_SAKE */ #ifdef EAP_GPSK if (ret == 0) ret = eap_peer_gpsk_register(); #endif /* EAP_GPSK */ #ifdef EAP_WSC if (ret == 0) ret = eap_peer_wsc_register(); #endif /* EAP_WSC */ #ifdef EAP_IKEV2 if (ret == 0) ret = eap_peer_ikev2_register(); #endif /* EAP_IKEV2 */ #ifdef EAP_VENDOR_TEST if (ret == 0) ret = eap_peer_vendor_test_register(); #endif /* EAP_VENDOR_TEST */ #ifdef EAP_TNC if (ret == 0) ret = eap_peer_tnc_register(); #endif /* EAP_TNC */ #ifdef EAP_PWD if (ret == 0) ret = eap_peer_pwd_register(); #endif /* EAP_PWD */ #ifdef EAP_EKE if (ret == 0) ret = eap_peer_eke_register(); #endif /* EAP_EKE */ #ifdef EAP_SERVER_IDENTITY if (ret == 0) ret = eap_server_identity_register(); #endif /* EAP_SERVER_IDENTITY */ #ifdef EAP_SERVER_MD5<span style="white-space:pre"> </span>//作为Authenticator端,编译时将定义EAP_SERVER_MD5 if (ret == 0) ret = eap_server_md5_register(); #endif /* EAP_SERVER_MD5 */ #ifdef EAP_SERVER_TLS if (ret == 0) ret = eap_server_tls_register(); #endif /* EAP_SERVER_TLS */ #ifdef EAP_SERVER_UNAUTH_TLS if (ret == 0) ret = eap_server_unauth_tls_register(); #endif /* EAP_SERVER_UNAUTH_TLS */ #ifdef EAP_SERVER_MSCHAPV2 if (ret == 0) ret = eap_server_mschapv2_register(); #endif /* EAP_SERVER_MSCHAPV2 */ #ifdef EAP_SERVER_PEAP if (ret == 0) ret = eap_server_peap_register(); #endif /* EAP_SERVER_PEAP */ #ifdef EAP_SERVER_TLV if (ret == 0) ret = eap_server_tlv_register(); #endif /* EAP_SERVER_TLV */ #ifdef EAP_SERVER_GTC if (ret == 0) ret = eap_server_gtc_register(); #endif /* EAP_SERVER_GTC */ #ifdef EAP_SERVER_TTLS if (ret == 0) ret = eap_server_ttls_register(); #endif /* EAP_SERVER_TTLS */ #ifdef EAP_SERVER_SIM if (ret == 0) ret = eap_server_sim_register(); #endif /* EAP_SERVER_SIM */ #ifdef EAP_SERVER_AKA if (ret == 0) ret = eap_server_aka_register(); #endif /* EAP_SERVER_AKA */ #ifdef EAP_SERVER_AKA_PRIME if (ret == 0) ret = eap_server_aka_prime_register(); #endif /* EAP_SERVER_AKA_PRIME */ #ifdef EAP_SERVER_PAX if (ret == 0) ret = eap_server_pax_register(); #endif /* EAP_SERVER_PAX */ #ifdef EAP_SERVER_PSK if (ret == 0) ret = eap_server_psk_register(); #endif /* EAP_SERVER_PSK */ #ifdef EAP_SERVER_SAKE if (ret == 0) ret = eap_server_sake_register(); #endif /* EAP_SERVER_SAKE */ #ifdef EAP_SERVER_GPSK if (ret == 0) ret = eap_server_gpsk_register(); #endif /* EAP_SERVER_GPSK */ #ifdef EAP_SERVER_VENDOR_TEST if (ret == 0) ret = eap_server_vendor_test_register(); #endif /* EAP_SERVER_VENDOR_TEST */ #ifdef EAP_SERVER_FAST if (ret == 0) ret = eap_server_fast_register(); #endif /* EAP_SERVER_FAST */ #ifdef EAP_SERVER_WSC if (ret == 0) ret = eap_server_wsc_register(); #endif /* EAP_SERVER_WSC */ #ifdef EAP_SERVER_IKEV2 if (ret == 0) ret = eap_server_ikev2_register(); #endif /* EAP_SERVER_IKEV2 */ #ifdef EAP_SERVER_TNC if (ret == 0) ret = eap_server_tnc_register(); #endif /* EAP_SERVER_TNC */ #ifdef EAP_SERVER_PWD if (ret == 0) ret = eap_server_pwd_register(); #endif /* EAP_SERVER_PWD */ return ret; } 2、eloop_init函数及event loop模块

初始化了wpa_supplicant中事件驱动的核心数据结构体

从事件角度来看,wpa_supplicant的事件驱动机制支持5中类型event:

(1)read event:读事件,例如来自socket的可读事件

(2)write event:写事件

(3)exception event:异常事件

(4)timeout event:定时事件

(5)signal:信号时间,信号时间来源于Kernel。

[-->eloop.c::eloop_run]

[cpp] view plaincopyvoid eloop_run(void) { #ifdef CONFIG_ELOOP_POLL int num_poll_fds; int timeout_ms = 0; #else /* CONFIG_ELOOP_POLL */ fd_set *rfds, *wfds, *efds; struct timeval _tv; #endif /* CONFIG_ELOOP_POLL */ int res; struct os_time tv, now; #ifndef CONFIG_ELOOP_POLL 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_POLL */ <span style="white-space:pre"> </span>//事件驱动循环 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; #ifdef CONFIG_ELOOP_POLL timeout_ms = tv.sec * &#; tv.usec / ; #else /* CONFIG_ELOOP_POLL */ _tv.tv_sec = tv.sec; _tv.tv_usec = tv.usec; #endif /* CONFIG_ELOOP_POLL */ } #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); if (res < 0 && errno != EINTR && errno != 0) { perror("poll"); goto out; } #else /* CONFIG_ELOOP_POLL */ eloop_sock_table_set_fds(&eloop.readers, rfds); eloop_sock_table_set_fds(&eloop.writers, wfds); eloop_sock_table_set_fds(&eloop.exceptions, efds); res = select(eloop.max_sock &#; 1, rfds, wfds, efds, timeout ? &_tv : NULL); if (res < 0 && errno != EINTR && errno != 0) { perror("select"); goto out; } #endif /* CONFIG_ELOOP_POLL */ eloop_process_pending_signals();<span style="white-space:pre"> </span>//先处理信号事件 /* check if some registered timeouts have occurred */ 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); } } 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); #else /* CONFIG_ELOOP_POLL */ eloop_sock_table_dispatch(&eloop.readers, rfds); eloop_sock_table_dispatch(&eloop.writers, wfds); eloop_sock_table_dispatch(&eloop.exceptions, efds); #endif /* CONFIG_ELOOP_POLL */ } eloop.terminate = 0; out: #ifndef CONFIG_ELOOP_POLL os_free(rfds); os_free(wfds); os_free(efds); #endif /* CONFIG_ELOOP_POLL */ return; } eloop_run中的while循环是wpa_supplicant进程的运行中枢。

3、wpa_drivers数组和driver i/f模块

wpa_drivers是一个全局数组变量,它通过extern方式声明于main.c中,其定义却在drivers.c:

[-->drivers.c::wpa_drivers定义]

[cpp] view plaincopystruct wpa_driver_ops *wpa_drivers[] = { #ifdef CONFIG_DRIVER_NL &wpa_driver_nl_ops, #endif /* CONFIG_DRIVER_NL */ #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_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_drivers数组成员指向一个wpa_driver_ops类型的对象。wpa_driver_ops是driver i/f模块的核心数据结构,其内部定义了很多函数指针。

[-->driver_nl.c::wpa_driver_nl_ops]

[cpp] view plaincopyconst struct wpa_driver_ops wpa_driver_nl_ops = { .name = "nl", .desc = "Linux nl/cfg", .get_bssid = wpa_driver_nl_get_bssid, .get_ssid = wpa_driver_nl_get_ssid, .set_key = driver_nl_set_key, .scan2 = driver_nl_scan2, .sched_scan = wpa_driver_nl_sched_scan, .stop_sched_scan = wpa_driver_nl_stop_sched_scan, .get_scan_results2 = wpa_driver_nl_get_scan_results, .deauthenticate = driver_nl_deauthenticate, .authenticate = driver_nl_authenticate, .associate = wpa_driver_nl_associate, .global_init = nl_global_init, .global_deinit = nl_global_deinit, .init2 = wpa_driver_nl_init, .deinit = driver_nl_deinit, .get_capa = wpa_driver_nl_get_capa, .set_operstate = wpa_driver_nl_set_operstate, .set_supp_port = wpa_driver_nl_set_supp_port, .set_country = wpa_driver_nl_set_country, .set_ap = wpa_driver_nl_set_ap, .set_acl = wpa_driver_nl_set_acl, .if_add = wpa_driver_nl_if_add, .if_remove = driver_nl_if_remove, .send_mlme = driver_nl_send_mlme, .get_hw_feature_data = wpa_driver_nl_get_hw_feature_data, .sta_add = wpa_driver_nl_sta_add, .sta_remove = driver_nl_sta_remove, .hapd_send_eapol = wpa_driver_nl_hapd_send_eapol, .sta_set_flags = wpa_driver_nl_sta_set_flags, #ifdef HOSTAPD .hapd_init = i_init, .hapd_deinit = i_deinit, .set_wds_sta = i_set_wds_sta, #endif /* HOSTAPD */ #if defined(HOSTAPD) || defined(CONFIG_AP) .get_seqnum = i_get_seqnum, .flush = i_flush, .get_inact_sec = i_get_inact_sec, .sta_clear_stats = i_sta_clear_stats, .set_rts = i_set_rts, .set_frag = i_set_frag, .set_tx_queue_params = i_set_tx_queue_params, .set_sta_vlan = driver_nl_set_sta_vlan, .sta_deauth = i_sta_deauth, .sta_disassoc = i_sta_disassoc, #endif /* HOSTAPD || CONFIG_AP */ .read_sta_data = driver_nl_read_sta_data, .set_freq = i_set_freq, .send_action = driver_nl_send_action, .send_action_cancel_wait = wpa_driver_nl_send_action_cancel_wait, .remain_on_channel = wpa_driver_nl_remain_on_channel, .cancel_remain_on_channel = wpa_driver_nl_cancel_remain_on_channel, .probe_req_report = driver_nl_probe_req_report, .deinit_ap = wpa_driver_nl_deinit_ap, .deinit_p2p_cli = wpa_driver_nl_deinit_p2p_cli, .resume = wpa_driver_nl_resume, .send_ft_action = nl_send_ft_action, .signal_monitor = nl_signal_monitor, .signal_poll = nl_signal_poll, .send_frame = nl_send_frame, .shared_freq = wpa_driver_nl_shared_freq, .set_param = nl_set_param, .get_radio_name = nl_get_radio_name, .add_pmkid = nl_add_pmkid, .remove_pmkid = nl_remove_pmkid, .flush_pmkid = nl_flush_pmkid, .set_rekey_info = nl_set_rekey_info, .poll_client = nl_poll_client, .set_p2p_powersave = nl_set_p2p_powersave, .start_dfs_cac = nl_start_radar_detection, .stop_ap = wpa_driver_nl_stop_ap, #ifdef CONFIG_TDLS .send_tdls_mgmt = nl_send_tdls_mgmt, .tdls_oper = nl_tdls_oper, #endif /* CONFIG_TDLS */ .update_ft_ies = wpa_driver_nl_update_ft_ies, .get_mac_addr = wpa_driver_nl_get_macaddr, .get_survey = wpa_driver_nl_get_survey, #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 #ifdef ANDROID .driver_cmd = wpa_driver_nl_driver_cmd, #endif }; 待续。。。

Android 本地文件读取, 数据库文件备份 众所周知Android有一套自己的安全模型,具体可参见Android开发文档。当应用程序(.apk)在安装时就会分配一个userid,当该应用要去访问其他资源比如文件的

Android——SharedPreferences实现登录界面的记住密码和自动登录功能 一、项目开发1、项目运行效果图2、开发概要主要功能SharedPreferences介绍,其是Android平台上一个轻量级的存储类,用来保存应用的一些常用配置,比如Act

俩个时间戳相减 importjava.text.ParseException;importjava.text.SimpleDateFormat;importjava.util.Date;/***俩个时间戳相减*年6月8日::*@authorcfs*/publicclasstestTime{publicstaticvoidmain(String[]args

标签: Android4.4 wpa_supplicant深入分析之wpa_supplicant初始化流程

本文链接地址:https://www.jiuchutong.com/biancheng/384209.html 转载请保留说明!

上一篇:android-MAT使用(android mat)

下一篇:Android 本地文件读取, 数据库文件备份(Android本地文件怎么显示歌词)

  • 增值税加计抵减的行业
  • 中华人民共和国国歌
  • 新个税年终奖计算公式
  • 增值税上月多交税本月怎么办
  • 代收款是什么套路
  • 主表第17栏应该等于定期
  • 开具了红字发票信息表的税额需要转出吗
  • 零食发票能抵税吗
  • 质量问题产生的影响
  • 月末应付职工薪酬计算方法
  • 以前年度亏损本季度盈利所得税申报
  • 记账凭证一定要签字吗
  • 应纳税额计算举例
  • 营改增通知及有关部门规定的税收优惠政策
  • 小规模纳税人开了3%的专票还能享受1%
  • 建筑安装施工过程
  • 个人股票期权收益所得税怎么缴纳?
  • 某房产开发公司向银行借款
  • Google Bard VS ChatGPT:哪个是更好的AI聊天机器人?
  • 以前年度损益调整怎么做账
  • 计提房租费
  • 子公司代总公司付款
  • 什么情况下出租人可以解除合同
  • 公司租的宿舍记什么科目
  • 荣耀x10的鸿蒙系统怎么开启
  • 私立医院交所得税吗
  • 公司劳务费收入涉及哪些税
  • frameworkservic.exe是什么进程 有什么作用 frameworkservic进程查询
  • 桌面图标归纳
  • 辞退补偿金额怎么做账
  • 租赁公司经营项目
  • 冲减其他应收款摘要怎么写
  • 产品设计费增值税怎么算
  • 巴黎先贤祠的名言
  • 委托加工物资账务怎么做
  • 车辆购置税税收缴款书
  • 集群怎么写
  • php访问数据库的方式
  • vue开发环境和生产环境域名配置
  • ptech模型
  • 长期待摊费用为负数怎么调整
  • 为etc充值
  • 贷款和应收款项属于金融资产的哪类
  • 收到上市公司分红企业所得税减半征收的情景
  • 农产品进项税抵扣填报方法
  • 公司注册资金多好还是少好
  • 基本生产成本和辅助生产成本区别
  • 不想预缴所得税交多了怎样先把利润转到费用
  • python解释器的多种使用
  • 我的Vue之旅 11 Vuex 实现购物车
  • javascript基础笔记
  • sqlserver存储过程if语句
  • 如何在sql server中建立一个表
  • 咨询费收入成本怎么算
  • 异地学校
  • 对外投资需要股东会决议吗
  • 购货方收到销售方提供的发票怎么做分录
  • 房地产企业收到政府土地补偿款如何入账
  • 企业发生坏账损失时,在当期确认坏账损失
  • 自产的产品用于生产缴纳增值税
  • 长期待摊费用的最新账务处理
  • 收到稳岗补贴要交税吗
  • 工资流水贷款需要什么手续
  • 收到技术服务费计入什么科目
  • mysql在指定字段前添加
  • 在linux操作系统中,/etc/rc.d/init.d
  • Ubuntu远程桌面连接
  • ubuntu20.04关闭图形界面命令
  • win8怎么恢复出厂设置找不到恢复环境
  • 遍历enumeration
  • css并集
  • python利用csv模块在对csv文件进行操作
  • pymysql作用
  • python写邮箱
  • bootstrap快速入门
  • 简单谈谈你对中国国防建设的认识
  • Dojo Javascript 编程规范 规范自己的JavaScript书写
  • jquery对象与dom对象可以相互转换
  • 哪些可以享受三免一补
  • A级纳税人和一般纳税人区别
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设