Merge branch 'moonshot' of ssh://moonshot.suchdamage.org:822/srv/git/libeap into...
[libeap.git] / wpa_supplicant / mlme.c
index b916122..eb60ac5 100644 (file)
 #include "eloop.h"
 #include "config_ssid.h"
 #include "wpa_supplicant_i.h"
-#include "wpa.h"
-#include "drivers/driver.h"
-#include "ieee802_11_defs.h"
+#include "notify.h"
+#include "driver_i.h"
+#include "rsn_supp/wpa.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
 #include "mlme.h"
 
 
@@ -93,177 +95,17 @@ static int ieee80211_sta_find_ibss(struct wpa_supplicant *wpa_s);
 static int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s);
 static void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx);
 static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx);
-
-
-/* Parsed Information Elements */
-struct ieee802_11_elems {
-       u8 *ssid;
-       u8 ssid_len;
-       u8 *supp_rates;
-       u8 supp_rates_len;
-       u8 *fh_params;
-       u8 fh_params_len;
-       u8 *ds_params;
-       u8 ds_params_len;
-       u8 *cf_params;
-       u8 cf_params_len;
-       u8 *tim;
-       u8 tim_len;
-       u8 *ibss_params;
-       u8 ibss_params_len;
-       u8 *challenge;
-       u8 challenge_len;
-       u8 *wpa;
-       u8 wpa_len;
-       u8 *rsn;
-       u8 rsn_len;
-       u8 *erp_info;
-       u8 erp_info_len;
-       u8 *ext_supp_rates;
-       u8 ext_supp_rates_len;
-       u8 *wmm_info;
-       u8 wmm_info_len;
-       u8 *wmm_param;
-       u8 wmm_param_len;
-       u8 *mdie;
-       u8 mdie_len;
-       u8 *ftie;
-       u8 ftie_len;
-       u8 *assoc_comeback;
-       u8 assoc_comeback_len;
-};
-
-typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
-
-
-static ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
-                                      struct ieee802_11_elems *elems)
-{
-       size_t left = len;
-       u8 *pos = start;
-       int unknown = 0;
-
-       os_memset(elems, 0, sizeof(*elems));
-
-       while (left >= 2) {
-               u8 id, elen;
-
-               id = *pos++;
-               elen = *pos++;
-               left -= 2;
-
-               if (elen > left) {
-#if 0
-                       wpa_printf(MSG_MSGDUMP, "MLME: IEEE 802.11 element "
-                                  "parse failed (id=%d elen=%d left=%d)",
-                                  id, elen, left);
-#endif
-                       return ParseFailed;
-               }
-
-               switch (id) {
-               case WLAN_EID_SSID:
-                       elems->ssid = pos;
-                       elems->ssid_len = elen;
-                       break;
-               case WLAN_EID_SUPP_RATES:
-                       elems->supp_rates = pos;
-                       elems->supp_rates_len = elen;
-                       break;
-               case WLAN_EID_FH_PARAMS:
-                       elems->fh_params = pos;
-                       elems->fh_params_len = elen;
-                       break;
-               case WLAN_EID_DS_PARAMS:
-                       elems->ds_params = pos;
-                       elems->ds_params_len = elen;
-                       break;
-               case WLAN_EID_CF_PARAMS:
-                       elems->cf_params = pos;
-                       elems->cf_params_len = elen;
-                       break;
-               case WLAN_EID_TIM:
-                       elems->tim = pos;
-                       elems->tim_len = elen;
-                       break;
-               case WLAN_EID_IBSS_PARAMS:
-                       elems->ibss_params = pos;
-                       elems->ibss_params_len = elen;
-                       break;
-               case WLAN_EID_CHALLENGE:
-                       elems->challenge = pos;
-                       elems->challenge_len = elen;
-                       break;
-               case WLAN_EID_VENDOR_SPECIFIC:
-                       if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
-                           pos[2] == 0xf2) {
-                               /* Microsoft OUI (00:50:F2) */
-                               if (pos[3] == 1) {
-                                       /* OUI Type 1 - WPA IE */
-                                       elems->wpa = pos;
-                                       elems->wpa_len = elen;
-                               } else if (elen >= 5 && pos[3] == 2) {
-                                       if (pos[4] == 0) {
-                                               elems->wmm_info = pos;
-                                               elems->wmm_info_len = elen;
-                                       } else if (pos[4] == 1) {
-                                               elems->wmm_param = pos;
-                                               elems->wmm_param_len = elen;
-                                       }
-                               }
-                       }
-                       break;
-               case WLAN_EID_RSN:
-                       elems->rsn = pos;
-                       elems->rsn_len = elen;
-                       break;
-               case WLAN_EID_ERP_INFO:
-                       elems->erp_info = pos;
-                       elems->erp_info_len = elen;
-                       break;
-               case WLAN_EID_EXT_SUPP_RATES:
-                       elems->ext_supp_rates = pos;
-                       elems->ext_supp_rates_len = elen;
-                       break;
-               case WLAN_EID_MOBILITY_DOMAIN:
-                       elems->mdie = pos;
-                       elems->mdie_len = elen;
-                       break;
-               case WLAN_EID_FAST_BSS_TRANSITION:
-                       elems->ftie = pos;
-                       elems->ftie_len = elen;
-                       break;
-               case WLAN_EID_ASSOC_COMEBACK_TIME:
-                       elems->assoc_comeback = pos;
-                       elems->assoc_comeback_len = elen;
-                       break;
-               default:
-#if 0
-                       wpa_printf(MSG_MSGDUMP "MLME: IEEE 802.11 element "
-                                  "parse ignored unknown element (id=%d "
-                                  "elen=%d)", id, elen);
-#endif
-                       unknown++;
-                       break;
-               }
-
-               left -= elen;
-               pos += elen;
-       }
-
-       if (left)
-               return ParseFailed;
-
-       return unknown ? ParseUnknown : ParseOK;
-}
+static void ieee80211_build_tspec(struct wpabuf *buf);
+static int ieee80211_sta_set_probe_req_ie(struct wpa_supplicant *wpa_s,
+                                         const u8 *ies, size_t ies_len);
 
 
 static int ieee80211_sta_set_channel(struct wpa_supplicant *wpa_s,
-                                    wpa_hw_mode phymode, int chan,
+                                    enum hostapd_hw_mode phymode, int chan,
                                     int freq)
 {
        size_t i;
-       struct wpa_hw_modes *mode;
+       struct hostapd_hw_modes *mode;
 
        for (i = 0; i < wpa_s->mlme.num_modes; i++) {
                mode = &wpa_s->mlme.modes[i];
@@ -278,8 +120,6 @@ static int ieee80211_sta_set_channel(struct wpa_supplicant *wpa_s,
 }
 
 
-
-#if 0 /* FIX */
 static int ecw2cw(int ecw)
 {
        int cw = 1;
@@ -289,15 +129,15 @@ static int ecw2cw(int ecw)
        }
        return cw - 1;
 }
-#endif
 
 
 static void ieee80211_sta_wmm_params(struct wpa_supplicant *wpa_s,
-                                    u8 *wmm_param, size_t wmm_param_len)
+                                    const u8 *wmm_param, size_t wmm_param_len)
 {
        size_t left;
        int count;
-       u8 *pos;
+       const u8 *pos;
+       u8 wmm_acm;
 
        if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
                return;
@@ -309,54 +149,42 @@ static void ieee80211_sta_wmm_params(struct wpa_supplicant *wpa_s,
        pos = wmm_param + 8;
        left = wmm_param_len - 8;
 
-#if 0 /* FIX */
        wmm_acm = 0;
        for (; left >= 4; left -= 4, pos += 4) {
                int aci = (pos[0] >> 5) & 0x03;
                int acm = (pos[0] >> 4) & 0x01;
-               int queue;
+               int aifs, cw_max, cw_min, burst_time;
 
                switch (aci) {
-               case 1:
-                       queue = IEEE80211_TX_QUEUE_DATA3;
+               case 1: /* AC_BK */
                        if (acm)
-                               wmm_acm |= BIT(1) | BIT(2);
+                               wmm_acm |= BIT(1) | BIT(2); /* BK/- */
                        break;
-               case 2:
-                       queue = IEEE80211_TX_QUEUE_DATA1;
+               case 2: /* AC_VI */
                        if (acm)
-                               wmm_acm |= BIT(4) | BIT(5);
+                               wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
                        break;
-               case 3:
-                       queue = IEEE80211_TX_QUEUE_DATA0;
+               case 3: /* AC_VO */
                        if (acm)
-                               wmm_acm |= BIT(6) | BIT(7);
+                               wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
                        break;
-               case 0:
+               case 0: /* AC_BE */
                default:
-                       queue = IEEE80211_TX_QUEUE_DATA2;
                        if (acm)
-                               wpa_s->mlme.wmm_acm |= BIT(0) | BIT(3);
+                               wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
                        break;
                }
 
-               params.aifs = pos[0] & 0x0f;
-               params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
-               params.cw_min = ecw2cw(pos[1] & 0x0f);
+               aifs = pos[0] & 0x0f;
+               cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
+               cw_min = ecw2cw(pos[1] & 0x0f);
                /* TXOP is in units of 32 usec; burst_time in 0.1 ms */
-               params.burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100;
-               wpa_printf(MSG_DEBUG, "MLME: WMM queue=%d aci=%d acm=%d "
-                          "aifs=%d cWmin=%d cWmax=%d burst=%d",
-                          queue, aci, acm, params.aifs, params.cw_min,
-                          params.cw_max, params.burst_time);
-               /* TODO: handle ACM (block TX, fallback to next lowest allowed
-                * AC for now) */
-               if (local->hw->conf_tx(local->mdev, queue, &params)) {
-                       wpa_printf(MSG_DEBUG, "MLME: failed to set TX queue "
-                                  "parameters for queue %d", queue);
-               }
+               burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100;
+               wpa_printf(MSG_DEBUG, "MLME: WMM aci=%d acm=%d aifs=%d "
+                          "cWmin=%d cWmax=%d burst=%d",
+                          aci, acm, aifs, cw_min, cw_max, burst_time);
+               /* TODO: driver configuration */
        }
-#endif
 }
 
 
@@ -376,6 +204,7 @@ static void ieee80211_set_associated(struct wpa_supplicant *wpa_s, int assoc)
                data.assoc_info.req_ies_len = wpa_s->mlme.assocreq_ies_len;
                data.assoc_info.resp_ies = wpa_s->mlme.assocresp_ies;
                data.assoc_info.resp_ies_len = wpa_s->mlme.assocresp_ies_len;
+               data.assoc_info.freq = wpa_s->mlme.freq;
                wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data);
        } else {
                wpa_supplicant_event(wpa_s, EVENT_DISASSOC, NULL);
@@ -392,8 +221,8 @@ static int ieee80211_sta_tx(struct wpa_supplicant *wpa_s, const u8 *buf,
 
 
 static void ieee80211_send_auth(struct wpa_supplicant *wpa_s,
-                               int transaction, u8 *extra, size_t extra_len,
-                               int encrypt)
+                               int transaction, const u8 *extra,
+                               size_t extra_len, int encrypt)
 {
        u8 *buf;
        size_t len;
@@ -514,7 +343,7 @@ static void ieee80211_send_assoc(struct wpa_supplicant *wpa_s)
        blen = 0;
 
        capab = wpa_s->mlme.capab;
-       if (wpa_s->mlme.phymode == WPA_MODE_IEEE80211G) {
+       if (wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211G) {
                capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
                        WLAN_CAPABILITY_SHORT_PREAMBLE;
        }
@@ -565,20 +394,16 @@ static void ieee80211_send_assoc(struct wpa_supplicant *wpa_s)
        blen += len + 2;
        *pos++ = WLAN_EID_SUPP_RATES;
        *pos++ = len;
-       for (i = 0; i < len; i++) {
-               int rate = wpa_s->mlme.curr_rates[i].rate;
-               *pos++ = (u8) (rate / 5);
-       }
+       for (i = 0; i < len; i++)
+               *pos++ = (u8) (wpa_s->mlme.curr_rates[i] / 5);
 
        if (wpa_s->mlme.num_curr_rates > len) {
                pos = buf + blen;
                blen += wpa_s->mlme.num_curr_rates - len + 2;
                *pos++ = WLAN_EID_EXT_SUPP_RATES;
                *pos++ = wpa_s->mlme.num_curr_rates - len;
-               for (i = len; i < wpa_s->mlme.num_curr_rates; i++) {
-                       int rate = wpa_s->mlme.curr_rates[i].rate;
-                       *pos++ = (u8) (rate / 5);
-               }
+               for (i = len; i < wpa_s->mlme.num_curr_rates; i++)
+                       *pos++ = (u8) (wpa_s->mlme.curr_rates[i] / 5);
        }
 
        if (wpa_s->mlme.extra_ie && wpa_s->mlme.auth_alg != WLAN_AUTH_FT) {
@@ -621,9 +446,9 @@ static void ieee80211_send_assoc(struct wpa_supplicant *wpa_s)
                *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
                *pos++ = 0x50;
                *pos++ = 0xf2;
-               *pos++ = 2; /* WME */
-               *pos++ = 0; /* WME info */
-               *pos++ = 1; /* WME ver */
+               *pos++ = 2; /* WMM */
+               *pos++ = 0; /* WMM info */
+               *pos++ = 1; /* WMM ver */
                *pos++ = 0;
        }
 
@@ -845,7 +670,6 @@ static void ieee80211_send_probe_req(struct wpa_supplicant *wpa_s,
        supp_rates[0] = WLAN_EID_SUPP_RATES;
        supp_rates[1] = 0;
        for (i = 0; i < wpa_s->mlme.num_curr_rates; i++) {
-               struct wpa_rate_data *rate = &wpa_s->mlme.curr_rates[i];
                if (esupp_rates) {
                        pos = buf + len;
                        len++;
@@ -861,7 +685,7 @@ static void ieee80211_send_probe_req(struct wpa_supplicant *wpa_s,
                        len++;
                        supp_rates[1]++;
                }
-               *pos++ = rate->rate / 5;
+               *pos++ = wpa_s->mlme.curr_rates[i] / 5;
        }
 
        if (wpa_s->mlme.extra_probe_ie) {
@@ -906,7 +730,7 @@ static void ieee80211_auth_challenge(struct wpa_supplicant *wpa_s,
 
        wpa_printf(MSG_DEBUG, "MLME: replying to auth challenge");
        pos = mgmt->u.auth.variable;
-       if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
+       if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems, 0)
            == ParseFailed) {
                wpa_printf(MSG_DEBUG, "MLME: failed to parse Auth(challenge)");
                return;
@@ -930,7 +754,7 @@ static void ieee80211_rx_mgmt_auth(struct wpa_supplicant *wpa_s,
        u16 auth_alg, auth_transaction, status_code;
        int adhoc;
 
-       adhoc = ssid && ssid->mode == 1;
+       adhoc = ssid && ssid->mode == WPAS_MODE_IBSS;
 
        if (wpa_s->mlme.state != IEEE80211_AUTHENTICATE && !adhoc) {
                wpa_printf(MSG_DEBUG, "MLME: authentication frame received "
@@ -1003,12 +827,11 @@ static void ieee80211_rx_mgmt_auth(struct wpa_supplicant *wpa_s,
                        u8 algs[num_algs];
                        int i, pos;
                        algs[0] = algs[1] = algs[2] = 0xff;
-                       if (wpa_s->mlme.auth_algs & IEEE80211_AUTH_ALG_OPEN)
+                       if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_OPEN)
                                algs[0] = WLAN_AUTH_OPEN;
-                       if (wpa_s->mlme.auth_algs &
-                           IEEE80211_AUTH_ALG_SHARED_KEY)
+                       if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_SHARED)
                                algs[1] = WLAN_AUTH_SHARED_KEY;
-                       if (wpa_s->mlme.auth_algs & IEEE80211_AUTH_ALG_LEAP)
+                       if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_LEAP)
                                algs[2] = WLAN_AUTH_LEAP;
                        if (wpa_s->mlme.auth_alg == WLAN_AUTH_OPEN)
                                pos = 0;
@@ -1052,12 +875,36 @@ static void ieee80211_rx_mgmt_auth(struct wpa_supplicant *wpa_s,
        case WLAN_AUTH_FT:
        {
                union wpa_event_data data;
+               struct wpabuf *ric = NULL;
                os_memset(&data, 0, sizeof(data));
                data.ft_ies.ies = mgmt->u.auth.variable;
                data.ft_ies.ies_len = len -
                        (mgmt->u.auth.variable - (u8 *) mgmt);
                os_memcpy(data.ft_ies.target_ap, wpa_s->bssid, ETH_ALEN);
+               if (os_strcmp(wpa_s->driver->name, "test") == 0 &&
+                   wpa_s->mlme.wmm_enabled) {
+                       ric = wpabuf_alloc(200);
+                       if (ric) {
+                               /* Build simple RIC-Request: RDIE | TSPEC */
+
+                               /* RIC Data (RDIE) */
+                               wpabuf_put_u8(ric, WLAN_EID_RIC_DATA);
+                               wpabuf_put_u8(ric, 4);
+                               wpabuf_put_u8(ric, 0); /* RDIE Identifier */
+                               wpabuf_put_u8(ric, 1); /* Resource Descriptor
+                                                       * Count */
+                               wpabuf_put_le16(ric, 0); /* Status Code */
+
+                               /* WMM TSPEC */
+                               ieee80211_build_tspec(ric);
+
+                               data.ft_ies.ric_ies = wpabuf_head(ric);
+                               data.ft_ies.ric_ies_len = wpabuf_len(ric);
+                       }
+               }
+
                wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data);
+               wpabuf_free(ric);
                ieee80211_auth_completed(wpa_s);
                break;
        }
@@ -1149,42 +996,63 @@ static void ieee80211_rx_mgmt_disassoc(struct wpa_supplicant *wpa_s,
 }
 
 
-static int ieee80211_ft_assoc_resp(struct wpa_supplicant *wpa_s,
-                                  struct ieee802_11_elems *elems)
+static void ieee80211_build_tspec(struct wpabuf *buf)
 {
-#ifdef CONFIG_IEEE80211R
-       const u8 *mobility_domain = NULL;
-       const u8 *r0kh_id = NULL;
-       size_t r0kh_id_len = 0;
-       const u8 *r1kh_id = NULL;
-       struct rsn_ftie *hdr;
-       const u8 *pos, *end;
-
-       if (elems->mdie && elems->mdie_len >= MOBILITY_DOMAIN_ID_LEN)
-               mobility_domain = elems->mdie;
-       if (elems->ftie && elems->ftie_len >= sizeof(struct rsn_ftie)) {
-               end = elems->ftie + elems->ftie_len;
-               hdr = (struct rsn_ftie *) elems->ftie;
-               pos = (const u8 *) (hdr + 1);
-               while (pos + 1 < end) {
-                       if (pos + 2 + pos[1] > end)
-                               break;
-                       if (pos[0] == FTIE_SUBELEM_R1KH_ID &&
-                           pos[1] == FT_R1KH_ID_LEN)
-                               r1kh_id = pos + 2;
-                       else if (pos[0] == FTIE_SUBELEM_R0KH_ID &&
-                                pos[1] >= 1 && pos[1] <= FT_R0KH_ID_MAX_LEN) {
-                               r0kh_id = pos + 2;
-                               r0kh_id_len = pos[1];
-                       }
-                       pos += 2 + pos[1];
-               }
-       }
-       return wpa_sm_set_ft_params(wpa_s->wpa, mobility_domain, r0kh_id,
-                                   r0kh_id_len, r1kh_id);
-#else /* CONFIG_IEEE80211R */
-       return 0;
-#endif /* CONFIG_IEEE80211R */
+       struct wmm_tspec_element *tspec;
+       int tid, up;
+
+       tspec = wpabuf_put(buf, sizeof(*tspec));
+       tspec->eid = WLAN_EID_VENDOR_SPECIFIC;
+       tspec->length = sizeof(*tspec) - 2;
+       tspec->oui[0] = 0x00;
+       tspec->oui[1] = 0x50;
+       tspec->oui[2] = 0xf2;
+       tspec->oui_type = 2;
+       tspec->oui_subtype = 2;
+       tspec->version = 1;
+
+       tid = 1;
+       up = 6; /* Voice */
+       tspec->ts_info[0] = (tid << 1) |
+               (WMM_TSPEC_DIRECTION_BI_DIRECTIONAL << 5) |
+               BIT(7);
+       tspec->ts_info[1] = up << 3;
+       tspec->nominal_msdu_size = host_to_le16(1530);
+       tspec->mean_data_rate = host_to_le32(128000); /* bits per second */
+       tspec->minimum_phy_rate = host_to_le32(6000000);
+       tspec->surplus_bandwidth_allowance = host_to_le16(0x3000); /* 150% */
+}
+
+
+static void ieee80211_tx_addts(struct wpa_supplicant *wpa_s)
+{
+       struct wpabuf *buf;
+       struct ieee80211_mgmt *mgmt;
+       size_t alen;
+
+       wpa_printf(MSG_DEBUG, "MLME: Send ADDTS Request for Voice TSPEC");
+       mgmt = NULL;
+       alen = mgmt->u.action.u.wmm_action.variable - (u8 *) mgmt;
+
+       buf = wpabuf_alloc(alen + sizeof(struct wmm_tspec_element));
+       if (buf == NULL)
+               return;
+
+       mgmt = wpabuf_put(buf, alen);
+       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_WMM;
+       mgmt->u.action.u.wmm_action.action_code = WMM_ACTION_CODE_ADDTS_REQ;
+       mgmt->u.action.u.wmm_action.dialog_token = 1;
+       mgmt->u.action.u.wmm_action.status_code = 0;
+
+       ieee80211_build_tspec(buf);
+
+       ieee80211_sta_tx(wpa_s, wpabuf_head(buf), wpabuf_len(buf));
+       wpabuf_free(buf);
 }
 
 
@@ -1238,7 +1106,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct wpa_supplicant *wpa_s,
                   capab_info, status_code, aid);
 
        pos = mgmt->u.assoc_resp.variable;
-       if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
+       if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems, 0)
            == ParseFailed) {
                wpa_printf(MSG_DEBUG, "MLME: failed to parse AssocResp");
                return;
@@ -1249,9 +1117,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct wpa_supplicant *wpa_s,
                           status_code);
 #ifdef CONFIG_IEEE80211W
                if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
-                   elems.assoc_comeback && elems.assoc_comeback_len == 4) {
+                   elems.timeout_int && elems.timeout_int_len == 5 &&
+                   elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) {
                        u32 tu, ms;
-                       tu = WPA_GET_LE32(elems.assoc_comeback);
+                       tu = WPA_GET_LE32(elems.timeout_int + 1);
                        ms = tu * 1024 / 1000;
                        wpa_printf(MSG_DEBUG, "MLME: AP rejected association "
                                   "temporarily; comeback duration %u TU "
@@ -1286,7 +1155,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct wpa_supplicant *wpa_s,
                                   "Resp failed");
                        return;
                }
-       } else if (ieee80211_ft_assoc_resp(wpa_s, &elems) < 0)
+       } else if (wpa_sm_set_ft_params(wpa_s->wpa, pos,
+                                       len - (pos - (u8 *) mgmt)) < 0)
                return;
 
        wpa_printf(MSG_DEBUG, "MLME: associated");
@@ -1333,17 +1203,17 @@ static void ieee80211_rx_mgmt_assoc_resp(struct wpa_supplicant *wpa_s,
                           "netstack");
        }
 
