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