nl80211: Add support for P2P Device in add interface
[mech_eap.git] / src / drivers / driver_nl80211.c
index 15f0407..a9a9c4a 100644 (file)
@@ -178,23 +178,25 @@ struct nl80211_wiphy_data {
 };
 
 static void nl80211_global_deinit(void *priv);
-static void wpa_driver_nl80211_deinit(void *priv);
 
 struct i802_bss {
        struct wpa_driver_nl80211_data *drv;
        struct i802_bss *next;
        int ifindex;
+       u64 wdev_id;
        char ifname[IFNAMSIZ + 1];
        char brname[IFNAMSIZ];
        unsigned int beacon_set:1;
        unsigned int added_if_into_bridge:1;
        unsigned int added_bridge:1;
        unsigned int in_deinit:1;
+       unsigned int wdev_id_set:1;
 
        u8 addr[ETH_ALEN];
 
        int freq;
 
+       void *ctx;
        struct nl_handle *nl_preq, *nl_mgmt;
        struct nl_cb *nl_cb;
 
@@ -214,6 +216,8 @@ struct wpa_driver_nl80211_data {
        int ignore_if_down_event;
        struct rfkill_data *rfkill;
        struct wpa_driver_capa capa;
+       u8 *extended_capa, *extended_capa_mask;
+       unsigned int extended_capa_len;
        int has_capability;
 
        int operstate;
@@ -223,7 +227,9 @@ struct wpa_driver_nl80211_data {
        struct nl_cb *nl_cb;
 
        u8 auth_bssid[ETH_ALEN];
+       u8 auth_attempt_bssid[ETH_ALEN];
        u8 bssid[ETH_ALEN];
+       u8 prev_bssid[ETH_ALEN];
        int associated;
        u8 ssid[32];
        size_t ssid_len;
@@ -244,6 +250,7 @@ struct wpa_driver_nl80211_data {
        unsigned int scan_for_auth:1;
        unsigned int retry_auth:1;
        unsigned int use_monitor:1;
+       unsigned int ignore_next_local_disconnect:1;
 
        u64 remain_on_chan_cookie;
        u64 send_action_cookie;
@@ -284,6 +291,7 @@ struct wpa_driver_nl80211_data {
 };
 
 
+static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
 static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
                                            void *timeout_ctx);
 static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
@@ -299,7 +307,8 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
                                  unsigned int freq, unsigned int wait,
                                  const u8 *buf, size_t buf_len, u64 *cookie,
                                  int no_cck, int no_ack, int offchanok);
-static int wpa_driver_nl80211_probe_req_report(void *priv, int report);
+static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
+                                              int report);
 #ifdef ANDROID
 static int android_pno_start(struct i802_bss *bss,
                             struct wpa_driver_scan_params *params);
@@ -310,7 +319,7 @@ static int android_pno_stop(struct i802_bss *bss);
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
-static int wpa_driver_nl80211_if_remove(void *priv,
+static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
                                        enum wpa_driver_if_type type,
                                        const char *ifname);
 #else /* HOSTAPD */
@@ -328,7 +337,8 @@ static inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 }
 #endif /* HOSTAPD */
 
-static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
+static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
+                                      struct hostapd_freq_params *freq);
 static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
                                     int ifindex, int disabled);
 
@@ -337,6 +347,117 @@ static int wpa_driver_nl80211_authenticate_retry(
        struct wpa_driver_nl80211_data *drv);
 
 
+static const char * nl80211_command_to_string(enum nl80211_commands cmd)
+{
+#define C2S(x) case x: return #x;
+       switch (cmd) {
+       C2S(NL80211_CMD_UNSPEC)
+       C2S(NL80211_CMD_GET_WIPHY)
+       C2S(NL80211_CMD_SET_WIPHY)
+       C2S(NL80211_CMD_NEW_WIPHY)
+       C2S(NL80211_CMD_DEL_WIPHY)
+       C2S(NL80211_CMD_GET_INTERFACE)
+       C2S(NL80211_CMD_SET_INTERFACE)
+       C2S(NL80211_CMD_NEW_INTERFACE)
+       C2S(NL80211_CMD_DEL_INTERFACE)
+       C2S(NL80211_CMD_GET_KEY)
+       C2S(NL80211_CMD_SET_KEY)
+       C2S(NL80211_CMD_NEW_KEY)
+       C2S(NL80211_CMD_DEL_KEY)
+       C2S(NL80211_CMD_GET_BEACON)
+       C2S(NL80211_CMD_SET_BEACON)
+       C2S(NL80211_CMD_START_AP)
+       C2S(NL80211_CMD_STOP_AP)
+       C2S(NL80211_CMD_GET_STATION)
+       C2S(NL80211_CMD_SET_STATION)
+       C2S(NL80211_CMD_NEW_STATION)
+       C2S(NL80211_CMD_DEL_STATION)
+       C2S(NL80211_CMD_GET_MPATH)
+       C2S(NL80211_CMD_SET_MPATH)
+       C2S(NL80211_CMD_NEW_MPATH)
+       C2S(NL80211_CMD_DEL_MPATH)
+       C2S(NL80211_CMD_SET_BSS)
+       C2S(NL80211_CMD_SET_REG)
+       C2S(NL80211_CMD_REQ_SET_REG)
+       C2S(NL80211_CMD_GET_MESH_CONFIG)
+       C2S(NL80211_CMD_SET_MESH_CONFIG)
+       C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
+       C2S(NL80211_CMD_GET_REG)
+       C2S(NL80211_CMD_GET_SCAN)
+       C2S(NL80211_CMD_TRIGGER_SCAN)
+       C2S(NL80211_CMD_NEW_SCAN_RESULTS)
+       C2S(NL80211_CMD_SCAN_ABORTED)
+       C2S(NL80211_CMD_REG_CHANGE)
+       C2S(NL80211_CMD_AUTHENTICATE)
+       C2S(NL80211_CMD_ASSOCIATE)
+       C2S(NL80211_CMD_DEAUTHENTICATE)
+       C2S(NL80211_CMD_DISASSOCIATE)
+       C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
+       C2S(NL80211_CMD_REG_BEACON_HINT)
+       C2S(NL80211_CMD_JOIN_IBSS)
+       C2S(NL80211_CMD_LEAVE_IBSS)
+       C2S(NL80211_CMD_TESTMODE)
+       C2S(NL80211_CMD_CONNECT)
+       C2S(NL80211_CMD_ROAM)
+       C2S(NL80211_CMD_DISCONNECT)
+       C2S(NL80211_CMD_SET_WIPHY_NETNS)
+       C2S(NL80211_CMD_GET_SURVEY)
+       C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
+       C2S(NL80211_CMD_SET_PMKSA)
+       C2S(NL80211_CMD_DEL_PMKSA)
+       C2S(NL80211_CMD_FLUSH_PMKSA)
+       C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
+       C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
+       C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
+       C2S(NL80211_CMD_REGISTER_FRAME)
+       C2S(NL80211_CMD_FRAME)
+       C2S(NL80211_CMD_FRAME_TX_STATUS)
+       C2S(NL80211_CMD_SET_POWER_SAVE)
+       C2S(NL80211_CMD_GET_POWER_SAVE)
+       C2S(NL80211_CMD_SET_CQM)
+       C2S(NL80211_CMD_NOTIFY_CQM)
+       C2S(NL80211_CMD_SET_CHANNEL)
+       C2S(NL80211_CMD_SET_WDS_PEER)
+       C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
+       C2S(NL80211_CMD_JOIN_MESH)
+       C2S(NL80211_CMD_LEAVE_MESH)
+       C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
+       C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
+       C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
+       C2S(NL80211_CMD_GET_WOWLAN)
+       C2S(NL80211_CMD_SET_WOWLAN)
+       C2S(NL80211_CMD_START_SCHED_SCAN)
+       C2S(NL80211_CMD_STOP_SCHED_SCAN)
+       C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
+       C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
+       C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
+       C2S(NL80211_CMD_PMKSA_CANDIDATE)
+       C2S(NL80211_CMD_TDLS_OPER)
+       C2S(NL80211_CMD_TDLS_MGMT)
+       C2S(NL80211_CMD_UNEXPECTED_FRAME)
+       C2S(NL80211_CMD_PROBE_CLIENT)
+       C2S(NL80211_CMD_REGISTER_BEACONS)
+       C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
+       C2S(NL80211_CMD_SET_NOACK_MAP)
+       C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
+       C2S(NL80211_CMD_START_P2P_DEVICE)
+       C2S(NL80211_CMD_STOP_P2P_DEVICE)
+       C2S(NL80211_CMD_CONN_FAILED)
+       C2S(NL80211_CMD_SET_MCAST_RATE)
+       C2S(NL80211_CMD_SET_MAC_ACL)
+       C2S(NL80211_CMD_RADAR_DETECT)
+       C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
+       C2S(NL80211_CMD_UPDATE_FT_IES)
+       C2S(NL80211_CMD_FT_EVENT)
+       C2S(NL80211_CMD_CRIT_PROTOCOL_START)
+       C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
+       default:
+               return "NL80211_CMD_UNKNOWN";
+       }
+#undef C2S
+}
+
+
 static int is_ap_interface(enum nl80211_iftype nlmode)
 {
        return (nlmode == NL80211_IFTYPE_AP ||
@@ -351,13 +472,22 @@ static int is_sta_interface(enum nl80211_iftype nlmode)
 }
 
 
-static int is_p2p_interface(enum nl80211_iftype nlmode)
+static int is_p2p_net_interface(enum nl80211_iftype nlmode)
 {
        return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
                nlmode == NL80211_IFTYPE_P2P_GO);
 }
 
 
+static void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
+{
+       if (drv->associated)
+               os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
+       drv->associated = 0;
+       os_memset(drv->bssid, 0, ETH_ALEN);
+}
+
+
 struct nl80211_bss_info_arg {
        struct wpa_driver_nl80211_data *drv;
        struct wpa_scan_results *res;
@@ -459,6 +589,19 @@ struct family_data {
 };
 
 
+static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
+{
+       if (bss->wdev_id_set)
+               NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+       else
+               NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       return 0;
+
+nla_put_failure:
+       return -1;
+}
+
+
 static int family_handler(struct nl_msg *msg, void *arg)
 {
        struct family_data *res = arg;
@@ -1023,6 +1166,7 @@ static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
        const struct ieee80211_mgmt *mgmt;
        union wpa_event_data event;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
        mgmt = (const struct ieee80211_mgmt *) frame;
        if (len < 24 + sizeof(mgmt->u.auth)) {
                wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
@@ -1031,9 +1175,12 @@ static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
        }
 
        os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
+       os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
        os_memset(&event, 0, sizeof(event));
        os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
        event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
+       event.auth.auth_transaction =
+               le_to_host16(mgmt->u.auth.auth_transaction);
        event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
        if (len > 24 + sizeof(mgmt->u.auth)) {
                event.auth.ies = mgmt->u.auth.variable;
@@ -1082,6 +1229,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
        union wpa_event_data event;
        u16 status;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Associate event");
        mgmt = (const struct ieee80211_mgmt *) frame;
        if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
                wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
@@ -1107,6 +1255,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
 
        drv->associated = 1;
        os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
+       os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN);
 
        os_memset(&event, 0, sizeof(event));
        if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
@@ -1138,6 +1287,11 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
                return;
        }
 
+       if (cmd == NL80211_CMD_CONNECT)
+               wpa_printf(MSG_DEBUG, "nl80211: Connect event");
+       else if (cmd == NL80211_CMD_ROAM)
+               wpa_printf(MSG_DEBUG, "nl80211: Roam event");
+
        os_memset(&event, 0, sizeof(event));
        if (cmd == NL80211_CMD_CONNECT &&
            nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
@@ -1153,8 +1307,10 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
        }
 
        drv->associated = 1;
-       if (addr)
+       if (addr) {
                os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
+               os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
+       }
 
        if (req_ie) {
                event.assoc_info.req_ies = nla_data(req_ie);
@@ -1176,6 +1332,7 @@ static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
                                  struct nlattr *by_ap)
 {
        union wpa_event_data data;
+       unsigned int locally_generated = by_ap == NULL;
 
        if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
                /*
@@ -1187,7 +1344,20 @@ static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
                return;
        }
 
-       drv->associated = 0;
+       if (drv->ignore_next_local_disconnect) {
+               drv->ignore_next_local_disconnect = 0;
+               if (locally_generated) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+                                  "event triggered during reassociation");
+                       return;
+               }
+               wpa_printf(MSG_WARNING, "nl80211: Was expecting local "
+                          "disconnect but got another disconnect "
+                          "event first");
+       }
+
+       wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
+       nl80211_mark_disconnected(drv);
        os_memset(&data, 0, sizeof(data));
        if (reason)
                data.deauth_info.reason_code = nla_get_u16(reason);
@@ -1196,6 +1366,40 @@ static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
+                                struct nlattr *freq, struct nlattr *type)
+{
+       union wpa_event_data data;
+       int ht_enabled = 1;
+       int chan_offset = 0;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
+
+       if (!freq || !type)
+               return;
+
+       switch (nla_get_u32(type)) {
+       case NL80211_CHAN_NO_HT:
+               ht_enabled = 0;
+               break;
+       case NL80211_CHAN_HT20:
+               break;
+       case NL80211_CHAN_HT40PLUS:
+               chan_offset = 1;
+               break;
+       case NL80211_CHAN_HT40MINUS:
+               chan_offset = -1;
+               break;
+       }
+
+       data.ch_switch.freq = nla_get_u32(freq);
+       data.ch_switch.ht_enabled = ht_enabled;
+       data.ch_switch.ch_offset = chan_offset;
+
+       wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
+}
+
+
 static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
                               enum nl80211_commands cmd, struct nlattr *addr)
 {
@@ -1230,6 +1434,7 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
        u16 fc, stype;
        int ssi_signal = 0;
 
+       wpa_printf(MSG_MSGDUMP, "nl80211: Frame event");
        mgmt = (const struct ieee80211_mgmt *) frame;
        if (len < 24) {
                wpa_printf(MSG_DEBUG, "nl80211: Too short action frame");
@@ -1272,6 +1477,7 @@ static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
        const struct ieee80211_hdr *hdr;
        u16 fc;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
        if (!is_ap_interface(drv->nlmode)) {
                u64 cookie_val;
 
@@ -1311,10 +1517,31 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
        const u8 *bssid = NULL;
        u16 reason_code = 0;
 
+       if (type == EVENT_DEAUTH)
+               wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event");
+       else
+               wpa_printf(MSG_DEBUG, "nl80211: Disassociate event");
+
        mgmt = (const struct ieee80211_mgmt *) frame;
        if (len >= 24) {
                bssid = mgmt->bssid;
 
+               if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+                   !drv->associated &&
+                   os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 &&
+                   os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 &&
+                   os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) {
+                       /*
+                        * Avoid issues with some roaming cases where
+                        * disconnection event for the old AP may show up after
+                        * we have started connection with the new AP.
+                        */
+                       wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
+                                  MAC2STR(bssid),
+                                  MAC2STR(drv->auth_attempt_bssid));
+                       return;
+               }
+
                if (drv->associated != 0 &&
                    os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
                    os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
@@ -1330,7 +1557,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
                }
        }
 
-       drv->associated = 0;
+       nl80211_mark_disconnected(drv);
        os_memset(&event, 0, sizeof(event));
 
        /* Note: Same offset for Reason Code in both frame subtypes */
@@ -1371,6 +1598,11 @@ static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
        union wpa_event_data event;
        u16 reason_code = 0;
 
+       if (type == EVENT_UNPROT_DEAUTH)
+               wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event");
+       else
+               wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event");
+
        if (len < 24)
                return;
 
@@ -1395,24 +1627,49 @@ static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
 }
 
 