-#if 0 /* FIX? */
-       sta->assoc_ap = 1;
-
-       if (elems.wmm_param && wpa_s->mlme.wmm_enabled) {
-               sta->flags |= WLAN_STA_WME;
-               ieee80211_sta_wmm_params(wpa_s, elems.wmm_param,
-                                        elems.wmm_param_len);
-       }
-#endif
+       if (elems.wmm && wpa_s->mlme.wmm_enabled)
+               ieee80211_sta_wmm_params(wpa_s, elems.wmm, elems.wmm_len);
 
        ieee80211_associated(wpa_s);
+
+       if (wpa_s->mlme.auth_alg != WLAN_AUTH_FT &&
+           os_strcmp(wpa_s->driver->name, "test") == 0 &&
+           elems.wmm && wpa_s->mlme.wmm_enabled) {
+               /* Test WMM-AC - send ADDTS for WMM TSPEC */
+               ieee80211_tx_addts(wpa_s);
+       }
 }
 
 
@@ -1492,7 +1362,7 @@ static void ieee80211_bss_info(struct wpa_supplicant *wpa_s,
 
        ie_pos = mgmt->u.beacon.variable;
        ie_len = len - baselen;
-       if (ieee802_11_parse_elems(ie_pos, ie_len, &elems) == ParseFailed)
+       if (ieee802_11_parse_elems(ie_pos, ie_len, &elems, 0) == ParseFailed)
                invalid = 1;
 
 #if 0 /* FIX */
@@ -1616,52 +1486,52 @@ static void ieee80211_bss_info(struct wpa_supplicant *wpa_s,
                bss->supp_rates_len += clen;
        }
 
-       if (elems.wpa &&
-           (bss->wpa_ie == NULL || bss->wpa_ie_len != elems.wpa_len ||
-            os_memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) {
+       if (elems.wpa_ie &&
+           (bss->wpa_ie == NULL || bss->wpa_ie_len != elems.wpa_ie_len ||
+            os_memcmp(bss->wpa_ie, elems.wpa_ie, elems.wpa_ie_len))) {
                os_free(bss->wpa_ie);
-               bss->wpa_ie = os_malloc(elems.wpa_len + 2);
+               bss->wpa_ie = os_malloc(elems.wpa_ie_len + 2);
                if (bss->wpa_ie) {
-                       os_memcpy(bss->wpa_ie, elems.wpa - 2,
-                                 elems.wpa_len + 2);
-                       bss->wpa_ie_len = elems.wpa_len + 2;
+                       os_memcpy(bss->wpa_ie, elems.wpa_ie - 2,
+                                 elems.wpa_ie_len + 2);
+                       bss->wpa_ie_len = elems.wpa_ie_len + 2;
                } else
                        bss->wpa_ie_len = 0;
-       } else if (!elems.wpa && bss->wpa_ie) {
+       } else if (!elems.wpa_ie && bss->wpa_ie) {
                os_free(bss->wpa_ie);
                bss->wpa_ie = NULL;
                bss->wpa_ie_len = 0;
        }
 
-       if (elems.rsn &&
-           (bss->rsn_ie == NULL || bss->rsn_ie_len != elems.rsn_len ||
-            os_memcmp(bss->rsn_ie, elems.rsn, elems.rsn_len))) {
+       if (elems.rsn_ie &&
+           (bss->rsn_ie == NULL || bss->rsn_ie_len != elems.rsn_ie_len ||
+            os_memcmp(bss->rsn_ie, elems.rsn_ie, elems.rsn_ie_len))) {
                os_free(bss->rsn_ie);
-               bss->rsn_ie = os_malloc(elems.rsn_len + 2);
+               bss->rsn_ie = os_malloc(elems.rsn_ie_len + 2);
                if (bss->rsn_ie) {
-                       os_memcpy(bss->rsn_ie, elems.rsn - 2,
-                                 elems.rsn_len + 2);
-                       bss->rsn_ie_len = elems.rsn_len + 2;
+                       os_memcpy(bss->rsn_ie, elems.rsn_ie - 2,
+                                 elems.rsn_ie_len + 2);
+                       bss->rsn_ie_len = elems.rsn_ie_len + 2;
                } else
                        bss->rsn_ie_len = 0;
-       } else if (!elems.rsn && bss->rsn_ie) {
+       } else if (!elems.rsn_ie && bss->rsn_ie) {
                os_free(bss->rsn_ie);
                bss->rsn_ie = NULL;
                bss->rsn_ie_len = 0;
        }
 
-       if (elems.wmm_param &&
-           (bss->wmm_ie == NULL || bss->wmm_ie_len != elems.wmm_param_len ||
-            os_memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) {
+       if (elems.wmm &&
+           (bss->wmm_ie == NULL || bss->wmm_ie_len != elems.wmm_len ||
+            os_memcmp(bss->wmm_ie, elems.wmm, elems.wmm_len))) {
                os_free(bss->wmm_ie);
-               bss->wmm_ie = os_malloc(elems.wmm_param_len + 2);
+               bss->wmm_ie = os_malloc(elems.wmm_len + 2);
                if (bss->wmm_ie) {
-                       os_memcpy(bss->wmm_ie, elems.wmm_param - 2,
-                                 elems.wmm_param_len + 2);
-                       bss->wmm_ie_len = elems.wmm_param_len + 2;
+                       os_memcpy(bss->wmm_ie, elems.wmm - 2,
+                                 elems.wmm_len + 2);
+                       bss->wmm_ie_len = elems.wmm_len + 2;
                } else
                        bss->wmm_ie_len = 0;
-       } else if (!elems.wmm_param && bss->wmm_ie) {
+       } else if (!elems.wmm && bss->wmm_ie) {
                os_free(bss->wmm_ie);
                bss->wmm_ie = NULL;
                bss->wmm_ie_len = 0;
@@ -1690,8 +1560,8 @@ static void ieee80211_bss_info(struct wpa_supplicant *wpa_s,
        bss->channel = channel;
        bss->freq = wpa_s->mlme.freq;
        if (channel != wpa_s->mlme.channel &&
-           (wpa_s->mlme.phymode == WPA_MODE_IEEE80211G ||
-            wpa_s->mlme.phymode == WPA_MODE_IEEE80211B) &&
+           (wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211G ||
+            wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211B) &&
            channel >= 1 && channel <= 14) {
                static const int freq_list[] = {
                        2412, 2417, 2422, 2427, 2432, 2437, 2442,
@@ -1739,7 +1609,7 @@ static void ieee80211_rx_mgmt_beacon(struct wpa_supplicant *wpa_s,
                return;
 
        if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
-                                  &elems) == ParseFailed)
+                                  &elems, 0) == ParseFailed)
                return;
 
        use_protection = 0;
@@ -1757,9 +1627,9 @@ static void ieee80211_rx_mgmt_beacon(struct wpa_supplicant *wpa_s,
                wpa_s->mlme.cts_protect_erp_frames = use_protection;
        }
 
-       if (elems.wmm_param && wpa_s->mlme.wmm_enabled) {
-               ieee80211_sta_wmm_params(wpa_s, elems.wmm_param,
-                                        elems.wmm_param_len);
+       if (elems.wmm && wpa_s->mlme.wmm_enabled) {
+               ieee80211_sta_wmm_params(wpa_s, elems.wmm,
+                                        elems.wmm_len);
        }
 }
 
@@ -1776,7 +1646,7 @@ static void ieee80211_rx_mgmt_probe_req(struct wpa_supplicant *wpa_s,
        u8 *pos, *end;
        struct wpa_ssid *ssid = wpa_s->current_ssid;
 
-       adhoc = ssid && ssid->mode == 1;
+       adhoc = ssid && ssid->mode == WPAS_MODE_IBSS;
 
        if (!adhoc || wpa_s->mlme.state != IEEE80211_IBSS_JOINED ||
            len < 24 + 2 || wpa_s->mlme.probe_resp == NULL)
@@ -1871,7 +1741,6 @@ static void ieee80211_rx_mgmt_ft_action(struct wpa_supplicant *wpa_s,
                wpa_printf(MSG_DEBUG, "MLME: Foreign STA Address " MACSTR
                           " in FT Action Response", MAC2STR(sta_addr));
                return;
-                          
        }
 
        if (status) {
@@ -1901,9 +1770,9 @@ static void ieee80211_rx_mgmt_ft_action(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_IEEE80211W
 
-/* MLME-PING.response */
-static int ieee80211_sta_send_ping_resp(struct wpa_supplicant *wpa_s,
-                                       const u8 *addr, const u8 *trans_id)
+/* MLME-SAQuery.response */
+static int ieee80211_sta_send_sa_query_resp(struct wpa_supplicant *wpa_s,
+                                           const u8 *addr, const u8 *trans_id)
 {
        struct ieee80211_mgmt *mgmt;
        int res;
@@ -1912,7 +1781,7 @@ static int ieee80211_sta_send_ping_resp(struct wpa_supplicant *wpa_s,
        mgmt = os_zalloc(sizeof(*mgmt));
        if (mgmt == NULL) {
                wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
-                          "ping action frame");
+                          "SA Query action frame");
                return -1;
        }
 
@@ -1922,11 +1791,11 @@ static int ieee80211_sta_send_ping_resp(struct wpa_supplicant *wpa_s,
        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_PING;
-       mgmt->u.action.u.ping_resp.action = WLAN_PING_RESPONSE;
-       os_memcpy(mgmt->u.action.u.ping_resp.trans_id, trans_id,
-                 WLAN_PING_TRANS_ID_LEN);
-       len += 1 + sizeof(mgmt->u.action.u.ping_resp);
+       mgmt->u.action.category = WLAN_ACTION_SA_QUERY;
+       mgmt->u.action.u.sa_query_resp.action = WLAN_SA_QUERY_RESPONSE;
+       os_memcpy(mgmt->u.action.u.sa_query_resp.trans_id, trans_id,
+                 WLAN_SA_QUERY_TR_ID_LEN);
+       len += 1 + sizeof(mgmt->u.action.u.sa_query_resp);
 
        res = ieee80211_sta_tx(wpa_s, (u8 *) mgmt, len);
        os_free(mgmt);
@@ -1935,41 +1804,154 @@ static int ieee80211_sta_send_ping_resp(struct wpa_supplicant *wpa_s,
 }
 
 
-static void ieee80211_rx_mgmt_ping_action(
+static void ieee80211_rx_mgmt_sa_query_action(
        struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
        struct ieee80211_rx_status *rx_status)
 {
-       if (len < 24 + 1 + sizeof(mgmt->u.action.u.ping_req)) {
-               wpa_printf(MSG_DEBUG, "MLME: Too short Ping Action frame");
+       if (len < 24 + 1 + sizeof(mgmt->u.action.u.sa_query_req)) {
+               wpa_printf(MSG_DEBUG, "MLME: Too short SA Query Action frame");
                return;
        }
 
-       if (mgmt->u.action.u.ping_req.action != WLAN_PING_REQUEST) {
-               wpa_printf(MSG_DEBUG, "MLME: Unexpected Ping Action %d",
-                          mgmt->u.action.u.ping_req.action);
+       if (mgmt->u.action.u.sa_query_req.action != WLAN_SA_QUERY_REQUEST) {
+               wpa_printf(MSG_DEBUG, "MLME: Unexpected SA Query Action %d",
+                          mgmt->u.action.u.sa_query_req.action);
                return;
        }
 
        if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) {
-               wpa_printf(MSG_DEBUG, "MLME: Ignore ping from unknown source "
-                          MACSTR, MAC2STR(mgmt->sa));
+               wpa_printf(MSG_DEBUG, "MLME: Ignore SA Query from unknown "
+                          "source " MACSTR, MAC2STR(mgmt->sa));
                return;
        }
 
        if (wpa_s->mlme.state == IEEE80211_ASSOCIATE) {
-               wpa_printf(MSG_DEBUG, "MLME: Ignore ping request during "
+               wpa_printf(MSG_DEBUG, "MLME: Ignore SA query request during "
                           "association process");
                return;
        }
 
-       wpa_printf(MSG_DEBUG, "MLME: Replying to ping request");
-       ieee80211_sta_send_ping_resp(wpa_s, mgmt->sa,
-                                    mgmt->u.action.u.ping_req.trans_id);
+       wpa_printf(MSG_DEBUG, "MLME: Replying to SA Query request");
+       ieee80211_sta_send_sa_query_resp(wpa_s, mgmt->sa, mgmt->u.action.u.
+                                        sa_query_req.trans_id);
 }
 
 #endif /* CONFIG_IEEE80211W */
 
 
+static void dump_tspec(struct wmm_tspec_element *tspec)
+{
+       int up, psb, dir, tid;
+       u16 val;
+
+       up = (tspec->ts_info[1] >> 3) & 0x07;
+       psb = (tspec->ts_info[1] >> 2) & 0x01;
+       dir = (tspec->ts_info[0] >> 5) & 0x03;
+       tid = (tspec->ts_info[0] >> 1) & 0x0f;
+       wpa_printf(MSG_DEBUG, "WMM: TS Info: UP=%d PSB=%d Direction=%d TID=%d",
+                  up, psb, dir, tid);
+       val = le_to_host16(tspec->nominal_msdu_size);
+       wpa_printf(MSG_DEBUG, "WMM: Nominal MSDU Size: %d%s",
+                  val & 0x7fff, val & 0x8000 ? " (fixed)" : "");
+       wpa_printf(MSG_DEBUG, "WMM: Mean Data Rate: %u bps",
+                  le_to_host32(tspec->mean_data_rate));
+       wpa_printf(MSG_DEBUG, "WMM: Minimum PHY Rate: %u bps",
+                  le_to_host32(tspec->minimum_phy_rate));
+       val = le_to_host16(tspec->surplus_bandwidth_allowance);
+       wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance: %u.%04u",
+                  val >> 13, 10000 * (val & 0x1fff) / 0x2000);
+       val = le_to_host16(tspec->medium_time);
+       wpa_printf(MSG_DEBUG, "WMM: Medium Time: %u (= %u usec/sec)",
+                  val, 32 * val);
+}
+
+
+static int is_wmm_tspec(const u8 *ie, size_t len)
+{
+       const struct wmm_tspec_element *tspec;
+
+       if (len < sizeof(*tspec))
+               return 0;
+
+       tspec = (const struct wmm_tspec_element *) ie;
+       if (tspec->eid != WLAN_EID_VENDOR_SPECIFIC ||
+           tspec->length < sizeof(*tspec) - 2 ||
+           tspec->oui[0] != 0x00 || tspec->oui[1] != 0x50 ||
+           tspec->oui[2] != 0xf2 || tspec->oui_type != 2 ||
+           tspec->oui_subtype != 2 || tspec->version != 1)
+               return 0;
+
+       return 1;
+}
+
+
+static void ieee80211_rx_addts_resp(
+       struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
+       size_t var_len)
+{
+       struct wmm_tspec_element *tspec;
+
+       wpa_printf(MSG_DEBUG, "WMM: Received ADDTS Response");
+       wpa_hexdump(MSG_MSGDUMP, "WMM: ADDTS Response IE(s)",
+                   mgmt->u.action.u.wmm_action.variable, var_len);
+       if (!is_wmm_tspec(mgmt->u.action.u.wmm_action.variable, var_len))
+               return;
+       tspec = (struct wmm_tspec_element *)
+               mgmt->u.action.u.wmm_action.variable;
+       dump_tspec(tspec);
+}
+
+
+static void ieee80211_rx_delts(
+       struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
+       size_t var_len)
+{
+       struct wmm_tspec_element *tspec;
+
+       wpa_printf(MSG_DEBUG, "WMM: Received DELTS");
+       wpa_hexdump(MSG_MSGDUMP, "WMM: DELTS IE(s)",
+                   mgmt->u.action.u.wmm_action.variable, var_len);
+       if (!is_wmm_tspec(mgmt->u.action.u.wmm_action.variable, var_len))
+               return;
+       tspec = (struct wmm_tspec_element *)
+               mgmt->u.action.u.wmm_action.variable;
+       dump_tspec(tspec);
+}
+
+
+static void ieee80211_rx_mgmt_wmm_action(
+       struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
+       struct ieee80211_rx_status *rx_status)
+{
+       size_t alen;
+
+       alen = mgmt->u.action.u.wmm_action.variable - (u8 *) mgmt;
+       if (len < alen) {
+               wpa_printf(MSG_DEBUG, "WMM: Received Action frame too short");
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "WMM: Received Action frame: Action Code %d, "
+                  "Dialog Token %d, Status Code %d",
+                  mgmt->u.action.u.wmm_action.action_code,
+                  mgmt->u.action.u.wmm_action.dialog_token,
+                  mgmt->u.action.u.wmm_action.status_code);
+
+       switch (mgmt->u.action.u.wmm_action.action_code) {
+       case WMM_ACTION_CODE_ADDTS_RESP:
+               ieee80211_rx_addts_resp(wpa_s, mgmt, len, len - alen);
+               break;
+       case WMM_ACTION_CODE_DELTS:
+               ieee80211_rx_delts(wpa_s, mgmt, len, len - alen);
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "WMM: Unsupported Action Code %d",
+                          mgmt->u.action.u.wmm_action.action_code);
+               break;
+       }
+}
+
+
 static void ieee80211_rx_mgmt_action(struct wpa_supplicant *wpa_s,
                                     struct ieee80211_mgmt *mgmt,
                                     size_t len,
@@ -1987,10 +1969,21 @@ static void ieee80211_rx_mgmt_action(struct wpa_supplicant *wpa_s,
                break;
 #endif /* CONFIG_IEEE80211R */
 #ifdef CONFIG_IEEE80211W
-       case WLAN_ACTION_PING:
-               ieee80211_rx_mgmt_ping_action(wpa_s, mgmt, len, rx_status);
+       case WLAN_ACTION_SA_QUERY:
+               ieee80211_rx_mgmt_sa_query_action(wpa_s, mgmt, len, rx_status);
                break;
 #endif /* CONFIG_IEEE80211W */
+       case WLAN_ACTION_WMM:
+               ieee80211_rx_mgmt_wmm_action(wpa_s, mgmt, len, rx_status);
+               break;
+       case WLAN_ACTION_PUBLIC:
+               if (wpa_s->mlme.public_action_cb) {
+                       wpa_s->mlme.public_action_cb(
+                               wpa_s->mlme.public_action_cb_ctx,
+                               (u8 *) mgmt, len, rx_status->freq);
+                       return;
+               }
+               break;
        default:
                wpa_printf(MSG_DEBUG, "MLME: unknown Action Category %d",
                           mgmt->u.action.category);
@@ -2110,6 +2103,8 @@ static void ieee80211_sta_expire(struct wpa_supplicant *wpa_s)
 
 static void ieee80211_sta_merge_ibss(struct wpa_supplicant *wpa_s)
 {
+       struct wpa_driver_scan_params params;
+
        ieee80211_reschedule_timer(wpa_s, IEEE80211_IBSS_MERGE_INTERVAL);
 
        ieee80211_sta_expire(wpa_s);
@@ -2118,7 +2113,11 @@ static void ieee80211_sta_merge_ibss(struct wpa_supplicant *wpa_s)
 
        wpa_printf(MSG_DEBUG, "MLME: No active IBSS STAs - trying to scan for "
                   "other IBSS networks with same SSID (merge)");
-       ieee80211_sta_req_scan(wpa_s, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len);
+       os_memset(&params, 0, sizeof(params));
+       params.ssids[0].ssid = wpa_s->mlme.ssid;
+       params.ssids[0].ssid_len = wpa_s->mlme.ssid_len;
+       params.num_ssids = wpa_s->mlme.ssid_len ? 1 : 0;
+       ieee80211_sta_req_scan(wpa_s, &params);
 }
 
 
@@ -2163,7 +2162,7 @@ static void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx)
 static void ieee80211_sta_new_auth(struct wpa_supplicant *wpa_s)
 {
        struct wpa_ssid *ssid = wpa_s->current_ssid;
-       if (ssid && ssid->mode != 0)
+       if (ssid && ssid->mode != WPAS_MODE_INFRA)
                return;
 
 #if 0 /* FIX */
@@ -2176,11 +2175,11 @@ static void ieee80211_sta_new_auth(struct wpa_supplicant *wpa_s)
        wpa_s->mlme.wmm_last_param_set = -1; /* allow any WMM update */
 
 
-       if (wpa_s->mlme.auth_algs & IEEE80211_AUTH_ALG_OPEN)
+       if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_OPEN)
                wpa_s->mlme.auth_alg = WLAN_AUTH_OPEN;
-       else if (wpa_s->mlme.auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)
+       else if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_SHARED)
                wpa_s->mlme.auth_alg = WLAN_AUTH_SHARED_KEY;
-       else if (wpa_s->mlme.auth_algs & IEEE80211_AUTH_ALG_LEAP)
+       else if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_LEAP)
                wpa_s->mlme.auth_alg = WLAN_AUTH_LEAP;
        else
                wpa_s->mlme.auth_alg = WLAN_AUTH_OPEN;
@@ -2220,7 +2219,7 @@ static int ieee80211_ibss_allowed(struct wpa_supplicant *wpa_s)
 static int ieee80211_sta_join_ibss(struct wpa_supplicant *wpa_s,
                                   struct ieee80211_sta_bss *bss)
 {
-       int res = 0, rates, done = 0;
+       int res = 0, rates, done = 0, bssid_changed;
        struct ieee80211_mgmt *mgmt;
 #if 0 /* FIX */
        struct ieee80211_tx_control control;
@@ -2239,7 +2238,10 @@ static int ieee80211_sta_join_ibss(struct wpa_supplicant *wpa_s,
                local->hw->reset_tsf(local->mdev);
        }
 #endif
+       bssid_changed = os_memcmp(wpa_s->bssid, bss->bssid, ETH_ALEN);
        os_memcpy(wpa_s->bssid, bss->bssid, ETH_ALEN);
+       if (bssid_changed)
+               wpas_notify_bssid_changed(wpa_s);
 
 #if 0 /* FIX */
        local->conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
@@ -2370,7 +2372,7 @@ static int ieee80211_sta_join_ibss(struct wpa_supplicant *wpa_s,
                        if (local->conf.phymode == MODE_ATHEROS_TURBO)
                                rate *= 2;
                        for (j = 0; j < local->num_curr_rates; j++)
-                               if (local->curr_rates[j].rate == rate)
+                               if (local->curr_rates[j] == rate)
                                        rates |= BIT(j);
                }
                wpa_s->mlme.supp_rates_bits = rates;
@@ -2439,7 +2441,7 @@ static int ieee80211_sta_create_ibss(struct wpa_supplicant *wpa_s)
        pos = bss->supp_rates;
 #if 0 /* FIX */
        for (i = 0; i < local->num_curr_rates; i++) {
-               int rate = local->curr_rates[i].rate;
+               int rate = local->curr_rates[i];
                if (local->conf.phymode == MODE_ATHEROS_TURBO)
                        rate /= 2;
                *pos++ = (u8) (rate / 5);
@@ -2555,11 +2557,17 @@ int ieee80211_sta_associate(struct wpa_supplicant *wpa_s,
                            struct wpa_driver_associate_params *params)
 {
        struct ieee80211_sta_bss *bss;
+       int bssid_changed;
 
        wpa_s->mlme.bssid_set = 0;
        wpa_s->mlme.freq = params->freq;
        if (params->bssid) {
+               bssid_changed = os_memcmp(wpa_s->bssid, params->bssid,
+                                         ETH_ALEN);
                os_memcpy(wpa_s->bssid, params->bssid, ETH_ALEN);
+               if (bssid_changed)
+                       wpas_notify_bssid_changed(wpa_s);
+
                if (!is_zero_ether_addr(params->bssid))
                        wpa_s->mlme.bssid_set = 1;
                bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
@@ -2626,7 +2634,7 @@ int ieee80211_sta_associate(struct wpa_supplicant *wpa_s,
        ieee80211_sta_set_channel(wpa_s, wpa_s->mlme.phymode,
                                  wpa_s->mlme.channel, wpa_s->mlme.freq);
 
-       if (params->mode == 1 && !wpa_s->mlme.bssid_set) {
+       if (params->mode == WPAS_MODE_IBSS && !wpa_s->mlme.bssid_set) {
                os_get_time(&wpa_s->mlme.ibss_join_req);
                wpa_s->mlme.state = IEEE80211_IBSS_SEARCH;
                return ieee80211_sta_find_ibss(wpa_s);
@@ -2666,14 +2674,14 @@ static int ieee80211_active_scan(struct wpa_supplicant *wpa_s)
        int c;
 
        for (m = 0; m < wpa_s->mlme.num_modes; m++) {
-               struct wpa_hw_modes *mode = &wpa_s->mlme.modes[m];
+               struct hostapd_hw_modes *mode = &wpa_s->mlme.modes[m];
                if ((int) mode->mode != (int) wpa_s->mlme.phymode)
                        continue;
                for (c = 0; c < mode->num_channels; c++) {
-                       struct wpa_channel_data *chan = &mode->channels[c];
-                       if (chan->flag & WPA_CHAN_W_SCAN &&
+                       struct hostapd_channel_data *chan = &mode->channels[c];
+                       if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
                            chan->chan == wpa_s->mlme.channel) {
-                               if (chan->flag & WPA_CHAN_W_ACTIVE_SCAN)
+                               if (!(chan->flag & HOSTAPD_CHAN_PASSIVE_SCAN))
                                        return 1;
                                break;
                        }
@@ -2687,8 +2695,8 @@ static int ieee80211_active_scan(struct wpa_supplicant *wpa_s)
 static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_supplicant *wpa_s = eloop_ctx;
-       struct wpa_hw_modes *mode;
-       struct wpa_channel_data *chan;
+       struct hostapd_hw_modes *mode;
+       struct hostapd_channel_data *chan;
        int skip = 0;
        int timeout = 0;
        struct wpa_ssid *ssid = wpa_s->current_ssid;
@@ -2727,12 +2735,23 @@ static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx)
                }
                skip = !(wpa_s->mlme.hw_modes & (1 << mode->mode));
                chan = &mode->channels[wpa_s->mlme.scan_channel_idx];
-               if (!(chan->flag & WPA_CHAN_W_SCAN) ||
-                   (adhoc && !(chan->flag & WPA_CHAN_W_IBSS)) ||
-                   (wpa_s->mlme.hw_modes & (1 << WPA_MODE_IEEE80211G) &&
-                    mode->mode == WPA_MODE_IEEE80211B &&
+               if ((chan->flag & HOSTAPD_CHAN_DISABLED) ||
+                   (adhoc && (chan->flag & HOSTAPD_CHAN_NO_IBSS)) ||
+                   (wpa_s->mlme.hw_modes & (1 << HOSTAPD_MODE_IEEE80211G) &&
+                    mode->mode == HOSTAPD_MODE_IEEE80211B &&
                     wpa_s->mlme.scan_skip_11b))
                        skip = 1;
+               if (!skip && wpa_s->mlme.scan_freqs) {
+                       int i, found = 0;
+                       for (i = 0; wpa_s->mlme.scan_freqs[i]; i++) {
+                               if (wpa_s->mlme.scan_freqs[i] == chan->freq) {
+                                       found = 1;
+                                       break;
+                               }
+                       }
+                       if (!found)
+                               skip = 1;
+               }
 
                if (!skip) {
                        wpa_printf(MSG_MSGDUMP,
@@ -2786,9 +2805,12 @@ static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx)
 }
 
 
-int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s, const u8 *ssid,
-                          size_t ssid_len)
+int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s,
+                          struct wpa_driver_scan_params *params)
 {
+       const u8 *ssid = params->ssids[0].ssid;
+       size_t ssid_len = params->ssids[0].ssid_len;
+
        if (ssid_len > MAX_SSID_LEN)
                return -1;
 
@@ -2817,6 +2839,21 @@ int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s, const u8 *ssid,
 
        wpa_printf(MSG_DEBUG, "MLME: starting scan");
 
+       ieee80211_sta_set_probe_req_ie(wpa_s, params->extra_ies,
+                                      params->extra_ies_len);
+
+       os_free(wpa_s->mlme.scan_freqs);
+       if (params->freqs) {
+               int i;
+               for (i = 0; params->freqs[i]; i++)
+                       ;
+               wpa_s->mlme.scan_freqs = os_malloc((i + 1) * sizeof(int));
+               if (wpa_s->mlme.scan_freqs)
+                       os_memcpy(wpa_s->mlme.scan_freqs, params->freqs,
+                                 (i + 1) * sizeof(int));
+       } else
+               wpa_s->mlme.scan_freqs = NULL;
+
        ieee80211_sta_save_oper_chan(wpa_s);
 
        wpa_s->mlme.sta_scanning = 1;
@@ -2993,7 +3030,7 @@ void ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len,
 }
 
 
-void ieee80211_sta_free_hw_features(struct wpa_hw_modes *hw_features,
+void ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features,
                                    size_t num_hw_features)
 {
        size_t i;
@@ -3024,9 +3061,11 @@ int ieee80211_sta_init(struct wpa_supplicant *wpa_s)
 
        wpa_s->mlme.num_modes = num_modes;
 
-       wpa_s->mlme.hw_modes = 1 << WPA_MODE_IEEE80211A;
-       wpa_s->mlme.hw_modes |= 1 << WPA_MODE_IEEE80211B;
-       wpa_s->mlme.hw_modes |= 1 << WPA_MODE_IEEE80211G;
+       wpa_s->mlme.hw_modes = 1 << HOSTAPD_MODE_IEEE80211A;
+       wpa_s->mlme.hw_modes |= 1 << HOSTAPD_MODE_IEEE80211B;
+       wpa_s->mlme.hw_modes |= 1 << HOSTAPD_MODE_IEEE80211G;
+
+       wpa_s->mlme.wmm_enabled = 1;
 
        return 0;
 }
@@ -3052,6 +3091,9 @@ void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s)
        wpa_s->mlme.ft_ies = NULL;
        wpa_s->mlme.ft_ies_len = 0;
 #endif /* CONFIG_IEEE80211R */
+
+       os_free(wpa_s->mlme.scan_freqs);
+       wpa_s->mlme.scan_freqs = NULL;
 }
 
 
@@ -3135,8 +3177,8 @@ int ieee80211_sta_send_ft_action(struct wpa_supplicant *wpa_s, u8 action,
 #endif /* CONFIG_IEEE80211R */
 
 
-int ieee80211_sta_set_probe_req_ie(struct wpa_supplicant *wpa_s, const u8 *ies,
-                                  size_t ies_len)
+static int ieee80211_sta_set_probe_req_ie(struct wpa_supplicant *wpa_s,
+                                         const u8 *ies, size_t ies_len)
 {
        os_free(wpa_s->mlme.extra_probe_ie);
        wpa_s->mlme.extra_probe_ie = NULL;