<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>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                P2pStateMachine收到P2P_PROV_DISC_PBC_RSP_EVENT消息后,將在ProvisionDiscoveryState中調用p2pConnectWithPinDisplay,該函數內部將發送P2P_CONNECT命令給WPAS。馬上來看該命令的處理流程。 **1、P2P_CONNECT處理流程** P2P_CONNECT命令的參數比較多,而本例中P2pStateMachine發送的命令格式如下。 ~~~ P2P_CONNECT 8a:32:9b:6c:d1:80 pbc go_intent=7 //其中,"8a:32:9b:6c:d1:80"代表對端P2P設備地址 //"pbc"指定了WSC配置方法為PBC,"go_intent=7"設置GO Intent值為7 ~~~ P2P_CONNECT對應的處理函數為p2p_ctrl_connect,其代碼如下所示。 **ctrl_iface.c::p2p_ctrl_connect** ~~~ static int p2p_ctrl_connect(struct wpa_supplicant*wpa_s,   char *cmd,char *buf, size_t buflen) { u8 addr[ETH_ALEN]; char *pos, *pos2; char *pin = NULL; enum p2p_wps_method wps_method; int new_pin; int ret; int persistent_group; int join; int auth; int go_intent = -1; int freq = 0; if (hwaddr_aton(cmd, addr)) return -1; ......// 參數處理,最終調用的函數為wpas_p2p_connect new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, persistent_group, join, auth, go_intent,freq); ...... os_memcpy(buf, "OK\n", 3); return 3; } ~~~ wpas_p2p_connect的代碼如下所示。 **p2p_supplicant.c::wpas_p2p_connect** ~~~ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, const char *pin, enum p2p_wps_method wps_method, int persistent_group, int join, int auth, int go_intent,int freq) { int force_freq = 0, oper_freq = 0; u8 bssid[ETH_ALEN]; int ret = 0; enum wpa_driver_if_type iftype; const u8 *if_addr; ...... if (go_intent < 0) go_intent = wpa_s->conf->p2p_go_intent; wpa_s->p2p_wps_method = wps_method; wpa_s->p2p_pin[0] = '\0'; // 本例中,由于GON還未完成,GO角色未能確定,所以join為0 if (join) {......} ......// 頻段設置 /* 注意下面這個wpas_p2p_create_iface函數,它將判斷是否需要創建一個新的virtual interface,還記得 7.4.1節介紹Driver Flags和重要數據結構時提到的WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P 標志嗎?就本例而言,wifi driver flags中包含了該標志,所以下面這個函數的返回值為1,表示需要單獨創建 一個新的virtual interface供P2P使用。這個virtual interface的地址應該就是P2P Interface Address。 */ wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s); if (wpa_s->create_p2p_iface) { // 本例滿足此if條件 iftype = WPA_IF_P2P_GROUP; // 設置interface type if (go_intent == 15) iftype = WPA_IF_P2P_GO; // 本例的go_intent為7 /* 下面這個函數將創建此virtual interface,并獲取其interface address。以Galaxy Note 2 為例。P2P Device Address是“92:18:7c:69:88:e2”,而P2P Interface Address是 “92:18:7c:69:08:e2”。 wpas_p2p_add_group_interface內部將調用driver_nl80211.c的wpa_driver_nl80211_if_add 函數。感興趣的讀者不妨自行研究。 */ if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0) return -1; if_addr = wpa_s->pending_interface_addr; } else if_addr = wpa_s->own_addr; ....... // 下面這個函數內部將調用p2p_connect,我們將直接分析 if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method, go_intent, if_addr, force_freq,persistent_group) < 0) {......} return ret; } ~~~ **2、GON Request發送流程** 來看p2p_connect函數,其代碼如下所示。 **p2p.c::p2p_connect** ~~~ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, enum p2p_wps_method wps_method, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group) { struct p2p_device *dev; // 如果指定了工作頻段,則需要判斷是否支持該工作頻段 if (p2p_prepare_channel(p2p, force_freq) < 0) return -1; p2p->ssid_set = 0; dev = p2p_get_device(p2p, peer_addr); ......// 設置dev的一些信息 p2p->go_intent = go_intent; os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN); // 如果P2P模塊的狀態不為P2P_IDLE,則先停止find工作 if (p2p->state != P2P_IDLE) p2p_stop_find(p2p); ...... dev->wps_method = wps_method; dev->status = P2P_SC_SUCCESS; ...... if (p2p->p2p_scan_running) { /* 如果當前P2P還在掃描過程中,則設置start_after_scan為P2P_AFTER_SCAN_CONNECT標志, 當scan結束后,在掃描結果處理流程中,該標志將通知P2P進入connect處理流程。 */ p2p->start_after_scan = P2P_AFTER_SCAN_CONNECT; os_memcpy(p2p->after_scan_peer, peer_addr, ETH_ALEN); return 0; } p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING; // 下面這個函數將發送GON Request幀,直接來看該函數 return p2p_connect_send(p2p, dev); } ~~~ **p2p_go_neg.c::p2p_connect_send** ~~~ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev) { struct wpabuf *req; int freq; ...... req = p2p_build_go_neg_req(p2p, dev); p2p_set_state(p2p, P2P_CONNECT); // 設置P2P模塊的狀態為P2P_CONNECT // 設置pending_action_state為P2P_PENDING_GO_NEG_REQUEST p2p->pending_action_state = P2P_PENDING_GO_NEG_REQUEST; p2p->go_neg_peer = dev; // 設置GON對端設備 dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE; dev->connect_reqs++; #ifdef ANDROID_P2P dev->go_neg_req_sent++; #endif // 發送GON Request幀 if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr, p2p->cfg->dev_addr, dev->info.p2p_device_addr, wpabuf_head(req), wpabuf_len(req), 200) < 0) {......} ...... return 0; } ~~~ 至此,GON Request幀就將發送給對端P2P設備。圖7-36描述了P2P_CONNECT命令的處理流程。 :-: ![](https://box.kancloud.cn/e30f403420be74c5c830507241477486_1191x719.jpg) 圖7-36 P2P_CONNECT命令處理流程 **3、GON Response幀處理流程** 根據前面對Action幀接收流程的分析可知,收到的GON Response幀將在p2p_process_go_neg_resp函數中被處理。該函數的代碼如下所示。 **p2p_go_neg.c::p2p_process_go_neg_resp** ~~~ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq) { struct p2p_device *dev; struct wpabuf *conf; int go = -1; struct p2p_message msg; u8 status = P2P_SC_SUCCESS; int freq; dev = p2p_get_device(p2p, sa); // 解析GON Response幀 if (p2p_parse(data, len, &msg)) return; ......// 參數檢查 /* 下面這個函數將利用圖7-13計算誰來扮演GO。返回值大于0,表示本機扮演GO, 返回-1表示雙方都想成為GO,返回值為0,表示對端扮演GO。本例中,假設GO為本機設備。 */ go = p2p_go_det(p2p->go_intent, *msg.go_intent); ......// 參數檢查,內容比較繁雜,感興趣的讀者請自行研究 if (go) { ...... // 處理工作頻段 } p2p_set_state(p2p, P2P_GO_NEG);// 設置P2P模塊的狀態為P2P_GO_NEG p2p_clear_timeout(p2p); ...... fail: // 構造GON Confirmation幀 conf = p2p_build_go_neg_conf(p2p, dev, msg.dialog_token, status, msg.operating_channel, go); p2p_parse_free(&msg); ....... if (status == P2P_SC_SUCCESS) { p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM; dev->go_state = go ? LOCAL_GO : REMOTE_GO;// 本機扮演GO } else p2p->pending_action_state = P2P_NO_PENDING_ACTION; ...... // 發送GON Confirmation幀 if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa, wpabuf_head(conf), wpabuf_len(conf), 200) < 0) {......} wpabuf_free(conf); } ~~~ p2p_process_go_neg_resp實際的代碼比較復雜,建議初學者先了解上面代碼所涉及的大體流程。 當GON Confirmation幀發送出去后,wifi driver將向WPAS發送一個NL80211_CMD_FRAME_TX_STATUS消息,而該消息將導致driver wrapper發送EVENT_TX_STATUS消息給WPAS。下面我們直接來看EVENT_TX_STATUS的處理流程。 **4、EVENT_TX_STATUS處理流程** 在events.c中,和P2P以及EVENT_TX_STATUS相關的處理函數是offchannel_send_action_tx_status,該函數的代碼如下所示。 **offchannel.c::offchannel_send_action_tx_status** ~~~ void offchannel_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,size_t data_len, enum offchannel_send_action_result result) { ......// 參數檢查 wpabuf_free(wpa_s->pending_action_tx); wpa_s->pending_action_tx = NULL; /* 注意下面這個pending_action_tx_status_cb參數,它是一個函數指針,P2P每次發送Action的時候, 都會設置該變量。其真實的函數為wpas_p2p_send_action_tx_status(在wpas_send_action 函數中設置) */ if (wpa_s->pending_action_tx_status_cb) { wpa_s->pending_action_tx_status_cb( wpa_s, wpa_s->pending_action_freq, wpa_s->pending_action_dst, wpa_s->pending_action_src, wpa_s->pending_action_bssid, data, data_len, result); } } ~~~ 來看wpas_p2p_send_action_tx_status,其代碼如下所示。 **p2p_supplicant.c::wpas_p2p_send_action_tx_status** ~~~ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s, unsigned int freq,const u8 *dst, const u8 *src, const u8 *bssid, const u8 *data, size_t data_len, enum offchannel_send_action_result result) { enum p2p_send_action_result res = P2P_SEND_ACTION_SUCCESS; ...... // 重要函數:p2p_send_action_cb p2p_send_action_cb(wpa_s->global->p2p, freq, dst, src, bssid, res); ...... } ~~~ p2p_send_action_cb的代碼如下所示。 **p2p.c::p2p_send_action_cb** ~~~ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid,enum p2p_send_action_result result) { enum p2p_pending_action_state state; int success; success = result == P2P_SEND_ACTION_SUCCESS; // 讀者還記得該變量的值嗎?它應該是P2P_PENDING_GO_NEG_CONFIRM state = p2p->pending_action_state; p2p->pending_action_state = P2P_NO_PENDING_ACTION; switch (state) { case P2P_NO_PENDING_ACTION: break; case P2P_PENDING_GO_NEG_REQUEST: // 讀者可自行研究此函數。當發送完GON Request幀后,此函數也會被觸發 p2p_go_neg_req_cb(p2p, success); break; ...... case P2P_PENDING_GO_NEG_CONFIRM: p2p_go_neg_conf_cb(p2p, result);// 分析這個函數 break; ......// 其他case處理 } } ~~~ 來看p2p_go_neg_conf_cb函數,代碼如下所示。 **p2p.c::p2p_go_neg_conf_cb** ~~~ static void p2p_go_neg_conf_cb(struct p2p_data *p2p, enum p2p_send_action_result result) { struct p2p_device *dev; /* 每次收到TX Report后,都需要調用send_action_cb,其對應的真實函數是wpas_send_action_done。 */ p2p->cfg->send_action_done(p2p->cfg->cb_ctx); ...... dev = p2p->go_neg_peer; if (dev == NULL) return; p2p_go_complete(p2p, dev); } ~~~ p2p_go_complete函數比較簡單,其代碼如下所示。 **p2p.c::p2p_go_complete** ~~~ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer) { struct p2p_go_neg_results res; int go = peer->go_state == LOCAL_GO; struct p2p_channels intersection; int freqs; size_t i, j; ......// 設置頻段等參數 p2p_set_state(p2p, P2P_PROVISIONING);// 進入Group Formation的Provisioning階段 // go_neg_completed對應的函數是wpas_go_neg_completed p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res); } ~~~ **p2p_supplicant.c::wpas_go_neg_compeleted** ~~~ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) { struct wpa_supplicant *wpa_s = ctx; ...... // 下面這個函數將導致P2pStateMachine收到P2P_GO_NEGOTIATION_SUCCESS_EVENT消息 wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS); wpas_notify_p2p_go_neg_completed(wpa_s, res); if (wpa_s->create_p2p_iface) {// 本例滿足此if條件 /* 再創建一個wpa_supplicant對象。感興趣的讀者可自行研究下面這個函數。其內部將調用4.4.3節 分析的wpa_supplicant_add_iface函數。 */ struct wpa_supplicant *group_wpa_s = wpas_p2p_init_group_interface(wpa_s, res->role_go); ...... // 如果本機扮演GO,則啟動WSC Registrar功能,否則啟動Enrollee功能 // 下面這兩個函數留給讀者自行分析 if (res->role_go) wpas_start_wps_go(group_wpa_s, res, 1); else wpas_start_wps_enrollee(group_wpa_s, res); } ...... wpa_s->p2p_long_listen = 0; eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL); // Group Formation的超時時間為15秒左右 eloop_register_timeout(15 + res->peer_config_timeout / 100, (res->peer_config_timeout % 100) * 10000, wpas_p2p_group_formation_timeout, wpa_s, NULL); } ~~~ 當Group Negotiation完成后,WPAS將新創建一個wpa_supplicant對象,它將用于管理和操作專門用于P2P Group的virtual interface,此處有幾點請讀者注意。 * 4.3.1節中介紹過,一個interface對應一個wpa_supplicant對象。 * 此處新創建的wpa_supplicant對象用于GO,即扮演AP的角色,專門處理和P2P Group相關的事情,其MAC地址為P2P Interface Address。 * 之前使用的wpa_supplicant用于非P2P Group操作,其MAC地址為P2P Device Address。 至此,整個EVENT_TX_STATUS處理流程就分析完畢了,其內容比較復雜。圖7-37整理了此過程中一些重要的函數調用。 注意,圖7-37實際上描述的是GON Confirmation幀對應的EVENT_TX_STATUS處理流程,和其他EVENT_TX_STATUS處理流程相比,前面7個函數調用都是一樣的。 :-: ![](https://box.kancloud.cn/03a8a22d3a7ac5a05140f95e8cd38b95_1003x570.jpg) 圖7-37 EVENT_TX_STATUS處理流程
                  <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>

                              哎呀哎呀视频在线观看