diff options
| author | Dmitry Shmidt <dimitrysh@google.com> | 2013-05-17 09:51:35 -0700 |
|---|---|---|
| committer | Dmitry Shmidt <dimitrysh@google.com> | 2013-05-17 09:51:35 -0700 |
| commit | 44c957860ca714a86357591f39aff0bfa904c743 (patch) | |
| tree | 69e00275f0ee7bcc65df0e19896ece899ec85042 | |
| parent | ea69e84a6f4455c59348485895d3d5e3af77a65b (diff) | |
| download | android_external_wpa_supplicant_8-44c957860ca714a86357591f39aff0bfa904c743.tar.gz android_external_wpa_supplicant_8-44c957860ca714a86357591f39aff0bfa904c743.tar.bz2 android_external_wpa_supplicant_8-44c957860ca714a86357591f39aff0bfa904c743.zip | |
Accumulative patch from commit c6ccf12d3f6f35e295f9522dded535da8af6ab98
c6ccf12 P2P: Use preferred channel list during GO creation
6d956c4 P2P: Re-select channel in invitation case with peer info
010b5f9 P2P: Fix p2p_pref_chan setting from configuration file
d7692b8 dbus: Terminate cleanly on messagebus shutdown
e2396a6 WNM: Enable CONFIG_WNM in Android.mk
65bcd0a WNM: Add sending of BSS Transition Management Query
e27d20b WNM: Add neighbor report processing for BSS Transition Management
f3e907a WPS: Clear connection failure counts on WPS success
170f566 NFC: Connect using learnt credential after NFC Tag read
0af2db7 edit: Fix libreadline history clearing with WPA_TRACE
Change-Id: I0599ea2179869ae8c250ff6b887bb16324fc02f4
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
| -rw-r--r-- | src/common/ieee802_11_defs.h | 17 | ||||
| -rw-r--r-- | src/p2p/p2p.h | 9 | ||||
| -rw-r--r-- | src/p2p/p2p_invitation.c | 8 | ||||
| -rw-r--r-- | src/p2p/p2p_utils.c | 28 | ||||
| -rw-r--r-- | src/utils/edit_readline.c | 4 | ||||
| -rw-r--r-- | wpa_supplicant/ctrl_iface.c | 16 | ||||
| -rw-r--r-- | wpa_supplicant/dbus/dbus_common.c | 25 | ||||
| -rw-r--r-- | wpa_supplicant/p2p_supplicant.c | 12 | ||||
| -rw-r--r-- | wpa_supplicant/wnm_sta.c | 362 | ||||
| -rw-r--r-- | wpa_supplicant/wnm_sta.h | 69 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_cli.c | 8 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant.c | 4 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant_i.h | 11 | ||||
| -rw-r--r-- | wpa_supplicant/wps_supplicant.c | 47 |
14 files changed, 588 insertions, 32 deletions
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index f782c865..08485902 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -549,6 +549,14 @@ struct ieee80211_mgmt { * Entries (optional) */ u8 variable[0]; } STRUCT_PACKED bss_tm_resp; + struct { + u8 action; /* 6 */ + u8 dialog_token; + u8 query_reason; + /* BSS Transition Candidate List + * Entries (optional) */ + u8 variable[0]; + } STRUCT_PACKED bss_tm_query; } u; } STRUCT_PACKED action; } u; @@ -1049,6 +1057,15 @@ enum wnm_action { #define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3) #define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4) +#define WNM_NEIGHBOR_TSF 1 +#define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING 2 +#define WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE 3 +#define WNM_NEIGHBOR_BSS_TERMINATION_DURATION 4 +#define WNM_NEIGHBOR_BEARING 5 +#define WNM_NEIGHBOR_MEASUREMENT_PILOT 66 +#define WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES 70 +#define WNM_NEIGHBOR_MULTIPLE_BSSID 71 + /* IEEE Std 802.11-2012, 8.4.2.62 20/40 BSS Coexistence element */ #define WLAN_20_40_BSS_COEX_INFO_REQ BIT(0) #define WLAN_20_40_BSS_COEX_40MHZ_INTOL BIT(1) diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 28a0a1d1..b1978934 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -1648,6 +1648,15 @@ int p2p_channels_includes_freq(const struct p2p_channels *channels, */ int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq); +/** + * p2p_get_pref_freq - Get channel from preferred channel list + * @p2p: P2P module context from p2p_init() + * @channels: List of channels + * Returns: Preferred channel + */ +unsigned int p2p_get_pref_freq(struct p2p_data *p2p, + const struct p2p_channels *channels); + void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan); /** diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c index 05822c65..5016f1b5 100644 --- a/src/p2p/p2p_invitation.c +++ b/src/p2p/p2p_invitation.c @@ -322,6 +322,14 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, status = P2P_SC_FAIL_NO_COMMON_CHANNELS; goto fail; } + } else if (!(dev->flags & P2P_DEV_FORCE_FREQ) && + !p2p->cfg->cfg_op_channel) { + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, + "P2P: Try to reselect channel selection with " + "peer information received; " + "previously selected op_class %u channel %u", + p2p->op_reg_class, p2p->op_channel); + p2p_reselect_channel(p2p, &intersection); } op_freq = p2p_channel_to_freq(p2p->op_reg_class, diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c index 69bd14b4..0da26827 100644 --- a/src/p2p/p2p_utils.c +++ b/src/p2p/p2p_utils.c @@ -243,3 +243,31 @@ int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq) return p2p_channels_includes(&p2p->cfg->channels, op_reg_class, op_channel); } + + +unsigned int p2p_get_pref_freq(struct p2p_data *p2p, + const struct p2p_channels *channels) +{ + unsigned int i; + int freq = 0; + + if (channels == NULL) { + if (p2p->cfg->num_pref_chan) { + freq = p2p_channel_to_freq( + p2p->cfg->pref_chan[0].op_class, + p2p->cfg->pref_chan[0].chan); + if (freq < 0) + freq = 0; + } + return freq; + } + + for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) { + freq = p2p_channel_to_freq(p2p->cfg->pref_chan[i].op_class, + p2p->cfg->pref_chan[i].chan); + if (p2p_channels_includes_freq(channels, freq)) + return freq; + } + + return 0; +} diff --git a/src/utils/edit_readline.c b/src/utils/edit_readline.c index add26fa3..c2a5bcaa 100644 --- a/src/utils/edit_readline.c +++ b/src/utils/edit_readline.c @@ -167,9 +167,9 @@ void edit_deinit(const char *history_file, if (filter_cb && filter_cb(edit_cb_ctx, p)) { h = remove_history(where_history()); if (h) { - os_free(h->line); + free(h->line); free(h->data); - os_free(h); + free(h); } else next_history(); } else diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 8c06334c..e8bfe0c5 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -4994,6 +4994,19 @@ static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd) return ret; } + +static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd) +{ + int query_reason; + + query_reason = atoi(cmd); + + wpa_printf(MSG_DEBUG, "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d", + query_reason); + + return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason); +} + #endif /* CONFIG_WNM */ @@ -5631,6 +5644,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) { if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10)) reply_len = -1; + } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 10) == 0) { + if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 10)) + reply_len = -1; #endif /* CONFIG_WNM */ } else if (os_strcmp(buf, "FLUSH") == 0) { wpa_supplicant_ctrl_iface_flush(wpa_s); diff --git a/wpa_supplicant/dbus/dbus_common.c b/wpa_supplicant/dbus/dbus_common.c index 5d0e31e2..6caf740e 100644 --- a/wpa_supplicant/dbus/dbus_common.c +++ b/wpa_supplicant/dbus/dbus_common.c @@ -17,6 +17,7 @@ #include "dbus_common_i.h" #include "dbus_new.h" #include "dbus_old.h" +#include "../wpa_supplicant_i.h" #ifndef SIGPOLL @@ -257,6 +258,22 @@ static int integrate_with_eloop(struct wpas_dbus_priv *priv) } +static DBusHandlerResult disconnect_filter(DBusConnection *conn, + DBusMessage *message, void *data) +{ + struct wpas_dbus_priv *priv = data; + + if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, + "Disconnected")) { + wpa_printf(MSG_DEBUG, "dbus: bus disconnected, terminating"); + dbus_connection_set_exit_on_disconnect(conn, FALSE); + wpa_supplicant_terminate_proc(priv->global); + return DBUS_HANDLER_RESULT_HANDLED; + } else + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + static int wpas_dbus_init_common(struct wpas_dbus_priv *priv) { DBusError error; @@ -265,7 +282,10 @@ static int wpas_dbus_init_common(struct wpas_dbus_priv *priv) /* Get a reference to the system bus */ dbus_error_init(&error); priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error); - if (!priv->con) { + if (priv->con) { + dbus_connection_add_filter(priv->con, disconnect_filter, priv, + NULL); + } else { wpa_printf(MSG_ERROR, "dbus: Could not acquire the system " "bus: %s - %s", error.name, error.message); ret = -1; @@ -304,6 +324,9 @@ static void wpas_dbus_deinit_common(struct wpas_dbus_priv *priv) NULL, NULL, NULL); dbus_connection_set_timeout_functions(priv->con, NULL, NULL, NULL, NULL, NULL); + dbus_connection_remove_filter(priv->con, disconnect_filter, + priv); + dbus_connection_unref(priv->con); } diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index f1e15ffc..b760e7fe 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -3103,6 +3103,12 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) wpa_printf(MSG_DEBUG, "P2P: Random operating channel: " "%d:%d", p2p.op_reg_class, p2p.op_channel); } + + if (wpa_s->conf->p2p_pref_chan && wpa_s->conf->num_p2p_pref_chan) { + p2p.pref_chan = wpa_s->conf->p2p_pref_chan; + p2p.num_pref_chan = wpa_s->conf->num_p2p_pref_chan; + } + if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) { os_memcpy(p2p.country, wpa_s->conf->country, 2); p2p.country[2] = 0x04; @@ -4084,6 +4090,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, { u8 bssid[ETH_ALEN]; int res; + unsigned int pref_freq; os_memset(params, 0, sizeof(*params)); params->role_go = 1; @@ -4140,6 +4147,11 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, params->freq = wpa_s->best_5_freq; wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz " "channel %d MHz", params->freq); + } else if ((pref_freq = p2p_get_pref_freq(wpa_s->global->p2p, + channels))) { + params->freq = pref_freq; + wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz from preferred " + "channels", params->freq); } else { int chan; for (chan = 0; chan < 11; chan++) { diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index 4d9e4533..7de96c54 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -14,8 +14,12 @@ #include "wpa_supplicant_i.h" #include "driver_i.h" #include "scan.h" +#include "ctrl_iface.h" +#include "bss.h" +#include "wnm_sta.h" #define MAX_TFS_IE_LEN 1024 +#define WNM_MAX_NEIGHBOR_REPORT 10 /* get the TFS IE from driver */ @@ -294,6 +298,199 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, } +void wnm_deallocate_memory(struct wpa_supplicant *wpa_s) +{ + int i; + + for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { + os_free(wpa_s->wnm_neighbor_report_elements[i].tsf_info); + os_free(wpa_s->wnm_neighbor_report_elements[i].con_coun_str); + os_free(wpa_s->wnm_neighbor_report_elements[i].bss_tran_can); + os_free(wpa_s->wnm_neighbor_report_elements[i].bss_term_dur); + os_free(wpa_s->wnm_neighbor_report_elements[i].bearing); + os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot); + os_free(wpa_s->wnm_neighbor_report_elements[i].rrm_cap); + os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid); + } + + os_free(wpa_s->wnm_neighbor_report_elements); + wpa_s->wnm_neighbor_report_elements = NULL; +} + + +static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, + u8 id, u8 elen, const u8 *pos) +{ + switch (id) { + case WNM_NEIGHBOR_TSF: + if (elen < 2 + 2) { + wpa_printf(MSG_DEBUG, "WNM: Too short TSF"); + break; + } + rep->tsf_info = os_zalloc(sizeof(struct tsf_info)); + if (rep->tsf_info == NULL) + break; + rep->tsf_info->present = 1; + os_memcpy(rep->tsf_info->tsf_offset, pos, 2); + os_memcpy(rep->tsf_info->beacon_interval, pos + 2, 2); + break; + case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING: + if (elen < 2) { + wpa_printf(MSG_DEBUG, "WNM: Too short condensed " + "country string"); + break; + } + rep->con_coun_str = + os_zalloc(sizeof(struct condensed_country_string)); + if (rep->con_coun_str == NULL) + break; + rep->con_coun_str->present = 1; + os_memcpy(rep->con_coun_str->country_string, pos, 2); + break; + case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE: + if (elen < 1) { + wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition " + "candidate"); + break; + } + rep->bss_tran_can = + os_zalloc(sizeof(struct bss_transition_candidate)); + if (rep->bss_tran_can == NULL) + break; + rep->bss_tran_can->present = 1; + rep->bss_tran_can->preference = pos[0]; + break; + case WNM_NEIGHBOR_BSS_TERMINATION_DURATION: + if (elen < 12) { + wpa_printf(MSG_DEBUG, "WNM: Too short BSS termination " + "duration"); + break; + } + rep->bss_term_dur = + os_zalloc(sizeof(struct bss_termination_duration)); + if (rep->bss_term_dur == NULL) + break; + rep->bss_term_dur->present = 1; + os_memcpy(rep->bss_term_dur->duration, pos, 12); + break; + case WNM_NEIGHBOR_BEARING: + if (elen < 8) { + wpa_printf(MSG_DEBUG, "WNM: Too short neighbor " + "bearing"); + break; + } + rep->bearing = os_zalloc(sizeof(struct bearing)); + if (rep->bearing == NULL) + break; + rep->bearing->present = 1; + os_memcpy(rep->bearing->bearing, pos, 8); + break; + case WNM_NEIGHBOR_MEASUREMENT_PILOT: + if (elen < 2) { + wpa_printf(MSG_DEBUG, "WNM: Too short measurement " + "pilot"); + break; + } + rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot)); + if (rep->meas_pilot == NULL) + break; + rep->meas_pilot->present = 1; + rep->meas_pilot->measurement_pilot = pos[0]; + rep->meas_pilot->num_vendor_specific = pos[1]; + os_memcpy(rep->meas_pilot->vendor_specific, pos + 2, elen - 2); + break; + case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES: + if (elen < 4) { + wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled " + "capabilities"); + break; + } + rep->rrm_cap = + os_zalloc(sizeof(struct rrm_enabled_capabilities)); + if (rep->rrm_cap == NULL) + break; + rep->rrm_cap->present = 1; + os_memcpy(rep->rrm_cap->capabilities, pos, 4); + break; + case WNM_NEIGHBOR_MULTIPLE_BSSID: + if (elen < 2) { + wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID"); + break; + } + rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid)); + if (rep->mul_bssid == NULL) + break; + rep->mul_bssid->present = 1; + rep->mul_bssid->max_bssid_indicator = pos[0]; + rep->mul_bssid->num_vendor_specific = pos[1]; + os_memcpy(rep->mul_bssid->vendor_specific, pos + 2, elen - 2); + break; + } +} + + +static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, + const u8 *pos, u8 len, + struct neighbor_report *rep) +{ + u8 left = len; + + if (left < 13) { + wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report"); + return; + } + + os_memcpy(rep->bssid, pos, ETH_ALEN); + os_memcpy(rep->bssid_information, pos + ETH_ALEN, 4); + rep->regulatory_class = *(pos + 10); + rep->channel_number = *(pos + 11); + rep->phy_type = *(pos + 12); + + pos += 13; + left -= 13; + + while (left >= 2) { + u8 id, elen; + + id = *pos++; + elen = *pos++; + wnm_parse_neighbor_report_elem(rep, id, elen, pos); + left -= 2 + elen; + pos += elen; + } +} + + +static int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *scan_res, + struct neighbor_report *neigh_rep, + u8 num_neigh_rep, u8 *bssid_to_connect) +{ + + u8 i, j; + + if (scan_res == NULL || num_neigh_rep == 0) + return 0; + + for (i = 0; i < num_neigh_rep; i++) { + for (j = 0; j < scan_res->num; j++) { + /* Check for a better RSSI AP */ + if (os_memcmp(scan_res->res[j]->bssid, + neigh_rep[i].bssid, ETH_ALEN) == 0 && + scan_res->res[j]->level > + wpa_s->current_bss->level) { + /* Got a BSSID with better RSSI value */ + os_memcpy(bssid_to_connect, neigh_rep[i].bssid, + ETH_ALEN); + return 1; + } + } + } + + return 0; +} + + static void wnm_send_bss_transition_mgmt_resp(struct wpa_supplicant *wpa_s, u8 dialog_token, u8 status, u8 delay, const u8 *target_bssid) @@ -332,29 +529,90 @@ static void wnm_send_bss_transition_mgmt_resp(struct wpa_supplicant *wpa_s, } +void wnm_scan_response(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *scan_res) +{ + u8 bssid[ETH_ALEN]; + + if (scan_res == NULL) { + wpa_printf(MSG_ERROR, "Scan result is NULL"); + goto send_bss_resp_fail; + } + + /* Compare the Neighbor Report and scan results */ + if (compare_scan_neighbor_results(wpa_s, scan_res, + wpa_s->wnm_neighbor_report_elements, + wpa_s->wnm_num_neighbor_report, + bssid) == 1) { + /* Associate to the network */ + struct wpa_bss *bss; + struct wpa_ssid *ssid = wpa_s->current_ssid; + + bss = wpa_bss_get_bssid(wpa_s, bssid); + if (!bss) { + wpa_printf(MSG_DEBUG, "WNM: Target AP not found from " + "BSS table"); + goto send_bss_resp_fail; + } + + /* Send the BSS Management Response - Accept */ + if (wpa_s->wnm_reply) { + wnm_send_bss_transition_mgmt_resp(wpa_s, + wpa_s->wnm_dialog_token, + 0, /* Accept */ + 0, NULL); + } + + wpa_s->reassociate = 1; + wpa_supplicant_connect(wpa_s, bss, ssid); + wnm_deallocate_memory(wpa_s); + return; + } + + /* Send reject response for all the failures */ +send_bss_resp_fail: + wnm_deallocate_memory(wpa_s); + if (wpa_s->wnm_reply) { + wnm_send_bss_transition_mgmt_resp(wpa_s, + wpa_s->wnm_dialog_token, + 1 /* Reject - unspecified */, + 0, NULL); + } + return; +} + + static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, const u8 *pos, const u8 *end, int reply) { - u8 dialog_token; - u8 mode; - u16 disassoc_timer; - if (pos + 5 > end) return; - dialog_token = pos[0]; - mode = pos[1]; - disassoc_timer = WPA_GET_LE16(pos + 2); + wpa_s->wnm_dialog_token = pos[0]; + wpa_s->wnm_mode = pos[1]; + wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); + wpa_s->wnm_validity_interval = pos[4]; + wpa_s->wnm_reply = reply; wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: " "dialog_token=%u request_mode=0x%x " "disassoc_timer=%u validity_interval=%u", - dialog_token, mode, disassoc_timer, pos[4]); + wpa_s->wnm_dialog_token, wpa_s->wnm_mode, + wpa_s->wnm_dissoc_timer, wpa_s->wnm_validity_interval); + pos += 5; - if (mode & 0x08) + + if (wpa_s->wnm_mode & 0x08) { + if (pos + 12 > end) { + wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); + return; + } + os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12); pos += 12; /* BSS Termination Duration */ - if (mode & 0x10) { + } + + if (wpa_s->wnm_mode & 0x10) { char url[256]; if (pos + 1 > end || pos + 1 + pos[0] > end) { wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " @@ -363,14 +621,15 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, } os_memcpy(url, pos + 1, pos[0]); url[pos[0]] = '\0'; + pos += 1 + pos[0]; wpa_msg(wpa_s, MSG_INFO, "WNM: ESS Disassociation Imminent - " "session_info_url=%s", url); } - if (mode & 0x04) { + if (wpa_s->wnm_mode & 0x04) { wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " - "Disassociation Timer %u", disassoc_timer); - if (disassoc_timer && !wpa_s->scanning) { + "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); + if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { /* TODO: mark current BSS less preferred for * selection */ wpa_printf(MSG_DEBUG, "Trying to find another BSS"); @@ -378,15 +637,85 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, } } - if (reply) { - /* TODO: add support for reporting Accept */ - wnm_send_bss_transition_mgmt_resp(wpa_s, dialog_token, + if (wpa_s->wnm_mode & 0x01) { + wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); + wpa_s->wnm_num_neighbor_report = 0; + os_free(wpa_s->wnm_neighbor_report_elements); + wpa_s->wnm_neighbor_report_elements = os_zalloc( + WNM_MAX_NEIGHBOR_REPORT * + sizeof(struct neighbor_report)); + if (wpa_s->wnm_neighbor_report_elements == NULL) + return; + + while (pos + 2 <= end && + wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) + { + u8 tag = *pos++; + u8 len = *pos++; + + wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", + tag); + if (pos + len > end) { + wpa_printf(MSG_DEBUG, "WNM: Truncated request"); + return; + } + wnm_parse_neighbor_report( + wpa_s, pos, len, + &wpa_s->wnm_neighbor_report_elements[ + wpa_s->wnm_num_neighbor_report]); + + pos += len; + wpa_s->wnm_num_neighbor_report++; + } + + wpa_s->scan_res_handler = wnm_scan_response; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } else if (reply) { + wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management " + "Request Mode is zero"); + wnm_send_bss_transition_mgmt_resp(wpa_s, + wpa_s->wnm_dialog_token, 1 /* Reject - unspecified */, 0, NULL); } } +int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, + u8 query_reason) +{ + u8 buf[1000], *pos; + struct ieee80211_mgmt *mgmt; + size_t len; + int ret; + + wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " + MACSTR " query_reason=%u", + MAC2STR(wpa_s->bssid), query_reason); + + mgmt = (struct ieee80211_mgmt *) buf; + os_memset(&buf, 0, sizeof(buf)); + os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); + os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + mgmt->u.action.category = WLAN_ACTION_WNM; + mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY; + mgmt->u.action.u.bss_tm_query.dialog_token = 0; + mgmt->u.action.u.bss_tm_query.query_reason = query_reason; + pos = mgmt->u.action.u.bss_tm_query.variable; + + len = pos - (u8 *) &mgmt->u.action.category; + + ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, + wpa_s->own_addr, wpa_s->bssid, + &mgmt->u.action.category, len, 0); + + return ret; +} + + void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, struct rx_action *action) { @@ -418,6 +747,7 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len); break; default: + wpa_printf(MSG_ERROR, "WNM: Unknown request"); break; } } diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h index 3f9d88b7..2933926c 100644 --- a/wpa_supplicant/wnm_sta.h +++ b/wpa_supplicant/wnm_sta.h @@ -12,10 +12,79 @@ struct rx_action; struct wpa_supplicant; +struct tsf_info { + u8 present; + u8 tsf_offset[2]; + u8 beacon_interval[2]; +}; + +struct condensed_country_string { + u8 present; + u8 country_string[2]; +}; + +struct bss_transition_candidate { + u8 present; + u8 preference; +}; + +struct bss_termination_duration { + u8 present; + u8 duration[12]; +}; + +struct bearing { + u8 present; + u8 bearing[8]; +}; + +struct measurement_pilot { + u8 present; + u8 measurement_pilot; + u8 num_vendor_specific; + u8 vendor_specific[255]; +}; + +struct rrm_enabled_capabilities { + u8 present; + u8 capabilities[4]; +}; + +struct multiple_bssid { + u8 present; + u8 max_bssid_indicator; + u8 num_vendor_specific; + u8 vendor_specific[255]; +}; + +struct neighbor_report { + u8 bssid[ETH_ALEN]; + u8 bssid_information[4]; + u8 regulatory_class; + u8 channel_number; + u8 phy_type; + struct tsf_info *tsf_info; + struct condensed_country_string *con_coun_str; + struct bss_transition_candidate *bss_tran_can; + struct bss_termination_duration *bss_term_dur; + struct bearing *bearing; + struct measurement_pilot *meas_pilot; + struct rrm_enabled_capabilities *rrm_cap; + struct multiple_bssid *mul_bssid; +}; + + int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, u8 action, u16 intval, struct wpabuf *tfs_req); void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, struct rx_action *action); +void wnm_scan_response(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *scan_res); + +int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, + u8 query_reason); +void wnm_deallocate_memory(struct wpa_supplicant *wpa_s); + #endif /* WNM_STA_H */ diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index b66dcd05..61d4b61d 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -2315,6 +2315,12 @@ static int wpa_cli_cmd_wnm_sleep(struct wpa_ctrl *ctrl, int argc, char *argv[]) return wpa_cli_cmd(ctrl, "WNM_SLEEP", 0, argc, argv); } + +static int wpa_cli_cmd_wnm_bss_query(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "WNM_BSS_QUERY", 1, argc, argv); +} + #endif /* CONFIG_WNM */ @@ -2798,6 +2804,8 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { #ifdef CONFIG_WNM { "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none, "<enter/exit> [interval=#] = enter/exit WNM-Sleep mode" }, + { "wnm_bss_query", wpa_cli_cmd_wnm_bss_query, NULL, cli_cmd_flag_none, + "<query reason> = Send BSS Transition Management Query" }, #endif /* CONFIG_WNM */ { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive, "<params..> = Sent unprocessed command" }, diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index dbdaf193..1a7c0ff3 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -49,6 +49,7 @@ #include "scan.h" #include "offchannel.h" #include "hs20_supplicant.h" +#include "wnm_sta.h" const char *wpa_supplicant_version = "wpa_supplicant v" VERSION_STR "\n" @@ -470,6 +471,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpa_s->disallow_aps_ssid = NULL; wnm_bss_keep_alive_deinit(wpa_s); +#ifdef CONFIG_WNM + wnm_deallocate_memory(wpa_s); +#endif /* CONFIG_WNM */ ext_password_deinit(wpa_s->ext_pw); wpa_s->ext_pw = NULL; diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 7559a756..a2a189b0 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -690,6 +690,17 @@ struct wpa_supplicant { u8 last_gas_dialog_token; unsigned int no_keep_alive:1; + +#ifdef CONFIG_WNM + u8 wnm_dialog_token; + u8 wnm_reply; + u8 wnm_num_neighbor_report; + u8 wnm_mode; + u16 wnm_dissoc_timer; + u8 wnm_validity_interval; + u8 wnm_bss_termination_duration[12]; + struct neighbor_report *wnm_neighbor_report_elements; +#endif /* CONFIG_WNM */ }; diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index b376fb08..d73e023e 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -648,6 +648,9 @@ static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s) wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS); wpa_s->wps_success = 1; wpas_notify_wps_event_success(wpa_s); + if (wpa_s->current_ssid) + wpas_clear_temp_disabled(wpa_s, wpa_s->current_ssid, 1); + wpa_s->extra_blacklist_count = 0; /* * Enable the networks disabled during wpas_wps_reassoc after 10 @@ -964,21 +967,10 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s, } -static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s, - struct wpa_ssid *selected, const u8 *bssid) +static void wpas_wps_temp_disable(struct wpa_supplicant *wpa_s, + struct wpa_ssid *selected) { struct wpa_ssid *ssid; - struct wpa_bss *bss; - - wpa_s->after_wps = 0; - wpa_s->known_wps_freq = 0; - if (bssid) { - bss = wpa_bss_get_bssid_latest(wpa_s, bssid); - if (bss && bss->freq > 0) { - wpa_s->known_wps_freq = 1; - wpa_s->wps_freq = bss->freq; - } - } if (wpa_s->current_ssid) wpa_supplicant_deauthenticate( @@ -1006,6 +998,26 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s, } ssid = ssid->next; } +} + + +static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s, + struct wpa_ssid *selected, const u8 *bssid) +{ + struct wpa_bss *bss; + + wpa_s->after_wps = 0; + wpa_s->known_wps_freq = 0; + if (bssid) { + bss = wpa_bss_get_bssid_latest(wpa_s, bssid); + if (bss && bss->freq > 0) { + wpa_s->known_wps_freq = 1; + wpa_s->wps_freq = bss->freq; + } + } + + wpas_wps_temp_disable(wpa_s, selected); + wpa_s->disconnected = 0; wpa_s->reassociate = 1; wpa_s->scan_runs = 0; @@ -2087,6 +2099,15 @@ static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s, { wpa_s->wps_ap_channel = 0; + /* + * Disable existing networks temporarily to allow the newly learned + * credential to be preferred. Enable the temporarily disabled networks + * after 10 seconds. + */ + wpas_wps_temp_disable(wpa_s, NULL); + eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s, + NULL); + if (wps_oob_use_cred(wpa_s->wps, attr) < 0) return -1; |
