nl80211: Add support for P2P Device in add interface
[mech_eap.git] / src / drivers / driver_nl80211.c
index 4635d05..a9a9c4a 100644 (file)
 
 #ifdef ANDROID
 #include "android_drv.h"
-
-/* system/core/libnl_2 in AOSP does not include nla_put_u32() */
-int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value)
-{
-       return nla_put(msg, attrtype, sizeof(uint32_t), &value);
-}
 #endif /* ANDROID */
 #ifdef CONFIG_LIBNL20
 /* libnl 2.0 compatibility code */
@@ -189,12 +183,14 @@ 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];
 
@@ -220,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;
@@ -229,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;
@@ -347,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 ||
@@ -361,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;
@@ -469,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;
@@ -1042,6 +1175,7 @@ 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);
@@ -1121,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)) {
@@ -1172,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);
@@ -1220,7 +1357,7 @@ static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
        }
 
        wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
-       drv->associated = 0;
+       nl80211_mark_disconnected(drv);
        os_memset(&data, 0, sizeof(data));
        if (reason)
                data.deauth_info.reason_code = nla_get_u16(reason);
@@ -1297,7 +1434,7 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
        u16 fc, stype;
        int ssi_signal = 0;
 
-       wpa_printf(MSG_DEBUG, "nl80211: Frame event");
+       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");
@@ -1389,6 +1526,22 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
        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) {
@@ -1404,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 */
@@ -1474,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));
 
@@ -1633,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[])
 {
@@ -1689,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] = {
@@ -1711,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],
@@ -2190,6 +2403,43 @@ static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
 }
 
 
+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)
 {
@@ -2213,6 +2463,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
 {
        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)) {
@@ -2223,29 +2476,30 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
 
        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.
@@ -2261,7 +2515,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
        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],
@@ -2330,9 +2584,15 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
        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;
        }
 }
@@ -2349,19 +2609,31 @@ static int process_drv_event(struct nl_msg *msg, void *arg)
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
-       if (tb[NL80211_ATTR_IFINDEX])
+       if (tb[NL80211_ATTR_IFINDEX]) {
                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;
+               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);
        }
 
-       wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d) for foreign "
-                  "interface (ifindex %d)", gnlh->cmd, ifidx);
-
        return NL_SKIP;
 }
 
@@ -2374,17 +2646,26 @@ static int process_global_event(struct nl_msg *msg, void *arg)
        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]);
+       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 || ifidx == bss->ifindex) {
+                       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;
                        }
@@ -2404,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],
@@ -2434,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);
 }
@@ -2513,6 +2798,7 @@ nla_put_failure:
 
 
 struct wiphy_info_data {
+       struct wpa_driver_nl80211_data *drv;
        struct wpa_driver_capa *capa;
 
        unsigned int error:1;
@@ -2560,6 +2846,13 @@ static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
                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;
@@ -2588,6 +2881,7 @@ static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
                [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 },
@@ -2601,6 +2895,9 @@ static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
            !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
                return 0; /* broken combination */
 
+       if (tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS])
+               info->capa->flags |= WPA_DRIVER_FLAGS_RADAR;
+
        nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS],
                            rem_limit) {
                err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT,
@@ -2680,9 +2977,6 @@ static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
 static void wiphy_info_max_roc(struct wpa_driver_capa *capa,
                               struct nlattr *tb)
 {
-       /* default to 5000 since early versions of mac80211 don't set it */
-       capa->max_remain_on_chan = 5000;
-
        if (tb)
                capa->max_remain_on_chan = nla_get_u32(tb);
 }
@@ -2751,6 +3045,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
        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);
@@ -2767,6 +3062,10 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
                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]);
@@ -2798,6 +3097,30 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
        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;
 }
 
@@ -2810,6 +3133,7 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
 
        os_memset(info, 0, sizeof(*info));
        info->capa = &drv->capa;
+       info->drv = drv;
 
        msg = nlmsg_alloc();
        if (!msg)
@@ -2848,6 +3172,11 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
                           "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);
@@ -3307,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);
 
@@ -3698,6 +4029,8 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
        if (drv->in_interface_list)
                dl_list_del(&drv->list);
 
+       os_free(drv->extended_capa);
+       os_free(drv->extended_capa_mask);
        os_free(drv);
 }
 
@@ -3725,10 +4058,9 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 
 static struct nl_msg *
 nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
-                   struct wpa_driver_scan_params *params)
+                   struct wpa_driver_scan_params *params, u64 *wdev_id)
 {
        struct nl_msg *msg;
-       int err;
        size_t i;
 
        msg = nlmsg_alloc();
@@ -3737,27 +4069,26 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
 
        nl80211_cmd(drv, msg, 0, cmd);
 
-       if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) < 0)
-               goto fail;
+       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 nl_msg *ssids = nlmsg_alloc();
+               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(ssids, i + 1, params->ssids[i].ssid_len,
-                                   params->ssids[i].ssid) < 0) {
-                               nlmsg_free(ssids);
+                       if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
+                                   params->ssids[i].ssid) < 0)
                                goto fail;
