加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

wpa_supplicant(2) wifi connect AP 跟踪

(2015-01-29 17:32:03)
标签:

it

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.        
  8.               mWifiManager.updateNetwork(config);
  9.               
  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的密码
       
                =====> wpa_config_update_prio_list 更新prioty
               根据命令set network 命令参数内容:
      
      如果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的区别 请看代码中的注释
        
        
  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_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);
                
                    =========> 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);
        注释如下:


5. 接分支4.
authenticate response 来了
和前面一样:
wpa_driver_nl80211_event_receive到
=> process_event
   收到 NL80211_CMD_AUTHENTICATE=37
   ==> mlme_event (37)
       ===> mlme_event_auth
            authenticate response 管理帧中的AP mac 是我们感兴趣的,
     收了它,放wpa_driver_nl80211_data 的auth_bssid
            并放到wpa_event_data->auth_info->peer
     ====> wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
           Event 11 received on interface wlan0 被扔出来
          =====> sme_event_auth(wpa_s, data);
                       紧接着
         D/wpa_supplicant( 2129): SME: Authentication response:
                        peer=00:1f:33:b9:5d:e0 auth_type=0 status_code=0
                       被扔出来
                       ======> eloop_cancel_timeout(sme_auth_timer,
                     wpa_s, NULL);
                               取消auth 失败的警戒,可以进城了
                       ======> sme_associate(wpa_s, ssid->mode,
                  data->auth.peer, data->auth.auth_type);
    启动关联
                               =======>wpa_supplicant_set_state(wpa_s,
                    WPA_ASSOCIATING);
                               ========> wpa_s->new_connection = 1;
                               ========> wpa_drv_set_operstate(wpa_s, 0);
                  
                               ========> wpa_s->wpa_state = state;
                               ========> wpas_notify_state_changed(wpa_s,
             wpa_s->wpa_state, old_state);
        如果 oldstate  不同情况下执行
                               =======> 设置参数等,ie
                               =======> wpa_drv_associate(wpa_s, &params)
                                wpa_driver_nl80211_associate  driver interface
           通过netlink 给dirver 发assoc request
                                wpa_printf(MSG_DEBUG, "nl80211:
       Association request send "  "successfully");
                                发完了应该,别忘警戒下:
                       =======> eloop_register_timeout(SME_ASSOC_TIMEOUT,
                                 0, sme_assoc_timer, wpa_s,  NULL);
                                
       
                             接下来到分支6.
6. 接分支5.
38 event 来了!
wpa_driver_nl80211_event_receive到
=> process_event
   ==> mlme_event (38= NL80211_CMD_ASSOCIATE)
       asscoicate response 来了
      ===> mlme_event_assoc(drv, nla_data(frame),
             nla_len(frame));
      这里的 frame 应该就是关联响应帧
             去读下rp frame state 判断response为成功
          ====> drv->associated = 1;
          ====> 获得resp 中的IE们 到 event.assoc_info.resp_ies
          ====> event.assoc_info.freq = drv->assoc_freq;
        关联时的频率放到 struct assoc_info
         有了IE,就象口袋有钱,可以来事了,EVENT_ASSOC发出去
          ====> wpa_supplicant_event(drv->ctx, EVENT_ASSOC,&event);
               =====> wpa_supplicant_event_assoc(wpa_s, data);
                     ======> wpa_supplicant_event_associnfo
                            获取AP 的assoc info!
       就是挖掘前面说的已经存到event.assoc_info的resp ie
       其中如果挖到PMKID,是要注意
       去call wpa_find_assoc_pmkid
       干什么? 如果忘记了,到第1篇搜索:
       '成对主蜜钥安全关联'字样,我就不讲了
                     ======> wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
                             State: ASSOCIATING -> ASSOCIATED
                     ======> wpa_clear_keys (clear driver config key)
                     ======> wpa_supplicant_select_config
              我们设置为AP_SCAN =1(让wpa_supplciant选择AP)
       所以它什么也不做,return
                     ======> wpa_sm_notify_assoc(wpa_s->wpa, bssid);
                            WPA state machine 的rx_replay_counter_set 清0,
       的renew_snonce 置1
       比较下是否是在preauth的ap 的mac,是的话就deinit它
       最后清下wap state machine 的 old PTK
       这么做是因为人家IEEE 802.11协议8.4.10部分说了
                            Delete PTK SA on (re)association if this is not
          part of a Fast BSS Transition.
                           
                            PTK 有两种格式,TKIP,和CCMP
                     ======> eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
                     ======>eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
       ======> if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
                                   ft_completed)
                          eapol_sm_notify_eap_success(wpa_s->eapol,
                                FALSE);  
                      到这里PAE还没变化,下面就要变了
                     ======> eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
                            portEnabled=1
       PAE状态要发生变化了,从disconnect 变到connecting
                            这个disconnect是在 eapol_sm_init,开始设置的
       之后一直保持该状态
       EAP状态一直为disable,因为我们是WPA-psk,所以
       没有EAP,他就一直处于disable
                     ======>
                       wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
        
                     ======> wpa_supplicant_cancel_sched_scan(wpa_s);
      
                  wpa_supplicant_cancel_scan(wpa_s);
                     ======> wpa_supplicant_event_assoc中
                接下来的部分不会执行到

