wpa_supplicant初始化关键函数
2014-07-29 09:59 白居不易 阅读(1605) 评论(0) 编辑 收藏 举报1. wpa_supplicant_init()
初始化成功后,返回的wpa_global指针可用于添加删除接口,最后,deinit wpa_supplicant。
传入的参数为命令行输入的接口无关的参数wpa_params。
一、main()
1、 wpa_supplicant的入口函数在external\wpa_supplicant\main.c里面,入口main()。
2、 main()函数里申明的结构体中,
wpa_global为最重要的结构体,是wpa_supplicant的全局数据结构;
wpa_interface结构体是wpa_supplicant_add_iface()函数为wpa_supplicant增加网络接口时要用到的接口配置选项,该函数的具体功能在函数申明(external\wpa_supplicant\wpa_supplicant.c)时有具体的解释;
wpa_params结构体是wpa_supplicant_init()函数为初始化wpa_supplicant时要使用的参数,该函数的具体功能在函数申明(external\wpa_supplicant\wpa_supplicant.c)时有具体的解释。
3、 main()函数主要做了四个工作:
a、根据命令行参数设置wpa_params结构体;
b、调用wpa_supplicant_init()函数初始化wpa_supplicant;
c、调用wpa_supplicant_add_iface()函数为wpa_supplicant增加网络接口;
d、调用wpa_supplicant_run()让wpa_supplicant跑起来。
二、wpa_supplicant_init ()
1、 该函数位于external\wpa_supplicant\wpa_supplicant.c文件下,用于初始化wpa_supplicant。
2、 调用eap_peer_register_methods()注册eap方法,EAP(Extensible Authentication Protocol)是可扩展身份验证协议的简称。代码中的解释为:This function is called at program initialization to register all EAP peer methods that were linked in statically。
3、 通过main()函数中传入的参数初始化global结构体。
4、 调用eloop_init()将初始化好的global结构体传给eloop结构体,该结构体是一个全局变量,存储了很多event loop循环需要使用的信息。
5、 调用wpa_supplicant_global_ctrl_iface_init()函数建立global控制接口,该函数建立一个socket,然后与初始化global结构体时给出的params.ctrl.interface参数进行连接,连接成功之后注册到eloop循环中,从而建立两个进程之间的通信。这是wpa_supplicant与外部进程建立的第一个通信通道,主要用于增加或删除网络接口。
6、 调用wpa_supplicant_dbus_ctrl_iface_init()函数建立dbus进程间通讯接口,该函数首先通过调用dbus_bus_get()函数获得系统总线引用,然后调用integrate_with_eloop()告诉dbus 设置eloop循环相关的处理函数(比如增加删除之类,dbus的socket也是在这些处理函数中建立的),之后调用dbus_connection_register_object_path()函数为dbus接口注册消息处理函数,最后调用dbus_bus_request_name()函数将该dbus注册为消息服务bus。函数在退出之前通过调用eloop_register_timeout()函数将处理函数添加进入eloop循环,注意这个注册是采用timeout的形式,原因可能是不想太早初始化这个dbus,因为这个时候eloop还没有启动,如果过早初始化,会导致别的进程使用,会出问题。这是wpa_supplicant与外部进程建立的第二个通信通道,主要用于处理dbus通信。
7、 调用wpa_supplicant_daemon()函数将该守护进程的pid写入pid_file中。
三、wpa_supplicant_add_iface()
1、该函数为wpa_supplicant增加网络接口,并且支持热插拔。
2、调用wpa_supplicant_init_iface()函数:
a、调用wpa_supplicant_set_driver()函数设置驱动函数;
b、读取配置文件信息,保存到结构体wpa_s->confname中,再分析配置参数,将分析结果保存到wpa_s->conf中;
c、检查命令行参数中是否设置了wpa_s->conf,如果设置,就用命令行设置的参数覆盖以上b中用配置文件设置的参数;
d、拷贝网络接口名称和桥接口名称到wpa_s结构体。
3、调用wpa_supplicant_init_iface2()函数:
a、调用wpa_supplicant_init_eapol()函数初始化eapol,该认证采用状态机的风格,在eloop循环中,设置定时器来定时更新eapol的认证状态,实现接入网络的认证;
b、调用wpa_drv_init()函数初始化网络驱动,该函数进一步调用在上述中由wpa_supplicant_set_driver()函数加载的驱动的.init函数,由于wpa_supplicant需要和内核进行socket通信,这个socket的建立和注册到eloop循环就在这个地方;这是wpa_supplicant与外部进程建立的第三个通信通道,主要用于与kernel交换数据;
c、调用wpa_drv_get_ifname()函数获得网络接口名称;
d、调用wpa_supplicant_init_wpa()函数初始化wpa;
e、调用wpa_supplicant_driver_init()函数初始化驱动接口,该函数会调用l2_packet_init()函数建立与802.1x进行报文通讯的socket,并注册到eloop循环中,这是wpa_supplicant与外部进程建立的第四个通信通道,主要用于处理802.1x报文;最后调用wpa_supplicant_req_scan()函数在指定时间之后发起scan;
f、调用wpa_supplicant_ctrl_iface_init()函数初始化控制接口,该函数建立与HAL层通信的socket,并注册到eloop循环,这是wpa_supplicant与外部进程建立的第五个通信通道,主要用于接受WIFI HAL层的控制。
四、wpa_supplicant_run()
1、该函数主要功能是启动eloop循环;
2、注册结束函数和重新配置函数;
3、调用eloop_run()进入循环,该循环通过select()机制,检测socket信号量并处理,并处理定时事件。
/** * wpa_supplicant_init - Initialize %wpa_supplicant * @params: Parameters for %wpa_supplicant * Returns: Pointer to global %wpa_supplicant data, or %NULL on failure * * This function is used to initialize %wpa_supplicant. After successful * initialization, the returned data pointer can be used to add and remove * network interfaces, and eventually, to deinitialize %wpa_supplicant. */ struct wpa_global * wpa_supplicant_init(struct wpa_params *params) { struct wpa_global *global; int ret, i; …… #ifndef CONFIG_NO_WPA_MSG wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);// 注册回调函数,获取当前ifname #endif /* CONFIG_NO_WPA_MSG */ …… ret = eap_register_methods();// 注册eap(Extensible Authentication Protocol)方法。 global = os_zalloc(sizeof(*global)); 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; global->params.pid_file = os_strdup(params->pid_file); global->params.ctrl_interface = os_strdup(params->ctrl_interface); global->params.override_driver = os_strdup(params->override_driver); 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; 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; } 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; } 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; }