OSDN Git Service

Accumulative patch from commit 376204934db44d45f798bdde4db005bc88d666f0
authorDmitry Shmidt <dimitrysh@google.com>
Thu, 23 May 2013 18:03:10 +0000 (11:03 -0700)
committerDmitry Shmidt <dimitrysh@google.com>
Thu, 23 May 2013 18:03:10 +0000 (11:03 -0700)
3762049 wpa_cli: Support tab completion with ifname= prefix
13b11ba wpa_cli: Allow IFNAME= prefix to be used
ae8535b WNM: Make ESS Disassoc Imminent event more convenient to use
6df634f WNM: Do not reject ESS Disassoc Imminent
7b53acd WNM: Use defines for BSS Trans Mgmt field values
8e1bc70 WNM: Fix ess_disassoc timeout to be specified in TBTTs
901d1fe WNM: Remove PMKSA cache entry on ESS disassoc imminent notification
dad153d Try to use fast-associate on ENABLE_NETWORK
b068001 Fix already-associated detection with driver-based BSS selection
72728c6 P2P: Relax channel forcing for invitation processing with MCC support
4033935 Fix OKC-based PMKSA cache entry clearing
1045ec3 nl80211: Add couple of additional iftypes to debug prints
2cadc8e TDLS: Retry TDLS Setup Response more quickly

Change-Id: Ib02db74ca336a4d2da66c21d361c5529ee85f864
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
20 files changed:
hostapd/ctrl_iface.c
src/ap/pmksa_cache_auth.c
src/ap/pmksa_cache_auth.h
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/common/ieee802_11_defs.h
src/common/wpa_ctrl.h
src/drivers/driver_nl80211.c
src/p2p/p2p.h
src/p2p/p2p_invitation.c
src/rsn_supp/pmksa_cache.c
src/rsn_supp/pmksa_cache.h
src/rsn_supp/tdls.c
src/rsn_supp/wpa.c
src/rsn_supp/wpa.h
wpa_supplicant/events.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/wnm_sta.c
wpa_supplicant/wpa_cli.c
wpa_supplicant/wpa_supplicant.c

index 7fc520c..dc9ede7 100644 (file)
@@ -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);
        }
 
index d27fd30..40972e9 100644 (file)
@@ -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;
 
index d473f3f..aa90024 100644 (file)
@@ -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 */
index 18ae86c..83cc857 100644 (file)
@@ -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)
 {
index 9126b90..ebfe86f 100644 (file)
@@ -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);
index 0848590..137c309 100644 (file)
@@ -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
index aab228b..0c05a41 100644 (file)
@@ -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 "
 
index c8f7478..3d16330 100644 (file)
@@ -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:
index 499b62e..c392d57 100644 (file)
@@ -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
index 214eae0..e3e760d 100644 (file)
@@ -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;
index df67583..93056ea 100644 (file)
@@ -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)
index 6f3dfb3..d5aa229 100644 (file)
@@ -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 */
 
index 81e2a5c..221d5fd 100644 (file)
@@ -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);
index e50404c..d83700a 100644 (file)
@@ -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 */
 }
 
index 78dfb52..c757dcf 100644 (file)
@@ -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);
 
index 6d9b587..60e71b6 100644 (file)
@@ -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;
index 7c19d0c..c36f61c 100644 (file)
@@ -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,
index 7de96c5..4f8d895 100644 (file)
@@ -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);
        }
 }
 
index 966ee83..20cd45e 100644 (file)
@@ -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) {
index 58605de..27791b3 100644 (file)
@@ -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);
        }
 }