到这里已经关联已经完成,在AP 发来EAPOL frame 前,我们会收到
NL80211_CMD_CONNECT 通知,根据cmd注释,可以了解该命令是在不分开进行认证
和关联的情况下,来请求连接到一个指点网络的,连接完成会收到NL80211_CMD_CONNECT
的response,目前的driver capa里设置了WPA_DRIVER_FLAGS_SME,表示driver 支持
auth 和associate 分开的命令,所以能收到NL80211_CMD_CONNECT,但不处理
为什么呢? 注释里已经写了,为了避免2次报告关联事件,引起核心代码混乱
                   进入7. 继续
7. 前面6.中完成asscicate 后,讲过就会等待EAPOL FRAME到来
  在wpa init 中 wpa_supplicant_driver_init 会注册 l2 rx callback
wpa_s->l2 = l2_packet_init(wpa_s->ifname,
     wpa_drv_get_mac_addr(wpa_s),
     ETH_P_EAPOL,
     wpa_supplicant_rx_eapol, wpa_s, 0);
可以看出收到l2 packet 后call back wpa_supplicant_rx_eapol,就从它开始
=> wpa_supplicant_rx_eapol:
   ==> wpa_supplicant_req_auth_timeout(wpa_s,
              (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
       wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA
               || wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) ? 70 : 10, 0);
        和前面associate最后设置的10s timeout 一样,这里只是收到
 第1个,reset 下一次认证超时为10s
   ==> wpa_s->eapol_received++;  是第1次,eapol_received++ 后等于1
   ==> wpa_drv_poll(wpa_s);
   ==> if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
          ===> wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
              该函数处理收到的 EAPOL frame
              分析可得:
                * type =2 时 EAPOL-Key
  * key_info =0x8a
     (ver=2 keyidx=0 rsvd=0 Pairwise Ack)
  * key length =16, key data lenght 22
key_info 各bit 所代表的内容在:
wpa_comm.h中定义如下:

  1. /* IEEE 802.11, 8.5.2 EAPOL-Key frames */
  2. #define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2)))
  3. #define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0)
  4. #define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1)
  5. #define WPA_KEY_INFO_TYPE_AES_128_CMAC 3
  6. #define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */
  7. /* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */
  8. #define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5))
  9. #define WPA_KEY_INFO_KEY_INDEX_SHIFT 4
  10. #define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */
  11. #define WPA_KEY_INFO_TXRX BIT(6) /* group */
  12. #define WPA_KEY_INFO_ACK BIT(7)
  13. #define WPA_KEY_INFO_MIC BIT(8)
  14. #define WPA_KEY_INFO_SECURE BIT(9)
  15. #define WPA_KEY_INFO_ERROR BIT(10)
  16. #define WPA_KEY_INFO_REQUEST BIT(11)
  17. #define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */
  18. #define WPA_KEY_INFO_SMK_MESSAGE BIT(13)


