diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-05-06 04:39:24 -0700 |
|---|---|---|
| committer | Linux Build Service Account <lnxbuild@localhost> | 2016-05-06 04:39:24 -0700 |
| commit | a8325dbdadd0095eeb2783d66daae3be1b1e5443 (patch) | |
| tree | b3327b1692b78abd0ee615aaff0544ec44bd8d11 | |
| parent | 93d4f498bb3784fcaa522760ea4349252f0c5c5e (diff) | |
| parent | 425ea41b56ad11cee78cf79ef3971583f95d63cc (diff) | |
| download | android_external_wpa_supplicant_8-a8325dbdadd0095eeb2783d66daae3be1b1e5443.tar.gz android_external_wpa_supplicant_8-a8325dbdadd0095eeb2783d66daae3be1b1e5443.tar.bz2 android_external_wpa_supplicant_8-a8325dbdadd0095eeb2783d66daae3be1b1e5443.zip | |
Promotion of wlan-service.lnx.1.0-00045.
CRs Change ID Subject
--------------------------------------------------------------------------------------------------------------
992076 I833a1b9e232485f3a7987ab824b88832cfd0821b eap_proxy: Resolve QMI EAP request length limitation
996616 I5c8ef7e1023e782cd7d18e0294dd3f84564a4c1a WNM: Optimize a single BSS transition management candida
1010891 I6a5cf51cd8b5986078039a4e5ea66dc25fbfa64b WNM: Fetch scan results before checking transition candi
996616 Ia449479732f6a15a78c9aabf821accf201970acf nl80211: Add an option to specify the BSSID to scan for
Change-Id: I06a2f58c24f9bc4bfacb8c399443844d47e3b55c
CRs-Fixed: 992076, 1010891, 996616
| -rw-r--r-- | src/drivers/driver.h | 9 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211_scan.c | 7 | ||||
| -rw-r--r-- | src/eap_peer/eap_proxy_qmi.c | 50 | ||||
| -rw-r--r-- | wpa_supplicant/scan.c | 46 | ||||
| -rw-r--r-- | wpa_supplicant/scan.h | 5 | ||||
| -rw-r--r-- | wpa_supplicant/wnm_sta.c | 169 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant_i.h | 1 |
7 files changed, 248 insertions, 39 deletions
diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 9cea60ca..1abfc1f7 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -416,6 +416,15 @@ struct wpa_driver_scan_params { */ const u8 *mac_addr_mask; + /** + * bssid - Specific BSSID to scan for + * + * This optional parameter can be used to replace the default wildcard + * BSSID with a specific BSSID to scan for if results are needed from + * only a single BSS. + */ + const u8 *bssid; + /* * NOTE: Whenever adding new parameters here, please make sure * wpa_scan_clone_params() and wpa_scan_free_params() get updated with diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c index a8ce7ea8..b84b6449 100644 --- a/src/drivers/driver_nl80211_scan.c +++ b/src/drivers/driver_nl80211_scan.c @@ -250,6 +250,13 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss, goto fail; } + if (params->bssid) { + wpa_printf(MSG_DEBUG, "nl80211: Scan for a specific BSSID: " + MACSTR, MAC2STR(params->bssid)); + if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid)) + goto fail; + } + ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { diff --git a/src/eap_peer/eap_proxy_qmi.c b/src/eap_peer/eap_proxy_qmi.c index 21f6b06d..49ecc4df 100644 --- a/src/eap_peer/eap_proxy_qmi.c +++ b/src/eap_peer/eap_proxy_qmi.c @@ -916,7 +916,8 @@ static void handle_qmi_eap_reply( eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT; return; } - if(QMI_AUTH_SEND_EAP_PACKET_REQ_V01 != msg_id) + if((QMI_AUTH_SEND_EAP_PACKET_REQ_V01 != msg_id) && + (QMI_AUTH_SEND_EAP_PACKET_EXT_REQ_V01 != msg_id)) { wpa_printf(MSG_ERROR, "eap_proxy: Invalid msgId =%d\n", msg_id); eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT; @@ -925,9 +926,10 @@ static void handle_qmi_eap_reply( /* ensure the reply packet exists */ if (rspData->eap_response_pkt_len <= 0 || - rspData->eap_response_pkt_len > QMI_AUTH_EAP_RESP_PACKET_MAX_V01) { + rspData->eap_response_pkt_len > QMI_AUTH_EAP_RESP_PACKET_EXT_MAX_V01) { wpa_printf(MSG_ERROR, "eap_proxy: Reply packet is of" - "invalid length\n"); + "invalid length %d error %d result %d\n", + rspData->eap_response_pkt_len, rspData->resp.error, rspData->resp.result); eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT; return; } @@ -972,8 +974,9 @@ static enum eap_proxy_status eap_proxy_process(struct eap_proxy_sm *eap_proxy, auth_send_eap_packet_resp_msg_v01 eap_send_packet_resp; qmi_txn_handle async_txn_hdl = 0; - os_memset(&eap_send_packet_req, 0, sizeof(auth_send_eap_packet_req_msg_v01)); - os_memset(&eap_send_packet_resp, 0, sizeof(auth_send_eap_packet_resp_msg_v01)); + auth_send_eap_packet_ext_req_msg_v01 eap_send_packet_ext_req; + auth_send_eap_packet_ext_resp_msg_v01 eap_send_packet_ext_resp; + hdr = (struct eap_hdr *)eapReqData; if ((EAP_CODE_REQUEST == hdr->code) && @@ -1005,8 +1008,15 @@ static enum eap_proxy_status eap_proxy_process(struct eap_proxy_sm *eap_proxy, wpa_printf(MSG_ERROR, "eap_proxy: ***********Dump ReqData len %d***********", eapReqDataLen); dump_buff(eapReqData, eapReqDataLen); if (eapReqDataLen <= QMI_AUTH_EAP_REQ_PACKET_MAX_V01) { + os_memset(&eap_send_packet_req, 0, sizeof(auth_send_eap_packet_req_msg_v01)); + os_memset(&eap_send_packet_resp, 0, sizeof(auth_send_eap_packet_resp_msg_v01)); eap_send_packet_req.eap_request_pkt_len = eapReqDataLen ; memcpy(eap_send_packet_req.eap_request_pkt, eapReqData, eapReqDataLen); + } else if (eapReqDataLen <= QMI_AUTH_EAP_REQ_PACKET_EXT_MAX_V01) { + os_memset(&eap_send_packet_ext_req, 0, sizeof(auth_send_eap_packet_ext_req_msg_v01)); + os_memset(&eap_send_packet_ext_resp, 0, sizeof(auth_send_eap_packet_ext_resp_msg_v01)); + eap_send_packet_ext_req.eap_request_ext_pkt_len = eapReqDataLen; + memcpy(eap_send_packet_ext_req.eap_request_ext_pkt, eapReqData, eapReqDataLen); } else { wpa_printf(MSG_ERROR, "eap_proxy: Error in eap_send_packet_req\n"); return EAP_PROXY_FAILURE; @@ -1022,15 +1032,27 @@ static enum eap_proxy_status eap_proxy_process(struct eap_proxy_sm *eap_proxy, wpa_printf (MSG_ERROR, "eap_proxy: In eap_proxy_process case %d\n", hdr->code); eap_proxy->qmi_state = QMI_STATE_RESP_PENDING; - qmiErrorCode = qmi_client_send_msg_async(eap_proxy->qmi_auth_svc_client_ptr[eap_proxy->user_selected_sim], - QMI_AUTH_SEND_EAP_PACKET_REQ_V01, - (void *) &eap_send_packet_req, - sizeof(auth_send_eap_packet_req_msg_v01), - (void *) &eap_send_packet_resp, - sizeof(auth_send_eap_packet_resp_msg_v01), - &handle_qmi_eap_reply, eap_proxy, - &async_txn_hdl); - + if(eapReqDataLen <= QMI_AUTH_EAP_REQ_PACKET_MAX_V01) { + qmiErrorCode = qmi_client_send_msg_async( + eap_proxy->qmi_auth_svc_client_ptr[eap_proxy->user_selected_sim], + QMI_AUTH_SEND_EAP_PACKET_REQ_V01, + (void *) &eap_send_packet_req, + sizeof(auth_send_eap_packet_req_msg_v01), + (void *) &eap_send_packet_resp, + sizeof(auth_send_eap_packet_resp_msg_v01), + &handle_qmi_eap_reply, eap_proxy, + &async_txn_hdl); + } else if(eapReqDataLen <= QMI_AUTH_EAP_REQ_PACKET_EXT_MAX_V01) { + qmiErrorCode = qmi_client_send_msg_async( + eap_proxy->qmi_auth_svc_client_ptr[eap_proxy->user_selected_sim], + QMI_AUTH_SEND_EAP_PACKET_EXT_REQ_V01, + (void *) &eap_send_packet_ext_req, + sizeof(auth_send_eap_packet_ext_req_msg_v01), + (void *) &eap_send_packet_ext_resp, + sizeof(auth_send_eap_packet_ext_resp_msg_v01), + &handle_qmi_eap_reply, eap_proxy, + &async_txn_hdl); + } if (QMI_NO_ERR != qmiErrorCode) { wpa_printf(MSG_ERROR, "QMI-ERROR Error in sending EAP packet;" diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 93eea4e6..acd3211c 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -1013,6 +1013,27 @@ ssid_list_set: } } + if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) { + struct wpa_bss *bss; + + params.bssid = wpa_s->next_scan_bssid; + bss = wpa_bss_get_bssid_latest(wpa_s, params.bssid); + if (bss && bss->ssid_len && params.num_ssids == 1 && + params.ssids[0].ssid_len == 0) { + params.ssids[0].ssid = bss->ssid; + params.ssids[0].ssid_len = bss->ssid_len; + wpa_dbg(wpa_s, MSG_DEBUG, + "Scan a previously specified BSSID " MACSTR + " and SSID %s", + MAC2STR(params.bssid), + wpa_ssid_txt(bss->ssid, bss->ssid_len)); + } else { + wpa_dbg(wpa_s, MSG_DEBUG, + "Scan a previously specified BSSID " MACSTR, + MAC2STR(params.bssid)); + } + } + scan_params = ¶ms; scan: @@ -1073,6 +1094,8 @@ scan: #ifdef CONFIG_INTERWORKING wpa_s->interworking_fast_assoc_tried = 0; #endif /* CONFIG_INTERWORKING */ + if (params.bssid) + os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN); } } @@ -1829,8 +1852,8 @@ int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s, } -static void filter_scan_res(struct wpa_supplicant *wpa_s, - struct wpa_scan_results *res) +void filter_scan_res(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *res) { size_t i, j; @@ -1863,7 +1886,7 @@ static void filter_scan_res(struct wpa_supplicant *wpa_s, #define DEFAULT_NOISE_FLOOR_2GHZ (-89) #define DEFAULT_NOISE_FLOOR_5GHZ (-92) -static void scan_snr(struct wpa_scan_res *res) +void scan_snr(struct wpa_scan_res *res) { if (res->flags & WPA_SCAN_NOISE_INVALID) { res->noise = IS_5GHZ(res->freq) ? @@ -1947,8 +1970,8 @@ static unsigned int max_vht80_rate(int snr) } -static void scan_est_throughput(struct wpa_supplicant *wpa_s, - struct wpa_scan_res *res) +void scan_est_throughput(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *res) { enum local_hw_capab capab = wpa_s->hw_capab; int rate; /* max legacy rate in 500 kb/s units */ @@ -2228,6 +2251,17 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src) params->mac_addr_mask = mac_addr + ETH_ALEN; } } + + if (src->bssid) { + u8 *bssid; + + bssid = os_malloc(ETH_ALEN); + if (!bssid) + goto failed; + os_memcpy(bssid, src->bssid, ETH_ALEN); + params->bssid = bssid; + } + return params; failed: @@ -2255,6 +2289,8 @@ void wpa_scan_free_params(struct wpa_driver_scan_params *params) */ os_free((u8 *) params->mac_addr); + os_free((u8 *) params->bssid); + os_free(params); } diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h index 0f1c8e49..893c3c02 100644 --- a/wpa_supplicant/scan.h +++ b/wpa_supplicant/scan.h @@ -55,5 +55,10 @@ int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s, unsigned int type, const u8 *addr, const u8 *mask); int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s); +void filter_scan_res(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *res); +void scan_snr(struct wpa_scan_res *res); +void scan_est_throughput(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *res); #endif /* SCAN_H */ diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index cec457d1..7a1d3662 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -24,6 +24,7 @@ #define MAX_TFS_IE_LEN 1024 #define WNM_MAX_NEIGHBOR_REPORT 10 +#define WNM_SCAN_RESULT_AGE 2 /* 2 seconds */ /* get the TFS IE from driver */ static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf, @@ -497,7 +498,7 @@ static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, static struct wpa_bss * -compare_scan_neighbor_results(struct wpa_supplicant *wpa_s) +compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs) { u8 i; @@ -530,6 +531,19 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s) continue; } + if (age_secs) { + struct os_reltime now; + + if (os_get_reltime(&now) == 0 && + os_reltime_expired(&now, &target->last_update, + age_secs)) { + wpa_printf(MSG_DEBUG, + "Candidate BSS is more than %ld seconds old", + age_secs); + continue; + } + } + if (bss->ssid_len != target->ssid_len || os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) { /* @@ -622,6 +636,41 @@ static void wnm_send_bss_transition_mgmt_resp( } +static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, struct wpa_ssid *ssid, + int after_new_scan) +{ + wpa_dbg(wpa_s, MSG_DEBUG, + "WNM: Transition to BSS " MACSTR + " based on BSS Transition Management Request (old BSSID " + MACSTR " after_new_scan=%d)", + MAC2STR(bss->bssid), MAC2STR(wpa_s->bssid), after_new_scan); + + /* Send the BSS Management Response - Accept */ + if (wpa_s->wnm_reply) { + wpa_s->wnm_reply = 0; + wpa_printf(MSG_DEBUG, + "WNM: Sending successful BSS Transition Management Response"); + wnm_send_bss_transition_mgmt_resp(wpa_s, + wpa_s->wnm_dialog_token, + WNM_BSS_TM_ACCEPT, + 0, bss->bssid); + } + + if (bss == wpa_s->current_bss) { + wpa_printf(MSG_DEBUG, + "WNM: Already associated with the preferred candidate"); + wnm_deallocate_memory(wpa_s); + return; + } + + wpa_s->reassociate = 1; + wpa_printf(MSG_DEBUG, "WNM: Issuing connect"); + wpa_supplicant_connect(wpa_s, bss, ssid); + wnm_deallocate_memory(wpa_s); +} + + int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) { struct wpa_bss *bss; @@ -631,6 +680,8 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) if (!wpa_s->wnm_neighbor_report_elements) return 0; + wpa_dbg(wpa_s, MSG_DEBUG, + "WNM: Process scan results for BSS Transition Management"); if (os_reltime_before(&wpa_s->wnm_cand_valid_until, &wpa_s->scan_trigger_time)) { wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it"); @@ -646,7 +697,7 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) } /* Compare the Neighbor Report and scan results */ - bss = compare_scan_neighbor_results(wpa_s); + bss = compare_scan_neighbor_results(wpa_s, 0); if (!bss) { wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found"); status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES; @@ -654,24 +705,7 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) } /* Associate to the network */ - /* Send the BSS Management Response - Accept */ - if (wpa_s->wnm_reply) { - wpa_s->wnm_reply = 0; - wnm_send_bss_transition_mgmt_resp(wpa_s, - wpa_s->wnm_dialog_token, - WNM_BSS_TM_ACCEPT, - 0, bss->bssid); - } - - if (bss == wpa_s->current_bss) { - wpa_printf(MSG_DEBUG, - "WNM: Already associated with the preferred candidate"); - return 1; - } - - wpa_s->reassociate = 1; - wpa_supplicant_connect(wpa_s, bss, ssid); - wnm_deallocate_memory(wpa_s); + wnm_bss_tm_connect(wpa_s, bss, ssid, 1); return 1; send_bss_resp_fail: @@ -812,6 +846,79 @@ static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s) } +static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s) +{ + struct wpa_scan_results *scan_res; + struct wpa_bss *bss; + struct wpa_ssid *ssid = wpa_s->current_ssid; + u8 i, found = 0; + size_t j; + + wpa_dbg(wpa_s, MSG_DEBUG, + "WNM: Fetch current scan results from the driver for checking transition candidates"); + scan_res = wpa_drv_get_scan_results2(wpa_s); + if (!scan_res) { + wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Failed to get scan results"); + return 0; + } + + if (scan_res->fetch_time.sec == 0) + os_get_reltime(&scan_res->fetch_time); + + filter_scan_res(wpa_s, scan_res); + + for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { + struct neighbor_report *nei; + + nei = &wpa_s->wnm_neighbor_report_elements[i]; + if (nei->preference_present && nei->preference == 0) + continue; + + for (j = 0; j < scan_res->num; j++) { + struct wpa_scan_res *res; + const u8 *ssid_ie; + + res = scan_res->res[j]; + if (os_memcmp(nei->bssid, res->bssid, ETH_ALEN) != 0 || + res->age > WNM_SCAN_RESULT_AGE * 1000) + continue; + bss = wpa_s->current_bss; + ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID); + if (bss && ssid_ie && + (bss->ssid_len != ssid_ie[1] || + os_memcmp(bss->ssid, ssid_ie + 2, + bss->ssid_len) != 0)) + continue; + + /* Potential candidate found */ + found = 1; + scan_snr(res); + scan_est_throughput(wpa_s, res); + wpa_bss_update_scan_res(wpa_s, res, + &scan_res->fetch_time); + } + } + + wpa_scan_results_free(scan_res); + if (!found) { + wpa_dbg(wpa_s, MSG_DEBUG, + "WNM: No transition candidate matches existing scan results"); + return 0; + } + + bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE); + if (!bss) { + wpa_dbg(wpa_s, MSG_DEBUG, + "WNM: Comparison of scan results against transition candidates did not find matches"); + return 0; + } + + /* Associate to the network */ + wnm_bss_tm_connect(wpa_s, bss, ssid, 0); + return 1; +} + + static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, const u8 *pos, const u8 *end, int reply) @@ -924,6 +1031,20 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, wpa_s->wnm_cand_valid_until.usec %= 1000000; os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN); + /* + * Fetch the latest scan results from the kernel and check for + * candidates based on those results first. This can help in + * finding more up-to-date information should the driver has + * done some internal scanning operations after the last scan + * result update in wpa_supplicant. + */ + if (wnm_fetch_scan_results(wpa_s) > 0) + return; + + /* + * Try to use previously received scan results, if they are + * recent enough to use for a connection. + */ if (wpa_s->last_scan_res_used > 0) { struct os_reltime now; @@ -939,6 +1060,14 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, } wnm_set_scan_freqs(wpa_s); + if (wpa_s->wnm_num_neighbor_report == 1) { + os_memcpy(wpa_s->next_scan_bssid, + wpa_s->wnm_neighbor_report_elements[0].bssid, + ETH_ALEN); + wpa_printf(MSG_DEBUG, + "WNM: Scan only for a specific BSSID since there is only a single candidate " + MACSTR, MAC2STR(wpa_s->next_scan_bssid)); + } wpa_supplicant_req_scan(wpa_s, 0, 0); } else if (reply) { enum bss_trans_mgmt_status_code status; diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 3b7a6994..852f7a6d 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -622,6 +622,7 @@ struct wpa_supplicant { #define MAX_SCAN_ID 16 int scan_id[MAX_SCAN_ID]; unsigned int scan_id_count; + u8 next_scan_bssid[ETH_ALEN]; struct wpa_ssid_value *ssids_from_scan_req; unsigned int num_ssids_from_scan_req; |
