wpa_supplicant软件架构分析
1.启动命令 wpa supplicant在启动时,启动命令可以带有很多参数,目前我们的启动命令 如下: wpa_supplicant /system/bin/wpa_supplicant -Dwext -ieth0 -c/data/wifi/wpa_supplicant.conf -f/data/wifi/wpa_log.txt wpa_supplicant 对于启动命令带的参数,用了两个数据结构来保存, 一个是 wpa_params,另一个是 wpa_interface. 这主要是考虑到 wpa_supplicant 是可以同时支持多个网络接口的。 wpa_params 数据结构主要记录与网络接口无关的一些参数设置。 而每一个网络接口就用一个 wpa_interface 数据结构来记录。 在启动命令行中,可以用-N 来指定将要描述一个新的网络接口,对于一个新 的网络接口,可以用下面六个参数描述: -i :网络接口名称 -c:配置文件名称 -C:控制接口名称 -D:驱动类型 -p:驱动参数 -b:桥接口名称 2. wpa_supplicant 初始化流程 2.1. main()函数: 在这个函数中,主要做了四件事。 a.解析命令行传进的参数。 b.调用 wpa_supplicant_init()函数,做 wpa_supplicant 的初始化工作。 c.调用 wpa_supplicant_add_iface()函数,增加网络接口。 d.调用 wpa_supplicant_run()函数,让 wpa_supplicant 真正的 run 起来。 2.2. wpa_supplicant_init()函数: a.打开 debug 文件。 b.注册 EAP peer 方法。 c.申请 wpa_global 内存,该数据结构作为统领其他数据结构的一个核心, 主 要包括四个部分: wpa_supplicant *ifaces /*每个网络接口都有一个对应的 wpa_supplicant 数据 结构,该指针指向最近加入的一个,在 wpa_supplicant 数据结构中有指针指 向 next*/ wpa_params params /*启动命令行中带的通用的参数*/ ctrl_iface_global_priv *ctrl_iface /*global 的控制接口*/ ctrl_iface_dbus_priv *dbus_ctrl_iface /*dbus的控制接口*/ d.设置 wpa_global 中的 wpa_params 中的参数。 e.调用 eloop_init 函数将全局变量 eloop 中的 user_data指针指向 wpa_global。 f.调用 wpa_supplicant_global_ctrl_iface_init 函数初始化 global 控制接口。 g.调用 wpa_supplicant_dbus_ctrl_iface_init函数初始化 dbus 控制接口。 h.将该 daemon 的 pid 写入 pid_file 中。 2.3. wpa_supplicant_add_iface()函数: 该函数根据启动命令行中带有的参数增加网络接口,有几个就增加几个。 a.因为 wpa_supplicant 是与网络接口对应的重要的数据结构,所以,首先分配 一个 wpa_supplicant数据结构的内存。 b.调用 wpa_supplicant_init_iface()函数来做网络接口的初始工作,主要包括: 设置驱动类型,默认是 wext; 读取配置文件,并将其中的信息设置到 wpa_supplicant 数据结构中的 conf 指 针指向的数据结构,它是一个 wpa_config 类型; 命令行设置的控制接口ctrl_interface和驱动参数driver_param覆盖配置文件里 设置,命令行中的优先; 拷贝网络接口名称和桥接口名称到 wpa_config 数据结构; 对于网络配置块有两个链表描述它, 一个是 config-ssid,它按照配置文件中的 顺序依次挂载在这个链表上,还有一个是 pssid,它是一个二级指针,指向一 个指针数组, 该指针数组按照优先级从高到底的顺序依次保存 wpa_ssid 指针, 相同优先级的在同一链表中挂载。 c.调用 wpa_supplicant_init_iface2()函数,主要包括: 调用 wpa_supplicant_init_eapol()函数来初始化 eapol; 调用相应类型的 driver 的 init()函数; 设置 driver 的 param 参数; 调用wpa_drv_get_ifname()函数获得网络接口的名称, 对于wext类型的driver, 没有这个接口函数; 调用 wpa_supplicant_init_wpa()函数来初始化 wpa,并做相应的初始化工作; 调用 wpa_supplicant_driver_init()函数,来初始化 driver 接口参数;在该函数 的最后,会 wpa_s-prev_scan_ssid = BROADCAST_SSID_SCAN; wpa_supplicant_req_scan(wpa_s, interface_count, 100000); 来主动发起 scan, 调用 wpa_supplicant_ctrl_iface_init()函数,来初始化控制接口;对于 UNIX SOCKET 这种方式,其本地 socket 文件是由配置文件里的 ctrl_interface 参数 指定的路径加上网络接口名称; 2.4. wpa_supplicant_run()函数: 初始化完成之后,让 wpa_supplicant 的 main event loop run 起来。 在 wpa_supplicant 中, 有许多与外界通信的 socket, 它们都是需要注册到 eloop event 模块中的,具体地说,就是在 eloop_sock_table 中增加一项记录,其中 包括了 sock_fd, handle, eloop_data, user_data。 eloop event 模块就是将这些 socket 组织起来,统一管理,然后在 eloop_run 中 利用 select 机制来管理 socket 的通信。 3.Wpa_supplicant 提供的接口 从通信层次上划分,wpa_supplicant 提供向上的控制接口 control interface,用 于与其他模块(如 UI)进行通信,其他模块可以通过 control interface 来获取 信息或下发命令。Wpa_supplicant 通过 socket 通信机制实现下行接口,与内 核进行通信,获取信息或下发命令。 3.1上行接口 Wpa_supplicant提供两种方式的上行接口。一种基于传统 dbus 机制实现与其 他进程间的 IPC 通信;另一种通过 Unix domain socket 机制实现进程间的 IPC 通信。 3.1.1 Dbus 接口 该 接 口 主 要 在 文 件 “ctrl_ifa