第1个发过来的eapol frame 表示4次握手的第1次握手已经开始了!!!
   ==> 接下来就是部分4 way handle 的代码,直接贴上:

  1. if (key_info & WPA_KEY_INFO_KEY_TYPE) {
  2.      /* 走到这里, WPA_KEY_INFO_KEY_TYPE ,pairwise ,or group key !!!*/
  3.    if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) {
  4.  wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
  5.  "WPA: Ignored EAPOL-Key (Pairwise) with "
  6.  "non-zero key index");
  7.  goto out;
  8.    }
  9.    if (peerkey) { /* 如果4way 的第1次没有peerkey */
  10.       /* PeerKey 4-Way Handshake */
  11.   peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver);
  12.    } else if (key_info & WPA_KEY_INFO_MIC) {
  13.      /* 3/4 4-Way Handshake */
  14.      wpa_supplicant_process_3_of_4(sm, key, ver);
  15.    } else {
  16.        /* 1/4 4-Way Handshake */
  17.  wpa_supplicant_process_1_of_4(sm, src_addr, key, ver);
  18.    }
  19. } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
  20.      /* PeerKey SMK Handshake */
  21.      peerkey_rx_eapol_smk(sm, src_addr, key, extra_len, key_info,ver);
  22. } else {
  23.  if (key_info & WPA_KEY_INFO_MIC) {
  24.  /* 1/2 Group Key Handshake */
  25.  wpa_supplicant_process_1_of_2(sm, src_addr, key, extra_len, ver);
  26.   } else {
  27.          wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
  28.         "WPA: EAPOL-Key (Group) without Mic bit - "
  29.   "dropped");
  30.  }
  31. }

 
wpa_supplicant_process_1_of_4(sm, src_addr, key, ver);
wpa_supplicant_process_3_of_4(sm, key, ver);
是我们关心的
为什么没有0_of_4, 2_of_4? 不是没有,4次握手的第1,3次都在AP端处理
我们不管了,所以目前阶段,直接跑到1_fo_4,处理如下
 
       ===> wpa_supplicant_process_1_of_4(sm, src_addr, key,  ver);
            ====> wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
                  wap state 变化了 , ASSOCIATED -> 4WAY_HANDSHAKE
            ====> wpa_supplicant_parse_ies(_buf, len, &ie);
                  将buf 内容解析到 struct wpa_eapol_ie_parse
                  包括我们下面要用的pmkid
            ====> wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
       如果pmksa cashe 不空,
       先从PMKSA cache中根据传来的ie.pmkid 去匹配
       然后获得PMK,它是计算 PTK必须的,但现在cur_pmksa
       为空,那如何获得pmk ,其实上面已经设置了,
       在wpa_supplicant_associate 的
       最后 wpa_sm_set_pmk 将预共享密钥PSK,copy到
        struct wpa_sm->pmk
                   
            ====> ptk = &sm->tptk;
            ====> wpa_derive_ptk(sm, src_addr, key, ptk);
                  计算方法:
               wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
                  sm->own_addr, sm->bssid, sm->snonce, key->key_nonce,
                  (u8 *) ptk, ptk_len,
                  wpa_key_mgmt_sha256(sm->key_mgmt));
                  公式:
                  * PTK = PRF-X(PMK, "Pairwise key expansion",
                             Min(AA, SA) || Max(AA, SA) ||
                             Min(ANonce, SNonce) || Max(ANonce, SNonce))
            ====> wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver,
         sm->snonce, sm->assoc_wpa_ie, sm->assoc_wpa_ie_len, ptk)
                  =====> wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
            NULL, sizeof(*reply) + wpa_ie_len, &rlen,
     (void *) &reply);
                       os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
                       wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL, 
             rbuf, rlen, reply->key_mic);
                     
                   接下来到8.
 
