WPA-PSK鏈接java
從packages\apps\Settings\src\com\android\settings\wifi\WifiSettings.java
和 WifiDialog.java 開始
1.
若是你點中某個AP
=> onClick執行 (WifiSettings.java)
代碼以下:linux
點擊(此處)摺疊或打開android
button == WifiDialog.BUTTON_SUBMIT
算法
WifiConfiguration config = mDialog.getConfig();(WifiDialog.java中)
安全
WifiDialog getConfig => ( 由於才你本身選的某個AP 有網絡ID,
網絡
因此network id !=-1,mSelected!=null)
app
if (config.networkId != -1) {
less
if (mSelected != null) { /* 走到這裏 */
dom
/*下面函數 到2.分支繼續分析 */
socket
mWifiManager.updateNetwork(config);
/*下面函數 到4.分支繼續分析 */
saveNetworks();
}
} else {
int networkId = mWifiManager.addNetwork(config);
if (networkId != -1) {
mWifiManager.enableNetwork(networkId, false);
config.networkId = networkId;
if (mDialog.edit || requireKeyStore(config)) {
saveNetworks();
} else {
connect(networkId);
}
}
}
2. 接上面分支1.的 mWifiManager.updateNetwork(config); 繼續分析
=> addOrUpdateNetwork (wifiManager.java)
==> mService.addOrUpdateNetwork(config);
(wifi manager 對wifi service function 的訪問)
===> mWifiStateTracker.addNetwork()
====> WifiNative.addNetworkCommand();
(上面這句執行完成到 setVariables: 部分 ,分支3.繼續)
=====> JNI 執行 doIntCommand("ADD_NETWORK");
上面是andorid ,下面就執行 wpa_cli的命令
---------------------------------------------------------
=> wpa_supplicant_ctrl_iface_add_network
==> wpa_config_add_network
===> wpa_config_update_prio_list
更新 wpa prioty list! 就是conf文件設置的priority 組
看下解釋:
# priority: Priority group
# By default, all networks and credentials get the same priority group
# (0). This field can be used to give higher priority for credentials
# (and similarly in struct wpa_ssid for network blocks) to change the
# Interworking automatic networking selection behavior. The matching
# network (based on either an enabled network block or a credential)
# with the highest priority value will be selected.
==> wpas_notify_network_added(wpa_s,
ssid); (dbus 部分,沒有用)
==> wpa_config_set_network_defaults ,設置network(ssid) 以下default 值:
#define DEFAULT_EAP_WORKAROUND ((unsigned int) -1)
#define DEFAULT_EAPOL_FLAGS (EAPOL_FLAG_REQUIRE_KEY_UNICAST | \
EAPOL_FLAG_REQUIRE_KEY_BROADCAST)
#define DEFAULT_PROTO (WPA_PROTO_WPA | WPA_PROTO_RSN)
#define DEFAULT_KEY_MGMT (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X)
#define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
#define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | \
WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)
#define DEFAULT_FRAGMENT_SIZE 1398
就是加密算法,密鑰管理,及EAPOL等等,struct wpa_ssid結構中註釋很全
android 發起的一條ADD_NETWORK命令完成了!
3. 又回到java,剛纔2.分支中mService.addOrUpdateNetwork部分
=> mService.addOrUpdateNetwork(config);繼續往下執行代碼以下:
setVariables: { 設置網絡變量以下
==> mWifiStateTracker.setNetworkVariable(netId,
WifiConfiguration.ssidVarName, config.SSID)
debugmessage: CTRL_IFACE: SET_NETWORK id=0 name='ssid'
===> WifiNative.setNetworkVariableCommand(netId, name, value);
(這中間還JNI部分,最後老是到 wpa_cli 執行set network命令)
====>到 wpa_supplicant wpa_supplicant_ctrl_iface_set_network
=====> wpa_config_set(ssid, name, value, 0) 更新ssid_fields
=====> wpa_config_update_psk 更新 wpa-psk的密碼
/* 密碼由SHA1 生成psk */
=====> wpa_config_update_prio_list 更新prioty
根據命令set network 命令參數內容:
<network id> <variable name> <value>
若是variable name 還會再設置prioty,
就是說,除了conf文件1開始設置好,後面根據命令也還能夠變
你能夠在java 中本身臨時改變network 部分的 priority
wpa_cli完成後,下面又返回java
===> mWifiStateTracker.setNetworkVariable(netId,
WifiConfiguration.KeyMgmt.varName, allowedKeyManagementString)
debugmessage: CTRL_IFACE: SET_NETWORK id=0 name='key_mgmt'
一看就知道設置id=0 的netword 的key manager 變量
===> mWifiStateTracker.setNetworkVariable( netId,
WifiConfiguration.priorityVarName,
Integer.toString(config.priority)
會跑到剛纔說的wpa_config_update_prio_list,
==> mWifiManager.enableNetwork(networkId, false);
==> mWifiStateTracker.enableNetwork(netId, false);
===> enableNetworkCommand(netId, false);
====> 到 wpa_cli 的 ENABLE_NETWORK 處理部分
wpa_supplicant_ctrl_iface_enable_network
(dbgmessage: CTRL_IFACE: ENABLE_NETWORK id=0)
=====> wpa_supplicant_enable_network(wpa_s, ssid);
第1次,if (wpa_s->current_ssid == NULL) 知足
1. wpa_supplicant_req_sched_scan
請求dirver 進行週期scan
(wpa_driver_nl80211_sched_scan NL80211_CMD_START_SCHED_SCAN)
scan paramater 好比ssids,filter_ssids
基原本自於將conf文件讀到內存的wpa_s->conf
帶着參數調用 wpa_supplicant_start_sched_scan
去執行nl80211 driver 的 sched_scan
2. wpa_supplicant_req_scan(wpa_s, 2, 0);
到eloop_register_timeout(sec, usec,
wpa_supplicant_scan, wpa_s, NULL);
2秒後
wpa_driver_nl80211_scan經過NL80211_CMD_TRIGGER_SCAN命令
以及給定參數觸發1個新的scan
wpa_supplicant_trigger_scan
wpa_drv_scan 到nl80211 driver 的 scan2
kerneldoc : http://linuxwireless.org/en/developers/Documentation/nl80211/kerneldoc
解釋以下:
NL80211_CMD_START_SCHED_SCAN:
start a scheduled scan at certain intervals, as specified by NL80211_ATTR_SCHED_SCAN_INTERVAL. Like with normal scans,
if SSIDs (NL80211_ATTR_SCAN_SSIDS) are passed, they are used in the probe requests. For broadcast,
a broadcast SSID must be passed (ie. an empty string). If no SSID is passed,
no probe requests are sent and a passive scan is performed. NL80211_ATTR_SCAN_FREQUENCIES,
if passed, define which channels should be scanned; if not passed, all channels allowed for the current regulatory domain are used.
Extra IEs can also be passed from the userspace by using the NL80211_ATTR_IE attribute
上面的意思就是讓STA driver開始1個在sched scan interval 時間間隔的scan,
若是有已經設置的網絡,就發probe request,若是沒有那麼執行
被動掃描(接收AP的beacon), 並根據設置的通道梳洗來判斷,scan 全部channel
仍是某些
NL80211_CMD_TRIGGER_SCAN
trigger a new scan with the given parameters NL80211_ATTR_TX_NO_CCK_RATE is
used to decide whether to send the probe requests at CCK rate or not.
wpa_supplicant_req_sched_scan wpa_supplicant_req_scan 區別:
就是 sched_scan 和scan2的區別 請看代碼中的註釋
/**
* scan2 - Request the driver to initiate scan
* @priv: private driver interface data
* @params : Scan parameters
*
* Returns: 0 on success, -1 on failure
*
* Once the scan results are ready, the driver should report scan
* results event for wpa_supplicant which will eventually request the
* results with wpa_driver_get_scan_results2().
*/
/**
* sched_scan - Request the driver to initiate scheduled scan
* @priv: private driver interface data
* @params : Scan parameters
* @interval: interval between scan cycles
*
* Returns: 0 on success, -1 on failure
*
* This operation should be used for scheduled scan offload to
* the hardware. Every time scan results are available, the
* driver should report scan results event for wpa_supplicant
* which will eventually request the results with
* wpa_driver_get_scan_results2(). This operation is optional
* and if not provided or if it returns -1, we fall back to
* normal host-scheduled scans.
*/
sched scan 就是所啓動一個定時掃描循環,而後scan2 觸發一個scan,
這樣driver 就在scan2 後按時間間隔循環scan
接下來到4.分支繼續
到這裏已是鏈接上AP後的處理部分了
=> saveNetworks(); (wifisettings.java)
==> enableNetworks(); (loop mAccessPoints.getPreferenceCount )
==> mWifiManager.saveConfiguration();
能看到以下message 表示在保存創建鏈接的network設置
Writing configuration file '/data/misc/wifi/wpa_supplicant.conf'
===>mService.saveConfiguration
====> mWifiStateTracker.saveConfig
=====> wpa_cli AP_SCAN 1 + wpa_cli SAVE_CONFIG
====> mWifiStateTracker.reloadConfig
------------------------------------------
wpa_cli RECONFIGURE 命令
=====> wpa_supplicant_reload_configuration(), message 以下:
點擊(此處)摺疊或打開
D/wpa_supplicant( 2129): Reading configuration file '/data/misc/wifi/wpa_supplicant.conf'
D/wpa_supplicant( 2129): ctrl_interface='wlan0:0'
wpa_config_read, wpa_config_process_global
D/wpa_supplicant( 2129): update_config=1
wpa_config_read, wpa_config_process_global
D/wpa_supplicant( 2129): Line: 5 - start of a new network block
wpa_config_read ,wpa_config_read_network
D/wpa_supplicant( 2129): key_mgmt: 0x2
D/wpa_supplicant( 2129): priority=1 (0x1)
D/wpa_supplicant( 2129): Priority group 1
wpa_config_read ,wpa_config_debug_dump_networks
D/wpa_supplicant( 2129): id=0 ssid='RD-Test
wpa_config_read ,wpa_config_debug_dump_networks
=====> wpa_sm_set_config(wpa_s->wpa, NULL);
wpa 狀態機 init,並將config 中相關內容設置到wpa狀態機
=====> wpa_supplicant_update_config 的 message :
D/wpa_supplicant( 2129): WPS: Set UUID for interface wlan0
對應 wpa_supplicant_update_config ,wpas_wps_set_uuid
D/wpa_supplicant( 2129): wlan0: P2P: Intra BSS distribution enabled
V/WifiMonitor( 1363): Event [CTRL-EVENT-STATE-CHANGE id=-1 state=0 BSSID=00:00:00:00:00:00]
V/WifiStateTracker( 1363): Changing supplicant state: SCANNING ==> DISCONNECTED
D/wpa_supplicant( 2129): Setting scan request: 2 sec 0 usec
D/wpa_supplicant( 2129): Reconfiguration completed
=====> wpa_supplicant_clear_status !
----------------------------------------------
又回到java
====> boardcast NETWORK_IDS_CHANGED_ACTION
==> updateAccessPoints();
上面 mWifiManager.enableNetwork(networkId, false);
=> WifiNative.enableNetworkCommand 發 ENABLE_NETWORK命令
==> wpa_supplicant_ctrl_iface_enable_network
===> wpa_supplicant_enable_network
===> 繼續scan
4. 接上面3.分支繼續
這時你會看到driver的消息:
Association completed. (bss_info_changed)
字面上看關聯成功? 還沒發requet associate ?
那麼在那裏發的request associate ?
前面3.分支,開始咱們SET_NETWORK,以後咱們又ENABLE_NETWORK
最後發起對咱們選擇的AP,進行scan2,scan以後就須要等待接收結果
在前面wap_supplicant init 部分
曾經作過這個動做 wpa_driver_nl80211_init_nl
該函數最後調用:
eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event),
wpa_driver_nl80211_event_receive, drv,
drv->nl_handle_event);
前面解釋過是用來接收scan result,mlme,regulator 相關的多播包
其實前面wifi eanalbe 時這部分應該也作,而且若是conf中有Network
它也會去pick network,而後開始鏈接過程,
如今你是第1次手動鏈接,一樣也是從scan result 中
找到你選擇的那個AP,進行鏈接,看下面:
=>wpa_driver_nl80211_event_receive
經過process_event callback 來繼續處理 NL80211_CMD_NEW_SCAN_RESULTS 以下:
這時先會 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout,
取消前面的10s scan timeout eloop
==> send_scan_event
===> wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
====> wpa_supplicant_event_scan_results
=====> _wpa_supplicant_event_scan_results
======>wpas_notify_scan_results(wpa_s);
=======> wpas_wps_notify_scan_results
"Event [WPS-AP-AVAILABLE]"
======> wpa_supplicant_pick_network
從scan results 中選擇AP,
根據scan 到的new ap 去匹配 (有prori等)
其中執行 wpa_supplicant_select_bss
能夠看到: Selecting BSS from priority group 1:
wpa_supplicant_pick_network最後返回一個
struct wpa_bss 結構的pointer,包含該AP的info
======> wpa_supplicant_rsn_preauth_scan_results
對scan results 啓動預身份驗證
注意 WPA 不支持預先身份驗證,WPA2才支持
======> wpa_supplicant_connect 開始鏈接AP
終於要開始鏈接了,這是應該會看到下面的msg:
wlan0: Request association: reassociate: 1
selected: 00:1f:33:b9:5d:e0
bssid: 00:00:00:00:00:00
pending: 00:00:00:00:00:00
wpa_state: SCANNING
wpa_supplicant_connect 去調用
=======> wpa_supplicant_associate(wpa_s, selected, ssid);
========> sme_authenticate(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid)
開始設置一堆參數爲driver層auth 調用作準備
就提下params.auth_alg = WPA_AUTH_ALG_OPEN;
其餘看代碼
/* WPA 802.11 author 使用OPEN !!! */
=========>wpa_supplicant_set_suites
(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid,
u8 *wpa_ie, size_t *wpa_ie_len)
它設置認證和加密的參數,這些參數從
這個AP scan result 發過的被處理後掛在
struct wpa_bss 的最後的IE部分得到
得到 WPA IE ,RSN IE 後就知道了,從message看:
WPA: Selected cipher suites: group WPA_CIPHER_TKIP,
pairwise WPA_CIPHER_CCMP,
key_mgmt WPA_KEY_MGMT_PSK
proto WPA_PROTO_RSN
表示:
group 使用TKIP, 成對密鑰 使用CCMP, key manager wpa_psk,
協議爲RSN ,就是強健安全網絡(RSN)的標準
調用兩次wpa_sm_set_param
設置proto,proto enanble 到 wpa state machine結構
struct wpa_sm 的,proto 和 rsn_enabled
還在wpa_supplicant_set_suites中,接下來經過
wpa_sm_set_assoc_wpa_ie_default去生成關聯須要
的WPA/RSN IE,放到struct wpa_sm->assoc_wpa_ie
最後 wpa_sm_set_pmk 將預共享密鑰PSK,copy到
struct wpa_sm->pmk,後面要用
=========> wpa_supplicant_cancel_sched_scan
wpa_supplicant_cancel_scan
開始認證時要取消sched scan ,並canle 當前scan
=========> wpa_msg(wpa_s, MSG_INFO,
"SME: Trying to authenticate with "
MACSTR (SSID='%s' freq=%d MHz)",
MAC2STR(params.bssid),
wpa_ssid_txt(params.ssid, params.ssid_len),
params.freq);
對應能夠看到WifiMonitor msg:
Event [SME: Trying to authenticate with 00:1f:33:b9:5d:e0
(SSID='RD-Test' freq=2462 MHz)]
由wpa_supplicant_ctrl_iface_send發到
wifi monitor 被 parse 爲 UNKNOWN,
monitor 不關心
=========> wpa_supplicant_set_state(wpa_s,
WPA_AUTHENTICATING);
=========> wpa_s->new_connection = 1;
=========> wpa_drv_set_operstate(wpa_s, 0);
/* 設置到IF_OPER_DORMANT */
=========> wpa_supplicant_stop_bgscan 中止back groud scan
=========> wpas_notify_state_changed
==========> wpa_msg_ctrl(wpa_s, MSG_INFO,
WPA_EVENT_STATE_CHANGE 給wifi monitor 發:
Event [SME: Trying to authenticate with 00:1f:33:b9:5d:e0 (SSID='RD-Test'
freq=2462 MHz)]
=========> wpa_supplicant_rsn_supp_set_config
註釋以下:
Notify WPA state machine that configuration has changed
配置的網絡上下文就是
struct wpa_ssid - Network configuration data
還有 PTK 生命週期
=========> wpa_supplicant_initiate_eapol
配置EAPOL 狀態機器, 啓動 EAPOL,EAP 狀態機器
調用 eapol_sm_notify_eap_success
清除EAP success
調用 eapol_sm_notify_eap_fail
清除 EAP failure
調用eapol_sm_notify_portControl(Auto)
設置prot control 爲自動,其餘還有
ForceUnauthorized, ForceAuthorized
每一個相似的eapol sm notify 函數中都
eapol_sm_step(sm); 這句很重要!
雖然簡單,但倒是狀態機的驅動中樞!
=========>wpas_notify_network_changed
=========> wpa_drv_authenticate
前面一大堆,爲的就是這句,這數執行nl80211 driver
authenticate,發出後等driver 響應
到分支5.繼續
=========>eloop_register_timeout(callback=>sme_auth_timer)
認證超時失敗處理
=========> eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE); eapol_sm_notify_portValid(wpa_s->eapol, FALSE); 註釋以下: /* * Set portEnabled first to FALSE in order to get EAP state machine out * of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE * state machine may transit to AUTHENTICATING state based on obsolete * eapSuccess and then trigger BE_AUTH to SUCCESS and PAE to * AUTHENTICATED without ever giving chance to EAP state machine to * reset the state. */