diff options
| -rw-r--r-- | hostapd/ctrl_iface.c | 21 | ||||
| -rw-r--r-- | src/ap/pmksa_cache_auth.c | 4 | ||||
| -rw-r--r-- | src/ap/pmksa_cache_auth.h | 2 | ||||
| -rw-r--r-- | src/ap/wpa_auth.c | 16 | ||||
| -rw-r--r-- | src/ap/wpa_auth.h | 2 | ||||
| -rw-r--r-- | src/common/ieee802_11_defs.h | 13 | ||||
| -rw-r--r-- | src/common/wpa_ctrl.h | 3 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211.c | 6 | ||||
| -rw-r--r-- | src/p2p/p2p.h | 4 | ||||
| -rw-r--r-- | src/p2p/p2p_invitation.c | 9 | ||||
| -rw-r--r-- | src/rsn_supp/pmksa_cache.c | 27 | ||||
| -rw-r--r-- | src/rsn_supp/pmksa_cache.h | 3 | ||||
| -rw-r--r-- | src/rsn_supp/tdls.c | 22 | ||||
| -rw-r--r-- | src/rsn_supp/wpa.c | 17 | ||||
| -rw-r--r-- | src/rsn_supp/wpa.h | 1 | ||||
| -rw-r--r-- | wpa_supplicant/events.c | 28 | ||||
| -rw-r--r-- | wpa_supplicant/p2p_supplicant.c | 39 | ||||
| -rw-r--r-- | wpa_supplicant/wnm_sta.c | 47 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_cli.c | 85 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant.c | 3 |
20 files changed, 288 insertions, 64 deletions
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 7fc520c4..dc9ede73 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -29,6 +29,7 @@ #include "ap/wps_hostapd.h" #include "ap/ctrl_iface_ap.h" #include "ap/ap_drv_ops.h" +#include "ap/wpa_auth.h" #include "wps/wps_defs.h" #include "wps/wps.h" #include "config_file.h" @@ -594,6 +595,14 @@ static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, /* send disassociation frame after time-out */ if (disassoc_timer) { struct sta_info *sta; + int timeout, beacon_int; + + /* + * Prevent STA from reconnecting using cached PMKSA to force + * full authentication with the authentication server (which may + * decide to reject the connection), + */ + wpa_auth_pmksa_remove(hapd->wpa_auth, addr); sta = ap_get_sta(hapd, addr); if (sta == NULL) { @@ -603,10 +612,18 @@ static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, return -1; } + beacon_int = hapd->iconf->beacon_int; + if (beacon_int < 1) + beacon_int = 100; /* best guess */ + /* Calculate timeout in ms based on beacon_int in TU */ + timeout = disassoc_timer * beacon_int * 128 / 125; + wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR + " set to %d ms", MAC2STR(addr), timeout); + sta->timeout_next = STA_DISASSOC_FROM_CLI; eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_register_timeout(disassoc_timer / 1000, - disassoc_timer % 1000 * 1000, + eloop_register_timeout(timeout / 1000, + timeout % 1000 * 1000, ap_handle_timer, hapd, sta); } diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c index d27fd302..40972e9a 100644 --- a/src/ap/pmksa_cache_auth.c +++ b/src/ap/pmksa_cache_auth.c @@ -48,8 +48,8 @@ static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry) } -static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, - struct rsn_pmksa_cache_entry *entry) +void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, + struct rsn_pmksa_cache_entry *entry) { struct rsn_pmksa_cache_entry *pos, *prev; diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h index d473f3fd..aa90024d 100644 --- a/src/ap/pmksa_cache_auth.h +++ b/src/ap/pmksa_cache_auth.h @@ -55,5 +55,7 @@ pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid); void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry, struct eapol_state_machine *eapol); +void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, + struct rsn_pmksa_cache_entry *entry); #endif /* PMKSA_CACHE_H */ diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 18ae86c8..83cc8578 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -2944,6 +2944,22 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth, } +void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth, + const u8 *sta_addr) +{ + struct rsn_pmksa_cache_entry *pmksa; + + if (wpa_auth == NULL || wpa_auth->pmksa == NULL) + return; + pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL); + if (pmksa) { + wpa_printf(MSG_DEBUG, "WPA: Remove PMKSA cache entry for " + MACSTR " based on request", MAC2STR(sta_addr)); + pmksa_cache_free_entry(wpa_auth->pmksa, pmksa); + } +} + + static struct wpa_group * wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id) { diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 9126b90d..ebfe86f0 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -263,6 +263,8 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth, const u8 *pmk, size_t len, const u8 *sta_addr, int session_timeout, struct eapol_state_machine *eapol); +void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth, + const u8 *sta_addr); int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id); void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, int ack); diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 08485902..137c3090 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1057,6 +1057,19 @@ enum wnm_action { #define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3) #define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4) +/* IEEE Std 802.11-2012 - Table 8-253 */ +enum bss_trans_mgmt_status_code { + WNM_BSS_TM_ACCEPT = 0, + WNM_BSS_TM_REJECT_UNSPECIFIED = 1, + WNM_BSS_TM_REJECT_INSUFFICIENT_BEACON = 2, + WNM_BSS_TM_REJECT_INSUFFICIENT_CAPABITY = 3, + WNM_BSS_TM_REJECT_UNDESIRED = 4, + WNM_BSS_TM_REJECT_DELAY_REQUEST = 5, + WNM_BSS_TM_REJECT_STA_CANDIDATE_LIST_PROVIDED = 6, + WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES = 7, + WNM_BSS_TM_REJECT_LEAVING_ESS = 8 +}; + #define WNM_NEIGHBOR_TSF 1 #define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING 2 #define WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE 3 diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index aab228b7..0c05a41d 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -136,6 +136,9 @@ extern "C" { #define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT " #define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED " +/* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */ +#define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT " + #define INTERWORKING_AP "INTERWORKING-AP " #define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH " diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index c8f74781..3d16330c 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -6298,8 +6298,14 @@ static const char * nl80211_iftype_str(enum nl80211_iftype mode) return "STATION"; case NL80211_IFTYPE_AP: return "AP"; + case NL80211_IFTYPE_AP_VLAN: + return "AP_VLAN"; + case NL80211_IFTYPE_WDS: + return "WDS"; case NL80211_IFTYPE_MONITOR: return "MONITOR"; + case NL80211_IFTYPE_MESH_POINT: + return "MESH_POINT"; case NL80211_IFTYPE_P2P_CLIENT: return "P2P_CLIENT"; case NL80211_IFTYPE_P2P_GO: diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 499b62e1..c392d571 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -702,6 +702,7 @@ struct p2p_config { * @persistent_group: Whether this is an invitation to reinvoke a * persistent group (instead of invitation to join an active * group) + * @channels: Available operating channels for the group * Returns: Status code (P2P_SC_*) * * This optional callback can be used to implement persistent reconnect @@ -722,7 +723,8 @@ struct p2p_config { u8 (*invitation_process)(void *ctx, const u8 *sa, const u8 *bssid, const u8 *go_dev_addr, const u8 *ssid, size_t ssid_len, int *go, u8 *group_bssid, - int *force_freq, int persistent_group); + int *force_freq, int persistent_group, + const struct p2p_channels *channels); /** * invitation_received - Callback on Invitation Request RX diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c index 214eae01..e3e760dc 100644 --- a/src/p2p/p2p_invitation.c +++ b/src/p2p/p2p_invitation.c @@ -221,11 +221,14 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, goto fail; } + p2p_channels_intersect(&p2p->cfg->channels, &dev->channels, + &intersection); + if (p2p->cfg->invitation_process) { status = p2p->cfg->invitation_process( p2p->cfg->cb_ctx, sa, msg.group_bssid, msg.group_id, msg.group_id + ETH_ALEN, msg.group_id_len - ETH_ALEN, - &go, group_bssid, &op_freq, persistent); + &go, group_bssid, &op_freq, persistent, &intersection); } if (op_freq) { @@ -238,8 +241,6 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, goto fail; } - p2p_channels_intersect(&p2p->cfg->channels, &dev->channels, - &intersection); if (!p2p_channels_includes(&intersection, reg_class, channel)) { p2p_dbg(p2p, "forced freq %d MHz not in the supported channels interaction", @@ -253,8 +254,6 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, } else { p2p_dbg(p2p, "No forced channel from invitation processing - figure out best one to use"); - p2p_channels_intersect(&p2p->cfg->channels, &dev->channels, - &intersection); /* Default to own configuration as a starting point */ p2p->op_reg_class = p2p->cfg->op_reg_class; p2p->op_channel = p2p->cfg->op_channel; diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c index df675834..93056ea8 100644 --- a/src/rsn_supp/pmksa_cache.c +++ b/src/rsn_supp/pmksa_cache.c @@ -164,17 +164,23 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, pmksa->pmksa = pos->next; else prev->next = pos->next; - wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for " - "the current AP"); - pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE); /* * If OKC is used, there may be other PMKSA cache * entries based on the same PMK. These needs to be * flushed so that a new entry can be created based on - * the new PMK. + * the new PMK. Only clear other entries if they have a + * matching PMK and this PMK has been used successfully + * with the current AP, i.e., if opportunistic flag has + * been cleared in wpa_supplicant_key_neg_complete(). */ - pmksa_cache_flush(pmksa, network_ctx); + wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for " + "the current AP and any PMKSA cache entry " + "that was based on the old PMK"); + if (!pos->opportunistic) + pmksa_cache_flush(pmksa, network_ctx, pos->pmk, + pos->pmk_len); + pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE); break; } prev = pos; @@ -235,15 +241,22 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, * pmksa_cache_flush - Flush PMKSA cache entries for a specific network * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() * @network_ctx: Network configuration context or %NULL to flush all entries + * @pmk: PMK to match for or %NYLL to match all PMKs + * @pmk_len: PMK length */ -void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx) +void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx, + const u8 *pmk, size_t pmk_len) { struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp; int removed = 0; entry = pmksa->pmksa; while (entry) { - if (entry->network_ctx == network_ctx || network_ctx == NULL) { + if ((entry->network_ctx == network_ctx || + network_ctx == NULL) && + (pmk == NULL || + (pmk_len == entry->pmk_len && + os_memcmp(pmk, entry->pmk, pmk_len) == 0))) { wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry " "for " MACSTR, MAC2STR(entry->aa)); if (prev) diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h index 6f3dfb31..d5aa229a 100644 --- a/src/rsn_supp/pmksa_cache.h +++ b/src/rsn_supp/pmksa_cache.h @@ -66,7 +66,8 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, struct rsn_pmksa_cache_entry * pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, const u8 *aa); -void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx); +void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx, + const u8 *pmk, size_t pmk_len); #else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */ diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c index 81e2a5c0..221d5fdd 100644 --- a/src/rsn_supp/tdls.c +++ b/src/rsn_supp/tdls.c @@ -37,8 +37,10 @@ unsigned int tdls_testing = 0; #endif /* CONFIG_TDLS_TESTING */ #define TPK_LIFETIME 43200 /* 12 hours */ -#define TPK_RETRY_COUNT 3 -#define TPK_TIMEOUT 5000 /* in milliseconds */ +#define TPK_M1_RETRY_COUNT 3 +#define TPK_M1_TIMEOUT 5000 /* in milliseconds */ +#define TPK_M2_RETRY_COUNT 10 +#define TPK_M2_TIMEOUT 500 /* in milliseconds */ #define TDLS_MIC_LEN 16 @@ -244,8 +246,13 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); - peer->sm_tmr.count = TPK_RETRY_COUNT; - peer->sm_tmr.timer = TPK_TIMEOUT; + if (action_code == WLAN_TDLS_SETUP_RESPONSE) { + peer->sm_tmr.count = TPK_M2_RETRY_COUNT; + peer->sm_tmr.timer = TPK_M2_TIMEOUT; + } else { + peer->sm_tmr.count = TPK_M1_RETRY_COUNT; + peer->sm_tmr.timer = TPK_M1_TIMEOUT; + } /* Copy message to resend on timeout */ os_memcpy(peer->sm_tmr.dest, dest, ETH_ALEN); @@ -261,7 +268,8 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered " "(action_code=%u)", action_code); - eloop_register_timeout(peer->sm_tmr.timer / 1000, 0, + eloop_register_timeout(peer->sm_tmr.timer / 1000, + (peer->sm_tmr.timer % 1000) * 1000, wpa_tdls_tpk_retry_timeout, sm, peer); return 0; } @@ -296,7 +304,6 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx) if (peer->sm_tmr.count) { peer->sm_tmr.count--; - peer->sm_tmr.timer = TPK_TIMEOUT; wpa_printf(MSG_INFO, "TDLS: Retrying sending of message " "(action_code=%u)", @@ -323,7 +330,8 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx) } eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); - eloop_register_timeout(peer->sm_tmr.timer / 1000, 0, + eloop_register_timeout(peer->sm_tmr.timer / 1000, + (peer->sm_tmr.timer % 1000) * 1000, wpa_tdls_tpk_retry_timeout, sm, peer); } else { eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index e50404ce..d83700a2 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -2412,6 +2412,21 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen, } +int wpa_sm_pmf_enabled(struct wpa_sm *sm) +{ + struct wpa_ie_data rsn; + + if (sm->mfp == NO_MGMT_FRAME_PROTECTION || !sm->ap_rsn_ie) + return 0; + + if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn) >= 0 && + rsn.capabilities & (WPA_CAPABILITY_MFPR | WPA_CAPABILITY_MFPC)) + return 1; + + return 0; +} + + /** * wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration * @sm: Pointer to WPA state machine data from wpa_sm_init() @@ -2622,7 +2637,7 @@ void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr) void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx) { #ifndef CONFIG_NO_WPA2 - pmksa_cache_flush(sm->pmksa, network_ctx); + pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0); #endif /* CONFIG_NO_WPA2 */ } diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 78dfb523..c757dcf1 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -123,6 +123,7 @@ unsigned int wpa_sm_get_param(struct wpa_sm *sm, int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen, int verbose); +int wpa_sm_pmf_enabled(struct wpa_sm *sm); void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 6d9b587f..60e71b69 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -929,6 +929,15 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s, return -1; } + wpa_msg(wpa_s, MSG_DEBUG, + "Considering connect request: reassociate: %d selected: " + MACSTR " bssid: " MACSTR " pending: " MACSTR + " wpa_state: %s ssid=%p current_ssid=%p", + wpa_s->reassociate, MAC2STR(selected->bssid), + MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid), + wpa_supplicant_state_txt(wpa_s->wpa_state), + ssid, wpa_s->current_ssid); + /* * Do not trigger new association unless the BSSID has changed or if * reassociation is requested. If we are in process of associating with @@ -938,22 +947,21 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s, (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 && ((wpa_s->wpa_state != WPA_ASSOCIATING && wpa_s->wpa_state != WPA_AUTHENTICATING) || - os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) != - 0))) { + (!is_zero_ether_addr(wpa_s->pending_bssid) && + os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) != + 0) || + (is_zero_ether_addr(wpa_s->pending_bssid) && + ssid != wpa_s->current_ssid)))) { if (wpa_supplicant_scard_init(wpa_s, ssid)) { wpa_supplicant_req_new_scan(wpa_s, 10, 0); return 0; } - wpa_msg(wpa_s, MSG_DEBUG, "Request association: " - "reassociate: %d selected: "MACSTR " bssid: " MACSTR - " pending: " MACSTR " wpa_state: %s", - wpa_s->reassociate, MAC2STR(selected->bssid), - MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid), - wpa_supplicant_state_txt(wpa_s->wpa_state)); + wpa_msg(wpa_s, MSG_DEBUG, "Request association with " MACSTR, + MAC2STR(selected->bssid)); wpa_supplicant_associate(wpa_s, selected, ssid); } else { - wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with the " - "selected AP"); + wpa_dbg(wpa_s, MSG_DEBUG, "Already associated or trying to " + "connect with the selected AP"); } return 0; diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 7c19d0cc..c36f61c2 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -2427,10 +2427,20 @@ static void wpas_prov_disc_fail(void *ctx, const u8 *peer, } +static int freq_included(const struct p2p_channels *channels, unsigned int freq) +{ + if (channels == NULL) + return 1; /* Assume no restrictions */ + return p2p_channels_includes_freq(channels, freq); + +} + + static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid, const u8 *go_dev_addr, const u8 *ssid, size_t ssid_len, int *go, u8 *group_bssid, - int *force_freq, int persistent_group) + int *force_freq, int persistent_group, + const struct p2p_channels *channels) { struct wpa_supplicant *wpa_s = ctx; struct wpa_ssid *s; @@ -2528,6 +2538,25 @@ accept_inv: wpas_p2p_set_own_freq_preference(wpa_s, res); } + if (*force_freq > 0 && + (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) { + if (*go == 0) { + /* We are the client */ + wpa_printf(MSG_DEBUG, "P2P: Peer was found to be " + "running a GO but we are capable of MCC, " + "figure out the best channel to use"); + *force_freq = 0; + } else if (!freq_included(channels, *force_freq)) { + /* We are the GO, and *force_freq is not in the + * intersection */ + wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not " + "in intersection but we are capable of MCC, " + "figure out the best channel to use", + *force_freq); + *force_freq = 0; + } + } + return P2P_SC_SUCCESS; } @@ -4102,14 +4131,6 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname) } -static int freq_included(const struct p2p_channels *channels, unsigned int freq) -{ - if (channels == NULL) - return 1; /* Assume no restrictions */ - return p2p_channels_includes_freq(channels, freq); -} - - static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, struct p2p_go_neg_results *params, int freq, int ht40, diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index 7de96c54..4f8d895a 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -1,6 +1,6 @@ /* * wpa_supplicant - WNM - * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. + * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -10,6 +10,7 @@ #include "utils/common.h" #include "common/ieee802_11_defs.h" +#include "common/wpa_ctrl.h" #include "rsn_supp/wpa.h" #include "wpa_supplicant_i.h" #include "driver_i.h" @@ -491,9 +492,10 @@ static int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, } -static void wnm_send_bss_transition_mgmt_resp(struct wpa_supplicant *wpa_s, - u8 dialog_token, u8 status, - u8 delay, const u8 *target_bssid) +static void wnm_send_bss_transition_mgmt_resp( + struct wpa_supplicant *wpa_s, u8 dialog_token, + enum bss_trans_mgmt_status_code status, u8 delay, + const u8 *target_bssid) { u8 buf[1000], *pos; struct ieee80211_mgmt *mgmt; @@ -559,7 +561,7 @@ void wnm_scan_response(struct wpa_supplicant *wpa_s, if (wpa_s->wnm_reply) { wnm_send_bss_transition_mgmt_resp(wpa_s, wpa_s->wnm_dialog_token, - 0, /* Accept */ + WNM_BSS_TM_ACCEPT, 0, NULL); } @@ -575,7 +577,7 @@ send_bss_resp_fail: if (wpa_s->wnm_reply) { wnm_send_bss_transition_mgmt_resp(wpa_s, wpa_s->wnm_dialog_token, - 1 /* Reject - unspecified */, + WNM_BSS_TM_REJECT_UNSPECIFIED, 0, NULL); } return; @@ -603,7 +605,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, pos += 5; - if (wpa_s->wnm_mode & 0x08) { + if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { if (pos + 12 > end) { wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); return; @@ -612,8 +614,10 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, pos += 12; /* BSS Termination Duration */ } - if (wpa_s->wnm_mode & 0x10) { + if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { char url[256]; + unsigned int beacon_int; + if (pos + 1 > end || pos + 1 + pos[0] > end) { wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " "Management Request (URL)"); @@ -622,11 +626,18 @@ 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 (wpa_s->current_bss) + beacon_int = wpa_s->current_bss->beacon_int; + else + beacon_int = 100; /* best guess */ + + wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", + wpa_sm_pmf_enabled(wpa_s->wpa), + wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); } - if (wpa_s->wnm_mode & 0x04) { + if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { @@ -637,7 +648,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, } } - if (wpa_s->wnm_mode & 0x01) { + if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { 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); @@ -671,12 +682,16 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, 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"); + enum bss_trans_mgmt_status_code status; + if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) + status = WNM_BSS_TM_ACCEPT; + else { + wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); + status = WNM_BSS_TM_REJECT_UNSPECIFIED; + } wnm_send_bss_transition_mgmt_resp(wpa_s, wpa_s->wnm_dialog_token, - 1 /* Reject - unspecified */, - 0, NULL); + status, 0, NULL); } } diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 966ee834..20cd45e3 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - command line interface for wpa_supplicant daemon - * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -81,6 +81,7 @@ static const char *pid_file = NULL; static const char *action_file = NULL; static int ping_interval = 5; static int interactive = 0; +static char *ifname_prefix = NULL; #if defined(CONFIG_P2P) && defined(ANDROID_P2P) static char* redirect_interface = NULL; #endif @@ -93,6 +94,7 @@ struct cli_txt_entry { static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */ static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */ static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */ +static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */ static void print_help(const char *cmd); @@ -1650,6 +1652,12 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd, printf("Not connected to hostapd - command dropped.\n"); return -1; } + if (ifname_prefix) { + os_snprintf(buf, sizeof(buf), "IFNAME=%s %s", + ifname_prefix, cmd); + buf[sizeof(buf) - 1] = '\0'; + cmd = buf; + } len = sizeof(buf) - 1; ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, wpa_cli_msg_cb); @@ -2874,9 +2882,12 @@ static char ** wpa_list_cmd_list(void) { char **res; int i, count; + struct cli_txt_entry *e; count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]); - res = os_calloc(count, sizeof(char *)); + count += dl_list_len(&p2p_groups); + count += dl_list_len(&ifnames); + res = os_calloc(count + 1, sizeof(char *)); if (res == NULL) return NULL; @@ -2886,6 +2897,22 @@ static char ** wpa_list_cmd_list(void) break; } + dl_list_for_each(e, &p2p_groups, struct cli_txt_entry, list) { + size_t len = 8 + os_strlen(e->txt); + res[i] = os_malloc(len); + if (res[i] == NULL) + break; + os_snprintf(res[i], len, "ifname=%s", e->txt); + i++; + } + + dl_list_for_each(e, &ifnames, struct cli_txt_entry, list) { + res[i] = os_strdup(e->txt); + if (res[i] == NULL) + break; + i++; + } + return res; } @@ -2917,6 +2944,14 @@ static char ** wpa_cli_edit_completion_cb(void *ctx, const char *str, int pos) const char *end; char *cmd; + if (pos > 7 && os_strncasecmp(str, "IFNAME=", 7) == 0) { + end = os_strchr(str, ' '); + if (end && pos > end - str) { + pos -= end - str + 1; + str = end + 1; + } + } + end = os_strchr(str, ' '); if (end == NULL || str + pos < end) return wpa_list_cmd_list(); @@ -2938,6 +2973,16 @@ static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) int count; int ret = 0; + if (argc > 1 && os_strncasecmp(argv[0], "IFNAME=", 7) == 0) { + ifname_prefix = argv[0] + 7; + argv = &argv[1]; + argc--; + } else + ifname_prefix = NULL; + + if (argc == 0) + return -1; + count = 0; cmd = wpa_cli_commands; while (cmd->cmd) { @@ -3092,6 +3137,8 @@ static void wpa_cli_action_process(const char *msg) wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_match(pos, AP_STA_DISCONNECTED)) { wpa_cli_exec(action_file, ctrl_ifname, pos); + } else if (str_match(pos, ESS_DISASSOC_IMMINENT)) { + wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_match(pos, WPA_EVENT_TERMINATING)) { printf("wpa_supplicant is terminating - stop monitoring\n"); wpa_cli_quit = 1; @@ -3384,6 +3431,38 @@ static void update_bssid_list(struct wpa_ctrl *ctrl) } +static void update_ifnames(struct wpa_ctrl *ctrl) +{ + char buf[4096]; + size_t len = sizeof(buf); + int ret; + char *cmd = "INTERFACES"; + char *pos, *end; + char txt[200]; + + cli_txt_list_flush(&ifnames); + + if (ctrl == NULL) + return; + ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL); + if (ret < 0) + return; + buf[len] = '\0'; + + pos = buf; + while (pos) { + end = os_strchr(pos, '\n'); + if (end == NULL) + break; + *end = '\0'; + ret = os_snprintf(txt, sizeof(txt), "ifname=%s", pos); + if (ret > 0 && ret < (int) sizeof(txt)) + cli_txt_list_add(&ifnames, txt); + pos = end + 1; + } +} + + static void try_connection(void *eloop_ctx, void *timeout_ctx) { if (ctrl_conn) @@ -3423,6 +3502,7 @@ static void wpa_cli_interactive(void) cli_txt_list_flush(&p2p_peers); cli_txt_list_flush(&p2p_groups); cli_txt_list_flush(&bsses); + cli_txt_list_flush(&ifnames); if (edit_started) edit_deinit(hfile, wpa_cli_edit_filter_history_cb); os_free(hfile); @@ -3625,6 +3705,7 @@ int main(int argc, char *argv[]) } if (interactive) { + update_ifnames(ctrl_conn); mon_conn = wpa_ctrl_open(global); if (mon_conn) { if (wpa_ctrl_attach(mon_conn) == 0) { diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 58605ded..27791b30 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1824,7 +1824,8 @@ void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s, wpa_supplicant_cancel_sched_scan(wpa_s); } - wpa_supplicant_req_scan(wpa_s, 0, 0); + if (wpa_supplicant_fast_associate(wpa_s) != 1) + wpa_supplicant_req_scan(wpa_s, 0, 0); } } |
