<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國際加速解決方案。 廣告
                P2pStateMachine的ProvisionDiscoveryState在其EA中將發送形如"P2P_PROV_DISC 8a:32:9b:6c:d1:80 pbc"的命令給WPAS(請參考7.3.2節“CONNECT處理流程分析”)去執行,其核心處理函數是p2p_ctrl_prov_disc,代碼如下所示。 **ctrl_iface.c::p2p_ctrl_prov_disc** ~~~ static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd) { u8 addr[ETH_ALEN]; char *pos; if (hwaddr_aton(cmd, addr)) return -1; .....// 參數處理。P2P_PROV_DISC命令的完整參數形式為“<addr> <config method> [join]” // 其最后一個join參數為可選項。WifiP2pService沒有使用它 // 調用wpas_p2p_prov_disc,其內部將調用p2p_prov_disc_req,我們直接來看它 return wpas_p2p_prov_disc(wpa_s, addr, pos, os_strstr(pos, "join") != NULL); } ~~~ **1、PD Request幀發送流程** p2p_prov_disc_req的代碼如下所示。 **p2p.c::p2p_prov_disc_req** ~~~ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, u16 config_methods, int join, int force_freq) { struct p2p_device *dev; dev = p2p_get_device(p2p, peer_addr);// 根據目標設備地址找到對應的p2p_device對象 if (dev == NULL) dev = p2p_get_device_interface(p2p, peer_addr); ...... dev->wps_prov_info = 0; dev->req_config_methods = config_methods; // 就本例而言,join的值為0 if (join) dev->flags |= P2P_DEV_PD_FOR_JOIN; else dev->flags &= ~P2P_DEV_PD_FOR_JOIN; // 取消dev->flags中的P2P_DEV_PD_FOR_JOIN標志 ...... p2p->user_initiated_pd = !join; if (p2p->user_initiated_pd && p2p->state == P2P_IDLE) p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES; // 最后調用p2p_send_prov_disc_req發送數據 return p2p_send_prov_disc_req(p2p, dev, join, force_freq); } ~~~ p2p_send_prov_disc_req比較簡單,代碼如下。 **p2p_pd.c::p2p_send_prov_disc_req** ~~~ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, int join, int force_freq) { struct wpabuf *req; int freq; // 確定對端設備所在的工作頻段 if (force_freq > 0) freq = force_freq; else freq = dev->listen_freq > 0 ? dev->listen_freq :dev->oper_freq; ...... dev->dialog_token++;// 還記得表7-3關于Dialog Token的描述嗎 if (dev->dialog_token == 0) dev->dialog_token = 1; // 構造Provision Discovery Request幀內容 req = p2p_build_prov_disc_req(p2p, dev->dialog_token, dev->req_config_methods,join ? dev : NULL); ...... p2p->pending_action_state = P2P_PENDING_PD;// 該標志表明當前pending的Action是PD // p2p_send_action內部將調用wpas_send_action。這部分內容比較簡單,請讀者自行研究 // 另外,第7.4.2節也會提到wpas_send_action函數,讀者也可學習完本章后再來研究它 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) {......} // 保存對端P2P設備地址 os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN); wpabuf_free(req); return 0; } ~~~ 上述代碼中,PD Request幀最終將通過p2p_send_action函數發送出去。不過,p2p_send_action并不簡單,它將涉及Off Channel發送以及處理對應netlink消息的過程。做為本書Wi-Fi部分的最后一章,請讀者在學習完本章后,再自行研究這個函數。 圖7-34展示了PD Request幀發送流程中的重要函數調用序列。 :-: ![](https://box.kancloud.cn/38c7f5c1ada587a66f5e9f03f0dc374f_1357x569.jpg) 圖7-34 PD Request幀發送流程 圖7-34列出了wpas_send_action中的幾個重要函數調用,請讀者自行研究時候注意相關內容。 下面來看PD Respone幀的處理流程。由于PD Response屬于Action幀,所以我們將介紹WPAS中Action幀的接收流程,然后再分析PD Response的處理流程。 **2、Action幀接收流程** PD Response幀屬于Public Action幀的一種,而根據7.4.1節“注冊Action幀監聽事件”的分析可知,當收到對端設備發來的PD Response幀后,process_bss_event函數將被調用。此函數的代碼如下所示。 **driver_nl80211.c::process_bss_event** ~~~ static int process_bss_event(struct nl_msg *msg, void *arg) { struct i802_bss *bss = arg; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *tb[NL80211_ATTR_MAX + 1]; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); switch (gnlh->cmd) { case NL80211_CMD_FRAME: // 收到對端發送的幀 case NL80211_CMD_FRAME_TX_STATUS: // 對應本機所發送的管理幀的TX Report mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME], tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], tb[NL80211_ATTR_COOKIE]); break; ...... } return NL_SKIP; } ~~~ 由上述代碼可知,不論是代表由本機所發送的管理幀TX Report的NL80211_CMD_FRAME_TX_STATUS消息,還是代表本機接收到對端發來的管理幀事件的NL80211_CMD_FRAME消息,最終都會調用mlme_event函數,其代碼如下所示。 **driver_nl80211.c::mlme_event** ~~~ static void mlme_event(struct wpa_driver_nl80211_data *drv, enum nl80211_commands cmd, struct nlattr *frame, struct nlattr *addr, struct nlattr *timed_out, struct nlattr *freq, struct nlattr *ack,struct nlattr *cookie) { ...... switch (cmd) { case NL80211_CMD_AUTHENTICATE: mlme_event_auth(drv, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_ASSOCIATE: mlme_event_assoc(drv, nla_data(frame), nla_len(frame)); break; ...... case NL80211_CMD_FRAME: mlme_event_mgmt(drv, freq, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_FRAME_TX_STATUS: mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame), nla_len(frame), ack); ...... } } ~~~ mlme_event將處理各種類型的幀事件。對于本例而言,此時將調用mlme_event_mgmt函數,其代碼如下所示。 **driver_nl80211.c::mlme_event_mgmt** ~~~ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv, struct nlattr *freq, const u8 *frame, size_t len) { const struct ieee80211_mgmt *mgmt; union wpa_event_data event; u16 fc, stype; mgmt = (const struct ieee80211_mgmt *) frame; ...... fc = le_to_host16(mgmt->frame_control); stype = WLAN_FC_GET_STYPE(fc); os_memset(&event, 0, sizeof(event)); if (freq) { event.rx_action.freq = nla_get_u32(freq); drv->last_mgmt_freq = event.rx_action.freq; } if (stype == WLAN_FC_STYPE_ACTION) { event.rx_action.da = mgmt->da; event.rx_action.sa = mgmt->sa; event.rx_action.bssid = mgmt->bssid; event.rx_action.category = mgmt->u.action.category; event.rx_action.data = &mgmt->u.action.category + 1; event.rx_action.len = frame + len - event.rx_action.data; // EVENT_RX_ACTION幀代表ACTION幀 wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event); } else { event.rx_mgmt.frame = frame; event.rx_mgmt.frame_len = len; // EVENT_RX_MGMT代表其他類型的管理幀 wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); } } ~~~ wpa_supplicant_event處理EVENT_RX_ACTION的內容比較豐富,不過對于P2P來說,wpa_supplicant_event將調用wpas_p2p_rx_action,而wpas_p2p_rx_action又會調用p2p_rx_action,所以此處直接看p2p_rx_action函數即可,其代碼如下所示。 **p2p.c::p2p_rx_action** ~~~ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa, const u8 *bssid, u8 category, const u8 *data, size_t len, int freq) { if (category == WLAN_ACTION_PUBLIC) {// 處理Public Action幀 p2p_rx_action_public(p2p, da, sa, bssid, data, len, freq); return; } ......// 參數檢查 switch (data[0]) {// P2P規范使用的其他非Public類型的Action幀 case P2P_NOA: break; case P2P_PRESENCE_REQ: p2p_process_presence_req(p2p, da, sa, data + 1, len - 1, freq); break; case P2P_PRESENCE_RESP: p2p_process_presence_resp(p2p, da, sa, data + 1, len - 1); break; case P2P_GO_DISC_REQ: p2p_process_go_disc_req(p2p, da, sa, data + 1, len - 1, freq); break; ...... } } ~~~ 上述代碼中專門處理Public Action幀的p2p_rx_action_public函數代碼如下所示。 **p2p.c::p2p_rx_action_public** ~~~ static void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da, const u8 *sa, const u8 *bssid, const u8 *data,size_t len, int freq) { ...... switch (data[0]) { case WLAN_PA_VENDOR_SPECIFIC:// P2P Public Action滿足此條件 ...... p2p_rx_p2p_action(p2p, sa, data + 1, len - 1, freq); break; case WLAN_PA_GAS_INITIAL_REQ: p2p_rx_gas_initial_req(p2p, sa, data + 1, len - 1, freq); break; ......// 其他類型的Public Action幀處理 } } ~~~ p2p_rx_p2p_action函數是P2P模塊中Public Action幀得到分類處理的最后一關,其代碼如下所示。 **p2p.c::p2p_rx_p2p_action** ~~~ static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq) { switch (data[0]) { // P2P支持的Public Action幀在此處得到分類和相應處理 case P2P_GO_NEG_REQ: // 處理GON Request幀 p2p_process_go_neg_req(p2p, sa, data + 1, len - 1, rx_freq); break; case P2P_GO_NEG_RESP: // 處理GON Response幀 p2p_process_go_neg_resp(p2p, sa, data + 1, len - 1, rx_freq); break; case P2P_GO_NEG_CONF: // 處理GON Confirmation幀 p2p_process_go_neg_conf(p2p, sa, data + 1, len - 1); break; case P2P_INVITATION_REQ: // 處理Invitation Request幀 p2p_process_invitation_req(p2p, sa, data + 1, len - 1,rx_freq); break; case P2P_INVITATION_RESP: // 處理Invitation Response幀 p2p_process_invitation_resp(p2p, sa, data + 1, len - 1); break; case P2P_PROV_DISC_REQ: // 處理PD Request幀 p2p_process_prov_disc_req(p2p, sa, data + 1, len - 1, rx_freq); break; case P2P_PROV_DISC_RESP: // 處理PD Response幀 p2p_process_prov_disc_resp(p2p, sa, data + 1, len - 1); break; case P2P_DEV_DISC_REQ: // 處理Device Discoverability Request幀 p2p_process_dev_disc_req(p2p, sa, data + 1, len - 1, rx_freq); break; case P2P_DEV_DISC_RESP: // 處理Device Discoverability Response幀 p2p_process_dev_disc_resp(p2p, sa, data + 1, len - 1); break; ......// default語句 } } ~~~ 至此,Action幀的接收流程就介紹完了。整體而言,這部分代碼難度不大,但是調用函數卻比較多。圖7-35總結了這部分流程所涉及的一些重要函數。 :-: ![](https://box.kancloud.cn/52ebc10f442044ee3aa5e31965ba61a6_1046x415.jpg) 圖7-35 Action幀接收流程 由圖7-35可知,p2p_rx_p2p_action為P2P Public Action幀處理邏輯的總入口,如果后文分析時碰到其他類型的P2P Public Action幀,我們將直接轉入該函數來分析。 **3、PD Response幀處理流程** 由上述的p2p_rx_p2p_action可知,PD Response幀對應的處理函數是p2p_process_prov_disc_resp,其代碼如下所示。 **p2p_pd.c::p2p_process_prov_disc_resp** ~~~ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len) { struct p2p_message msg; struct p2p_device *dev; u16 report_config_methods = 0; // 解析PD Response幀 if (p2p_parse(data, len, &msg)) return; // 獲取對應的P2P Device對象 dev = p2p_get_device(p2p, sa); ...... /* 當前我們pending的action是PD,由于已經收到了PD Response,所以可以置pending_action_state 變量為P2P_NO_PENDING_ACTION。 */ if (p2p->pending_action_state == P2P_PENDING_PD) { os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN); p2p->pending_action_state = P2P_NO_PENDING_ACTION; } if (dev->dialog_token != msg.dialog_token)return; if (p2p->user_initiated_pd && os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0) p2p_reset_pending_pd(p2p); /* 如果所要求的WSC方法和PD Response返回的WSC方法不一致,則表明對端P2P設備不支持所要求的WSC方法。 */ if (msg.wps_config_methods != dev->req_config_methods) { // 調用wpas_prov_disc_fail,以處理PD失敗的情況 // 不過WPAS中,該函數沒有干什么有意義的事情 if (p2p->cfg->prov_disc_fail) p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,P2P_PROV_DISC_REJECTED); p2p_parse_free(&msg); goto out; } report_config_methods = dev->req_config_methods; dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY | P2P_DEV_PD_PEER_KEYPAD); ...... dev->wps_prov_info = msg.wps_config_methods; p2p_parse_free(&msg); out: dev->req_config_methods = 0; p2p->cfg->send_action_done(p2p->cfg->cb_ctx);// 請讀者自行研究send_action_done函數 if (p2p->cfg->prov_disc_resp)// prov_disc_respz指向wpas_prov_disc_resp p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,report_config_methods); } ~~~ 馬上來看wpas_prov_disc_resp函數,其代碼如下所示。 **p2p_supplicant.c::wpas_prov_disc_resp** ~~~ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods) { struct wpa_supplicant *wpa_s = ctx; unsigned int generated_pin = 0; /* pending_pd_before_join變量對應于這樣一種場景:即GON已經完成,但WSC配置方法還沒有確定。 在后文分析GON時,我們將見到這種場景。 */ if (wpa_s->pending_pd_before_join && (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 || os_memcmp(peer, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) { wpa_s->pending_pd_before_join = 0; wpas_p2p_join_start(wpa_s); return; } if (config_methods & WPS_CONFIG_DISPLAY) wpas_prov_disc_local_keypad(wpa_s, peer, ""); else if (config_methods & WPS_CONFIG_KEYPAD) { generated_pin = wps_generate_pin(); wpas_prov_disc_local_display(wpa_s, peer, "", generated_pin); } else if (config_methods & WPS_CONFIG_PUSHBUTTON) wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR,MAC2STR(peer)); ...... } ~~~ 對于WSC PBC方法而言,wpa_msg將發送P2P_EVENT_PROV_DISC_PBC_RESP(字符串,值為"P2P-PROV-DISC-PBC-RESP")消息給客戶端,這也觸發了7.3.2節分析P2P_PROV_DISC_PBC_RSP_EVENT處理流程中所描述的工作流程。 現在來看本章關于P2P的最后一到工序。
                  <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>

                              哎呀哎呀视频在线观看