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

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

service wpa_supplicant /system/bin/wpa_supplicant \
    -iwlan0 -Dnl80211 -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 660 wifi wifi
    disabled
    oneshot
以上众多启动参数中,最重要的是通过“-c“参数制定的wpa_supplicant启动配置文件。
ctrl_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=10-0050F204-5
config_methods=physical_display virtual_push_button
p2p_listen_reg_class=81
p2p_listen_channel=11
p2p_oper_reg_class=81
p2p_oper_channel=11
p2p_ssid_postfix=-Android_7006
persistent_reconnect=1

network={
	ssid="AP_5D34E3"
	psk="12345678"
	key_mgmt=WPA-PSK
	priority=1
}

network={
	ssid="Android-02"
	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]

int 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("%s\n", 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 = "nl80211"





 

 

 


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用于描述一个无线设备。该参数在初始化时用到。

(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]

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
<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;
	}
<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]

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;
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函数、eloop_init函数及event loop模块、wpa_drivers数组和driver i/f模块

1、eap_register_method函数

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

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

int 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]

void 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 * 1000 + tv.usec / 1000;
#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定义]

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_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_nl80211.c::wpa_driver_nl80211_ops]

const struct wpa_driver_ops wpa_driver_nl80211_ops = {
	.name = "nl80211",
	.desc = "Linux nl80211/cfg80211",
	.get_bssid = wpa_driver_nl80211_get_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,
	.associate = wpa_driver_nl80211_associate,
	.global_init = nl80211_global_init,
	.global_deinit = nl80211_global_deinit,
	.init2 = wpa_driver_nl80211_init,
	.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,
	.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,
#ifdef HOSTAPD
	.hapd_init = i802_init,
	.hapd_deinit = i802_deinit,
	.set_wds_sta = i802_set_wds_sta,
#endif /* HOSTAPD */
#if defined(HOSTAPD) || defined(CONFIG_AP)
	.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,
#endif /* HOSTAPD || CONFIG_AP */
	.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,
#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_nl80211_driver_cmd,
#endif
};

待续。。。


  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值