您的位置:首页 > 移动开发 > Android开发

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

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

[cpp] view
plain copy







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启动配置文件。

[cpp] view
plain copy







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]

[cpp] view
plain copy







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

[cpp] view
plain copy







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

[cpp] view
plain copy







<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
plain copy







<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
plain copy







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;

[cpp] view
plain copy







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]

[cpp] view
plain copy







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]

[cpp] view
plain copy







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定义]

[cpp] view
plain copy







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]

[cpp] view
plain copy







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

};

待续。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: