1. 概况描述
1.1 问题场景
假设有两个AP热点的essid以及安全策略均相同,用户打开手机wifi开关,会发现只能够搜索到一个wlan条目,因为对用户来说,essid与安全策略均相同的几个热点,被认为是多个bss组成的ess。那么当用户点击连接后,究竟连接的是哪一个AP的热点呢?过程又是什么样?下面我们就慢慢讲述
1.2 名词术语
本文涉及的专有名词、定义和缩写的含义如下:
Num | 名词 | 说明 |
1 | wpa_supplicant | Android手机中对无线网络管理和控制的程序 |
2 | bss | 基础服务集,一般指wifi热点信号 |
3 | ess | 扩展服务集,可包含多个bss |
4 | bssid | 标识一个bss的信息,一般表示为48bit的mac地址 |
5 | essid | 标识一个ess的信息,一般为字符串形式,即网络信号名 |
6 |
|
|
|
2. 连接过程
2.1 命令下发
首先,当用户在手机界面上点击某个wifi信号进行连接时,wifi service会通过wpa_cli控制接口向wpa_supplicant连续下发三条命令:
ADD_NETWORK
在wpa_supplicant中分配一个wpa_ssid对象,并设置一些默认属性。具体处理函数为wpa_supplicant_ctrl_iface_add_network().
SET_NETWORK
对所添加的wlan信息进行配置,主要包括essid,keymgt,passphrase等信息。
设置完毕后,在wpa_supplicant.conf中将以如下方式保存:
network={
ssid="example"
proto=WPA
key_mgmt=WPA-PSK
pairwise=TKIP
group=TKIP
psk="1234567890"
}
ENABLE_NETWORK
将配置好的wlan对应的wpa_ssid结构中disable状态置为0,填充扫描请求的参数,其中可以指定扫描周围所有无线网络,也可以指定扫描某个特定的网络。然后并向驱动发起一次扫描请求。
2.2 扫描结果处理
wpa_supplicant中维护着一个wpa_bss的链表,用来表示当前环境中存在的无线网络。其中每个节点都有一个定时器,每次扫描后将根据扫描结果更新节点以及定时器,若某个节点定时器超时未被更新,则表示此网络不存在,将从链表中删除。
驱动扫描结束后,扫描结果通过driverinterface返回到wpa_supplicant,保存在一个数组中,并对扫描结果按照信号强度从高到低进行快速排序。(假设A与A(1)具有相同的essid)
然后用扫描结果去更新bss链表中对应网络的信号强度,以及此节点的定时器。
更新的方式为:依次用扫描结果中的每一项去添加或更新bss链表中对应BSS,每更新一个节点,则将这个节点移动到链表尾部。这样,就保证了未被更新的节点永远在链表首部。
此次扫描未扫描到网络B与E,则更新后,B与E处于链表头位置。若它们的定时器超时但仍然未被更新,则说明网络B、E在当前环境下已经不存在,则从BSS链表头部删除。
此时,BSS链表经过更新后,并非按照信号强度排列,所以,在更新BSS链表的同时,用一个指针数组来维护BSS链表按照信号强度从高到低的序列,如下图:
注意:
为什么不直接使用数组保存bss,或直接对链表进行排序?
第一,因为bss表需要进行频繁的插入与删除操作,并且需要频繁移动表中元素的位置,使用数组代价太大。
第二,由于链表结构本身的特点,无法对其使用快速排序。所以额外添加一个指针数组来维护bss表的有序序列。
这是一个典型的利用空间换时间的例子。
2.3 选择BSS
接下来,将wpa_ssid链表中disable状态为0的wpa_ssid结构与上述bss链表的有序序列的每个bss依次进行匹配,直到找到相匹配的bss。而用户通过手动点击连接的wpa_ssid具有最高的优先级(priority字段),所以对其优先进行匹配。由于bss序列中信号较强的bss排在前面,一旦匹配成功则进行连接,所以默认总是去连接信号较强的bss.
匹配成功后,将以此bss作为参数,向驱动发起连接接请求。经过认证、关联的步骤,即可连接上wifi热点。
3. 代码位置
external/wpa_supplicant_8/wpa_supplicant/ctrl_iface.c
external/wpa_supplicant_8/wpa_supplicant/wpa_supplicant.c
external/wpa_supplicant_8/wpa_supplicant/scant.c
external/wpa_supplicant_8/wpa_supplicant/bss.c
external/wpa_supplicant_8/wpa_supplicant/events.c