-static void mlme_event(struct wpa_driver_nl80211_data *drv,
+static void mlme_event(struct i802_bss *bss,
                       enum nl80211_commands cmd, struct nlattr *frame,
                       struct nlattr *addr, struct nlattr *timed_out,
                       struct nlattr *freq, struct nlattr *ack,
                       struct nlattr *cookie, struct nlattr *sig)
 {
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       const u8 *data;
+       size_t len;
+
        if (timed_out && addr) {
                mlme_timeout_event(drv, cmd, addr);
                return;
        }
 
        if (frame == NULL) {
-               wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame "
-                          "data", cmd);
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: MLME event %d (%s) without frame data",
+                          cmd, nl80211_command_to_string(cmd));
                return;
        }
 
-       wpa_printf(MSG_DEBUG, "nl80211: MLME event %d", cmd);
+       data = nla_data(frame);
+       len = nla_len(frame);
+       if (len < 4 + 2 * ETH_ALEN) {
+               wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s("
+                          MACSTR ") - too short",
+                          cmd, nl80211_command_to_string(cmd), bss->ifname,
+                          MAC2STR(bss->addr));
+               return;
+       }
+       wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR
+                  ") A1=" MACSTR " A2=" MACSTR, cmd,
+                  nl80211_command_to_string(cmd), bss->ifname,
+                  MAC2STR(bss->addr), MAC2STR(data + 4),
+                  MAC2STR(data + 4 + ETH_ALEN));
+       if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
+           os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
+           os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
+               wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
+                          "for foreign address", bss->ifname);
+               return;
+       }
        wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
                    nla_data(frame), nla_len(frame));
 
@@ -1453,7 +1710,7 @@ static void mlme_event(struct wpa_driver_nl80211_data *drv,
 }
 
 
-static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv,
+static void mlme_event_michael_mic_failure(struct i802_bss *bss,
                                           struct nlattr *tb[])
 {
        union wpa_event_data data;
@@ -1485,7 +1742,7 @@ static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv,
                wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
        }
 
-       wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+       wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
 }
 
 
@@ -1554,6 +1811,34 @@ static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv,
+                               struct nlattr *tb[])
+{
+       union wpa_event_data data;
+
+       os_memset(&data, 0, sizeof(data));
+
+       if (tb[NL80211_ATTR_IE]) {
+               data.ft_ies.ies = nla_data(tb[NL80211_ATTR_IE]);
+               data.ft_ies.ies_len = nla_len(tb[NL80211_ATTR_IE]);
+       }
+
+       if (tb[NL80211_ATTR_IE_RIC]) {
+               data.ft_ies.ric_ies = nla_data(tb[NL80211_ATTR_IE_RIC]);
+               data.ft_ies.ric_ies_len = nla_len(tb[NL80211_ATTR_IE_RIC]);
+       }
+
+       if (tb[NL80211_ATTR_MAC])
+               os_memcpy(data.ft_ies.target_ap,
+                         nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+       wpa_printf(MSG_DEBUG, "nl80211: FT event target_ap " MACSTR,
+                  MAC2STR(data.ft_ies.target_ap));
+
+       wpa_supplicant_event(drv->ctx, EVENT_FT_RESPONSE, &data);
+}
+
+
 static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
                            struct nlattr *tb[])
 {
@@ -1610,6 +1895,7 @@ static int get_link_signal(struct nl_msg *msg, void *arg)
        struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
        static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
                [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
+               [NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
        };
        struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
        static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
@@ -1632,6 +1918,12 @@ static int get_link_signal(struct nl_msg *msg, void *arg)
        sig_change->current_signal =
                (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
 
+       if (sinfo[NL80211_STA_INFO_SIGNAL_AVG])
+               sig_change->avg_signal =
+                       (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]);
+       else
+               sig_change->avg_signal = 0;
+
        if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
                if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
                                     sinfo[NL80211_STA_INFO_TX_BITRATE],
@@ -1997,6 +2289,8 @@ static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
        };
        union wpa_event_data data;
 
+       wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event");
+
        if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
                return;
        if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
@@ -2022,6 +2316,8 @@ static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
 {
        union wpa_event_data data;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
+
        if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
                return;
 
@@ -2033,6 +2329,117 @@ static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
+                                   struct nlattr **tb)
+{
+       union wpa_event_data data;
+
+       wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event");
+
+       if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION])
+               return;
+
+       os_memset(&data, 0, sizeof(data));
+       os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+       switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) {
+       case NL80211_TDLS_SETUP:
+               wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer "
+                          MACSTR, MAC2STR(data.tdls.peer));
+               data.tdls.oper = TDLS_REQUEST_SETUP;
+               break;
+       case NL80211_TDLS_TEARDOWN:
+               wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer "
+                          MACSTR, MAC2STR(data.tdls.peer));
+               data.tdls.oper = TDLS_REQUEST_TEARDOWN;
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione "
+                          "event");
+               return;
+       }
+       if (tb[NL80211_ATTR_REASON_CODE]) {
+               data.tdls.reason_code =
+                       nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
+       }
+
+       wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data);
+}
+
+
+static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
+                                        struct nlattr **tb)
+{
+       union wpa_event_data data;
+       u32 reason;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Connect failed event");
+
+       if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON])
+               return;
+
+       os_memset(&data, 0, sizeof(data));
+       os_memcpy(data.connect_failed_reason.addr,
+                 nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+       reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]);
+       switch (reason) {
+       case NL80211_CONN_FAIL_MAX_CLIENTS:
+               wpa_printf(MSG_DEBUG, "nl80211: Max client reached");
+               data.connect_failed_reason.code = MAX_CLIENT_REACHED;
+               break;
+       case NL80211_CONN_FAIL_BLOCKED_CLIENT:
+               wpa_printf(MSG_DEBUG, "nl80211: Blocked client " MACSTR
+                          " tried to connect",
+                          MAC2STR(data.connect_failed_reason.addr));
+               data.connect_failed_reason.code = BLOCKED_CLIENT;
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason "
+                          "%u", reason);
+               return;
+       }
+
+       wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data);
+}
+
+
+static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
+                               struct nlattr **tb)
+{
+       union wpa_event_data data;
+       enum nl80211_radar_event event_type;
+
+       if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT])
+               return;
+
+       os_memset(&data, 0, sizeof(data));
+       data.dfs_event.freq = nla_get_u16(tb[NL80211_ATTR_WIPHY_FREQ]);
+       event_type = nla_get_u8(tb[NL80211_ATTR_RADAR_EVENT]);
+
+       wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz",
+                  data.dfs_event.freq);
+
+       switch (event_type) {
+       case NL80211_RADAR_DETECTED:
+               wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data);
+               break;
+       case NL80211_RADAR_CAC_FINISHED:
+               wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data);
+               break;
+       case NL80211_RADAR_CAC_ABORTED:
+               wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data);
+               break;
+       case NL80211_RADAR_NOP_FINISHED:
+               wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data);
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d "
+                          "received", event_type);
+               break;
+       }
+}
+
+
 static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
                                   int wds)
 {
@@ -2051,9 +2458,14 @@ static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
 }
 
 
-static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
-                                int cmd, struct nlattr **tb)
+static void do_process_drv_event(struct i802_bss *bss, int cmd,
+                                struct nlattr **tb)
 {
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
+                  cmd, nl80211_command_to_string(cmd), bss->ifname);
+
        if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
            (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
             cmd == NL80211_CMD_SCAN_ABORTED)) {
@@ -2064,29 +2476,30 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
 
        switch (cmd) {
        case NL80211_CMD_TRIGGER_SCAN:
-               wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
+               wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
                break;
        case NL80211_CMD_START_SCHED_SCAN:
-               wpa_printf(MSG_DEBUG, "nl80211: Sched scan started");
+               wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
                break;
        case NL80211_CMD_SCHED_SCAN_STOPPED:
-               wpa_printf(MSG_DEBUG, "nl80211: Sched scan stopped");
+               wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
                wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
                break;
        case NL80211_CMD_NEW_SCAN_RESULTS:
-               wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
+               wpa_dbg(drv->ctx, MSG_DEBUG,
+                       "nl80211: New scan results available");
                drv->scan_complete_events = 1;
                eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
                                     drv->ctx);
                send_scan_event(drv, 0, tb);
                break;
        case NL80211_CMD_SCHED_SCAN_RESULTS:
-               wpa_printf(MSG_DEBUG,
-                          "nl80211: New sched scan results available");
+               wpa_dbg(drv->ctx, MSG_DEBUG,
+                       "nl80211: New sched scan results available");
                send_scan_event(drv, 0, tb);
                break;
        case NL80211_CMD_SCAN_ABORTED:
-               wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
+               wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
                /*
                 * Need to indicate that scan results are available in order
                 * not to make wpa_supplicant stop its scanning.
@@ -2102,7 +2515,7 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
        case NL80211_CMD_FRAME_TX_STATUS:
        case NL80211_CMD_UNPROT_DEAUTHENTICATE:
        case NL80211_CMD_UNPROT_DISASSOCIATE:
-               mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME],
+               mlme_event(bss, cmd, tb[NL80211_ATTR_FRAME],
                           tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
                           tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
                           tb[NL80211_ATTR_COOKIE],
@@ -2116,13 +2529,17 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
                                   tb[NL80211_ATTR_REQ_IE],
                                   tb[NL80211_ATTR_RESP_IE]);
                break;
+       case NL80211_CMD_CH_SWITCH_NOTIFY:
+               mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
+                                    tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+               break;
        case NL80211_CMD_DISCONNECT:
                mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
                                      tb[NL80211_ATTR_MAC],
                                      tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
                break;
        case NL80211_CMD_MICHAEL_MIC_FAILURE:
-               mlme_event_michael_mic_failure(drv, tb);
+               mlme_event_michael_mic_failure(bss, tb);
                break;
        case NL80211_CMD_JOIN_IBSS:
                mlme_event_join_ibss(drv, tb);
@@ -2161,9 +2578,21 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
        case NL80211_CMD_PROBE_CLIENT:
                nl80211_client_probe_event(drv, tb);
                break;
+       case NL80211_CMD_TDLS_OPER:
+               nl80211_tdls_oper_event(drv, tb);
+               break;
+       case NL80211_CMD_CONN_FAILED:
+               nl80211_connect_failed_event(drv, tb);
+               break;
+       case NL80211_CMD_FT_EVENT:
+               mlme_event_ft_event(drv, tb);
+               break;
+       case NL80211_CMD_RADAR_DETECT:
+               nl80211_radar_event(drv, tb);
+               break;
        default:
-               wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
-                          "(cmd=%d)", cmd);
+               wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
+                       "(cmd=%d)", cmd);
                break;
        }
 }
@@ -2174,21 +2603,37 @@ static int process_drv_event(struct nl_msg *msg, void *arg)
        struct wpa_driver_nl80211_data *drv = arg;
        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
        struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct i802_bss *bss;
+       int ifidx = -1;
 
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
        if (tb[NL80211_ATTR_IFINDEX]) {
-               int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
-               if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) {
-                       wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
-                                  " for foreign interface (ifindex %d)",
-                                  gnlh->cmd, ifindex);
-                       return NL_SKIP;
+               ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+
+               for (bss = &drv->first_bss; bss; bss = bss->next)
+                       if (ifidx == -1 || ifidx == bss->ifindex) {
+                               do_process_drv_event(bss, gnlh->cmd, tb);
+                               return NL_SKIP;
+                       }
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d)",
+                          gnlh->cmd, ifidx);
+       } else if (tb[NL80211_ATTR_WDEV]) {
+               u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+               wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device");
+               for (bss = &drv->first_bss; bss; bss = bss->next) {
+                       if (bss->wdev_id_set && wdev_id == bss->wdev_id) {
+                               do_process_drv_event(bss, gnlh->cmd, tb);
+                               return NL_SKIP;
+                       }
                }
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Ignored event (cmd=%d) for foreign interface (wdev 0x%llx)",
+                          gnlh->cmd, (long long unsigned int) wdev_id);
        }
 
-       do_process_drv_event(drv, gnlh->cmd, tb);
        return NL_SKIP;
 }
 
@@ -2198,20 +2643,33 @@ static int process_global_event(struct nl_msg *msg, void *arg)
        struct nl80211_global *global = arg;
        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
        struct nlattr *tb[NL80211_ATTR_MAX + 1];
-       struct wpa_driver_nl80211_data *drv;
+       struct wpa_driver_nl80211_data *drv, *tmp;
        int ifidx = -1;
+       struct i802_bss *bss;
+       u64 wdev_id;
+       int wdev_id_set = 0;
 
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
        if (tb[NL80211_ATTR_IFINDEX])
                ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
-
-       dl_list_for_each(drv, &global->interfaces,
-                        struct wpa_driver_nl80211_data, list) {
-               if (ifidx == -1 || ifidx == drv->ifindex ||
-                   have_ifidx(drv, ifidx))
-                       do_process_drv_event(drv, gnlh->cmd, tb);
+       else if (tb[NL80211_ATTR_WDEV]) {
+               wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+               wdev_id_set = 1;
+       }
+
+       dl_list_for_each_safe(drv, tmp, &global->interfaces,
+                             struct wpa_driver_nl80211_data, list) {
+               for (bss = &drv->first_bss; bss; bss = bss->next) {
+                       if ((ifidx == -1 && !wdev_id_set) ||
+                           ifidx == bss->ifindex ||
+                           (wdev_id_set && bss->wdev_id_set &&
+                            wdev_id == bss->wdev_id)) {
+                               do_process_drv_event(bss, gnlh->cmd, tb);
+                               return NL_SKIP;
+                       }
+               }
        }
 
        return NL_SKIP;
@@ -2227,10 +2685,14 @@ static int process_bss_event(struct nl_msg *msg, void *arg)
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
+       wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s",
+                  gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
+                  bss->ifname);
+
        switch (gnlh->cmd) {
        case NL80211_CMD_FRAME:
        case NL80211_CMD_FRAME_TX_STATUS:
-               mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+               mlme_event(bss, gnlh->cmd, tb[NL80211_ATTR_FRAME],
                           tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
                           tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
                           tb[NL80211_ATTR_COOKIE],
@@ -2257,7 +2719,7 @@ static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
 {
        struct nl_cb *cb = eloop_ctx;
 
-       wpa_printf(MSG_DEBUG, "nl80211: Event message available");
+       wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
 
        nl_recvmsgs(handle, cb);
 }
@@ -2299,7 +2761,44 @@ nla_put_failure:
 }
 
 
+static int protocol_feature_handler(struct nl_msg *msg, void *arg)
+{
+       u32 *feat = arg;
+       struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+       nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
+               *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
+
+       return NL_SKIP;
+}
+
+
+static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
+{
+       u32 feat = 0;
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               goto nla_put_failure;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES);
+       if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0)
+               return feat;
+
+       msg = NULL;
+nla_put_failure:
+       nlmsg_free(msg);
+       return 0;
+}
+
+
 struct wiphy_info_data {
+       struct wpa_driver_nl80211_data *drv;
        struct wpa_driver_capa *capa;
 
        unsigned int error:1;
@@ -2307,6 +2806,12 @@ struct wiphy_info_data {
        unsigned int poll_command_supported:1;
        unsigned int data_tx_status:1;
        unsigned int monitor_supported:1;
+       unsigned int auth_supported:1;
+       unsigned int connect_supported:1;
+       unsigned int p2p_go_supported:1;
+       unsigned int p2p_client_supported:1;
+       unsigned int p2p_concurrent:1;
+       unsigned int p2p_multichan_concurrent:1;
 };
 
 
@@ -2327,145 +2832,245 @@ static unsigned int probe_resp_offload_support(int supp_protocols)
 }
 
 
-static int wiphy_info_handler(struct nl_msg *msg, void *arg)
+static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
+                                        struct nlattr *tb)
 {
-       struct nlattr *tb[NL80211_ATTR_MAX + 1];
-       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-       struct wiphy_info_data *info = arg;
-       int p2p_go_supported = 0, p2p_client_supported = 0;
-       int p2p_concurrent = 0;
-       int auth_supported = 0, connect_supported = 0;
-       struct wpa_driver_capa *capa = info->capa;
+       struct nlattr *nl_mode;
+       int i;
+
+       if (tb == NULL)
+               return;
+
+       nla_for_each_nested(nl_mode, tb, i) {
+               switch (nla_type(nl_mode)) {
+               case NL80211_IFTYPE_AP:
+                       info->capa->flags |= WPA_DRIVER_FLAGS_AP;
+                       break;
+               case NL80211_IFTYPE_ADHOC:
+                       info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
+                       break;
+               case NL80211_IFTYPE_P2P_DEVICE:
+                       info->capa->flags |=
+                               WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+                       break;
+               case NL80211_IFTYPE_P2P_GO:
+                       info->p2p_go_supported = 1;
+                       break;
+               case NL80211_IFTYPE_P2P_CLIENT:
+                       info->p2p_client_supported = 1;
+                       break;
+               case NL80211_IFTYPE_MONITOR:
+                       info->monitor_supported = 1;
+                       break;
+               }
+       }
+}
+
+
+static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
+                                        struct nlattr *nl_combi)
+{
+       struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
+       struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
+       struct nlattr *nl_limit, *nl_mode;
+       int err, rem_limit, rem_mode;
+       int combination_has_p2p = 0, combination_has_mgd = 0;
        static struct nla_policy
        iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
                [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
                [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
                [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
                [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
+               [NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS] = { .type = NLA_U32 },
        },
        iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
                [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
                [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
        };
 
-       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-                 genlmsg_attrlen(gnlh, 0), NULL);
-
-       if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
-               capa->max_scan_ssids =
-                       nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
+       err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
+                              nl_combi, iface_combination_policy);
+       if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
+           !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
+           !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
+               return 0; /* broken combination */
 
-       if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
-               capa->max_sched_scan_ssids =
-                       nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
+       if (tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS])
+               info->capa->flags |= WPA_DRIVER_FLAGS_RADAR;
 
