现在的位置: 首页 > 综合 > 正文

跟一下wpa_supplicant(3-1) connect AP

2013年10月19日 ⁄ 综合 ⁄ 共 15685字 ⁄ 字号 评论关闭
WPA-PSK连接
从packages\apps\Settings\src\com\android\settings\wifi\WifiSettings.java

  和 WifiDialog.java 开始

1.

如果你点中某个AP

=> onClick执行 (WifiSettings.java)

   代码如下:

点击(此处)折叠或打开

  1. button == WifiDialog.BUTTON_SUBMIT
  2.    WifiConfiguration config = mDialog.getConfig();(WifiDialog.java中)
  3.    WifiDialog getConfig => ( 因为才你自己选的某个AP
    有网络ID,
  4.                              所以network id !=-1,mSelected!=null)
  5.    if (config.networkId != -1) {
  6.         if (mSelected != null) { /*
    走到这里 */

  7.        /*下面函数 到2.分支继续分析 */
  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=(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.

*/

WPA-PSK连接
从packages\apps\Settings\src\com\android\settings\wifi\WifiSettings.java

  和 WifiDialog.java 开始

1.

如果你点中某个AP

=> onClick执行 (WifiSettings.java)

   代码如下:

点击(此处)折叠或打开

  1. button == WifiDialog.BUTTON_SUBMIT
  2.    WifiConfiguration config = mDialog.getConfig();(WifiDialog.java中)
  3.    WifiDialog getConfig => ( 因为才你自己选的某个AP
    有网络ID,
  4.                              所以network id !=-1,mSelected!=null)
  5.    if (config.networkId != -1) {
  6.         if (mSelected != null) { /*
    走到这里 */

  7.        /*下面函数 到2.分支继续分析 */
  8.               mWifiManager.updateNetwork(config);
  9.               /*下面函数 到4.分支继续分析 */
  10.               saveNetworks();
  11.         }
  12.     } else {
  13.         int networkId = mWifiManager.addNetwork(config)

抱歉!评论已关闭.