1.系统架构
Android WiFi系统引入了wpa_supplicant,它的整个WiFi系统以wpa_supplicant为核心来定义上层用户接口和下层驱动接口。整个WiFi系统架构如下图所示:
1.1 WifiService
由SystemServer启动的时候生成的ConnecttivityService创建,负责启动关闭wpa_supplicant,启动和关闭WifiMonitor线程,把命令下发给wpa_supplicant以及更新WIFI的状态。
处理其它模块通过IWifiManager接口发送过来的远端WiFi操作。
1.2 WifiMonitor
负责从wpa_supplicant接收事件通知。
1.3 wpa_supplicant
1) 读取配置文件
2) 初始化配置参数,驱动函数
3) 让驱动scan当前所有的bssid
4) 检查扫描的参数是否和用户设置的相符
5) 如果相符,通知驱动进行权限和认证操作
6) 连上AP
1.4 Wifi驱动模块
厂商提供的source,主要进行load firware和kernel的wireless进行通信
1.5 Wifi电源管理模块
主要控制硬件的GPIO和上下电,让CPU和Wifi模组之间通过sdio接口或USB接口通信
1.6 Wifi工作步骤
1) Wifi启动
2) 开始扫描
3) 显示扫描的AP
4) 配置AP
5) 连接AP
6) 获取IP地址
7) 上网
1.7 Wifi模块代码
1) Wifi Settings应用程序
packages/apps/Settings/src/com/android/settings/wifi
frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi
2) Wifi Framework
frameworks/base/wifi/Java/android/net/wifi(WifiManager)
frameworks/base/core/java/android/net
frameworks/base/core/java/android/app(SystemServiceRegistry)
frameworks/base/services/java/com/android/server(SystemServer)
frameworks/base/services/core/java/com/android/server(SystemServiceManager) frameworks/opt/net/wifi/service/java/com/android/server/wifi(WifiService/WifiServiceImpl/WifiMonitor/WifiStateMachine/WifiNative)
3) Wifi JNI
frameworks/opt/net/wifi/service/jni/com_android_server_wifi_WifiNative.cpp
4) Wifi Hardware (wifi管理库)
hardware/libhardware_legacy/wifi/wifi.c
5) wpa_supplicant(wifi tool)
external/wpa_supplicant8
(1) wpa_client (生成库libwpaclient.so)
external/wpa_supplicant_8/wpa_supplicant/src/common/wpa_ctrl.c
(2) wpa_server (生成守护进程wpa_supplicant)
external/wpa_supplicant_8/wpa_supplicant/main.c
6) Wifi kernel
net/wireless drivers/wlan_xxx arch/arm/mach-xxx/wlan_pm.c
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内存,该数据结构作为统领其他数据结构的一个核心, 主要包括四个部分:
- 1
- 2
- 3
- 4
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() 函数来做网络接口的初始工作,主要包括:
设置驱动类型,现常用nl80211;
读取配置文件,并将其中的信息设置到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接口参数;在该函数的最后,会设置
- 1
- 2
来主动发起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_iface_dbus.h”,“ctrl_iface_dbus.c”,“ctrl_iface_dbus_handler.h”和“ctrl_iface_dbus_handler.c”中实现,提供一些基本的控制方法。
3.1.2 Unix domain socket 接口
该接口主要在文件“wpa_ctrl.h”,“wpa_ctrl.c”,“ctrl_iface_unix.c”,“ctrl_iface.h”和“ctrl_iface.c”实现。
(1)“wpa_ctrl.h”,“wpa_ctrl.c”完成对control interface的封装,对外提供统一的接口。其主要的工作是通过Unix domain socket建立一个control interface 的client结点,与作为server的wpa_supplicant结点通信。
主要功能函数:
- 1
- 2
- 1
- 2
- 1
- 2
- 3
- 4
- 5
Note:
Wpa_supplicant 提供两种由外部模块获取信息的方式:一种是外部模块通过发送request命令然后获取response的问答模式,另一种是wpa_supplicant主动向外部发送event事件,由外部模块监听接收。
一般的常用做法是外部模块通过调用wpa_ctrl_open()两次,建立两个control interface接口,一个为ctrl interface,用于发送命令,获取信息,另一个为monitor interface,用于监听接收来自于wpa_supplicant的event时间。此举可以降低通信的耦合性,避免response和event的相互干扰。
- 1
- 2
- 1
- 2
- 1
- 2
- 1
- 2
(2)“ctrl_iface_unix.c”实现wpa_supplicant的Unix domain socket通信机制中server结点,完成对client结点的响应。
其中最主要的两个函数为:
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
(3)“ctrl_iface.h”和“ctrl_iface.c”主要实现了各种request命令的底层处理函数。
3.2 下行接口
Wpa_supplicant提供的下行接口主要用于和kernel(driver)进行通信,下发命令和获取信息。
Wpa_supplicant下行接口主要包括三种重要的接口:
1. PF_INET socket接口,主要用于向kernel 发送ioctl命令,控制并获取相应信息。
2. PF_NETLINK socket接口,主要用于接收kernel发送上来的event 事件。
3. PF_PACKET socket接口,主要用于向driver传递802.1X报文。
主要涉及到的文件包括:“driver.h”,“drivers.c”,“driver_nl80211.h”,“driver_nl80211.c”,“l2_packet.h”和“l2_packet_linux.c”。
其中“driver.h”,“drivers.c”,“driver_wext.h”和“driver_wext.c”实现PF_INETsocket接口和PF_NETLINK socket接口;“l2_packet.h”和“l2_packet_linux.c”实现PF_PACKET socket接口。
(1)“driver.h”,“drivers.c”主要用于封装底层差异对外显示一个相同的wpa_driver_ops接口。Wpa_supplicant可支持atmel, Broadcom, ipw, madwifi, ndis, nl80211, wext等多种驱动。
其中一个最主要的数据结构为wpa_driver_ops, 其定义了driver相关的各种操作接口。
(2)“driver_nl80211.h”,“driver_nl80211.c”实现了netlink形式的wpa_driver_ops,通过netlink完成与kernel的信息交互。
(3)“l2_packet.h”和“l2_packet_linux.c”主要用于实现PF_PACKET socket接口,通过该接口,wpa_supplicant可以直接将802.1X packet发送到L2层,而不经过TCP/IP协议栈。
其中主要的功能函数为:
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 1
- 2
- 3
- 1
- 2
参考资料:http://blog.csdn.net/hatchuel/article/details/50779546
参考资料:http://blog.csdn.net/fxfzz/article/details/6176414