跟一下wpa_supplicant(3-1) connect AP

WPA-PSK鏈接java

從packages\apps\Settings\src\com\android\settings\wifi\WifiSettings.java
  和 WifiDialog.java 開始
1.
若是你點中某個AP
=> onClick執行 (WifiSettings.java)
   代碼以下:linux


點擊(此處)摺疊或打開android

  1. button == WifiDialog.BUTTON_SUBMIT
    算法

  2.    WifiConfiguration config = mDialog.getConfig();(WifiDialog.java中)
    安全

  3.    WifiDialog getConfig => ( 由於才你本身選的某個AP 有網絡ID,
    網絡

  4.                              因此network id !=-1,mSelected!=null)
    app

  5.    if (config.networkId != -1) {
    less

  6.         if (mSelected != null) { /* 走到這裏 */
    dom

  7.        /*下面函數 到2.分支繼續分析 */
    socket

  8.               mWifiManager.updateNetwork(config);

  9.               /*下面函數 到4.分支繼續分析 */

  10.               saveNetworks();

  11.         }

  12.     } else {

  13.         int networkId = mWifiManager.addNetwork(config);

  14.         if (networkId != -1) {

  15.             mWifiManager.enableNetwork(networkId, false);

  16.             config.networkId = networkId;

  17.             if (mDialog.edit || requireKeyStore(config)) {

  18.                saveNetworks();

  19.             } else {

  20.                connect(networkId);

  21.             }

  22.          }

  23.     }



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 以下:

點擊(此處)摺疊或打開

  1. D/wpa_supplicant( 2129): Reading configuration file '/data/misc/wifi/wpa_supplicant.conf'

  2. D/wpa_supplicant( 2129): ctrl_interface='wlan0:0'

  3.                   wpa_config_read, wpa_config_process_global

  4. D/wpa_supplicant( 2129): update_config=1

  5.                   wpa_config_read, wpa_config_process_global

  6. D/wpa_supplicant( 2129): Line: 5 - start of a new network block

  7.                   wpa_config_read ,wpa_config_read_network

  8. D/wpa_supplicant( 2129): key_mgmt: 0x2

  9. D/wpa_supplicant( 2129): priority=1 (0x1)

  10. D/wpa_supplicant( 2129): Priority group 1

  11.                 wpa_config_read ,wpa_config_debug_dump_networks

  12. 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. */

相關文章
相關標籤/搜索