这一章主要进行wpa_supplicant_init函数的分析
struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
{
struct wpa_global *global;
//设置全局回调函数
wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
//设置输出到文件或终端
if (params->wpa_debug_file_path)
wpa_debug_open_file(params->wpa_debug_file_path);
else
wpa_debug_setup_stdout();
//注册EAP
ret = eap_register_methods();
//创建一个global对象
global = os_zalloc(sizeof(*global));
dl_list_init(&global->p2p_srv_bonjour);
dl_list_init(&global->p2p_srv_upnp);
//事件循环机制初始化
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;
}
//初始化通知机制相关资源,和dbug有关
if (wpas_notify_supplicant_initialized(global)) {
wpa_supplicant_deinit(global);
return NULL;
}
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_calloc(global->drv_count, sizeof(void *));
if (global->drv_priv == NULL) {
wpa_supplicant_deinit(global);
return NULL;
}
// 注册超时
eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
wpas_periodic, global, NULL);
return global;
}
分析函数可知wpa_supplicant_init函数的主要功能是初始化wpa_global以及相关资源,包括注册EAP,事件循环,回调函数处理
int eap_register_methods(void)
{
int ret = 0;
#ifdef 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_TLS
#ifdef CONFIG_HS20
if (ret == 0)
ret = eap_peer_wfa_unauth_tls_register();
#endif /* CONFIG_HS20 */
#endif /* EAP_TLS */
....
return ret;
}
根据不同的编译选项来注册所需要的eap method。 例如 MD5身份验证对应的注册函数eap_peer_md5_register。该函数内部将填充一个eap_method的数据结构
int eloop_init(void)
{
os_memset(&eloop, 0, sizeof(eloop));
dl_list_init(&eloop.timeout);
// epoll 创建
eloop.epollfd = epoll_create1(0);
// 队列 创建
eloop.kqueuefd = kqueue();
// 指定eloop 读写事件类型
eloop.readers.type = EVENT_TYPE_READ;
eloop.writers.type = EVENT_TYPE_WRITE;
eloop.exceptions.type = EVENT_TYPE_EXCEPTION;
//信号捕获
signal(SIGSEGV, eloop_sigsegv_handler);
return 0;
}
函数采用epoll实现了I/O复用,并指定了一些事件类型
wpa_drivers 是一个全局数据变量,定义在drivers.c中如下所示
const struct wpa_driver_ops *const 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 */
... 其他driver接口
};
wpa_drivers定义
const struct wpa_driver_ops *const wpa_drivers[] = { NULL };
wpa_drivers 数组成员指向一个wpa_driver_ops类型对象,其中wpa_driver_ops是driver i/f 模块的核心数据结构,内部定义了很多函数指针,正是通过定义函数指针的方法wpa_supplicant能够隔离上层使用者和具体的drivers。
wpa_driver_ops原型定义如下
struct wpa_driver_ops {
/** Name of the driver interface */
const char *name;
/** One line description of the driver interface */
const char *desc;
int (*get_bssid)(void *priv, u8 *bssid);
int (*get_ssid)(void *priv, u8 *ssid);
int (*set_key)(const char *ifname, void *priv, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len);
void * (*init)(void *ctx, const char *ifname);
.... //其它函数指针
}
wpa_drivers 数据包含多个drivers wrapper对象是由编译选项来控制的,如代码中的CONFIG_DRIVER_NL80211,可在defconfig修改
wpa_driver_nl80211_ops的定义
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
//名称
.name = "nl80211",
//描述信息
.desc = "Linux nl80211/cfg80211",
//获取bssid
.get_bssid = wpa_driver_nl80211_get_bssid,
//获取ssid
.get_ssid = wpa_driver_nl80211_get_ssid,
//扫描
.scan2 = driver_nl80211_scan2,
//获取扫描结果
.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
//触发deauthenticate操作
.deauthenticate = driver_nl80211_deauthenticate,
//触发authenticat操作
.authenticate = driver_nl80211_authenticate,
//触发associate操作
.associate = wpa_driver_nl80211_associate,
//全局初始化,返回值保存在wpa_global成员变量drv_pri数组中
.global_init = nl80211_global_init,
.global_deinit = nl80211_global_deinit,
....
// 处理和具体驱动相关的命令
.driver_cmd = wpa_driver_nl80211_driver_cmd,
};
本文介绍了main函数中一个关键函数wpa_supplicant_init。其中涉及重要的数据结构,如wpa_drivers_ops,eap_method等,由于这一节只是初步介绍了event的初始化,下一节重点介绍
event_loop的工作原理,这也是wpa_supplicant的事件核心点。