<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國際加速解決方案。 廣告
                根據7.3.2節中對DISCOVER_PEERS命令的代碼分析可知,P2pStateMachine將發 送"P2P_FIND 120"命令給WPAS以觸發P2P Device Discovery流程。處理該命令的代碼如下所 示。 **ctrl_iface.c::wpa_supplicant_ctrl_iface_process** ~~~ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, char *buf, size_t *resp_len) { char *reply; const int reply_size = 4096; int ctrl_rsp = 0; int reply_len; ...... #ifdef CONFIG_P2P // 處理帶參數的P2P_FIND命令 } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) { // 注意“P2P_FIND ”多了一個空格 if (p2p_ctrl_find(wpa_s, buf + 9)) reply_len = -1; } else if (os_strcmp(buf, "P2P_FIND") == 0) { // 處理不帶參數的P2P_FIND命令 if (p2p_ctrl_find(wpa_s, "")) reply_len = -1; } ......// 其他P2P命令處理 #endif ...... } ~~~ 不論P2P_FIND命令是否攜帶參數,其最終的處理函數都將對應為p2p_ctrl_find,如下所示。 **ctrl_iface.c::p2p_ctrl_find** ~~~ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd) { unsigned int timeout = atoi(cmd); enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL; // 搜索方式,見下文解釋 u8 dev_id[ETH_ALEN], *_dev_id = NULL; char *pos; // 設置搜索方式,見下文解釋 if (os_strstr(cmd, "type=social")) type = P2P_FIND_ONLY_SOCIAL; else if (os_strstr(cmd, "type=progressive")) type = P2P_FIND_PROGRESSIVE; pos = os_strstr(cmd, "dev_id=");// dev_id代表peer端device的MAC地址 if (pos) {......} // wpas_p2p_find內部將調用p2p_find,下文將直接分析p2p_find return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id); } ~~~ P2P_FIND支持三種不同的Discovery Type,分別如下。 * P2P_FIND_START_WITH_FULL:默認設置。表示先掃描所有頻段,然后再掃描socialchannels。這種搜索方式如圖7-3所示。 * P2P_FIND_ONLY_SOCIAL:只掃描social channels。它將跳過“掃描所有頻段”這一過程。這種搜索方式能加快搜索的速度。 * P2P_FIND_PROGRESSIVE:它和P2P_FIND_START_WITH_FULL類似,只不過在SearchState階段將逐個掃描所有頻段。為什么在search state階段會掃描所有頻段呢?請讀者參考圖7-22中的狀態切換路線14。當周圍已經存在Group的時候,如果在最初的“掃描所有頻段”這一過程中沒有發現Group,則在后續的search state逐個掃描頻段過程中就有可能發現之前那些沒有找到的Group。 >[info] 注意 GO將工作在Operation Channel,而Listen Channel只在最初的P2P Device Discovery階段使用。 **1、P2P設備掃描流程** P2P設備掃描流程從wpas_p2p_find開始,其代碼如下所示。 **p2p_supplicant.c::wpas_p2p_find** ~~~ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout, enum p2p_discovery_type type,unsigned int num_req_dev_types, const u8 *req_dev_types, const u8 *dev_id) { /* 取消還未發送的Action幀數據。WPAS中,待發送的Action幀數據保存在wpa_supplicant對象的 pending_action_tx變量中,它指向一塊數據緩沖區。 */ wpas_p2p_clear_pending_action_tx(wpa_s); wpa_s->p2p_long_listen = 0; /* 如果wifi driver能直接處理P2P管理,則主要工作將由wifi driver來完成。Galaxy Note 2 不支持WPA_DRIVER_FLAGS_P2P_MGMT。 */ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) return wpa_drv_p2p_find(wpa_s, timeout, type); ...... // 取消計劃掃描任務 wpa_supplicant_cancel_sched_scan(wpa_s); // 調用p2p_find函數 return p2p_find(wpa_s->global->p2p, timeout, type, num_req_dev_types, req_dev_types, dev_id); } ~~~ 來看p2p_find函數,其代碼如下所示。 **p2p.c::p2p_find** ~~~ int p2p_find(struct p2p_data *p2p, unsigned int timeout, enum p2p_discovery_type type, unsigned int num_req_dev_types, const u8 *req_dev_types, const u8 *dev_id) { int res; p2p_free_req_dev_types(p2p); if (req_dev_types && num_req_dev_types) {......// 本例沒有設置request dev type屬性} if (dev_id) { os_memcpy(p2p->find_dev_id_buf, dev_id, ETH_ALEN); p2p->find_dev_id = p2p->find_dev_id_buf; } else p2p->find_dev_id = NULL; // 注意下面這個P2P_AFTER_SCAN_NOTHING標志,它表示P2P設備完成scan動作后,無須做其他動作 p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING; p2p_clear_timeout(p2p); p2p->cfg->stop_listen(p2p->cfg->cb_ctx);// 停止監聽 p2p->find_type = type; p2p_device_clear_reported(p2p); p2p_set_state(p2p, P2P_SEARCH); // 設置P2P模塊的狀態為P2P_SEARCH eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); p2p->last_p2p_find_timeout = timeout; // 注冊一個掃描超時處理任務 if (timeout) eloop_register_timeout(timeout, 0, p2p_find_timeout,p2p, NULL); switch (type) { case P2P_FIND_START_WITH_FULL: case P2P_FIND_PROGRESSIVE: // p2p_scan函數指針指向wpas_p2p_scan res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0, p2p->num_req_dev_types,p2p->req_dev_types, dev_id); break; case P2P_FIND_ONLY_SOCIAL: res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SOCIAL, 0, p2p->num_req_dev_types,p2p->req_dev_types, dev_id); break; default: return -1; } if (res == 0) { // 設置p2p_scan_running值為1,該變量后面用到的地方比較多,請讀者注意 p2p->p2p_scan_running = 1; eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL); eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,p2p, NULL); } ...... // 略去res為其他值的處理情況 return res; } ~~~ 上述代碼中p2p_config對象的p2p_scan函數指針變量將指向p2p_supplicant.c中的wpas_p2p_scan,馬上來看它,代碼如下所示。 **p2p_supplicant.c::wpas_p2p_scan** ~~~ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, unsigned int num_req_dev_types, const u8 *req_dev_types, const u8 *dev_id) { struct wpa_supplicant *wpa_s = ctx; // 掃描參數 struct wpa_driver_scan_params params; int ret; struct wpabuf *wps_ie, *ies; int social_channels[] = { 2412, 2437, 2462, 0, 0 }; size_t ielen; int was_in_p2p_scan; os_memset(&params, 0, sizeof(params)); params.num_ssids = 1; // 設置SSID參數,P2P_WILDCARD_SSID的值為“DIRECT-” params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID; params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN; wpa_s->wps->dev.p2p = 1; // 構造Probe Request幀中WSC IE信息 wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid, WPS_REQ_ENROLLEE,num_req_dev_types, req_dev_types); ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen); ...... // 構造P2P IE信息,感興趣的讀者不妨自行閱讀p2p_scan_ie函數 p2p_scan_ie(wpa_s->global->p2p, ies, dev_id); params.p2p_probe = 1; params.extra_ies = wpabuf_head(ies); params.extra_ies_len = wpabuf_len(ies); switch (type) { case P2P_SCAN_SOCIAL: // 只掃描social channels的話,將設置params.freqs變量 params.freqs = social_channels; break; case P2P_SCAN_FULL: break; ......// 其他掃描頻段控制 } was_in_p2p_scan = wpa_s->scan_res_handler == wpas_p2p_scan_res_handler; // 設置P2P掃描結果處理函數 wpa_s->scan_res_handler = wpas_p2p_scan_res_handler; // 發起P2P設備掃描,該函數內部將調用driver_nl80211.c的wpa_driver_nl80211_scan函數 ret = wpa_drv_scan(wpa_s, &params); wpabuf_free(ies); ...... return ret; } ~~~ 讀者可比較本節和4.5.3節無線網絡掃描流程分析的內容。總體而言,P2P設備掃描的代碼邏輯比無線網絡掃描的代碼邏輯要簡單得多。圖7-31為WPAS中P2P設備掃描所涉及的幾個重要函數調用。 :-: ![](https://box.kancloud.cn/047f76b28481e0e5ba5868126492983f_1251x576.jpg) 圖7-31 P2P Device掃描流程 下面來看P2P設備掃描結果的處理流程。 **2、P2P設備掃描結果處理流程** 由4.5.3節“_wpa_supplicant_event_scan_results分析之二”中的代碼可知,當scan_res_handler不為空的時候,掃描結果將交給scan_res_handler來處理。由圖7-31可知,對P2P設備掃描時將設置scan_res_handler為wpas_p2p_scan_res_handler,其代碼如下所示。 **p2p_supplicant.c::wpas_p2p_scan_res_handler** ~~~ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { size_t i; ...... for (i = 0; i < scan_res->num; i++) { struct wpa_scan_res *bss = scan_res->res[i]; // ①對每一個掃描結果調用p2p_scan_res_handler函數 if (p2p_scan_res_handler(wpa_s->global->p2p, bss->bssid,// 處理掃描結果 bss->freq, bss->level,(const u8 *) (bss + 1), bss->ie_len) > 0) break; } p2p_scan_res_handled(wpa_s->global->p2p);// ②處理完畢后調用p2p_scan_res_handled } ~~~ wpas_p2p_scan_res_handler中有兩個關鍵函數,先來看第一個。 **①、p2p_scan_res_handler函數** p2p_scan_res_handler的代碼如下所示。 **p2p.c::p2p_scan_res_handler** ~~~ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq, int level, const u8 *ies, size_t ies_len) { // 添加一個P2P Device,詳情見下文代碼分析 p2p_add_device(p2p, bssid, freq, level, ies, ies_len); /* go_neg_peer代表GON的對端設備,如果go_neg_peer不為空而且設備掃描時由發現了它,則直接通過 p2p_connect_send向其發送GON Request幀以開展GON流程。 */ if (p2p->go_neg_peer && p2p->state == P2P_SEARCH && os_memcmp(p2p->go_neg_peer->info.p2p_device_addr, bssid, ETH_ALEN) == 0) { p2p_connect_send(p2p, p2p->go_neg_peer); return 1; } return 0; } ~~~ 上述代碼中最重要的是p2p_add_device函數,其代碼如下所示。 **p2p.c::p2p_add_device** ~~~ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level, const u8 *ies, size_t ies_len) { struct p2p_device *dev; struct p2p_message msg; const u8 *p2p_dev_addr; int i; os_memset(&msg, 0, sizeof(msg)); // 解析掃描結果中的IE信息,解析完的結果保存在一個p2p_message對象中 if (p2p_parse_ies(ies, ies_len, &msg)) {......// 解析掃描結果} // p2p device info中的屬性 if (msg.p2p_device_addr) p2p_dev_addr = msg.p2p_device_addr; else if (msg.device_id) p2p_dev_addr = msg.device_id; ...... // 過濾那些被阻止的P2P Device if (!is_zero_ether_addr(p2p->peer_filter) && os_memcmp(p2p_dev_addr, p2p->peer_filter, ETH_ALEN) != 0) {......} // 構造一個p2p_device對象,并將其加入p2p_data結構體的devices鏈表中 dev = p2p_create_device(p2p, p2p_dev_addr);// 創建一個P2P Device對象 ...... os_get_time(&dev->last_seen);// 設置發現該P2P Device的時間 // p2p_device的flags變量代表該p2p_device的一些信息 dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY); if (os_memcmp(addr, p2p_dev_addr, ETH_ALEN) != 0) os_memcpy(dev->interface_addr, addr, ETH_ALEN); ......// 處理ssid、listen channel等內容 dev->listen_freq = freq; // 如果對端P2P Device是GO,它回復的Probe Response幀P2P IE信息中將包含Group Info屬性 if (msg.group_info) dev->oper_freq = freq; dev->info.level = level; p2p_copy_wps_info(dev, 0, &msg);// 復制WSC IE ......// 處理Vendor相關的IE信息 // 根據Group Info信息添加Client。就本例而言,周圍還不存在GO p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq, msg.group_info,msg.group_info_len); p2p_parse_free(&msg); // 判斷是否有Service Discovery Request,如果有,需要為flags設置P2P_DEV_SD_SCHEDULE標志位 if (p2p_pending_sd_req(p2p, dev)) dev->flags |= P2P_DEV_SD_SCHEDULE; // P2P_DEV_REPORTED表示WPAS已經向客戶端匯報過該P2P Device信息了 if (dev->flags & P2P_DEV_REPORTED) return 0; // P2P_DEV_USER_REJECTED表示用戶拒絕該P2P Device信息 if (dev->flags & P2P_DEV_USER_REJECTED) {return 0;} /* dev_found函數指針指向wpas_dev_found,該函數將向WifiMonitor發送消息以告知我們找到了一個 P2P Device,該消息也稱為P2P Device Found消息。 */ p2p->cfg->dev_found(p2p->cfg->cb_ctx, addr, &dev->info, !(dev->flags & P2P_DEV_REPORTED_ONCE)); // 下面這兩個標志表示該P2P Device已經向客戶端匯報過并且匯報過一次了 dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE; return 0; } ~~~ 圖7-32為WPAS向其客戶端匯報的P2P Device Found消息的格式示例。 :-: ![](https://box.kancloud.cn/f038f613f3ec8aaa98406da54b57ebfd_768x97.jpg) 圖7-32 P2P Device Found消息 **②、p2p_scan_res_handled函數** 接著來看第二個關鍵函數p2p_scan_res_handled。 **p2p.c::p2p_scan_res_handled** ~~~ void p2p_scan_res_handled(struct p2p_data *p2p) { ...... p2p->p2p_scan_running = 0; // 設置p2p_scan_running值為0 eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);// 取消掃描超時處理任務 /* 還記得p2p_find函數中介紹的P2P_AFTER_SCAN_NOTHING標志嗎(參考7.4.2節)?它將用在 下面這個p2p_run_after_scan函數中。由于指定了P2P_AFTER_SCAN_NOTHING標志,所以下面這個 函數返回0。感興趣的讀者可自行研究p2p_run_after_scan函數。 */ if (p2p_run_after_scan(p2p)) return; if (p2p->state == P2P_SEARCH) // 就本例而言,將滿足此if條件 p2p_continue_find(p2p); } ~~~ p2p_continue_find的代碼如下所示。 **p2p.c::p2p_continue_find** ~~~ void p2p_continue_find(struct p2p_data *p2p) { struct p2p_device *dev; #ifdef ANDROID_P2P int skip=1; #endif p2p_set_state(p2p, P2P_SEARCH); ......// Service Discovery和Provision Discovery處理。就本例而言,這部分代碼邏輯意義不大 p2p_listen_in_find(p2p); // 進入listen state。來看此函數的代碼 } ~~~ **p2p.c::p2p_listen_in_find** ~~~ static void p2p_listen_in_find(struct p2p_data *p2p) { unsigned int r, tu; int freq; struct wpabuf *ies; // 根據p2p_supplicant.conf中listen_channel等配置參數獲取對應的頻段 freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class,p2p->cfg->channel); ...... // 計算需要在listen state等待的時間 os_get_random((u8 *) &r, sizeof(r)); tu = (r % ((p2p->max_disc_int - p2p->min_disc_int) + 1) +     p2p->min_disc_int) * 100; p2p->pending_listen_freq = freq; p2p->pending_listen_sec = 0; p2p->pending_listen_usec = 1024 * tu; /* 構造P2P Probe Response幀,當我們在Listen state收到其他設備發來的Probe Request幀后,wifi 驅動將直接回復此處設置的P2P Probe Response幀。 */ ies = p2p_build_probe_resp_ies(p2p); // start_listen指向wpas_start_listen函數 if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, 1024 *tu/1000,ies)<0){...... } wpabuf_free(ies); } ~~~ 由上述代碼可知,p2p_listen_in_find的內部實現完全遵循了7.2.2節介紹的和listen state相關的理論知識。 下面來看wpas_start_listen函數。 **p2p_supplicant.c::wpas_start_listen** ~~~ static int wpas_start_listen(void *ctx, unsigned int freq, unsigned int duration, const struct wpabuf *probe_resp_ie) { struct wpa_supplicant *wpa_s = ctx; /* 調用driver_nl80211.c的wpa_driver_set_ap_wps_p2p_ie函數,它用于將Probe Response幀信息和 Association Response幀信息。此函數為Android新增的功能,由廠商實現。 */ wpa_drv_set_ap_wps_ie(wpa_s, NULL, probe_resp_ie, NULL); /* 調用driver_nl80211.c的wpa_driver_nl80211_probe_req_report函數,其目的是讓wifi driver 收到Probe Request幀后,返回一個EVENT_RX_PROBE_REQ netlink消息給WPAS。 */ if (wpa_drv_probe_req_report(wpa_s, 1) < 0) {......} wpa_s->pending_listen_freq = freq; wpa_s->pending_listen_duration = duration; /* 調用driver_nl80211.c的wpa_driver_nl80211_remain_on_channel函數,其目的是讓 wlan設備在指定頻段(第二個參數freq)上停留duration毫秒。注意,這個函數的返回值只是表示 wifi driver是否成功處理了這個請求,它不能用于判斷wifi driver是否已經切換到了指定頻段。 如果一切正常,當wifi driver切換到指定頻段后,它將發送一個名為EVENT_REMAIN_ON_CHANNEL的 netlink消息給WPAS。 */ if (wpa_drv_remain_on_channel(wpa_s, freq, duration) < 0) {......} wpa_s->off_channel_freq = 0; wpa_s->roc_waiting_drv_freq = freq; return 0; } ~~~ wpas_start_listen比較簡單,不過有一些知識點請讀者注意。 * wpa_drv_set_ap_wps_ie為wifi driver設置了P2P IE信息。如果wifi driver自己處理Probe Resquest幀(即不發送EVENT_RX_PROBE_REQ消息給WPAS),則wifi driver將把此處設置的P2P IE信息填寫到Probe Response幀中。 * wpa_drv_probe_req_report要求wifi driver收到Probe Request幀后,發送EVENT_RX_PROBE_REQ消息給WPAS。WPAS內部將處理此消息,最終會回復一個Probe Response幀。這部分代碼請讀者自行閱讀。 * wpa_drv_remain_on_channel要求wifi driver在指定頻段工作一段時間。當wifi driver切換到指定頻段后,會發送EVENT_REMAIN_ON_CHANNEL消息給WPAS,WPAS內部將處理一些事情。這部分代碼也請讀者自行閱讀。 >[info] 提醒 筆者感覺wpa_drv_set_ap_wps_ie和wpa_drv_probe_req_report功能重復。不過由于driver.h對set_ap_wps_ie的功能描述不是特別清晰,請了解細節的讀者和我們分享相關的知識。另外,請讀者認真閱讀EVENT_RX_PROBE_REQ和EVENT_REMAIN_ON_CHANNEL消息的處理代碼。 **③、P2P設備掃描結果處理流程總結** 圖7-33展示了P2P設備掃描結果處理的流程。 :-: ![](https://box.kancloud.cn/37c720811f6860b2c6d14ae53414ed24_1000x681.jpg) 圖7-33 P2P設備掃描結果處理流程 >[info] 注意 圖7-33中,只有滿足一定條件,第6個及以后的函數才能執行。請讀者結合p2p_scan_res_handled的代碼來加深對圖7-32的體會。另外,由于Android平臺中wpa_driver_set_ap_wps_p2p_ie由廠商實現,故圖7-33沒有列出該函數。設備找到以后,下一步工作就是發起Provision Discovery流程,馬上來看它。
                  <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>

                              哎呀哎呀视频在线观看