8.
l2 packet 又来了
=> wpa_supplicant_rx_eapol:
   ==> wpa_drv_poll(wpa_s);
   ==> if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
        wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
        该函数处理收到的 EAPOL frame
        分析可得:
        * type =2 时 EAPOL-Key
 * key_info =0x13ca
    (ver=2 keyidx=0 rsvd=0 Pairwise Install Ack MIC Secure Encr)
 * key length =16, key data lenght 80
   ==>  else if (key_info & WPA_KEY_INFO_MIC) {
        
 
   ==>  wpa_supplicant_process_3_of_4(sm, key, ver);
       其中key 就是 EAPOL-KEY 内容
struct wpa_eapol_key {  
 u8 type;
 
 u8 key_info[2];
 u8 key_length[2];
 u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
 u8 key_nonce[WPA_NONCE_LEN];
 u8 key_iv[16];
 u8 key_rsc[WPA_KEY_RSC_LEN];
 u8 key_id[8];
 u8 key_mic[16];
 u8 key_data_length[2];
 
} STRUCT_PACKED;
        下面对eapol key data 部分进行处理,将获得的ie,放到
 struct wpa_eapol_ie_parse
        ===> pos = (const u8 *) (key + 1);  eapol key 后就是ie
             len = WPA_GET_BE16(key->key_data_length);   
             wpa_supplicant_parse_ies(pos, len, &ie);
                    
        ===> wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
                      NULL, 0, &sm->ptk)
             ====> wpa_sm_alloc_eapol ,init epaol packet
                   =====> wpa_eapol_key_send(sm, ptk->kck, ver, dst,
               ETH_P_EAPOL,  rbuf, rlen, reply->key_mic);
        一个ACK ,没有什么实质内容,也不加密
        ===> wpa_supplicant_install_ptk (struct wpa_sm *sm,
                   const struct wpa_eapol_key *key)
              ====> 设置driver key !!! wpa_sm_set_key
                    wpa_driver_nl80211_set_key  (nl80211 driver)
                    wap_supplicant 的 终极目标,终于看到了!
      PTK 安装好了,稍侯片刻,马上结束
        ===> eapol_sm_notify_portValid(sm->eapol, TRUE);
               前面associate 成功后 PAE 处于 CONNECTING
               到这里 portValid = TRUE, 但PAE 状态没发生变化
        ===> wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
             WPA State 从 4WAY_HANDSHAKE -> GROUP_HANDSHAKE
        ===> wpa_supplicant_pairwise_gtk(sm, key, ie.gtk,ie.gtk_len,
                                    key_info)
             从代码中看加密的GTK 3/4 way  中的IE部分就发来了!!!
             wpa_supplicant_check_group_cipher
      用双方都已知道的PTK 的 EPAOL KEK 加的密 )现在解开来
             ====> wpa_supplicant_install_gtk(sm, &gd, key->key_rsc)
            安装组密码
             ====> wpa_supplicant_key_neg_complete   key 协商完成
                   =====> wpa_sm_cancel_auth_timeout(sm);
            将前面设置的认证超时处理取消
                   =====> wpa_sm_set_state(sm, WPA_COMPLETED);
             wpa state 从 GROUP_HANDSHAKE -> COMPLETED
                   =====> if (secure) {
                            ......
                     eapol_sm_notify_portValid(sm->eapol, TRUE);
                     eapol_sm_notify_eap_success(sm->eapol, TRUE);
       PAE 进入AUTHENTICATING
       BE  进入success
       EAP 返回diable
       PAE 最终进入AUTHENTICATED
         然后eapol_sm_set_port_authorized
                              然后wpa_supplicant_port_cb
         然后wpa_drv_set_supp_port
         设置driver NL80211_STA_FLAG_AUTHORIZED
到此为止,认证完成
整个过程的WPA State变化如下:
(wpa_supplicant)
DISCONNECTED    -> SCANNING
SCANNING        -> AUTHENTICATING      (802.11身份认证 )
AUTHENTICATING  -> ASSOCIATING
SCANNING        -> ASSOCIATING
ASSOCIATING     -> ASSOCIATED    
     
ASSOCIATED      -> 4WAY_HANDSHAKE
4WAY_HANDSHAKE  -> 4WAY_HANDSHAKE
4WAY_HANDSHAKE  -> GROUP_HANDSHAKE
GROUP_HANDSHAKE -> COMPLETED
PAE supplicant 端状态图
 
http://blog.chinaunix.net/attachment/201207/2/20514606_1341204365oGMo.jpgwifi connect AP 跟踪" TITLE="wpa_supplicant(2) wifi connect AP 跟踪" />
 
结束
 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有