-                       }
                }
-               err = nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
-               nlmsg_free(ssids);
-               if (err < 0)
-                       goto fail;
+               nla_nest_end(msg, ssids);
        }
 
        if (params->extra_ies) {
@@ -3769,22 +4100,17 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
        }
 
        if (params->freqs) {
-               struct nl_msg *freqs = nlmsg_alloc();
+               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]);
-                       if (nla_put_u32(freqs, i + 1, params->freqs[i]) < 0) {
-                               nlmsg_free(freqs);
+                       if (nla_put_u32(msg, i + 1, params->freqs[i]) < 0)
                                goto fail;
-                       }
                }
-               err = nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES,
-                                    freqs);
-               nlmsg_free(freqs);
-               if (err < 0)
-                       goto fail;
+               nla_nest_end(msg, freqs);
        }
 
        os_free(drv->filter_ssids);
@@ -3795,6 +4121,7 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
        return msg;
 
 fail:
+nla_put_failure:
        nlmsg_free(msg);
        return NULL;
 }
@@ -3811,18 +4138,22 @@ static int wpa_driver_nl80211_scan(struct i802_bss *bss,
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ret = -1, timeout;
-       struct nl_msg *msg, *rates = NULL;
+       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);
+       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 = nlmsg_alloc();
+               rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
                if (rates == NULL)
                        goto nla_put_failure;
 
@@ -3832,11 +4163,9 @@ static int wpa_driver_nl80211_scan(struct i802_bss *bss,
                 * 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");
-               if (nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates) <
-                   0)
-                       goto nla_put_failure;
+               nla_nest_end(msg, rates);
 
                NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
        }
@@ -3890,7 +4219,6 @@ static int wpa_driver_nl80211_scan(struct i802_bss *bss,
 
 nla_put_failure:
        nlmsg_free(msg);
-       nlmsg_free(rates);
        return ret;
 }
 
@@ -3910,16 +4238,17 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ret = -1;
        struct nl_msg *msg;
-       struct nl_msg *match_set_ssid = NULL, *match_sets = NULL;
-       struct nl_msg *match_set_rssi = NULL;
        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 = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params);
+       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;
 
@@ -3928,46 +4257,42 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
        if ((drv->num_filter_ssids &&
            (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
            params->filter_rssi) {
-               match_sets = nlmsg_alloc();
+               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();
+                       match_set_ssid = nla_nest_start(msg, i + 1);
                        if (match_set_ssid == NULL)
                                goto nla_put_failure;
-                       NLA_PUT(match_set_ssid,
-                               NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+                       NLA_PUT(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
                                drv->filter_ssids[i].ssid_len,
                                drv->filter_ssids[i].ssid);
 
-                       if (nla_put_nested(match_sets, i + 1, match_set_ssid) <
-                           0)
-                               goto nla_put_failure;
+                       nla_nest_end(msg, match_set_ssid);
                }
 
                if (params->filter_rssi) {
-                       match_set_rssi = nlmsg_alloc();
+                       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(match_set_rssi,
-                                   NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+                       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);
-                       if (nla_put_nested(match_sets, 0, match_set_rssi) < 0)
-                               goto nla_put_failure;
+                       nla_nest_end(msg, match_set_rssi);
                }
 
-               if (nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
-                                  match_sets) < 0)
-                       goto nla_put_failure;
+               nla_nest_end(msg, match_sets);
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -3985,9 +4310,6 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
                   "scan interval %d msec", ret, interval);
 
 nla_put_failure:
-       nlmsg_free(match_set_ssid);
-       nlmsg_free(match_sets);
-       nlmsg_free(match_set_rssi);
        nlmsg_free(msg);
        return ret;
 }
@@ -4404,9 +4726,9 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
        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)
@@ -4476,18 +4798,15 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
                                    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);
@@ -4521,29 +4840,21 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
        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);
@@ -4717,7 +5028,7 @@ static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
                                         int reason_code)
 {
        wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
-       drv->associated = 0;
+       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,
@@ -4733,7 +5044,7 @@ static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
                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,
@@ -4801,8 +5112,12 @@ 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;
@@ -5044,37 +5359,11 @@ 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;
-
-       /* mode is not set */
-       if (mode->mode >= NUM_HOSTAPD_MODES) {
-               /* crude heuristic */
-               if (chan->freq < 4000)
-                       mode->mode = HOSTAPD_MODE_IEEE80211B;
-               else if (chan->freq > 50000)
-                       mode->mode = HOSTAPD_MODE_IEEE80211AD;
-               else
-                       mode->mode = HOSTAPD_MODE_IEEE80211A;
-       }
-
-       switch (mode->mode) {
-       case HOSTAPD_MODE_IEEE80211AD:
-               chan->chan = (chan->freq - 56160) / 2160;
-               break;
-       case HOSTAPD_MODE_IEEE80211A:
-               chan->chan = chan->freq / 5 - 1000;
-               break;
-       case HOSTAPD_MODE_IEEE80211B:
-       case HOSTAPD_MODE_IEEE80211G:
-               if (chan->freq == 2484)
-                       chan->chan = 14;
-               else
-                       chan->chan = (chan->freq - 2407) / 5;
-               break;
-       default:
-               break;
-       }
+       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;
@@ -5089,6 +5378,22 @@ static void phy_info_freq(struct hostapd_hw_modes *mode,
            !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;
+               }
+       }
 }
 
 
@@ -5102,6 +5407,7 @@ static int phy_info_freqs(struct phy_info_arg *phy_info,
                [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 },
        };
        int new_channels = 0;
        struct hostapd_channel_data *channel;
@@ -5182,12 +5488,6 @@ static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
                        continue;
                mode->rates[idx] = nla_get_u32(
                        tb_rate[NL80211_BITRATE_ATTR_RATE]);
-
-               /* crude heuristic */
-               if (mode->mode == HOSTAPD_MODE_IEEE80211B &&
-                   mode->rates[idx] > 200)
-                       mode->mode = HOSTAPD_MODE_IEEE80211G;
-
                idx++;
        }
 
@@ -5265,12 +5565,31 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
 
 
 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. */
 
@@ -5516,7 +5835,8 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
 
        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:
@@ -5708,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)
 {
@@ -5734,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 */
@@ -5770,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;
@@ -5778,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;
@@ -5792,6 +6186,8 @@ 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;
@@ -5808,6 +6204,8 @@ 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,
@@ -5832,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);
        }
@@ -5971,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;
 
@@ -5995,12 +6401,25 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        wpa_hexdump(MSG_DEBUG, "  * supported rates", params->supp_rates,
                    params->supp_rates_len);
        if (!params->set) {
-               wpa_printf(MSG_DEBUG, "  * aid=%u", params->aid);
-               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",
@@ -6038,18 +6457,18 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        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;
 
                wpa_printf(MSG_DEBUG, "  * qosinfo=0x%x", params->qosinfo);
-               NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
+               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,
+               NLA_PUT_U8(msg, NL80211_STA_WME_MAX_SP,
                                (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
                                WMM_QOSINFO_STA_SP_MASK);
-               if (nla_put_nested(msg, NL80211_ATTR_STA_WME, wme) < 0)
-                       goto nla_put_failure;
+               nla_nest_end(msg, wme);
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6061,7 +6480,6 @@ 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;
 }
@@ -6128,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";
        }
@@ -6143,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;
 
@@ -6162,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);
-
-               err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
-
-               nlmsg_free(flags);
+               NLA_PUT_FLAG(msg, NL80211_MNTR_FLAG_COOK_FRAMES);
 
-               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:
@@ -6190,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);
@@ -6212,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)) {
@@ -6227,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;
@@ -6577,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) {
                /*
@@ -6795,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,
@@ -6818,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;
 }
 
@@ -7142,6 +7569,8 @@ 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_FT_802_1X ||
+           params->key_mgmt_suite == KEY_MGMT_FT_PSK ||
            params->key_mgmt_suite == KEY_MGMT_CCKM) {
                int mgmt = WLAN_AKM_SUITE_PSK;
 
@@ -7152,6 +7581,12 @@ skip_auth_type:
                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;
@@ -7258,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)
@@ -7509,7 +7944,7 @@ done:
                return ret;
        }
 
-       if (is_p2p_interface(nlmode))
+       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);
@@ -7543,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;
 }
 
@@ -7567,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;
@@ -8078,7 +8521,7 @@ 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,
-                                                bss->addr, 1) < 0)
+                                                bss->addr, 1, NULL, NULL) < 0)
                                return -1;
                        if (bridge_ifname &&
                            linux_br_add_if(drv->global->ioctl_sock,
@@ -8294,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;
 }
@@ -8363,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);
@@ -8535,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);
@@ -8562,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);
 
@@ -8662,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);
 
@@ -8709,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);
@@ -8839,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;
@@ -8911,7 +9374,8 @@ 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 "
@@ -8925,25 +9389,92 @@ 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)
                goto nla_put_failure;
 
-       NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
-       NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
-       if (nla_put_nested(msg, NL80211_ATTR_CQM, cqm) < 0)
-               goto nla_put_failure;
+       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);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
 
 nla_put_failure:
-       nlmsg_free(cqm);
        nlmsg_free(msg);
        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;
+}
+
+
 static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
 {
        struct i802_bss *bss = priv;
@@ -8955,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);
 }
 
@@ -9300,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,
@@ -9628,6 +10197,39 @@ static int driver_nl80211_probe_req_report(void *priv, int 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",
@@ -9650,6 +10252,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .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 = driver_nl80211_if_remove,
        .send_mlme = driver_nl80211_send_mlme,
@@ -9699,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,
 };