-       if (tb[NL80211_ATTR_MAX_MATCH_SETS])
-               capa->max_match_sets =
-                       nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
+       nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS],
+                           rem_limit) {
+               err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT,
+                                      nl_limit, iface_limit_policy);
+               if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES])
+                       return 0; /* broken combination */
 
-       if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
-               struct nlattr *nl_mode;
-               int i;
                nla_for_each_nested(nl_mode,
-                                   tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
-                       switch (nla_type(nl_mode)) {
-                       case NL80211_IFTYPE_AP:
-                               capa->flags |= WPA_DRIVER_FLAGS_AP;
-                               break;
-                       case NL80211_IFTYPE_P2P_GO:
-                               p2p_go_supported = 1;
-                               break;
-                       case NL80211_IFTYPE_P2P_CLIENT:
-                               p2p_client_supported = 1;
-                               break;
-                       case NL80211_IFTYPE_MONITOR:
-                               info->monitor_supported = 1;
-                               break;
-                       }
+                                   tb_limit[NL80211_IFACE_LIMIT_TYPES],
+                                   rem_mode) {
+                       int ift = nla_type(nl_mode);
+                       if (ift == NL80211_IFTYPE_P2P_GO ||
+                           ift == NL80211_IFTYPE_P2P_CLIENT)
+                               combination_has_p2p = 1;
+                       if (ift == NL80211_IFTYPE_STATION)
+                               combination_has_mgd = 1;
                }
+               if (combination_has_p2p && combination_has_mgd)
+                       break;
        }
 
-       if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) {
-               struct nlattr *nl_combi;
-               int rem_combi;
-
-               nla_for_each_nested(nl_combi,
-                                   tb[NL80211_ATTR_INTERFACE_COMBINATIONS],
-                                   rem_combi) {
-                       struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
-                       struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
-                       struct nlattr *nl_limit, *nl_mode;
-                       int err, rem_limit, rem_mode;
-                       int combination_has_p2p = 0, combination_has_mgd = 0;
-
-                       err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
-                                              nl_combi,
-                                              iface_combination_policy);
-                       if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
-                           !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
-                           !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
-                               goto broken_combination;
-
-                       nla_for_each_nested(nl_limit,
-                                           tb_comb[NL80211_IFACE_COMB_LIMITS],
-                                           rem_limit) {
-                               err = nla_parse_nested(tb_limit,
-                                                      MAX_NL80211_IFACE_LIMIT,
-                                                      nl_limit,
-                                                      iface_limit_policy);
-                               if (err ||
-                                   !tb_limit[NL80211_IFACE_LIMIT_TYPES])
-                                       goto broken_combination;
-
-                               nla_for_each_nested(
-                                       nl_mode,
-                                       tb_limit[NL80211_IFACE_LIMIT_TYPES],
-                                       rem_mode) {
-                                       int ift = nla_type(nl_mode);
-                                       if (ift == NL80211_IFTYPE_P2P_GO ||
-                                           ift == NL80211_IFTYPE_P2P_CLIENT)
-                                               combination_has_p2p = 1;
-                                       if (ift == NL80211_IFTYPE_STATION)
-                                               combination_has_mgd = 1;
-                               }
-                               if (combination_has_p2p && combination_has_mgd)
-                                       break;
-                       }
+       if (combination_has_p2p && combination_has_mgd) {
+               info->p2p_concurrent = 1;
+               if (nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) > 1)
+                       info->p2p_multichan_concurrent = 1;
+               return 1;
+       }
 
-                       if (combination_has_p2p && combination_has_mgd) {
-                               p2p_concurrent = 1;
-                               break;
-                       }
+       return 0;
+}
 
-broken_combination:
-                       ;
-               }
-       }
 
-       if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
-               struct nlattr *nl_cmd;
-               int i;
+static void wiphy_info_iface_comb(struct wiphy_info_data *info,
+                                 struct nlattr *tb)
+{
+       struct nlattr *nl_combi;
+       int rem_combi;
 
-               nla_for_each_nested(nl_cmd,
-                                   tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
-                       switch (nla_get_u32(nl_cmd)) {
-                       case NL80211_CMD_AUTHENTICATE:
-                               auth_supported = 1;
-                               break;
-                       case NL80211_CMD_CONNECT:
-                               connect_supported = 1;
-                               break;
-                       case NL80211_CMD_START_SCHED_SCAN:
-                               capa->sched_scan_supported = 1;
-                               break;
-                       case NL80211_CMD_PROBE_CLIENT:
-                               info->poll_command_supported = 1;
-                               break;
-                       }
-               }
-       }
+       if (tb == NULL)
+               return;
 
-       if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
+       nla_for_each_nested(nl_combi, tb, rem_combi) {
+               if (wiphy_info_iface_comb_process(info, nl_combi) > 0)
+                       break;
+       }
+}
+
+
+static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
+                                struct nlattr *tb)
+{
+       struct nlattr *nl_cmd;
+       int i;
+
+       if (tb == NULL)
+               return;
+
+       nla_for_each_nested(nl_cmd, tb, i) {
+               switch (nla_get_u32(nl_cmd)) {
+               case NL80211_CMD_AUTHENTICATE:
+                       info->auth_supported = 1;
+                       break;
+               case NL80211_CMD_CONNECT:
+                       info->connect_supported = 1;
+                       break;
+               case NL80211_CMD_START_SCHED_SCAN:
+                       info->capa->sched_scan_supported = 1;
+                       break;
+               case NL80211_CMD_PROBE_CLIENT:
+                       info->poll_command_supported = 1;
+                       break;
+               }
+       }
+}
+
+
+static void wiphy_info_max_roc(struct wpa_driver_capa *capa,
+                              struct nlattr *tb)
+{
+       if (tb)
+               capa->max_remain_on_chan = nla_get_u32(tb);
+}
+
+
+static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls,
+                           struct nlattr *ext_setup)
+{
+       if (tdls == NULL)
+               return;
+
+       wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
+       capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
+
+       if (ext_setup) {
+               wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
+               capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
+       }
+}
+
+
+static void wiphy_info_feature_flags(struct wiphy_info_data *info,
+                                    struct nlattr *tb)
+{
+       u32 flags;
+       struct wpa_driver_capa *capa = info->capa;
+
+       if (tb == NULL)
+               return;
+
+       flags = nla_get_u32(tb);
+
+       if (flags & NL80211_FEATURE_SK_TX_STATUS)
+               info->data_tx_status = 1;
+
+       if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
+               capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
+
+       if (flags & NL80211_FEATURE_SAE)
+               capa->flags |= WPA_DRIVER_FLAGS_SAE;
+
+       if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
+               capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
+}
+
+
+static void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa,
+                                         struct nlattr *tb)
+{
+       u32 protocols;
+
+       if (tb == NULL)
+               return;
+
+       protocols = nla_get_u32(tb);
+       wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response offload in AP "
+                  "mode");
+       capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
+       capa->probe_resp_offloads = probe_resp_offload_support(protocols);
+}
+
+
+static int wiphy_info_handler(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct wiphy_info_data *info = arg;
+       struct wpa_driver_capa *capa = info->capa;
+       struct wpa_driver_nl80211_data *drv = info->drv;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
+               capa->max_scan_ssids =
+                       nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
+
+       if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
+               capa->max_sched_scan_ssids =
+                       nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
+
+       if (tb[NL80211_ATTR_MAX_MATCH_SETS])
+               capa->max_match_sets =
+                       nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
+
+       if (tb[NL80211_ATTR_MAC_ACL_MAX])
+               capa->max_acl_mac_addrs =
+                       nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]);
+
+       wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]);
+       wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]);
+       wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]);
+
+       if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
                wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
                           "off-channel TX");
                capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
@@ -2476,65 +3081,44 @@ broken_combination:
                capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
        }
 
-       /* default to 5000 since early versions of mac80211 don't set it */
-       capa->max_remain_on_chan = 5000;
+       wiphy_info_max_roc(capa,
+                          tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
 
        if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
                capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
 
-       if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION])
-               capa->max_remain_on_chan =
-                       nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
-
-       if (auth_supported)
-               capa->flags |= WPA_DRIVER_FLAGS_SME;
-       else if (!connect_supported) {
-               wpa_printf(MSG_INFO, "nl80211: Driver does not support "
-                          "authentication/association or connect commands");
-               info->error = 1;
-       }
-
-       if (p2p_go_supported && p2p_client_supported)
-               capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
-       if (p2p_concurrent) {
-               wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
-                          "interface (driver advertised support)");
-               capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
-               capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
-       }
-
-       if (tb[NL80211_ATTR_TDLS_SUPPORT]) {
-               wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
-               capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
-
-               if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) {
-                       wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
-                       capa->flags |=
-                               WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
-               }
-       }
+       wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT],
+                       tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]);
 
        if (tb[NL80211_ATTR_DEVICE_AP_SME])
                info->device_ap_sme = 1;
 
-       if (tb[NL80211_ATTR_FEATURE_FLAGS]) {
-               u32 flags = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]);
-
-               if (flags & NL80211_FEATURE_SK_TX_STATUS)
-                       info->data_tx_status = 1;
-
-               if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
-                       capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
-       }
-
-       if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) {
-               int protocols =
-                       nla_get_u32(tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
-               wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response "
-                          "offload in AP mode");
-               capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
-               capa->probe_resp_offloads =
-                       probe_resp_offload_support(protocols);
+       wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
+       wiphy_info_probe_resp_offload(capa,
+                                     tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
+
+       if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
+           drv->extended_capa == NULL) {
+               drv->extended_capa =
+                       os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+               if (drv->extended_capa) {
+                       os_memcpy(drv->extended_capa,
+                                 nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+                                 nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+                       drv->extended_capa_len =
+                               nla_len(tb[NL80211_ATTR_EXT_CAPA]);
+               }
+               drv->extended_capa_mask =
+                       os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+               if (drv->extended_capa_mask) {
+                       os_memcpy(drv->extended_capa_mask,
+                                 nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+                                 nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+               } else {
+                       os_free(drv->extended_capa);
+                       drv->extended_capa = NULL;
+                       drv->extended_capa_len = 0;
+               }
        }
 
        return NL_SKIP;
@@ -2544,22 +3128,56 @@ broken_combination:
 static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
                                       struct wiphy_info_data *info)
 {
+       u32 feat;
        struct nl_msg *msg;
 
        os_memset(info, 0, sizeof(*info));
        info->capa = &drv->capa;
+       info->drv = drv;
 
        msg = nlmsg_alloc();
        if (!msg)
                return -1;
 
-       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
+       feat = get_nl80211_protocol_features(drv);
+       if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+               nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_WIPHY);
+       else
+               nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
 
+       NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
 
-       if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0)
-               return 0;
-       msg = NULL;
+       if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
+               return -1;
+
+       if (info->auth_supported)
+               drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
+       else if (!info->connect_supported) {
+               wpa_printf(MSG_INFO, "nl80211: Driver does not support "
+                          "authentication/association or connect commands");
+               info->error = 1;
+       }
+
+       if (info->p2p_go_supported && info->p2p_client_supported)
+               drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
+       if (info->p2p_concurrent) {
+               wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
+                          "interface (driver advertised support)");
+               drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
+               drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+       }
+       if (info->p2p_multichan_concurrent) {
+               wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
+                          "concurrent (driver advertised support)");
+               drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
+       }
+
+       /* default to 5000 since early versions of mac80211 don't set it */
+       if (!drv->capa.max_remain_on_chan)
+               drv->capa.max_remain_on_chan = 5000;
+
+       return 0;
 nla_put_failure:
        nlmsg_free(msg);
        return -1;
@@ -2593,18 +3211,25 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
        drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
        drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
 
-       if (!info.device_ap_sme)
+       if (!info.device_ap_sme) {
                drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
 
+               /*
+                * No AP SME is currently assumed to also indicate no AP MLME
+                * in the driver/firmware.
+                */
+               drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
+       }
+
        drv->device_ap_sme = info.device_ap_sme;
        drv->poll_command_supported = info.poll_command_supported;
        drv->data_tx_status = info.data_tx_status;
 
        /*
-        * If poll command is supported mac80211 is new enough to
-        * have everything we need to not need monitor interfaces.
+        * If poll command and tx status are supported, mac80211 is new enough
+        * to have everything we need to not need monitor interfaces.
         */
-       drv->use_monitor = !info.poll_command_supported;
+       drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
 
        if (drv->device_ap_sme && drv->use_monitor) {
                /*
@@ -2826,10 +3451,7 @@ static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
        u8 data[2048];
        struct msghdr msg;
        struct iovec entry;
-       struct {
-               struct cmsghdr cm;
-               char control[512];
-       } control;
+       u8 control[512];
        struct cmsghdr *cmsg;
        int res, found_ee = 0, found_wifi = 0, acked = 0;
        union wpa_event_data event;
@@ -2926,6 +3548,8 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
        drv->ctx = ctx;
        bss = &drv->first_bss;
        bss->drv = drv;
+       bss->ctx = ctx;
+
        os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
        drv->monitor_ifidx = -1;
        drv->monitor_sock = -1;
@@ -3012,7 +3636,9 @@ static int nl80211_register_frame(struct i802_bss *bss,
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       if (nl80211_set_iface_id(msg, bss))
+               goto nla_put_failure;
+
        NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
        NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
 
@@ -3123,6 +3749,9 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
        /* WNM - BSS Transition Management Request */
        if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
                return -1;
+       /* WNM-Sleep Mode Response */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
+               return -1;
 
        return 0;
 }
@@ -3322,14 +3951,13 @@ static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
 
 /**
  * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
- * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init()
+ * @bss: Pointer to private nl80211 data from wpa_driver_nl80211_init()
  *
  * Shut down driver interface and processing of driver events. Free
  * private data buffer if one was allocated in wpa_driver_nl80211_init().
  */
-static void wpa_driver_nl80211_deinit(void *priv)
+static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
 
        bss->in_deinit = 1;
@@ -3365,7 +3993,7 @@ static void wpa_driver_nl80211_deinit(void *priv)
                struct hostapd_freq_params freq;
                os_memset(&freq, 0, sizeof(freq));
                freq.freq = drv->last_freq;
-               i802_set_freq(priv, &freq);
+               wpa_driver_nl80211_set_freq(bss, &freq);
        }
 
        if (drv->eapol_sock >= 0) {
@@ -3401,6 +4029,8 @@ static void wpa_driver_nl80211_deinit(void *priv)
        if (drv->in_interface_list)
                dl_list_del(&drv->list);
 
+       os_free(drv->extended_capa);
+       os_free(drv->extended_capa_mask);
        os_free(drv);
 }
 
@@ -3426,82 +4056,116 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 }
 
 
-/**
- * wpa_driver_nl80211_scan - Request the driver to initiate scan
- * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
- * @params: Scan parameters
- * Returns: 0 on success, -1 on failure
- */
-static int wpa_driver_nl80211_scan(void *priv,
-                                  struct wpa_driver_scan_params *params)
+static struct nl_msg *
+nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
+                   struct wpa_driver_scan_params *params, u64 *wdev_id)
 {
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       int ret = 0, timeout;
-       struct nl_msg *msg, *ssids, *freqs, *rates;
+       struct nl_msg *msg;
        size_t i;
 
-       drv->scan_for_auth = 0;
-
        msg = nlmsg_alloc();
-       ssids = nlmsg_alloc();
-       freqs = nlmsg_alloc();
-       rates = nlmsg_alloc();
-       if (!msg || !ssids || !freqs || !rates) {
-               nlmsg_free(msg);
-               nlmsg_free(ssids);
-               nlmsg_free(freqs);
-               nlmsg_free(rates);
-               return -1;
-       }
-
-       os_free(drv->filter_ssids);
-       drv->filter_ssids = params->filter_ssids;
-       params->filter_ssids = NULL;
-       drv->num_filter_ssids = params->num_filter_ssids;
-
-       nl80211_cmd(drv, msg, 0, NL80211_CMD_TRIGGER_SCAN);
+       if (!msg)
+               return NULL;
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       nl80211_cmd(drv, msg, 0, cmd);
 
-       for (i = 0; i < params->num_ssids; i++) {
-               wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
-                                 params->ssids[i].ssid,
-                                 params->ssids[i].ssid_len);
-               NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
-                       params->ssids[i].ssid);
+       if (!wdev_id)
+               NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       else
+               NLA_PUT_U64(msg, NL80211_ATTR_WDEV, *wdev_id);
+
+       if (params->num_ssids) {
+               struct nlattr *ssids;
+
+               ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
+               if (ssids == NULL)
+                       goto fail;
+               for (i = 0; i < params->num_ssids; i++) {
+                       wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
+                                         params->ssids[i].ssid,
+                                         params->ssids[i].ssid_len);
+                       if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
+                                   params->ssids[i].ssid) < 0)
+                               goto fail;
+               }
+               nla_nest_end(msg, ssids);
        }
-       if (params->num_ssids)
-               nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
 
        if (params->extra_ies) {
                wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
                            params->extra_ies, params->extra_ies_len);
-               NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
-                       params->extra_ies);
+               if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
+                           params->extra_ies) < 0)
+                       goto fail;
        }
 
        if (params->freqs) {
+               struct nlattr *freqs;
+               freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
+               if (freqs == NULL)
+                       goto fail;
                for (i = 0; params->freqs[i]; i++) {
                        wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
                                   "MHz", params->freqs[i]);
-                       NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
+                       if (nla_put_u32(msg, i + 1, params->freqs[i]) < 0)
+                               goto fail;
                }
-               nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
+               nla_nest_end(msg, freqs);
        }
 
+       os_free(drv->filter_ssids);
+       drv->filter_ssids = params->filter_ssids;
+       params->filter_ssids = NULL;
+       drv->num_filter_ssids = params->num_filter_ssids;
+
+       return msg;
+
+fail:
+nla_put_failure:
+       nlmsg_free(msg);
+       return NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_scan - Request the driver to initiate scan
+ * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_scan(struct i802_bss *bss,
+                                  struct wpa_driver_scan_params *params)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       int ret = -1, timeout;
+       struct nl_msg *msg = NULL;
+
+       wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
+       drv->scan_for_auth = 0;
+
+       msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params,
+                                 bss->wdev_id_set ? &bss->wdev_id : NULL);
+       if (!msg)
+               return -1;
+
        if (params->p2p_probe) {
+               struct nlattr *rates;
+
                wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
 
+               rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
+               if (rates == NULL)
+                       goto nla_put_failure;
+
                /*
                 * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
                 * by masking out everything else apart from the OFDM rates 6,
                 * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
                 * rates are left enabled.
                 */
-               NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
+               NLA_PUT(msg, NL80211_BAND_2GHZ, 8,
                        "\x0c\x12\x18\x24\x30\x48\x60\x6c");
-               nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates);
+               nla_nest_end(msg, rates);
 
                NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
        }
@@ -3521,7 +4185,7 @@ static int wpa_driver_nl80211_scan(void *priv,
                                    bss, NL80211_IFTYPE_STATION))
                                goto nla_put_failure;
 
-                       if (wpa_driver_nl80211_scan(drv, params)) {
+                       if (wpa_driver_nl80211_scan(bss, params)) {
                                wpa_driver_nl80211_set_mode(bss, drv->nlmode);
                                goto nla_put_failure;
                        }
@@ -3554,10 +4218,7 @@ static int wpa_driver_nl80211_scan(void *priv,
                               drv, drv->ctx);
 
 nla_put_failure:
-       nlmsg_free(ssids);
        nlmsg_free(msg);
-       nlmsg_free(freqs);
-       nlmsg_free(rates);
        return ret;
 }
 
@@ -3575,86 +4236,63 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       int ret = 0;
-       struct nl_msg *msg, *ssids, *freqs, *match_set_ssid, *match_sets;
+       int ret = -1;
+       struct nl_msg *msg;
        size_t i;
 
+       wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
+
 #ifdef ANDROID
        if (!drv->capa.sched_scan_supported)
                return android_pno_start(bss, params);
 #endif /* ANDROID */
 
-       msg = nlmsg_alloc();
-       ssids = nlmsg_alloc();
-       freqs = nlmsg_alloc();
-       if (!msg || !ssids || !freqs) {
-               nlmsg_free(msg);
-               nlmsg_free(ssids);
-               nlmsg_free(freqs);
-               return -1;
-       }
-
-       os_free(drv->filter_ssids);
-       drv->filter_ssids = params->filter_ssids;
-       params->filter_ssids = NULL;
-       drv->num_filter_ssids = params->num_filter_ssids;
-
-       nl80211_cmd(drv, msg, 0, NL80211_CMD_START_SCHED_SCAN);
-
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params,
+                                 bss->wdev_id_set ? &bss->wdev_id : NULL);
+       if (!msg)
+               goto nla_put_failure;
 
        NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval);
 
-       if (drv->num_filter_ssids &&
-           (int) drv->num_filter_ssids <= drv->capa.max_match_sets) {
-               match_sets = nlmsg_alloc();
+       if ((drv->num_filter_ssids &&
+           (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
+           params->filter_rssi) {
+               struct nlattr *match_sets;
+               match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
+               if (match_sets == NULL)
+                       goto nla_put_failure;
 
                for (i = 0; i < drv->num_filter_ssids; i++) {
+                       struct nlattr *match_set_ssid;
                        wpa_hexdump_ascii(MSG_MSGDUMP,
                                          "nl80211: Sched scan filter SSID",
                                          drv->filter_ssids[i].ssid,
                                          drv->filter_ssids[i].ssid_len);
 
-                       match_set_ssid = nlmsg_alloc();
-                       nla_put(match_set_ssid,
-                               NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+                       match_set_ssid = nla_nest_start(msg, i + 1);
+                       if (match_set_ssid == NULL)
+                               goto nla_put_failure;
+                       NLA_PUT(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
                                drv->filter_ssids[i].ssid_len,
                                drv->filter_ssids[i].ssid);
 
-                       nla_put_nested(match_sets, i + 1, match_set_ssid);
-
-                       nlmsg_free(match_set_ssid);
+                       nla_nest_end(msg, match_set_ssid);
                }
 
-               nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
-                              match_sets);
-               nlmsg_free(match_sets);
-       }
-
-       for (i = 0; i < params->num_ssids; i++) {
-               wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan SSID",
-                                 params->ssids[i].ssid,
-                                 params->ssids[i].ssid_len);
-               NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
-                       params->ssids[i].ssid);
-       }
-       if (params->num_ssids)
-               nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
-
-       if (params->extra_ies) {
-               wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan extra IEs",
-                                 params->extra_ies, params->extra_ies_len);
-               NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
-                       params->extra_ies);
-       }
-
-       if (params->freqs) {
-               for (i = 0; params->freqs[i]; i++) {
-                       wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
-                                  "MHz", params->freqs[i]);
-                       NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
+               if (params->filter_rssi) {
+                       struct nlattr *match_set_rssi;
+                       match_set_rssi = nla_nest_start(msg, 0);
+                       if (match_set_rssi == NULL)
+                               goto nla_put_failure;
+                       NLA_PUT_U32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+                                   params->filter_rssi);
+                       wpa_printf(MSG_MSGDUMP,
+                                  "nl80211: Sched scan RSSI filter %d dBm",
+                                  params->filter_rssi);
+                       nla_nest_end(msg, match_set_rssi);
                }
-               nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
+
+               nla_nest_end(msg, match_sets);
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -3672,9 +4310,7 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
                   "scan interval %d msec", ret, interval);
 
 nla_put_failure:
-       nlmsg_free(ssids);
        nlmsg_free(msg);
-       nlmsg_free(freqs);
        return ret;
 }
 
@@ -3922,8 +4558,8 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
                return NL_SKIP;
        }
 
-       tmp = os_realloc(res->res,
-                        (res->num + 1) * sizeof(struct wpa_scan_res *));
+       tmp = os_realloc_array(res->res, res->num + 1,
+                              sizeof(struct wpa_scan_res *));
        if (tmp == NULL) {
                os_free(r);
                return NL_SKIP;
@@ -4079,21 +4715,20 @@ static void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
 }
 
 
-static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
+static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
                                      enum wpa_alg alg, const u8 *addr,
                                      int key_idx, int set_tx,
                                      const u8 *seq, size_t seq_len,
                                      const u8 *key, size_t key_len)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ifindex = if_nametoindex(ifname);
        struct nl_msg *msg;
        int ret;
 
-       wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d "
+       wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
                   "set_tx=%d seq_len=%lu key_len=%lu",
-                  __func__, ifindex, alg, addr, key_idx, set_tx,
+                  __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
                   (unsigned long) seq_len, (unsigned long) key_len);
 #ifdef CONFIG_TDLS
        if (key_idx == -1)
@@ -4126,10 +4761,22 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
                        NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
                                    WLAN_CIPHER_SUITE_CCMP);
                        break;
+               case WPA_ALG_GCMP:
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+                                   WLAN_CIPHER_SUITE_GCMP);
+                       break;
                case WPA_ALG_IGTK:
                        NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
                                    WLAN_CIPHER_SUITE_AES_CMAC);
                        break;
+               case WPA_ALG_SMS4:
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+                                   WLAN_CIPHER_SUITE_SMS4);
+                       break;
+               case WPA_ALG_KRK:
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+                                   WLAN_CIPHER_SUITE_KRK);
+                       break;
                default:
                        wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
                                   "algorithm %d", __func__, alg);
@@ -4151,18 +4798,15 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
                                    NL80211_KEYTYPE_GROUP);
                }
        } else if (addr && is_broadcast_ether_addr(addr)) {
-               struct nl_msg *types;
-               int err;
+               struct nlattr *types;
+
                wpa_printf(MSG_DEBUG, "   broadcast key");
-               types = nlmsg_alloc();
+
+               types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
                if (!types)
                        goto nla_put_failure;
-               NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
-               err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
-                                    types);
-               nlmsg_free(types);
-               if (err)
-                       goto nla_put_failure;
+               NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+               nla_nest_end(msg, types);
        }
        NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
@@ -4196,29 +4840,21 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
        else
                NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
        if (addr && is_broadcast_ether_addr(addr)) {
-               struct nl_msg *types;
-               int err;
-               types = nlmsg_alloc();
+               struct nlattr *types;
+
+               types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
                if (!types)
                        goto nla_put_failure;
-               NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
-               err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
-                                    types);
-               nlmsg_free(types);
-               if (err)
-                       goto nla_put_failure;
+               NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+               nla_nest_end(msg, types);
        } else if (addr) {
-               struct nl_msg *types;
-               int err;
-               types = nlmsg_alloc();
+               struct nlattr *types;
+
+               types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
                if (!types)
                        goto nla_put_failure;
-               NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST);
-               err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
-                                    types);
-               nlmsg_free(types);
-               if (err)
-                       goto nla_put_failure;
+               NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST);
+               nla_nest_end(msg, types);
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -4266,6 +4902,9 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
        case WPA_ALG_CCMP:
                NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP);
                break;
+       case WPA_ALG_GCMP:
+               NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_GCMP);
+               break;
        case WPA_ALG_IGTK:
                NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
                            WLAN_CIPHER_SUITE_AES_CMAC);
@@ -4364,7 +5003,8 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
        NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
-       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+       if (addr)
+               NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
        if (local_state_change)
                NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
 
@@ -4385,26 +5025,26 @@ nla_put_failure:
 
 
 static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
-                                        const u8 *addr, int reason_code)
+                                        int reason_code)
 {
-       wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
-                  __func__, MAC2STR(addr), reason_code);
-       drv->associated = 0;
-       return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISCONNECT,
+       wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
+       nl80211_mark_disconnected(drv);
+       drv->ignore_next_local_disconnect = 0;
+       /* Disconnect command doesn't need BSSID - it uses cached value */
+       return wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
                                       reason_code, 0);
 }
 
 
-static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
-                                            int reason_code)
+static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
+                                            const u8 *addr, int reason_code)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
-               return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
+               return wpa_driver_nl80211_disconnect(drv, reason_code);
        wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
                   __func__, MAC2STR(addr), reason_code);
-       drv->associated = 0;
+       nl80211_mark_disconnected(drv);
        if (drv->nlmode == NL80211_IFTYPE_ADHOC)
                return nl80211_leave_ibss(drv);
        return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
@@ -4412,20 +5052,6 @@ static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
 }
 
 
-static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
-                                          int reason_code)
-{
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
-               return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
-       wpa_printf(MSG_DEBUG, "%s", __func__);
-       drv->associated = 0;
-       return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISASSOCIATE,
-                                      reason_code, 0);
-}
-
-
 static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
                                     struct wpa_driver_auth_params *params)
 {
@@ -4473,9 +5099,8 @@ static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
 
 
 static int wpa_driver_nl80211_authenticate(
-       void *priv, struct wpa_driver_auth_params *params)
+       struct i802_bss *bss, struct wpa_driver_auth_params *params)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ret = -1, i;
        struct nl_msg *msg;
