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(¶ms); //关键函数,根据传入的参数,创建并初始化一个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_priv | struct 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
//设置全局回调函数
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));
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);
//初始化事件循环机制
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_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;
}
//分配全局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 //作为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 //作为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 */
//事件驱动循环
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(); //先处理信号事件
/* 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
};