<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                WPAS中,WSC的處理就不像在App及Framework WifiService中那么簡單。先來看WSC的初始化流程。 **1、WSC模塊初始化** WSC模塊的初始化工作位于wpa_supplicant_init_iface(不熟悉的讀者請參考4.3.4節“wpa_supplicant_init_iface分析之五”)函數的最后幾行中,相關代碼如下所示。 **wpa_supplicant.c::wpa_supplicant_init_iface** ~~~ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,struct wpa_interface *iface) { ......// 其他代碼。可參考4.3.4節“wpa_supplicant_init_iface分析之五” // 調用wpas_wps_init函數初始化WSC相關模塊 if (wpas_wps_init(wpa_s)) return -1; if (wpa_supplicant_init_eapol(wpa_s) < 0) return -1; wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol); ...... } ~~~ 注意,在WPAS代碼中WSC稱為WPS2。為了行文方便,以后將不再區分WPS和WSC。 wpas_wps_init的代碼如下所示。 **wps_supplicant.c::wpas_wps_init** ~~~ int wpas_wps_init(struct wpa_supplicant *wpa_s) { struct wps_context *wps; // wps_context是WPS模塊的核心數據結構 // wps_registrar_config代表Registrar的配置信息 struct wps_registrar_config rcfg; struct hostapd_hw_modes *modes; u16 m; wps = os_zalloc(sizeof(*wps)); ...... /* 設置兩個重要的回調函數。其中,cred_cb在EAP-WSC模塊解析credential屬性集時使用。后面將見到其用法。 event_cb用于通知WSC模塊發生的一些事件。例如“WSC-SUCCESS”就在wpa_supplicant_wps_event 中處理。 */ wps->cred_cb = wpa_supplicant_wps_cred; wps->event_cb = wpa_supplicant_wps_event; wps->cb_ctx = wpa_s; // 初始化設備信息,這些信息來自圖6-33中的配置 wps->dev.device_name = wpa_s->conf->device_name; wps->dev.manufacturer = wpa_s->conf->manufacturer; wps->dev.model_name = wpa_s->conf->model_name; wps->dev.model_number = wpa_s->conf->model_number; wps->dev.serial_number = wpa_s->conf->serial_number; wps->config_methods = // 將字符串描述的WSC方法轉換成對應的標志位 wps_config_methods_str2bin(wpa_s->conf->config_methods); ......// 配置參數檢查,Label和Display不能同時配置。即設備不能同時使用靜態PIN碼和動態PIN碼 /* WSC規范新增了Virtual Push Button和Virtual Display兩種方法,wps_fix_config_methods 函數將判斷設備是否支持Push Button或者Display。如果二者支持,需要為WSC添加對應的Virtual 方法。下面這個函數僅在CONFIG_WPS2宏被定義的情況下有實際作用。 */ wps->config_methods = wps_fix_config_methods(wps->config_methods); wps->dev.config_methods = wps->config_methods; os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type, WPS_DEV_TYPE_LEN); wps->dev.num_sec_dev_types = wpa_s->conf->num_sec_device_types; os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type, WPS_DEV_TYPE_LEN * wps->dev.num_sec_dev_types); wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version); modes = wpa_s->hw.modes; // 設置RF Bands相關信息 if (modes) { for (m = 0; m < wpa_s->hw.num_modes; m++) { if (modes[m].mode == HOSTAPD_MODE_IEEE80211B || modes[m].mode == HOSTAPD_MODE_IEEE80211G){ wps->dev.rf_bands |= WPS_RF_24GHZ; } else if (modes[m].mode == HOSTAPD_MODE_IEEE80211A){ wps->dev.rf_bands |= WPS_RF_50GHZ; } } } if (wps->dev.rf_bands == 0) wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ; os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN); wpas_wps_set_uuid(wpa_s, wps); // 設置uuid,如果沒有配置的話,則利用MAC地址生成UUID // STA默認支持的認證算法和加密算法 // 結合前面介紹的理論知識,讀者能想起來對應的Attribute是什么嗎 wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK; wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP; os_memset(&rcfg, 0, sizeof(rcfg)); rcfg.new_psk_cb = wpas_wps_new_psk_cb; rcfg.pin_needed_cb = wpas_wps_pin_needed_cb; rcfg.set_sel_reg_cb = wpas_wps_set_sel_reg_cb; rcfg.cb_ctx = wpa_s; /* 創建一個wps_registrar對象,該對象代表Registrar。不過Enrollee中用不到它,故此處不開展 分析。感興趣的讀者請在學完本章后再自行研究相關內容。 */ wps->registrar = wps_registrar_init(wps, &rcfg); ...... wpa_s->wps = wps; return 0; } ~~~ 圖6-33為Galaxy Note 2中wpa_supplicant.conf的配置文件。 :-: ![](https://box.kancloud.cn/7530cc5c12effc8636ae777ebf17b5aa_860x290.jpg) 圖6-33 wpa_supplicant.conf示例 下面來看WPS_PIN命令的處理流程。 **2、WPS_PIN命令處理** 根據前文介紹,WifiStateMachine將發送"WPS_PIN any"命令給WPAS以觸發WSC的工作流程。該命令的處理代碼如下所示。 **ctrl_iface.c::wpa_supplicant_ctrl_iface_wps_pin** ~~~ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s, char *cmd,char *buf, size_t buflen) { u8 bssid[ETH_ALEN], *_bssid = bssid; char *pin; int ret; /* cmd傳入此函數時已經將“WPS_PIN any”中的“WPS_PIN ”(注意右邊引號前的空格)子串忽略了, 所以cmd的取值是“any”。 */ pin = os_strchr(cmd, ' '); if (pin) *pin++ = '\0'; if (os_strcmp(cmd, "any") == 0) _bssid = NULL; ...... if (pin) { // 上層沒有傳入PIN碼,故略去此段代碼 } // 啟動WPS流程。詳情見下文 ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT); ...... done: ret = os_snprintf(buf, buflen, "%08d", ret); // 將PIN碼轉成字符串返回給WifiStateMachine return ret; } ~~~ 上述代碼中,wpas_wps_start_pin函數將被調用以開始WPS流程。調用該函數時,相關的參數取值情況是:_bssid為NULL,DEV_PW_DEFAULT值為0。 來看wpas_wps_start_pin的代碼,如下所示。 **wps_supplicant.c::wpas_wps_start_pin** ~~~ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,const char *pin, int p2p_group, u16 dev_pw_id) { struct wpa_ssid *ssid; char val[128]; unsigned int rpin = 0; wpas_clear_wps(wpa_s); // 清空之前的WPS信息 /* wpas_wps_add_network將創建一個wpa_ssid對象,它用于保存一個無線網絡的配置信息。 在wpas_wps_add_network中,該網絡的key_mgmt將被為WPA_KEY_MGMT_WPS。另外,每一個wpa_ssid對象 都有一個類型為eap_peer_config的成員,該成員用于保存EAP Supplicant的配置信息。對于WPS來說, 該配置信息的Method被設置為EAP-WSC,identity被設為“WFA-SimpleConfig-Enrollee-1-0”。 wpas_wps_add_network函數比較簡單,請讀者自行研究。 */ ssid = wpas_wps_add_network(wpa_s, 0, bssid); ...... ssid->temporary = 1; ssid->p2p_group = p2p_group; ......// CONFIG_P2P的處理 if (pin){ os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u\"",pin, dev_pw_id); }else { /* 生成一個隨機PIN碼。WSC對PIN碼格式有所規定。PIN碼一共包含8個數字,最后一個數字(即最右邊的 一個數字是前7個數字的校驗和)。 */ rpin = wps_generate_pin(); // 以圖6-2為例,PIN碼為“01308204”,所以下面val的值為“pin=01308204 dev_pw_id=0” os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u\"",rpin, dev_pw_id); } // 將value值保存到wpa_ssid中eap成員變量的phase1中 wpa_config_set(ssid, "phase1", val, 0); if (wpa_s->wps_fragment_size) ssid->eap.fragment_size = wpa_s->wps_fragment_size; // 注冊一個WSC超時任務,超時時間是120秒。該時間也是由WSC規范規定的 eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, wpa_s, NULL); // 重新關聯并發起掃描。該函數比較簡單,請讀者自行研究。該函數內部將發起掃描請求 wpas_wps_reassoc(wpa_s, ssid, bssid); return rpin; } ~~~ 由上述代碼可知,wpas_wps_start_pin添加了一個潛在的和WPS相關的無線網絡配置項。接下來的工作自然是需要掃描周圍的無線網絡以搜索那些支持WSC功能的AP。這一工作正是屬于前文介紹的WSC Discovery Phase。 **3、發起掃描請求** 根據前文對WSC基礎知識的介紹,STA發起掃描請求時需要在Probe Request幀中添加WSC IE。WPAS中,掃描工作的代碼在wpa_supplicant_scan函數中,我們重點關注其中和WSC相關的部分,如下所示。 **scan.c::wpa_supplicant_scan** ~~~ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx){ ......// 該函數的詳情請參考4.5.3節“無線網絡掃描流程分析” wpa_supplicant_optimize_freqs(wpa_s, &params); // 下面這個函數將處理WSC IE extra_ie = wpa_supplicant_extra_ies(wpa_s, &params); } ~~~ **scan.c::wpa_supplicant_extra_ies** ~~~ static struct wpabuf *wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params){ struct wpabuf *extra_ie = NULL; #ifdef CONFIG_WPS // 處理WPS int wps = 0; enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; #endif /* CONFIG_WPS */ #ifdef CONFIG_WPS /* wpas_wps_in_use判斷是否需要在Probe Request中添加WSC IE。WPAS的判斷標準比較簡單, 就是查詢所有的wpa_ssid對象,判斷它們的key_mgmt是否設置了WPA_KEY_MGMT_WPS。如果有, 表明搜索的時候需要支持WSC IE。我們在介紹“WPS_PIN命令處理”時曾說過,WPAS將添加一個 wpa_ssid對象,并設置key_mgmt為WPA_KEY_MGMT_WPS。 wpas_wps_in_use的返回值也有含義,返回1表明使用PIN方法,返回2表明使用PBC方法。 wpas_wps_in_use函數比較簡單,請讀者自行閱讀。 */ wps = wpas_wps_in_use(wpa_s, &req_type); if (wps) { struct wpabuf *wps_ie; // 構造Probe Request中的WSC IE wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev, wpa_s->wps->uuid, req_type, 0, NULL); if (wps_ie) { if (wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0) wpabuf_put_buf(extra_ie, wps_ie); wpabuf_free(wps_ie); } } ......// CONFIG_P2P處理 #endif /* CONFIG_WPS */ return extra_ie; } ~~~ wps_build_probe_req_ie用于構造WSC IE,讀者可簡單了解一下該函數,相關代碼如下所示。 **wps.c::wps_build_probe_req_ie** ~~~ struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev, const u8 *uuid, enum wps_request_type req_type,unsigned int num_req_dev_types, const u8 *req_dev_types) { struct wpabuf *ie; ie = wpabuf_alloc(500); ...... if (wps_build_version(ie) ||wps_build_req_type(ie, req_type) || wps_build_config_methods(ie, dev->config_methods) ||wps_build_uuid_e(ie, uuid) || wps_build_primary_dev_type(dev, ie) || wps_build_rf_bands(dev, ie) || wps_build_assoc_state(NULL, ie) || wps_build_config_error(ie, WPS_CFG_NO_ERROR) || wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT) || #ifdef CONFIG_WPS2 // WPS2即WSC wps_build_manufacturer(dev, ie) || wps_build_model_name(dev, ie) || wps_build_model_number(dev, ie) || wps_build_dev_name(dev, ie) || wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0) || #endif /* CONFIG_WPS2 */ wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types) ||wps_build_secondary_dev_type(dev, ie)) { ...... // 錯誤處理 } ...... return wps_ie_encapsulate(ie); } ~~~ 最后,WPAS將發送攜帶了WSC IE的Probe Request幀。對于Galaxy Note 2來說,其發送的WSC IE信息可參考圖6-18。 **4、處理掃描結果** 發送掃描請求后,WPAS下一步的工作就是處理搜索到的掃描結果。這部分的流程在4.5.3節掃描結果處理流程中有詳細分析。在該流程中,和WSC相關的工作如下。 * wpa_supplicant_get_scan_results:獲取掃描結果。該函數內部將對搜索到的AP進行排序,它對WSC有特殊處理。 * wpa_supplicant_pick_network:選擇合適的AP作為目標AP。如果使用WSC的話,該函數將優先選擇支持WSC的AP。 下面將分別介紹上述兩個函數中和WSC處理相關的流程。 **①、wpa_supplicant_get_scan_results處理** 代碼如下。 **scan.c::wpa_supplicant_get_scan_results** ~~~ struct wpa_scan_results * wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,struct scan_info *info, int new_scan) { ...... // 獲取掃描結果 scan_res = wpa_drv_get_scan_results2(wpa_s); #ifdef CONFIG_WPS // WPAS當前處于WPS處理過程中,設置排序函數為wpa_scan_result_wps_compar if (wpas_wps_in_progress(wpa_s)) compar = wpa_scan_result_wps_compar; #endif /* CONFIG_WPS */ // 利用qsort函數對掃描結果進行升序排序。排序時將使用compar函數將較兩個元素A、B的大小 // compar返回負數,表示A < B,compar返回0,表示A=B,compar返回正數,表示A > B qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *),compar); ......// 更新BSS return scan_res; } struct wpa_scan_results * wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,struct scan_info *info, int new_scan) { ...... // 獲取掃描結果 scan_res = wpa_drv_get_scan_results2(wpa_s); #ifdef CONFIG_WPS // WPAS當前處于WPS處理過程中,設置排序函數為wpa_scan_result_wps_compar if (wpas_wps_in_progress(wpa_s)) compar = wpa_scan_result_wps_compar; #endif /* CONFIG_WPS */ // 利用qsort函數對掃描結果進行升序排序。排序時將使用compar函數將較兩個元素A、B的大小 // compar返回負數,表示A < B,compar返回0,表示A=B,compar返回正數,表示A > B qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *),compar); ......// 更新BSS return scan_res; } ~~~ 由上述代碼可知,當WPAS正處于WPS處理流程中,搜索到的AP將通過qsort以及wpa_scan_result_wps_compar進行排序比較。wpa_scan_result_wps_compar的代碼如下所示。 **scan.c::wpa_scan_result_wps_compar** ~~~ static int wpa_scan_result_wps_compar(const void *a, const void *b) { struct wpa_scan_res **_wa = (void *) a; struct wpa_scan_res **_wb = (void *) b; struct wpa_scan_res *wa = *_wa; struct wpa_scan_res *wb = *_wb; int uses_wps_a, uses_wps_b; struct wpabuf *wps_a, *wps_b; int res; /* wpa_scan_get_vendor_ie返回值的類型為u8*,它指向wpa_scan_res中指定IE(此處是 WSC IE)所在的內存位置。如果wpa_scan_res中沒有WSC IE,則返回為空。 */ uses_wps_a = wpa_scan_get_vendor_ie(wa, WPS_IE_VENDOR_TYPE) != NULL; uses_wps_b = wpa_scan_get_vendor_ie(wb, WPS_IE_VENDOR_TYPE) != NULL; // 無線網絡A支持WPS,而B不支持,則返回-1。這樣,在“排座位”的時候,A將排在前面(A < B) if (uses_wps_a && !uses_wps_b) return -1; // 無線網絡A不支持WPS,而B支持,則B排在前面(B < A) if (!uses_wps_a && uses_wps_b) return 1; // 如果無線網絡A和B均支持WPS,則還需要進一步判斷 if (uses_wps_a && uses_wps_b) { /* wpa_scan_get_vendor_ie_multi將從拷貝指定IE的內容復制到一塊新的內存中,該內存地址即 wpa_scan_get_vendor_ie_multi的返回值。 */ wps_a = wpa_scan_get_vendor_ie_multi(wa, WPS_IE_VENDOR_TYPE); wps_b = wpa_scan_get_vendor_ie_multi(wb, WPS_IE_VENDOR_TYPE); /* 如果周圍有多個支持WPS的無線網絡,則設置Selected Registrar屬性(而且值為1)的AP 將位于前排。 */ res = wps_ap_priority_compar(wps_a, wps_b); wpabuf_free(wps_a); // 釋放wpa_scan_get_vendor_ie_multi創建的新內存 wpabuf_free(wps_b); if (res) return res; } // 對于沒有WSC支持的AP,其排座順序僅考慮它們的信號強度和質量 if (wb->level == wa->level) return wb->qual - wa->qual; return wb->level - wa->level; } ~~~ 根據上面的代碼可知,WSC的AP掃描結果“排座”規則如下。 * 支持WSC功能的AP排在不支持WSC的AP之前。 * 對于兩個同時支持WSC功能的AP來說,Selected Regsitrar值為1的AP排在前面。 * 對于不支持WSC的AP來說,信號強度和質量好的AP排在前面。 當掃描結果排完序后,WPAS的下一步工作就是從眾多搜索到的AP中挑選一個作為目標AP以發起關聯請求。該工作由wpa_supplicant_pick_network完成。 **2、wpa_supplicant_pick_network處理** wpa_supplicant_pick_nework的代碼比較簡單,如下所示。 **events.c::wpa_supplicant_pick_nework** ~~~ static struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res, struct wpa_ssid **selected_ssid) { struct wpa_bss *selected = NULL; int prio; while (selected == NULL) { // 按照優先級搜索掃描結果 for (prio = 0; prio < wpa_s->conf->num_prio; prio++) { selected = wpa_supplicant_select_bss(wpa_s, scan_res, wpa_s->conf->pssid[prio], selected_ssid); if (selected) break; } ......// 其他處理 } return selected; } ~~~ wpa_supplicant_select_bss內部將通過調用wpa_scan_res_match的函數來選取一個合適的無線網絡。該函數的代碼如下所示。 **events.c::wpa_scan_res_match** ~~~ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, int i, struct wpa_scan_res *bss,struct wpa_ssid *group) { const u8 *ssid_; u8 wpa_ie_len, rsn_ie_len, ssid_len; int wpa; struct wpa_blacklist *e; const u8 *ie; struct wpa_ssid *ssid; ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); ssid_ = ie ? ie + 2 : (u8 *) ""; ssid_len = ie ? ie[1] : 0; ...... for (ssid = group; ssid; ssid = ssid->pnext) { int check_ssid = wpa ? 1 : (ssid->ssid_len != 0); ...... #ifdef CONFIG_WPS if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) continue; /* 通過“WPS_PIN any”命令創建的wpa_ssid還沒有設置ssid。wpas_wps_ssid_wildcard_ok 用于判斷是否需要進行ssid檢查。該函數內部將利用下文代碼中提到的wps_is_addr_authorized函數。 由于筆者測試用的AP僅支持WPS,所以wpas_wps_ssid_wildcard_ok返回非零值。這樣,if條件生效, check_ssid被設置為0。 */ if (wpa && ssid->ssid_len == 0 && wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss)) check_ssid = 0; ...... #endif /* CONFIG_WPS */ ......// 其他判斷 // 該函數內部先調用wpas_wps_ssid_bss_match函數以判斷是否有合適的AP,如果有則選中它 if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss)) continue; ......// 其他判斷。例如檢查wpa_ssid中的ssid是否匹配搜索結果中的ssid。如果不匹配,則不能選擇該AP return ssid; } return NULL; } ~~~ 直接來看wpas_wps_ssid_bss_match函數,代碼如下所示。 **wpa_supplicant.c::wpas_wps_ssid_bss_match** ~~~ int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,struct wpa_ssid *ssid, struct wpa_scan_res *bss) { struct wpabuf *wps_ie; if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) return -1; // 獲取該WSC IE信息 wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); if (eap_is_wps_pbc_enrollee(&ssid->eap)) { ...... // PBC處理 } // 判斷eap_peer_config設置的identity是否為“WFA-SimpleConfig-Enrollee-1-0” if (eap_is_wps_pin_enrollee(&ssid->eap)) { ....... /* 筆者使用的AP沒有包含AuthorizedMACs子屬性,并且該AP也不支持WSC。所以下面這個函數將返回1, 如此,if判斷失敗。讀者可參考圖6-19。 */ // AP返回的Probe Response幀信息 if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) ...... else { wpa_printf(MSG_DEBUG, " selected based on WPS IE " "(Authorized MAC or Active PIN)"); } wpabuf_free(wps_ie); return 1; // 選中 } ...... return -1; } ~~~ 總之,在周圍空間有很多無線網絡的情況下,筆者測試WSC時使用的AP將會被選中作為目標AP。接下來的流程就和4.5.3節關聯無線網絡處理流程分析的內容一樣,STA將關聯到目標AP。對于非WSC來說,AP和STA將開展4-Way Handshake流程,而對于WSC來說,AP和STA將開展EAP-WSC流程。 馬上來看EAP-WSC處理流程,它也是整個WSC流程的核心內容。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看