@@ -4487,13 +5112,17 @@ static int wpa_driver_nl80211_authenticate(
        is_retry = drv->retry_auth;
        drv->retry_auth = 0;
 
-       drv->associated = 0;
+       nl80211_mark_disconnected(drv);
        os_memset(drv->auth_bssid, 0, ETH_ALEN);
+       if (params->bssid)
+               os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
+       else
+               os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
        /* FIX: IBSS mode */
        nlmode = params->p2p ?
                NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
        if (drv->nlmode != nlmode &&
-           wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
+           wpa_driver_nl80211_set_mode(bss, nlmode) < 0)
                return -1;
 
 retry:
@@ -4509,7 +5138,7 @@ retry:
        for (i = 0; i < 4; i++) {
                if (!params->wep_key[i])
                        continue;
-               wpa_driver_nl80211_set_key(bss->ifname, priv, WPA_ALG_WEP,
+               wpa_driver_nl80211_set_key(bss->ifname, bss, WPA_ALG_WEP,
                                           NULL, i,
                                           i == params->wep_tx_keyidx, NULL, 0,
                                           params->wep_key[i],
@@ -4542,6 +5171,12 @@ retry:
        wpa_hexdump(MSG_DEBUG, "  * IEs", params->ie, params->ie_len);
        if (params->ie)
                NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie);
+       if (params->sae_data) {
+               wpa_hexdump(MSG_DEBUG, "  * SAE data", params->sae_data,
+                           params->sae_data_len);
+               NLA_PUT(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len,
+                       params->sae_data);
+       }
        if (params->auth_alg & WPA_AUTH_ALG_OPEN)
                type = NL80211_AUTHTYPE_OPEN_SYSTEM;
        else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
@@ -4550,6 +5185,8 @@ retry:
                type = NL80211_AUTHTYPE_NETWORK_EAP;
        else if (params->auth_alg & WPA_AUTH_ALG_FT)
                type = NL80211_AUTHTYPE_FT;
+       else if (params->auth_alg & WPA_AUTH_ALG_SAE)
+               type = NL80211_AUTHTYPE_SAE;
        else
                goto nla_put_failure;
        wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
@@ -4678,17 +5315,91 @@ static int wpa_driver_nl80211_authenticate_retry(
 struct phy_info_arg {
        u16 *num_modes;
        struct hostapd_hw_modes *modes;
+       int last_mode, last_chan_idx;
 };
 
-static int phy_info_handler(struct nl_msg *msg, void *arg)
+static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa,
+                            struct nlattr *ampdu_factor,
+                            struct nlattr *ampdu_density,
+                            struct nlattr *mcs_set)
 {
-       struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
-       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-       struct phy_info_arg *phy_info = arg;
+       if (capa)
+               mode->ht_capab = nla_get_u16(capa);
 
-       struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+       if (ampdu_factor)
+               mode->a_mpdu_params |= nla_get_u8(ampdu_factor) & 0x03;
 
-       struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
+       if (ampdu_density)
+               mode->a_mpdu_params |= nla_get_u8(ampdu_density) << 2;
+
+       if (mcs_set && nla_len(mcs_set) >= 16) {
+               u8 *mcs;
+               mcs = nla_data(mcs_set);
+               os_memcpy(mode->mcs_set, mcs, 16);
+       }
+}
+
+
+static void phy_info_vht_capa(struct hostapd_hw_modes *mode,
+                             struct nlattr *capa,
+                             struct nlattr *mcs_set)
+{
+       if (capa)
+               mode->vht_capab = nla_get_u32(capa);
+
+       if (mcs_set && nla_len(mcs_set) >= 8) {
+               u8 *mcs;
+               mcs = nla_data(mcs_set);
+               os_memcpy(mode->vht_mcs_set, mcs, 8);
+       }
+}
+
+
+static void phy_info_freq(struct hostapd_hw_modes *mode,
+                         struct hostapd_channel_data *chan,
+                         struct nlattr *tb_freq[])
+{
+       u8 channel;
+       chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+       chan->flag = 0;
+       if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
+               chan->chan = channel;
+
+       if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+               chan->flag |= HOSTAPD_CHAN_DISABLED;
+       if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
+               chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN;
+       if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
+               chan->flag |= HOSTAPD_CHAN_NO_IBSS;
+       if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
+               chan->flag |= HOSTAPD_CHAN_RADAR;
+
+       if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
+           !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+               chan->max_tx_power = nla_get_u32(
+                       tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
+       if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
+               enum nl80211_dfs_state state =
+                       nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
+
+               switch (state) {
+               case NL80211_DFS_USABLE:
+                       chan->flag |= HOSTAPD_CHAN_DFS_USABLE;
+                       break;
+               case NL80211_DFS_AVAILABLE:
+                       chan->flag |= HOSTAPD_CHAN_DFS_AVAILABLE;
+                       break;
+               case NL80211_DFS_UNAVAILABLE:
+                       chan->flag |= HOSTAPD_CHAN_DFS_UNAVAILABLE;
+                       break;
+               }
+       }
+}
+
+
+static int phy_info_freqs(struct phy_info_arg *phy_info,
+                         struct hostapd_hw_modes *mode, struct nlattr *tb)
+{
        static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
                [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
                [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
@@ -4696,169 +5407,189 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
                [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
                [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
                [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
+               [NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 },
        };
-
-       struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
-       static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
-               [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
-               [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG },
-       };
-
-       struct nlattr *nl_band;
+       int new_channels = 0;
+       struct hostapd_channel_data *channel;
+       struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
        struct nlattr *nl_freq;
-       struct nlattr *nl_rate;
-       int rem_band, rem_freq, rem_rate;
-       struct hostapd_hw_modes *mode;
-       int idx, mode_is_set;
+       int rem_freq, idx;
 
-       nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-                 genlmsg_attrlen(gnlh, 0), NULL);
+       if (tb == NULL)
+               return NL_OK;
 
-       if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+       nla_for_each_nested(nl_freq, tb, rem_freq) {
+               nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+                         nla_data(nl_freq), nla_len(nl_freq), freq_policy);
+               if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+                       continue;
+               new_channels++;
+       }
+
+       channel = os_realloc_array(mode->channels,
+                                  mode->num_channels + new_channels,
+                                  sizeof(struct hostapd_channel_data));
+       if (!channel)
                return NL_SKIP;
 
-       nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
-               mode = os_realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode));
-               if (!mode)
-                       return NL_SKIP;
-               phy_info->modes = mode;
+       mode->channels = channel;
+       mode->num_channels += new_channels;
 
-               mode_is_set = 0;
+       idx = phy_info->last_chan_idx;
 
-               mode = &phy_info->modes[*(phy_info->num_modes)];
-               memset(mode, 0, sizeof(*mode));
-               mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
-               *(phy_info->num_modes) += 1;
+       nla_for_each_nested(nl_freq, tb, rem_freq) {
+               nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+                         nla_data(nl_freq), nla_len(nl_freq), freq_policy);
+               if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+                       continue;
+               phy_info_freq(mode, &mode->channels[idx], tb_freq);
+               idx++;
+       }
+       phy_info->last_chan_idx = idx;
 
-               nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
-                         nla_len(nl_band), NULL);
+       return NL_OK;
+}
 
-               if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
-                       mode->ht_capab = nla_get_u16(
-                               tb_band[NL80211_BAND_ATTR_HT_CAPA]);
-               }
 
-               if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) {
-                       mode->a_mpdu_params |= nla_get_u8(
-                               tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) &
-                               0x03;
-               }
+static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
+{
+       static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
+               [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
+               [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] =
+               { .type = NLA_FLAG },
+       };
+       struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
+       struct nlattr *nl_rate;
+       int rem_rate, idx;
 
-               if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) {
-                       mode->a_mpdu_params |= nla_get_u8(
-                               tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) <<
-                               2;
-               }
+       if (tb == NULL)
+               return NL_OK;
 
-               if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] &&
-                   nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])) {
-                       u8 *mcs;
-                       mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
-                       os_memcpy(mode->mcs_set, mcs, 16);
-               }
+       nla_for_each_nested(nl_rate, tb, rem_rate) {
+               nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
+                         nla_data(nl_rate), nla_len(nl_rate),
+                         rate_policy);
+               if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+                       continue;
+               mode->num_rates++;
+       }
 
-               nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
-                       nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
-                                 nla_len(nl_freq), freq_policy);
-                       if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
-                               continue;
-                       mode->num_channels++;
-               }
+       mode->rates = os_calloc(mode->num_rates, sizeof(int));
+       if (!mode->rates)
+               return NL_SKIP;
 
-               mode->channels = os_zalloc(mode->num_channels * sizeof(struct hostapd_channel_data));
-               if (!mode->channels)
-                       return NL_SKIP;
+       idx = 0;
 
-               idx = 0;
+       nla_for_each_nested(nl_rate, tb, rem_rate) {
+               nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
+                         nla_data(nl_rate), nla_len(nl_rate),
+                         rate_policy);
+               if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+                       continue;
+               mode->rates[idx] = nla_get_u32(
+                       tb_rate[NL80211_BITRATE_ATTR_RATE]);
+               idx++;
+       }
 
-               nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
-                       nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
-                                 nla_len(nl_freq), freq_policy);
-                       if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
-                               continue;
+       return NL_OK;
+}
 
-                       mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
-                       mode->channels[idx].flag = 0;
 
-                       if (!mode_is_set) {
-                               /* crude heuristic */
-                               if (mode->channels[idx].freq < 4000)
-                                       mode->mode = HOSTAPD_MODE_IEEE80211B;
-                               else
-                                       mode->mode = HOSTAPD_MODE_IEEE80211A;
-                               mode_is_set = 1;
-                       }
+static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
+{
+       struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+       struct hostapd_hw_modes *mode;
+       int ret;
 
-                       /* crude heuristic */
-                       if (mode->channels[idx].freq < 4000)
-                               if (mode->channels[idx].freq == 2484)
-                                       mode->channels[idx].chan = 14;
-                               else
-                                       mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5;
-                       else
-                               mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000;
-
-                       if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
-                               mode->channels[idx].flag |=
-                                       HOSTAPD_CHAN_DISABLED;
-                       if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
-                               mode->channels[idx].flag |=
-                                       HOSTAPD_CHAN_PASSIVE_SCAN;
-                       if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
-                               mode->channels[idx].flag |=
-                                       HOSTAPD_CHAN_NO_IBSS;
-                       if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
-                               mode->channels[idx].flag |=
-                                       HOSTAPD_CHAN_RADAR;
-
-                       if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
-                           !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
-                               mode->channels[idx].max_tx_power =
-                                       nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
-
-                       idx++;
-               }
+       if (phy_info->last_mode != nl_band->nla_type) {
+               mode = os_realloc_array(phy_info->modes,
+                                       *phy_info->num_modes + 1,
+                                       sizeof(*mode));
+               if (!mode)
+                       return NL_SKIP;
+               phy_info->modes = mode;
 
-               nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
-                       nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
-                                 nla_len(nl_rate), rate_policy);
-                       if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
-                               continue;
-                       mode->num_rates++;
-               }
+               mode = &phy_info->modes[*(phy_info->num_modes)];
+               os_memset(mode, 0, sizeof(*mode));
+               mode->mode = NUM_HOSTAPD_MODES;
+               mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
+               *(phy_info->num_modes) += 1;
+               phy_info->last_mode = nl_band->nla_type;
+               phy_info->last_chan_idx = 0;
+       } else
+               mode = &phy_info->modes[*(phy_info->num_modes) - 1];
+
+       nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
+                 nla_len(nl_band), NULL);
+
+       phy_info_ht_capa(mode, tb_band[NL80211_BAND_ATTR_HT_CAPA],
+                        tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR],
+                        tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY],
+                        tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
+       phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
+                         tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
+       ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
+       if (ret != NL_OK)
+               return ret;
+       ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
+       if (ret != NL_OK)
+               return ret;
 
-               mode->rates = os_zalloc(mode->num_rates * sizeof(int));
-               if (!mode->rates)
-                       return NL_SKIP;
+       return NL_OK;
+}
 
-               idx = 0;
 
-               nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
-                       nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
-                                 nla_len(nl_rate), rate_policy);
-                       if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
-                               continue;
-                       mode->rates[idx] = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]);
+static int phy_info_handler(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct phy_info_arg *phy_info = arg;
+       struct nlattr *nl_band;
+       int rem_band;
 
-                       /* crude heuristic */
-                       if (mode->mode == HOSTAPD_MODE_IEEE80211B &&
-                           mode->rates[idx] > 200)
-                               mode->mode = HOSTAPD_MODE_IEEE80211G;
+       nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
 
-                       idx++;
-               }
+       if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+               return NL_SKIP;
+
+       nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band)
+       {
+               int res = phy_info_band(phy_info, nl_band);
+               if (res != NL_OK)
+                       return res;
        }
 
        return NL_SKIP;
 }
 
+
 static struct hostapd_hw_modes *
-wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
+wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
+                                    u16 *num_modes)
 {
        u16 m;
        struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
        int i, mode11g_idx = -1;
 
+       /* heuristic to set up modes */
+       for (m = 0; m < *num_modes; m++) {
+               if (!modes[m].num_channels)
+                       continue;
+               if (modes[m].channels[0].freq < 4000) {
+                       modes[m].mode = HOSTAPD_MODE_IEEE80211B;
+                       for (i = 0; i < modes[m].num_rates; i++) {
+                               if (modes[m].rates[i] > 200) {
+                                       modes[m].mode = HOSTAPD_MODE_IEEE80211G;
+                                       break;
+                               }
+                       }
+               } else if (modes[m].channels[0].freq > 50000)
+                       modes[m].mode = HOSTAPD_MODE_IEEE80211AD;
+               else
+                       modes[m].mode = HOSTAPD_MODE_IEEE80211A;
+       }
+
        /* If only 802.11g mode is included, use it to construct matching
         * 802.11b mode data. */
 
@@ -4872,7 +5603,7 @@ wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
        if (mode11g_idx < 0)
                return modes; /* 2.4 GHz band not supported at all */
 
-       nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes));
+       nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
        if (nmodes == NULL)
                return modes; /* Could not add 802.11b mode */
 
@@ -5076,12 +5807,14 @@ static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv,
 static struct hostapd_hw_modes *
 wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
 {
+       u32 feat;
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        struct phy_info_arg result = {
                .num_modes = num_modes,
                .modes = NULL,
+               .last_mode = -1,
        };
 
        *num_modes = 0;
@@ -5091,13 +5824,19 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
        if (!msg)
                return NULL;
 
-       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
+       feat = get_nl80211_protocol_features(drv);
+       if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+               nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_WIPHY);
+       else
+               nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
 
+       NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
        if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
                nl80211_set_ht40_flags(drv, &result);
-               return wpa_driver_nl80211_add_11b(result.modes, num_modes);
+               return wpa_driver_nl80211_postprocess_modes(result.modes,
+                                                           num_modes);
        }
        msg = NULL;
  nla_put_failure:
@@ -5152,7 +5891,7 @@ static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv,
 
        if (noack)
                txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
-       *(le16 *) &rtap_hdr[12] = host_to_le16(txflags);
+       WPA_PUT_LE16(&rtap_hdr[12], txflags);
 
        res = sendmsg(drv->monitor_sock, &msg, 0);
        if (res < 0) {
@@ -5184,12 +5923,11 @@ static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
 }
 
 
-static int wpa_driver_nl80211_send_mlme_freq(struct i802_bss *bss,
-                                            const u8 *data,
-                                            size_t data_len, int noack,
-                                            unsigned int freq, int no_cck,
-                                            int offchanok,
-                                            unsigned int wait_time)
+static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
+                                       size_t data_len, int noack,
+                                       unsigned int freq, int no_cck,
+                                       int offchanok,
+                                       unsigned int wait_time)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct ieee80211_mgmt *mgmt;
@@ -5217,7 +5955,9 @@ static int wpa_driver_nl80211_send_mlme_freq(struct i802_bss *bss,
        if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
                if (freq == 0)
                        freq = bss->freq;
-               return nl80211_send_frame_cmd(bss, freq, 0,
+               return nl80211_send_frame_cmd(bss, freq,
+                                             (int) freq == bss->freq ? 0 :
+                                             wait_time,
                                              data, data_len,
                                              &drv->send_action_cookie,
                                              no_cck, noack, offchanok);
@@ -5243,15 +5983,6 @@ static int wpa_driver_nl80211_send_mlme_freq(struct i802_bss *bss,
 }
 
 
-static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
-                                       size_t data_len, int noack)
-{
-       struct i802_bss *bss = priv;
-       return wpa_driver_nl80211_send_mlme_freq(bss, data, data_len, noack,
-                                                0, 0, 0, 0);
-}
-
-
 static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
                           int slot, int ht_opmode, int ap_isolate,
                           int *basic_rates)
@@ -5297,6 +6028,60 @@ static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
 }
 
 
+static int wpa_driver_nl80211_set_acl(void *priv,
+                                     struct hostapd_acl_params *params)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       struct nlattr *acl;
+       unsigned int i;
+       int ret = 0;
+
+       if (!(drv->capa.max_acl_mac_addrs))
+               return -ENOTSUP;
+
+       if (params->num_mac_acl > drv->capa.max_acl_mac_addrs)
+               return -ENOTSUP;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
+                  params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_MAC_ACL);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
+                   NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
+                   NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED);
+
+       acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS);
+       if (acl == NULL)
+               goto nla_put_failure;
+
+       for (i = 0; i < params->num_mac_acl; i++)
+               NLA_PUT(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr);
+
+       nla_nest_end(msg, acl);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
+                          ret, strerror(-ret));
+       }
+
+nla_put_failure:
+       nlmsg_free(msg);
+
+       return ret;
+}
+
+
 static int wpa_driver_nl80211_set_ap(void *priv,
                                     struct wpa_driver_ap_params *params)
 {
@@ -5323,32 +6108,49 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                cmd = NL80211_CMD_SET_BEACON;
 
        nl80211_cmd(drv, msg, 0, cmd);
+       wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
+                   params->head, params->head_len);
        NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head);
+       wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail",
+                   params->tail, params->tail_len);
        NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail);
+       wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", ifindex);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+       wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
        NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int);
+       wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
        NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period);
+       wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
+                         params->ssid, params->ssid_len);
        NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
                params->ssid);
-       if (params->proberesp && params->proberesp_len)
+       if (params->proberesp && params->proberesp_len) {
+               wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)",
+                           params->proberesp, params->proberesp_len);
                NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
                        params->proberesp);
+       }
        switch (params->hide_ssid) {
        case NO_SSID_HIDING:
+               wpa_printf(MSG_DEBUG, "nl80211: hidden SSID not in use");
                NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
                            NL80211_HIDDEN_SSID_NOT_IN_USE);
                break;
        case HIDDEN_SSID_ZERO_LEN:
+               wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero len");
                NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
                            NL80211_HIDDEN_SSID_ZERO_LEN);
                break;
        case HIDDEN_SSID_ZERO_CONTENTS:
+               wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero contents");
                NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
                            NL80211_HIDDEN_SSID_ZERO_CONTENTS);
                break;
        }
+       wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy);
        if (params->privacy)
                NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+       wpa_printf(MSG_DEBUG, "nl80211: auth_algs=0x%x", params->auth_algs);
        if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
            (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
                /* Leave out the attribute */
@@ -5359,6 +6161,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
                            NL80211_AUTHTYPE_OPEN_SYSTEM);
 
+       wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version);
        ver = 0;
        if (params->wpa_version & WPA_PROTO_WPA)
                ver |= NL80211_WPA_VERSION_1;
@@ -5367,6 +6170,8 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        if (ver)
                NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
 
+       wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
+                  params->key_mgmt_suites);
        num_suites = 0;
        if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
                suites[num_suites++] = WLAN_AKM_SUITE_8021X;
@@ -5381,9 +6186,13 @@ static int wpa_driver_nl80211_set_ap(void *priv,
            params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
                NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
 
+       wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
+                  params->pairwise_ciphers);
        num_suites = 0;
        if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
                suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
+       if (params->pairwise_ciphers & WPA_CIPHER_GCMP)
+               suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP;
        if (params->pairwise_ciphers & WPA_CIPHER_TKIP)
                suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
        if (params->pairwise_ciphers & WPA_CIPHER_WEP104)
@@ -5395,11 +6204,17 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                        num_suites * sizeof(u32), suites);
        }
 
+       wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
+                  params->group_cipher);
        switch (params->group_cipher) {
        case WPA_CIPHER_CCMP:
                NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
                            WLAN_CIPHER_SUITE_CCMP);
                break;
+       case WPA_CIPHER_GCMP:
+               NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+                           WLAN_CIPHER_SUITE_GCMP);
+               break;
        case WPA_CIPHER_TKIP:
                NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
                            WLAN_CIPHER_SUITE_TKIP);
@@ -5415,21 +6230,29 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        }
 
        if (params->beacon_ies) {
+               wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
+                               params->beacon_ies);
                NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
                        wpabuf_head(params->beacon_ies));
        }
        if (params->proberesp_ies) {
+               wpa_hexdump_buf(MSG_DEBUG, "nl80211: proberesp_ies",
+                               params->proberesp_ies);
                NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
                        wpabuf_len(params->proberesp_ies),
                        wpabuf_head(params->proberesp_ies));
        }
        if (params->assocresp_ies) {
+               wpa_hexdump_buf(MSG_DEBUG, "nl80211: assocresp_ies",
+                               params->assocresp_ies);
                NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP,
                        wpabuf_len(params->assocresp_ies),
                        wpabuf_head(params->assocresp_ies));
        }
 
        if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)  {
+               wpa_printf(MSG_DEBUG, "nl80211: ap_max_inactivity=%d",
+                          params->ap_max_inactivity);
                NLA_PUT_U16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
                            params->ap_max_inactivity);
        }
@@ -5452,16 +6275,16 @@ static int wpa_driver_nl80211_set_ap(void *priv,
 
 
 static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
-                                      int freq, int ht_enabled,
-                                      int sec_channel_offset)
+                                      struct hostapd_freq_params *freq)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret;
 
-       wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d "
-                  "sec_channel_offset=%d)",
-                  freq, ht_enabled, sec_channel_offset);
+       wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d,"
+                  " bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
+                  freq->freq, freq->ht_enabled, freq->vht_enabled,
+                  freq->bandwidth, freq->center_freq1, freq->center_freq2);
        msg = nlmsg_alloc();
        if (!msg)
                return -1;
@@ -5469,9 +6292,38 @@ static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
        nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
-       if (ht_enabled) {
-               switch (sec_channel_offset) {
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
+       if (freq->vht_enabled) {
+               switch (freq->bandwidth) {
+               case 20:
+                       NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+                                   NL80211_CHAN_WIDTH_20);
+                       break;
+               case 40:
+                       NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+                                   NL80211_CHAN_WIDTH_40);
+                       break;
+               case 80:
+                       if (freq->center_freq2)
+                               NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+                                           NL80211_CHAN_WIDTH_80P80);
+                       else
+                               NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+                                           NL80211_CHAN_WIDTH_80);
+                       break;
+               case 160:
+                       NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+                                   NL80211_CHAN_WIDTH_160);
+                       break;
+               default:
+                       return -1;
+               }
+               NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
+               if (freq->center_freq2)
+                       NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2,
+                                   freq->center_freq2);
+       } else if (freq->ht_enabled) {
+               switch (freq->sec_channel_offset) {
                case -1:
                        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
                                    NL80211_CHAN_HT40MINUS);
@@ -5490,11 +6342,11 @@ static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret == 0) {
-               bss->freq = freq;
+               bss->freq = freq->freq;
                return 0;
        }
        wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
-                  "%d (%s)", freq, ret, strerror(-ret));
+                  "%d (%s)", freq->freq, ret, strerror(-ret));
 nla_put_failure:
        nlmsg_free(msg);
        return -1;
@@ -5525,7 +6377,7 @@ static int wpa_driver_nl80211_sta_add(void *priv,
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct nl_msg *msg, *wme = NULL;
+       struct nl_msg *msg;
        struct nl80211_sta_flag_update upd;
        int ret = -ENOBUFS;
 
@@ -5537,6 +6389,8 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        if (!msg)
                return -ENOMEM;
 
+       wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
+                  params->set ? "Set" : "Add", MAC2STR(params->addr));
        nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
                    NL80211_CMD_NEW_STATION);
 
@@ -5544,33 +6398,77 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
        NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
                params->supp_rates);
+       wpa_hexdump(MSG_DEBUG, "  * supported rates", params->supp_rates,
+                   params->supp_rates_len);
        if (!params->set) {
-               NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+               if (params->aid) {
+                       wpa_printf(MSG_DEBUG, "  * aid=%u", params->aid);
+                       NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+               } else {
+                       /*
+                        * cfg80211 validates that AID is non-zero, so we have
+                        * to make this a non-zero value for the TDLS case where
+                        * a dummy STA entry is used for now.
+                        */
+                       wpa_printf(MSG_DEBUG, "  * aid=1 (TDLS workaround)");
+                       NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, 1);
+               }
+               wpa_printf(MSG_DEBUG, "  * listen_interval=%u",
+                          params->listen_interval);
                NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
                            params->listen_interval);
+       } else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) {
+               wpa_printf(MSG_DEBUG, "  * peer_aid=%u", params->aid);
+               NLA_PUT_U16(msg, NL80211_ATTR_PEER_AID, params->aid);
        }
        if (params->ht_capabilities) {
+               wpa_hexdump(MSG_DEBUG, "  * ht_capabilities",
+                           (u8 *) params->ht_capabilities,
+                           sizeof(*params->ht_capabilities));
                NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
                        sizeof(*params->ht_capabilities),
                        params->ht_capabilities);
        }
 
+       if (params->vht_capabilities) {
+               wpa_hexdump(MSG_DEBUG, "  * vht_capabilities",
+                           (u8 *) params->vht_capabilities,
+                           sizeof(*params->vht_capabilities));
+               NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY,
+                       sizeof(*params->vht_capabilities),
+                       params->vht_capabilities);
+       }
+
+       wpa_printf(MSG_DEBUG, "  * capability=0x%x", params->capability);
+       NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability);
+
+       if (params->ext_capab) {
+               wpa_hexdump(MSG_DEBUG, "  * ext_capab",
+                           params->ext_capab, params->ext_capab_len);
+               NLA_PUT(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
+                       params->ext_capab_len, params->ext_capab);
+       }
+
        os_memset(&upd, 0, sizeof(upd));
        upd.mask = sta_flags_nl80211(params->flags);
        upd.set = upd.mask;
+       wpa_printf(MSG_DEBUG, "  * flags set=0x%x mask=0x%x",
+                  upd.set, upd.mask);
        NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
 
        if (params->flags & WPA_STA_WMM) {
-               wme = nlmsg_alloc();
+               struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
+
                if (!wme)
                        goto nla_put_failure;
 
-               NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
+               wpa_printf(MSG_DEBUG, "  * qosinfo=0x%x", params->qosinfo);
+               NLA_PUT_U8(msg, NL80211_STA_WME_UAPSD_QUEUES,
                                params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
-               NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
-                               (params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) &
+               NLA_PUT_U8(msg, NL80211_STA_WME_MAX_SP,
+                               (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
                                WMM_QOSINFO_STA_SP_MASK);
-               nla_put_nested(msg, NL80211_ATTR_STA_WME, wme);
+               nla_nest_end(msg, wme);
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -5582,15 +6480,13 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        if (ret == -EEXIST)
                ret = 0;
  nla_put_failure:
-       nlmsg_free(wme);
        nlmsg_free(msg);
        return ret;
 }
 
 
-static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
+static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret;
@@ -5650,12 +6546,20 @@ 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:
                return "P2P_GO";
+       case NL80211_IFTYPE_P2P_DEVICE:
+               return "P2P_DEVICE";
        default:
                return "unknown";
        }
@@ -5665,9 +6569,11 @@ static const char * nl80211_iftype_str(enum nl80211_iftype mode)
 static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                                     const char *ifname,
                                     enum nl80211_iftype iftype,
-                                    const u8 *addr, int wds)
+                                    const u8 *addr, int wds,
+                                    int (*handler)(struct nl_msg *, void *),
+                                    void *arg)
 {
-       struct nl_msg *msg, *flags = NULL;
+       struct nl_msg *msg;
        int ifidx;
        int ret = -ENOBUFS;
 
@@ -5684,25 +6590,20 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
        NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
 
        if (iftype == NL80211_IFTYPE_MONITOR) {
-               int err;
+               struct nlattr *flags;
 
-               flags = nlmsg_alloc();
+               flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
                if (!flags)
                        goto nla_put_failure;
 
-               NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
+               NLA_PUT_FLAG(msg, NL80211_MNTR_FLAG_COOK_FRAMES);
 
-               err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
-
-               nlmsg_free(flags);
-
-               if (err)
-                       goto nla_put_failure;
+               nla_nest_end(msg, flags);
        } else if (wds) {
                NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
        }
 
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       ret = send_and_recv_msgs(drv, msg, handler, arg);
        msg = NULL;
        if (ret) {
  nla_put_failure:
@@ -5712,6 +6613,13 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                return ret;
        }
 
+       if (iftype == NL80211_IFTYPE_P2P_DEVICE) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: New P2P Device interface %s created",
+                          ifname);
+               return 0;
+       }
+
        ifidx = if_nametoindex(ifname);
        wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
                   ifname, ifidx);
@@ -5734,11 +6642,14 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
 
 static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
                                const char *ifname, enum nl80211_iftype iftype,
-                               const u8 *addr, int wds)
+                               const u8 *addr, int wds,
+                               int (*handler)(struct nl_msg *, void *),
+                               void *arg)
 {
        int ret;
 
-       ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
+       ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler,
+                                       arg);
 
        /* if error occurred and interface exists already */
        if (ret == -ENFILE && if_nametoindex(ifname)) {
@@ -5749,10 +6660,10 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
 
                /* Try to create the interface again */
                ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
-                                               wds);
+                                               wds, handler, arg);
        }
 
-       if (ret >= 0 && is_p2p_interface(iftype))
+       if (ret >= 0 && is_p2p_net_interface(iftype))
                nl80211_disable_11b_rates(drv, ret, 1);
 
        return ret;
@@ -6099,7 +7010,7 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
 
        drv->monitor_ifidx =
                nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
-                                    0);
+                                    0, NULL, NULL);
 
        if (drv->monitor_ifidx == -EOPNOTSUPP) {
                /*
@@ -6286,8 +7197,8 @@ static int wpa_driver_nl80211_hapd_send_eapol(
        pos = (u8 *) (hdr + 1);
 
        if (qos) {
-               /* add an empty QoS header if needed */
-               pos[0] = 0;
+               /* Set highest priority in QoS header */
+               pos[0] = 7;
                pos[1] = 0;
                pos += 2;
        }
@@ -6317,19 +7228,14 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct nl_msg *msg, *flags = NULL;
+       struct nl_msg *msg;
+       struct nlattr *flags;
        struct nl80211_sta_flag_update upd;
 
        msg = nlmsg_alloc();
        if (!msg)
                return -ENOMEM;
 
-       flags = nlmsg_alloc();
-       if (!flags) {
-               nlmsg_free(msg);
-               return -ENOMEM;
-       }
-
        nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
@@ -6340,35 +7246,34 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
         * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
         * can be removed eventually.
         */
+       flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
+       if (!flags)
+               goto nla_put_failure;
        if (total_flags & WPA_STA_AUTHORIZED)
-               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
+               NLA_PUT_FLAG(msg, NL80211_STA_FLAG_AUTHORIZED);
 
        if (total_flags & WPA_STA_WMM)
-               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
+               NLA_PUT_FLAG(msg, NL80211_STA_FLAG_WME);
 
        if (total_flags & WPA_STA_SHORT_PREAMBLE)
-               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
+               NLA_PUT_FLAG(msg, NL80211_STA_FLAG_SHORT_PREAMBLE);
 
        if (total_flags & WPA_STA_MFP)
-               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
+               NLA_PUT_FLAG(msg, NL80211_STA_FLAG_MFP);
 
        if (total_flags & WPA_STA_TDLS_PEER)
-               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
+               NLA_PUT_FLAG(msg, NL80211_STA_FLAG_TDLS_PEER);
 
-       if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
-               goto nla_put_failure;
+       nla_nest_end(msg, flags);
 
        os_memset(&upd, 0, sizeof(upd));
        upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
        upd.set = sta_flags_nl80211(flags_or);
        NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
 
-       nlmsg_free(flags);
-
        return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
        nlmsg_free(msg);
-       nlmsg_free(flags);
        return -ENOBUFS;
 }
 
@@ -6376,7 +7281,10 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
 static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
                                 struct wpa_driver_associate_params *params)
 {
-       enum nl80211_iftype nlmode;
+       enum nl80211_iftype nlmode, old_mode;
+       struct hostapd_freq_params freq = {
+               .freq = params->freq,
+       };
 
        if (params->p2p) {
                wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
@@ -6385,8 +7293,15 @@ static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
        } else
                nlmode = NL80211_IFTYPE_AP;
 
-       if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode) ||
-           wpa_driver_nl80211_set_freq(&drv->first_bss, params->freq, 0, 0)) {
+       old_mode = drv->nlmode;
+       if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode)) {
+               nl80211_remove_monitor_interface(drv);
+               return -1;
+       }
+
+       if (wpa_driver_nl80211_set_freq(&drv->first_bss, &freq)) {
+               if (old_mode != nlmode)
+                       wpa_driver_nl80211_set_mode(&drv->first_bss, old_mode);
                nl80211_remove_monitor_interface(drv);
                return -1;
        }
@@ -6502,65 +7417,16 @@ retry:
 
                goto nla_put_failure;
        }
-       ret = 0;
-       wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");
-
-nla_put_failure:
-       nlmsg_free(msg);
-       return ret;
-}
-
-
-static unsigned int nl80211_get_assoc_bssid(struct wpa_driver_nl80211_data *drv,
-                                           u8 *bssid)
-{
-       struct nl_msg *msg;
-       int ret;
-       struct nl80211_bss_info_arg arg;
-
-       os_memset(&arg, 0, sizeof(arg));
-       msg = nlmsg_alloc();
-       if (!msg)
-               goto nla_put_failure;
-
-       nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
-       arg.drv = drv;
-       ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
-       msg = NULL;
-       if (ret == 0) {
-               if (is_zero_ether_addr(arg.assoc_bssid))
-                       return -ENOTCONN;
-               os_memcpy(bssid, arg.assoc_bssid, ETH_ALEN);
-               return 0;
-       }
-       wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
-                  "(%s)", ret, strerror(-ret));
-nla_put_failure:
-       nlmsg_free(msg);
-       return drv->assoc_freq;
-}
-
-
-static int nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
-                             const u8 *bssid)
-{
-       u8 addr[ETH_ALEN];
-
-       if (bssid == NULL) {
-               int res = nl80211_get_assoc_bssid(drv, addr);
-               if (res)
-                       return res;
-               bssid = addr;
-       }
+       ret = 0;
+       wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");
 
-       return wpa_driver_nl80211_disconnect(drv, bssid,
-                                            WLAN_REASON_PREV_AUTH_NOT_VALID);
+nla_put_failure:
+       nlmsg_free(msg);
+       return ret;
 }
 
 
-static int wpa_driver_nl80211_connect(
+static int wpa_driver_nl80211_try_connect(
        struct wpa_driver_nl80211_data *drv,
        struct wpa_driver_associate_params *params)
 {
@@ -6651,6 +7517,9 @@ skip_auth_type:
                int cipher;
 
                switch (params->pairwise_suite) {
+               case CIPHER_SMS4:
+                       cipher = WLAN_CIPHER_SUITE_SMS4;
+                       break;
                case CIPHER_WEP40:
                        cipher = WLAN_CIPHER_SUITE_WEP40;
                        break;
@@ -6660,6 +7529,9 @@ skip_auth_type:
                case CIPHER_CCMP:
                        cipher = WLAN_CIPHER_SUITE_CCMP;
                        break;
+               case CIPHER_GCMP:
+                       cipher = WLAN_CIPHER_SUITE_GCMP;
+                       break;
                case CIPHER_TKIP:
                default:
                        cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -6672,6 +7544,9 @@ skip_auth_type:
                int cipher;
 
                switch (params->group_suite) {
+               case CIPHER_SMS4:
+                       cipher = WLAN_CIPHER_SUITE_SMS4;
+                       break;
                case CIPHER_WEP40:
                        cipher = WLAN_CIPHER_SUITE_WEP40;
                        break;
@@ -6681,6 +7556,9 @@ skip_auth_type:
                case CIPHER_CCMP:
                        cipher = WLAN_CIPHER_SUITE_CCMP;
                        break;
+               case CIPHER_GCMP:
+                       cipher = WLAN_CIPHER_SUITE_GCMP;
+                       break;
                case CIPHER_TKIP:
                default:
                        cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -6690,13 +7568,25 @@ skip_auth_type:
        }
 
        if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
-           params->key_mgmt_suite == KEY_MGMT_PSK) {
+           params->key_mgmt_suite == KEY_MGMT_PSK ||
+           params->key_mgmt_suite == KEY_MGMT_FT_802_1X ||
+           params->key_mgmt_suite == KEY_MGMT_FT_PSK ||
+           params->key_mgmt_suite == KEY_MGMT_CCKM) {
                int mgmt = WLAN_AKM_SUITE_PSK;
 
                switch (params->key_mgmt_suite) {
+               case KEY_MGMT_CCKM:
+                       mgmt = WLAN_AKM_SUITE_CCKM;
+                       break;
                case KEY_MGMT_802_1X:
                        mgmt = WLAN_AKM_SUITE_8021X;
                        break;
+               case KEY_MGMT_FT_802_1X:
+                       mgmt = WLAN_AKM_SUITE_FT_8021X;
+                       break;
+               case KEY_MGMT_FT_PSK:
+                       mgmt = WLAN_AKM_SUITE_FT_PSK;
+                       break;
                case KEY_MGMT_PSK:
                default:
                        mgmt = WLAN_AKM_SUITE_PSK;
@@ -6705,6 +7595,11 @@ skip_auth_type:
                NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
        }
 
+#ifdef CONFIG_IEEE80211W
+       if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
+               NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
+#endif /* CONFIG_IEEE80211W */
+
        if (params->disable_ht)
                NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
 
@@ -6715,6 +7610,20 @@ skip_auth_type:
                        params->htcaps_mask);
        }
 
+#ifdef CONFIG_VHT_OVERRIDES
+       if (params->disable_vht) {
+               wpa_printf(MSG_DEBUG, "  * VHT disabled");
+               NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
+       }
+
+       if (params->vhtcaps && params->vhtcaps_mask) {
+               int sz = sizeof(struct ieee80211_vht_capabilities);
+               NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps);
+               NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+                       params->vhtcaps_mask);
+       }
+#endif /* CONFIG_VHT_OVERRIDES */
+
        ret = nl80211_set_conn_keys(params, msg);
        if (ret)
                goto nla_put_failure;
@@ -6724,14 +7633,6 @@ skip_auth_type:
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
                           "(%s)", ret, strerror(-ret));
-               /*
-                * cfg80211 does not currently accept new connection if we are
-                * already connected. As a workaround, force disconnection and
-                * try again once the driver indicates it completed
-                * disconnection.
-                */
-               if (ret == -EALREADY)
-                       nl80211_disconnect(drv, params->bssid);
                goto nla_put_failure;
        }
        ret = 0;
@@ -6744,6 +7645,31 @@ nla_put_failure:
 }
 
 
+static int wpa_driver_nl80211_connect(
+       struct wpa_driver_nl80211_data *drv,
+       struct wpa_driver_associate_params *params)
+{
+       int ret = wpa_driver_nl80211_try_connect(drv, params);
+       if (ret == -EALREADY) {
+               /*
+                * cfg80211 does not currently accept new connections if
+                * we are already connected. As a workaround, force
+                * disconnection and try again.
+                */
+               wpa_printf(MSG_DEBUG, "nl80211: Explicitly "
+                          "disconnecting before reassociation "
+                          "attempt");
+               if (wpa_driver_nl80211_disconnect(
+                           drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
+                       return -1;
+               /* Ignore the next local disconnect message. */
+               drv->ignore_next_local_disconnect = 1;
+               ret = wpa_driver_nl80211_try_connect(drv, params);
+       }
+       return ret;
+}
+
+
 static int wpa_driver_nl80211_associate(
        void *priv, struct wpa_driver_associate_params *params)
 {
@@ -6767,7 +7693,7 @@ static int wpa_driver_nl80211_associate(
                return wpa_driver_nl80211_connect(drv, params);
        }
 
-       drv->associated = 0;
+       nl80211_mark_disconnected(drv);
 
        msg = nlmsg_alloc();
        if (!msg)
@@ -6823,6 +7749,9 @@ static int wpa_driver_nl80211_associate(
                case CIPHER_CCMP:
                        cipher = WLAN_CIPHER_SUITE_CCMP;
                        break;
+               case CIPHER_GCMP:
+                       cipher = WLAN_CIPHER_SUITE_GCMP;
+                       break;
                case CIPHER_TKIP:
                default:
                        cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -6845,6 +7774,9 @@ static int wpa_driver_nl80211_associate(
                case CIPHER_CCMP:
                        cipher = WLAN_CIPHER_SUITE_CCMP;
                        break;
+               case CIPHER_GCMP:
+                       cipher = WLAN_CIPHER_SUITE_GCMP;
+                       break;
                case CIPHER_TKIP:
                default:
                        cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -6878,6 +7810,20 @@ static int wpa_driver_nl80211_associate(
                        params->htcaps_mask);
        }
 
+#ifdef CONFIG_VHT_OVERRIDES
+       if (params->disable_vht) {
+               wpa_printf(MSG_DEBUG, "  * VHT disabled");
+               NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
+       }
+
+       if (params->vhtcaps && params->vhtcaps_mask) {
+               int sz = sizeof(struct ieee80211_vht_capabilities);
+               NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps);
+               NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+                       params->vhtcaps_mask);
+       }
+#endif /* CONFIG_VHT_OVERRIDES */
+
        if (params->p2p)
                wpa_printf(MSG_DEBUG, "  * P2P group");
 
@@ -6998,6 +7944,11 @@ done:
                return ret;
        }
 
+       if (is_p2p_net_interface(nlmode))
+               nl80211_disable_11b_rates(drv, drv->ifindex, 1);
+       else if (drv->disabled_11b_rates)
+               nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+
        if (is_ap_interface(nlmode)) {
                nl80211_mgmt_unsubscribe(bss, "start AP");
                /* Setup additional AP mode functionality if needed */
@@ -7027,6 +7978,11 @@ static int wpa_driver_nl80211_get_capa(void *priv,
        if (!drv->has_capability)
                return -1;
        os_memcpy(capa, &drv->capa, sizeof(*capa));
+       if (drv->extended_capa && drv->extended_capa_mask) {
+               capa->extended_capa = drv->extended_capa;
+               capa->extended_capa_mask = drv->extended_capa_mask;
+               capa->extended_capa_len = drv->extended_capa_len;
+       }
        return 0;
 }
 
@@ -7051,6 +8007,9 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
        struct nl_msg *msg;
        struct nl80211_sta_flag_update upd;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
+                  MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
+
        msg = nlmsg_alloc();
        if (!msg)
                return -ENOMEM;
@@ -7078,8 +8037,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
 static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
 {
        struct i802_bss *bss = priv;
-       return wpa_driver_nl80211_set_freq(bss, freq->freq, freq->ht_enabled,
-                                          freq->sec_channel_offset);
+       return wpa_driver_nl80211_set_freq(bss, freq);
 }
 
 
@@ -7237,6 +8195,8 @@ static int i802_flush(void *priv)
        return -ENOBUFS;
 }
 
+#endif /* HOSTAPD || CONFIG_AP */
+
 
 static int get_sta_handler(struct nl_msg *msg, void *arg)
 {
@@ -7250,6 +8210,7 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
                [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
                [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
                [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
+               [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
        };
 
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
@@ -7285,14 +8246,17 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
        if (stats[NL80211_STA_INFO_TX_PACKETS])
                data->tx_packets =
                        nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
+       if (stats[NL80211_STA_INFO_TX_FAILED])
+               data->tx_retry_failed =
+                       nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
 
        return NL_SKIP;
 }
 
-static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
+static int i802_read_sta_data(struct i802_bss *bss,
+                             struct hostap_sta_driver_data *data,
                              const u8 *addr)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
 
@@ -7313,6 +8277,8 @@ static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
 }
 
 
+#if defined(HOSTAPD) || defined(CONFIG_AP)
+
 static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
                                    int cw_min, int cw_max, int burst_time)
 {
@@ -7372,10 +8338,9 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
 }
 
 
-static int i802_set_sta_vlan(void *priv, const u8 *addr,
+static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
                             const char *ifname, int vlan_id)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret = -ENOBUFS;
@@ -7447,7 +8412,8 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
        mgmt.u.deauth.reason_code = host_to_le16(reason);
        return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
                                            IEEE80211_HDRLEN +
-                                           sizeof(mgmt.u.deauth), 0);
+                                           sizeof(mgmt.u.deauth), 0, 0, 0, 0,
+                                           0);
 }
 
 
@@ -7470,7 +8436,8 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
        mgmt.u.disassoc.reason_code = host_to_le16(reason);
        return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
                                            IEEE80211_HDRLEN +
-                                           sizeof(mgmt.u.disassoc), 0);
+                                           sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
+                                           0);
 }
 
 #endif /* HOSTAPD || CONFIG_AP */
@@ -7496,8 +8463,8 @@ static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
        else
                old = NULL;
 
-       drv->if_indices = os_realloc(old,
-                                    sizeof(int) * (drv->num_if_indices + 1));
+       drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
+                                          sizeof(int));
        if (!drv->if_indices) {
                if (!old)
                        drv->if_indices = drv->default_if_indices;
@@ -7554,16 +8521,23 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
                if (!if_nametoindex(name)) {
                        if (nl80211_create_iface(drv, name,
                                                 NL80211_IFTYPE_AP_VLAN,
-                                                NULL, 1) < 0)
+                                                bss->addr, 1, NULL, NULL) < 0)
                                return -1;
                        if (bridge_ifname &&
                            linux_br_add_if(drv->global->ioctl_sock,
                                            bridge_ifname, name) < 0)
                                return -1;
                }
-               linux_set_iface_flags(drv->global->ioctl_sock, name, 1);
+               if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
+                       wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
+                                  "interface %s up", name);
+               }
                return i802_set_sta_vlan(priv, addr, name, 0);
        } else {
+               if (bridge_ifname)
+                       linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
+                                       name);
+
                i802_set_sta_vlan(priv, addr, bss->ifname, 0);
                return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
                                                    name);
@@ -7741,7 +8715,8 @@ failed:
 
 static void i802_deinit(void *priv)
 {
-       wpa_driver_nl80211_deinit(priv);
+       struct i802_bss *bss = priv;
+       wpa_driver_nl80211_deinit(bss);
 }
 
 #endif /* HOSTAPD */
@@ -7762,6 +8737,8 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type(
                return NL80211_IFTYPE_AP;
        case WPA_IF_P2P_GO:
                return NL80211_IFTYPE_P2P_GO;
+       case WPA_IF_P2P_DEVICE:
+               return NL80211_IFTYPE_P2P_DEVICE;
        }
        return -1;
 }
@@ -7831,7 +8808,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                os_memcpy(if_addr, addr, ETH_ALEN);
        ifidx = nl80211_create_iface(drv, ifname,
                                     wpa_driver_nl80211_if_type(type), addr,
-                                    0);
+                                    0, NULL, NULL);
        if (ifidx < 0) {
 #ifdef HOSTAPD
                os_free(new_bss);
@@ -7900,6 +8877,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                new_bss->drv = drv;
                new_bss->next = drv->first_bss.next;
                new_bss->freq = drv->first_bss.freq;
+               new_bss->ctx = bss_ctx;
                drv->first_bss.next = new_bss;
                if (drv_priv)
                        *drv_priv = new_bss;
@@ -7918,11 +8896,10 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
 }
 
 
-static int wpa_driver_nl80211_if_remove(void *priv,
+static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
                                        enum wpa_driver_if_type type,
                                        const char *ifname)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ifindex = if_nametoindex(ifname);
 
@@ -7931,7 +8908,12 @@ static int wpa_driver_nl80211_if_remove(void *priv,
        if (ifindex <= 0)
                return -1;
 
+       nl80211_remove_iface(drv, ifindex);
+
 #ifdef HOSTAPD
+       if (type != WPA_IF_AP_BSS)
+               return 0;
+
        if (bss->added_if_into_bridge) {
                if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
                                    bss->ifname) < 0)
@@ -7945,13 +8927,6 @@ static int wpa_driver_nl80211_if_remove(void *priv,
                                   "bridge %s: %s",
                                   bss->brname, strerror(errno));
        }
-#endif /* HOSTAPD */
-
-       nl80211_remove_iface(drv, ifindex);
-
-#ifdef HOSTAPD
-       if (type != WPA_IF_AP_BSS)
-               return 0;
 
        if (bss != &drv->first_bss) {
                struct i802_bss *tbss;
@@ -8005,12 +8980,14 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
        if (!msg)
                return -1;
 
-       wpa_printf(MSG_DEBUG, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
+       wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
                   "no_ack=%d offchanok=%d",
                   freq, wait, no_cck, no_ack, offchanok);
        nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       if (nl80211_set_iface_id(msg, bss))
+               goto nla_put_failure;
+
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
        if (wait)
                NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
@@ -8032,7 +9009,7 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
                           freq, wait);
                goto nla_put_failure;
        }
-       wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted%s; "
+       wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
                   "cookie 0x%llx", no_ack ? " (no ACK)" : "",
                   (long long unsigned int) cookie);
 
@@ -8045,14 +9022,14 @@ nla_put_failure:
 }
 
 
-static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
+static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
+                                         unsigned int freq,
                                          unsigned int wait_time,
                                          const u8 *dst, const u8 *src,
                                          const u8 *bssid,
                                          const u8 *data, size_t data_len,
                                          int no_cck)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ret = -1;
        u8 *buf;
@@ -8074,10 +9051,9 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
        os_memcpy(hdr->addr3, bssid, ETH_ALEN);
 
        if (is_ap_interface(drv->nlmode))
-               ret = wpa_driver_nl80211_send_mlme_freq(priv, buf,
-                                                       24 + data_len,
-                                                       0, freq, no_cck, 1,
-                                                       wait_time);
+               ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
+                                                  0, freq, no_cck, 1,
+                                                  wait_time);
        else
                ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
                                             24 + data_len,
@@ -8100,6 +9076,8 @@ static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
        if (!msg)
                return;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Cancel TX frame wait: cookie=0x%llx",
+                  (long long unsigned int) drv->send_action_cookie);
        nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
@@ -8131,7 +9109,9 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, bss))
+               goto nla_put_failure;
+
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
        NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
 
@@ -8178,7 +9158,9 @@ static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, bss))
+               goto nla_put_failure;
+
        NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -8193,9 +9175,8 @@ nla_put_failure:
 }
 
 
-static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
+static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
 
        if (!report) {
@@ -8287,7 +9268,8 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
                           "(%s)", ret, strerror(-ret));
-       }
+       } else
+               drv->disabled_11b_rates = disabled;
 
        return ret;
 
@@ -8308,6 +9290,18 @@ static int wpa_driver_nl80211_deinit_ap(void *priv)
 }
 
 
+static int wpa_driver_nl80211_stop_ap(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       if (!is_ap_interface(drv->nlmode))
+               return -1;
+       wpa_driver_nl80211_del_beacon(drv);
+       bss->beacon_set = 0;
+       return 0;
+}
+
+
 static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
 {
        struct i802_bss *bss = priv;
@@ -8380,7 +9374,9 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct nl_msg *msg, *cqm = NULL;
+       struct nl_msg *msg;
+       struct nlattr *cqm;
+       int ret = -1;
 
        wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
                   "hysteresis=%d", threshold, hysteresis);
@@ -8393,22 +9389,89 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
 
-       cqm = nlmsg_alloc();
+       cqm = nla_nest_start(msg, NL80211_ATTR_CQM);
        if (cqm == NULL)
-               return -1;
+               goto nla_put_failure;
 
-       NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
-       NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
-       nla_put_nested(msg, NL80211_ATTR_CQM, cqm);
+       NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
+       NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
+       nla_nest_end(msg, cqm);
 
-       if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
-               return 0;
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
 
 nla_put_failure:
-       nlmsg_free(cqm);
        nlmsg_free(msg);
-       return -1;
+       return ret;
+}
+
+
+/* Converts nl80211_chan_width to a common format */
+static enum chan_width convert2width(int width)
+{
+       switch (width) {
+       case NL80211_CHAN_WIDTH_20_NOHT:
+               return CHAN_WIDTH_20_NOHT;
+       case NL80211_CHAN_WIDTH_20:
+               return CHAN_WIDTH_20;
+       case NL80211_CHAN_WIDTH_40:
+               return CHAN_WIDTH_40;
+       case NL80211_CHAN_WIDTH_80:
+               return CHAN_WIDTH_80;
+       case NL80211_CHAN_WIDTH_80P80:
+               return CHAN_WIDTH_80P80;
+       case NL80211_CHAN_WIDTH_160:
+               return CHAN_WIDTH_160;
+       }
+       return CHAN_WIDTH_UNKNOWN;
+}
+
+
+static int get_channel_width(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct wpa_signal_info *sig_change = arg;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       sig_change->center_frq1 = -1;
+       sig_change->center_frq2 = -1;
+       sig_change->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+       if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
+               sig_change->chanwidth = convert2width(
+                       nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
+               if (tb[NL80211_ATTR_CENTER_FREQ1])
+                       sig_change->center_frq1 =
+                               nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+               if (tb[NL80211_ATTR_CENTER_FREQ2])
+                       sig_change->center_frq2 =
+                               nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+       }
+
+       return NL_SKIP;
+}
+
+
+static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
+                                    struct wpa_signal_info *sig)
+{
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+       return send_and_recv_msgs(drv, msg, get_channel_width, sig);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
 }
 
 
@@ -8423,6 +9486,10 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
        if (res != 0)
                return res;
 
+       res = nl80211_get_channel_width(drv, si);
+       if (res != 0)
+               return res;
+
        return nl80211_get_link_noise(drv, si);
 }
 
@@ -8695,7 +9762,8 @@ static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
        os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
        os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
 
-       if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0) < 0)
+       if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
+                                        0, 0) < 0)
                wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
                           "send poll frame");
 }
@@ -8767,6 +9835,40 @@ static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
 }
 
 
+static int nl80211_start_radar_detection(void *priv, int freq)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC)");
+       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
+               wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
+                          "detection");
+               return -1;
+       }
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_RADAR_DETECT);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+
+       /* only HT20 is supported at this point */
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (ret == 0)
+               return 0;
+       wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
+                  "%d (%s)", ret, strerror(-ret));
+nla_put_failure:
+       return -1;
+}
+
 #ifdef CONFIG_TDLS
 
 static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
@@ -8989,35 +10091,174 @@ static int android_pno_stop(struct i802_bss *bss)
 #endif /* ANDROID */
 
 
+static int driver_nl80211_set_key(const char *ifname, void *priv,
+                                 enum wpa_alg alg, const u8 *addr,
+                                 int key_idx, int set_tx,
+                                 const u8 *seq, size_t seq_len,
+                                 const u8 *key, size_t key_len)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_set_key(ifname, bss, alg, addr, key_idx,
+                                         set_tx, seq, seq_len, key, key_len);
+}
+
+
+static int driver_nl80211_scan2(void *priv,
+                               struct wpa_driver_scan_params *params)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_scan(bss, params);
+}
+
+
+static int driver_nl80211_deauthenticate(void *priv, const u8 *addr,
+                                        int reason_code)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code);
+}
+
+
+static int driver_nl80211_authenticate(void *priv,
+                                      struct wpa_driver_auth_params *params)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_authenticate(bss, params);
+}
+
+
+static void driver_nl80211_deinit(void *priv)
+{
+       struct i802_bss *bss = priv;
+       wpa_driver_nl80211_deinit(bss);
+}
+
+
+static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
+                                   const char *ifname)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_if_remove(bss, type, ifname);
+}
+
+
+static int driver_nl80211_send_mlme(void *priv, const u8 *data,
+                                   size_t data_len, int noack)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
+                                           0, 0, 0, 0);
+}
+
+
+static int driver_nl80211_sta_remove(void *priv, const u8 *addr)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_sta_remove(bss, addr);
+}
+
+
+#if defined(HOSTAPD) || defined(CONFIG_AP)
+static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
+                                      const char *ifname, int vlan_id)
+{
+       struct i802_bss *bss = priv;
+       return i802_set_sta_vlan(bss, addr, ifname, vlan_id);
+}
+#endif /* HOSTAPD || CONFIG_AP */
+
+
+static int driver_nl80211_read_sta_data(void *priv,
+                                       struct hostap_sta_driver_data *data,
+                                       const u8 *addr)
+{
+       struct i802_bss *bss = priv;
+       return i802_read_sta_data(bss, data, addr);
+}
+
+
+static int driver_nl80211_send_action(void *priv, unsigned int freq,
+                                     unsigned int wait_time,
+                                     const u8 *dst, const u8 *src,
+                                     const u8 *bssid,
+                                     const u8 *data, size_t data_len,
+                                     int no_cck)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_send_action(bss, freq, wait_time, dst, src,
+                                             bssid, data, data_len, no_cck);
+}
+
+
+static int driver_nl80211_probe_req_report(void *priv, int report)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_probe_req_report(bss, report);
+}
+
+
+static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
+                                           const u8 *ies, size_t ies_len)
+{
+       int ret;
+       struct nl_msg *msg;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       u16 mdid = WPA_GET_LE16(md);
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs");
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_UPDATE_FT_IES);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_IE, ies_len, ies);
+       NLA_PUT_U16(msg, NL80211_ATTR_MDID, mdid);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed "
+                          "err=%d (%s)", ret, strerror(-ret));
+       }
+
+       return ret;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
        .get_bssid = wpa_driver_nl80211_get_bssid,
        .get_ssid = wpa_driver_nl80211_get_ssid,
-       .set_key = wpa_driver_nl80211_set_key,
-       .scan2 = wpa_driver_nl80211_scan,
+       .set_key = driver_nl80211_set_key,
+       .scan2 = driver_nl80211_scan2,
        .sched_scan = wpa_driver_nl80211_sched_scan,
        .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
        .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
-       .deauthenticate = wpa_driver_nl80211_deauthenticate,
-       .disassociate = wpa_driver_nl80211_disassociate,
-       .authenticate = wpa_driver_nl80211_authenticate,
+       .deauthenticate = driver_nl80211_deauthenticate,
+       .authenticate = driver_nl80211_authenticate,
        .associate = wpa_driver_nl80211_associate,
        .global_init = nl80211_global_init,
        .global_deinit = nl80211_global_deinit,
        .init2 = wpa_driver_nl80211_init,
-       .deinit = wpa_driver_nl80211_deinit,
+       .deinit = driver_nl80211_deinit,
        .get_capa = wpa_driver_nl80211_get_capa,
        .set_operstate = wpa_driver_nl80211_set_operstate,
        .set_supp_port = wpa_driver_nl80211_set_supp_port,
        .set_country = wpa_driver_nl80211_set_country,
        .set_ap = wpa_driver_nl80211_set_ap,
+       .set_acl = wpa_driver_nl80211_set_acl,
        .if_add = wpa_driver_nl80211_if_add,
-       .if_remove = wpa_driver_nl80211_if_remove,
-       .send_mlme = wpa_driver_nl80211_send_mlme,
+       .if_remove = driver_nl80211_if_remove,
+       .send_mlme = driver_nl80211_send_mlme,
        .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
        .sta_add = wpa_driver_nl80211_sta_add,
-       .sta_remove = wpa_driver_nl80211_sta_remove,
+       .sta_remove = driver_nl80211_sta_remove,
        .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
        .sta_set_flags = wpa_driver_nl80211_sta_set_flags,
 #ifdef HOSTAPD
@@ -9028,23 +10269,23 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 #if defined(HOSTAPD) || defined(CONFIG_AP)
        .get_seqnum = i802_get_seqnum,
        .flush = i802_flush,
-       .read_sta_data = i802_read_sta_data,
        .get_inact_sec = i802_get_inact_sec,
        .sta_clear_stats = i802_sta_clear_stats,
        .set_rts = i802_set_rts,
        .set_frag = i802_set_frag,
        .set_tx_queue_params = i802_set_tx_queue_params,
-       .set_sta_vlan = i802_set_sta_vlan,
+       .set_sta_vlan = driver_nl80211_set_sta_vlan,
        .sta_deauth = i802_sta_deauth,
        .sta_disassoc = i802_sta_disassoc,
 #endif /* HOSTAPD || CONFIG_AP */
+       .read_sta_data = driver_nl80211_read_sta_data,
        .set_freq = i802_set_freq,
-       .send_action = wpa_driver_nl80211_send_action,
+       .send_action = driver_nl80211_send_action,
        .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
        .remain_on_channel = wpa_driver_nl80211_remain_on_channel,
        .cancel_remain_on_channel =
        wpa_driver_nl80211_cancel_remain_on_channel,
-       .probe_req_report = wpa_driver_nl80211_probe_req_report,
+       .probe_req_report = driver_nl80211_probe_req_report,
        .deinit_ap = wpa_driver_nl80211_deinit_ap,
        .deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
        .resume = wpa_driver_nl80211_resume,
@@ -9061,8 +10302,11 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .set_rekey_info = nl80211_set_rekey_info,
        .poll_client = nl80211_poll_client,
        .set_p2p_powersave = nl80211_set_p2p_powersave,
+       .start_dfs_cac = nl80211_start_radar_detection,
+       .stop_ap = wpa_driver_nl80211_stop_ap,
 #ifdef CONFIG_TDLS
        .send_tdls_mgmt = nl80211_send_tdls_mgmt,
        .tdls_oper = nl80211_tdls_oper,
 #endif /* CONFIG_TDLS */
+       .update_ft_ies = wpa_driver_nl80211_update_ft_ies,
 };