Track whether scan was started by us or an external program
[mech_eap.git] / src / drivers / driver_nl80211.c
index b7a70ba..a782c11 100644 (file)
@@ -109,6 +109,17 @@ static void nl80211_handle_destroy(struct nl_handle *handle)
 #endif /* CONFIG_LIBNL20 */
 
 
+#ifdef ANDROID
+/* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
+static int android_nl_socket_set_nonblocking(struct nl_handle *handle)
+{
+       return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
+}
+#undef nl_socket_set_nonblocking
+#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
+#endif /* ANDROID */
+
+
 static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
 {
        struct nl_handle *handle;
@@ -140,6 +151,31 @@ static void nl_destroy_handles(struct nl_handle **handle)
 }
 
 
+#if __WORDSIZE == 64
+#define ELOOP_SOCKET_INVALID   (intptr_t) 0x8888888888888889ULL
+#else
+#define ELOOP_SOCKET_INVALID   (intptr_t) 0x88888889ULL
+#endif
+
+static void nl80211_register_eloop_read(struct nl_handle **handle,
+                                       eloop_sock_handler handler,
+                                       void *eloop_data)
+{
+       nl_socket_set_nonblocking(*handle);
+       eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
+                                eloop_data, *handle);
+       *handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+}
+
+
+static void nl80211_destroy_eloop_handle(struct nl_handle **handle)
+{
+       *handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+       eloop_unregister_read_sock(nl_socket_get_fd(*handle));
+       nl_destroy_handles(handle);
+}
+
+
 #ifndef IFF_LOWER_UP
 #define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
 #endif
@@ -157,6 +193,8 @@ static void nl_destroy_handles(struct nl_handle **handle)
 struct nl80211_global {
        struct dl_list interfaces;
        int if_add_ifindex;
+       u64 if_add_wdevid;
+       int if_add_wdevid_set;
        struct netlink_data *netlink;
        struct nl_cb *nl_cb;
        struct nl_handle *nl;
@@ -183,16 +221,20 @@ 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;
+       unsigned int added_if:1;
 
        u8 addr[ETH_ALEN];
 
        int freq;
+       int if_dynamic;
 
        void *ctx;
        struct nl_handle *nl_preq, *nl_mgmt;
@@ -221,6 +263,11 @@ struct wpa_driver_nl80211_data {
        int operstate;
 
        int scan_complete_events;
+       enum scan_states {
+               NO_SCAN, SCAN_REQUESTED, SCAN_STARTED, SCAN_COMPLETED,
+               SCAN_ABORTED, SCHED_SCAN_STARTED, SCHED_SCAN_STOPPED,
+               SCHED_SCAN_RESULTS
+       } scan_state;
 
        struct nl_cb *nl_cb;
 
@@ -249,6 +296,11 @@ struct wpa_driver_nl80211_data {
        unsigned int retry_auth:1;
        unsigned int use_monitor:1;
        unsigned int ignore_next_local_disconnect:1;
+       unsigned int allow_p2p_device:1;
+       unsigned int hostapd:1;
+       unsigned int start_mode_ap:1;
+       unsigned int start_iface_up:1;
+       unsigned int channel_switch_supported:1;
 
        u64 remain_on_chan_cookie;
        u64 send_action_cookie;
@@ -258,21 +310,16 @@ struct wpa_driver_nl80211_data {
        struct wpa_driver_scan_filter *filter_ssids;
        size_t num_filter_ssids;
 
-       struct i802_bss first_bss;
+       struct i802_bss *first_bss;
 
        int eapol_tx_sock;
 
-#ifdef HOSTAPD
        int eapol_sock; /* socket for EAPOL frames */
 
        int default_if_indices[16];
        int *if_indices;
        int num_if_indices;
 
-       int last_freq;
-       int last_freq_ht;
-#endif /* HOSTAPD */
-
        /* From failed authentication command */
        int auth_freq;
        u8 auth_bssid_[ETH_ALEN];
@@ -295,7 +342,8 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
 static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
                                       enum nl80211_iftype nlmode);
 static int
-wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
+                                  const u8 *set_addr, int first);
 static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
                                   const u8 *addr, int cmd, u16 reason_code,
                                   int local_state_change);
@@ -305,35 +353,33 @@ 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 nl80211_register_frame(struct i802_bss *bss,
+                                 struct nl_handle *hl_handle,
+                                 u16 type, const u8 *match, size_t match_len);
 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);
 static int android_pno_stop(struct i802_bss *bss);
+extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
+                                        size_t buf_len);
 #endif /* ANDROID */
+#ifdef ANDROID_P2P
+int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
+int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
+int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
+int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
+                                const struct wpabuf *proberesp,
+                                const struct wpabuf *assocresp);
+#endif /* ANDROID_P2P */
 
-#ifdef HOSTAPD
 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(struct i802_bss *bss,
                                        enum wpa_driver_if_type type,
                                        const char *ifname);
-#else /* HOSTAPD */
-static inline void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-}
-
-static inline void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-}
-
-static inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-       return 0;
-}
-#endif /* HOSTAPD */
 
 static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
                                       struct hostapd_freq_params *freq);
@@ -344,6 +390,8 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv);
 static int wpa_driver_nl80211_authenticate_retry(
        struct wpa_driver_nl80211_data *drv);
 
+static int i802_set_iface_flags(struct i802_bss *bss, int up);
+
 
 static const char * nl80211_command_to_string(enum nl80211_commands cmd)
 {
@@ -456,6 +504,27 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd)
 }
 
 
+/* 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 is_ap_interface(enum nl80211_iftype nlmode)
 {
        return (nlmode == NL80211_IFTYPE_AP ||
@@ -470,7 +539,7 @@ 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);
@@ -552,8 +621,14 @@ static int send_and_recv(struct nl80211_global *global,
                nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
                          valid_handler, valid_data);
 
-       while (err > 0)
-               nl_recvmsgs(nl_handle, cb);
+       while (err > 0) {
+               int res = nl_recvmsgs(nl_handle, cb);
+               if (res) {
+                       wpa_printf(MSG_INFO,
+                                  "nl80211: %s->nl_recvmsgs failed: %d",
+                                  __func__, res);
+               }
+       }
  out:
        nl_cb_put(cb);
        nlmsg_free(msg);
@@ -587,6 +662,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;
@@ -653,6 +741,8 @@ static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
 
 struct wiphy_idx_data {
        int wiphy_idx;
+       enum nl80211_iftype nlmode;
+       u8 *macaddr;
 };
 
 
@@ -668,6 +758,13 @@ static int netdev_info_handler(struct nl_msg *msg, void *arg)
        if (tb[NL80211_ATTR_WIPHY])
                info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
 
+       if (tb[NL80211_ATTR_IFTYPE])
+               info->nlmode = nla_get_u32(tb[NL80211_ATTR_IFTYPE]);
+
+       if (tb[NL80211_ATTR_MAC] && info->macaddr)
+               os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
+                         ETH_ALEN);
+
        return NL_SKIP;
 }
 
@@ -677,15 +774,17 @@ static int nl80211_get_wiphy_index(struct i802_bss *bss)
        struct nl_msg *msg;
        struct wiphy_idx_data data = {
                .wiphy_idx = -1,
+               .macaddr = NULL,
        };
 
        msg = nlmsg_alloc();
        if (!msg)
-               return -1;
+               return NL80211_IFTYPE_UNSPECIFIED;
 
        nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
 
        if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
                return data.wiphy_idx;
@@ -696,6 +795,55 @@ nla_put_failure:
 }
 
 
+static enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss)
+{
+       struct nl_msg *msg;
+       struct wiphy_idx_data data = {
+               .nlmode = NL80211_IFTYPE_UNSPECIFIED,
+               .macaddr = NULL,
+       };
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
+
+       if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
+               return data.nlmode;
+       msg = NULL;
+nla_put_failure:
+       nlmsg_free(msg);
+       return NL80211_IFTYPE_UNSPECIFIED;
+}
+
+
+static int nl80211_get_macaddr(struct i802_bss *bss)
+{
+       struct nl_msg *msg;
+       struct wiphy_idx_data data = {
+               .macaddr = bss->addr,
+       };
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return NL80211_IFTYPE_UNSPECIFIED;
+
+       nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
+
+       return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return NL80211_IFTYPE_UNSPECIFIED;
+}
+
+
 static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
                                    struct nl80211_wiphy_data *w)
 {
@@ -728,10 +876,15 @@ nla_put_failure:
 static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
 {
        struct nl80211_wiphy_data *w = eloop_ctx;
+       int res;
 
        wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
 
-       nl_recvmsgs(handle, w->nl_cb);
+       res = nl_recvmsgs(handle, w->nl_cb);
+       if (res) {
+               wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
+                          __func__, res);
+       }
 }
 
 
@@ -815,8 +968,7 @@ nl80211_get_wiphy_data_ap(struct i802_bss *bss)
                return NULL;
        }
 
-       eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons),
-                                nl80211_recv_beacons, w, w->nl_beacons);
+       nl80211_register_eloop_read(&w->nl_beacons, nl80211_recv_beacons, w);
 
        dl_list_add(&nl80211_wiphys, &w->list);
 
@@ -863,10 +1015,9 @@ static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
        if (!dl_list_empty(&w->bsss))
                return;
 
-       eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons));
+       nl80211_destroy_eloop_handle(&w->nl_beacons);
 
        nl_cb_put(w->nl_cb);
-       nl_destroy_handles(&w->nl_beacons);
        dl_list_del(&w->list);
        os_free(w);
 }
@@ -911,7 +1062,8 @@ static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
                   event.interface_status.ifname,
                   del ? "removed" : "added");
 
-       if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
+       if (os_strcmp(drv->first_bss->ifname, event.interface_status.ifname) ==
+           0) {
                if (del) {
                        if (drv->if_removed) {
                                wpa_printf(MSG_DEBUG, "nl80211: if_removed "
@@ -920,11 +1072,11 @@ static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
                        }
                        drv->if_removed = 1;
                } else {
-                       if (if_nametoindex(drv->first_bss.ifname) == 0) {
+                       if (if_nametoindex(drv->first_bss->ifname) == 0) {
                                wpa_printf(MSG_DEBUG, "nl80211: Interface %s "
                                           "does not exist - ignore "
                                           "RTM_NEWLINK",
-                                          drv->first_bss.ifname);
+                                          drv->first_bss->ifname);
                                return;
                        }
                        if (!drv->if_removed) {
@@ -952,8 +1104,8 @@ static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
        rta_len = RTA_ALIGN(sizeof(struct rtattr));
        while (RTA_OK(attr, attrlen)) {
                if (attr->rta_type == IFLA_IFNAME) {
-                       if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname)
-                           == 0)
+                       if (os_strcmp(((char *) attr) + rta_len,
+                                     drv->first_bss->ifname) == 0)
                                return 1;
                        else
                                break;
@@ -972,10 +1124,9 @@ static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
                return 1;
 
        if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
-               drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname);
                wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
                           "interface");
-               wpa_driver_nl80211_finish_drv_init(drv);
+               wpa_driver_nl80211_finish_drv_init(drv, NULL, 0);
                return 1;
        }
 
@@ -1026,7 +1177,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
        if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
                if (if_indextoname(ifi->ifi_index, namebuf) &&
                    linux_iface_up(drv->global->ioctl_sock,
-                                  drv->first_bss.ifname) > 0) {
+                                  drv->first_bss->ifname) > 0) {
                        wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
                                   "event since interface %s is up", namebuf);
                        return;
@@ -1046,18 +1197,18 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
        if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
                if (if_indextoname(ifi->ifi_index, namebuf) &&
                    linux_iface_up(drv->global->ioctl_sock,
-                                  drv->first_bss.ifname) == 0) {
+                                  drv->first_bss->ifname) == 0) {
                        wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
                                   "event since interface %s is down",
                                   namebuf);
-               } else if (if_nametoindex(drv->first_bss.ifname) == 0) {
+               } else if (if_nametoindex(drv->first_bss->ifname) == 0) {
                        wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
                                   "event since interface %s does not exist",
-                                  drv->first_bss.ifname);
+                                  drv->first_bss->ifname);
                } else if (drv->if_removed) {
                        wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
                                   "event since interface %s is marked "
-                                  "removed", drv->first_bss.ifname);
+                                  "removed", drv->first_bss->ifname);
                } else {
                        wpa_printf(MSG_DEBUG, "nl80211: Interface up");
                        drv->if_disabled = 0;
@@ -1197,7 +1348,9 @@ static unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
                wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
                           "associated BSS from scan results: %u MHz",
                           arg.assoc_freq);
-               return arg.assoc_freq ? arg.assoc_freq : drv->assoc_freq;
+               if (arg.assoc_freq)
+                       drv->assoc_freq = arg.assoc_freq;
+               return drv->assoc_freq;
        }
        wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
                   "(%s)", ret, strerror(-ret));
@@ -1352,34 +1505,60 @@ 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)
+                                struct nlattr *ifindex, struct nlattr *freq,
+                                struct nlattr *type, struct nlattr *bw,
+                                struct nlattr *cf1, struct nlattr *cf2)
 {
+       struct i802_bss *bss;
        union wpa_event_data data;
        int ht_enabled = 1;
        int chan_offset = 0;
+       int ifidx;
 
        wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
 
-       if (!freq || !type)
+       if (!freq)
                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;
+       ifidx = nla_get_u32(ifindex);
+       for (bss = drv->first_bss; bss; bss = bss->next)
+               if (bss->ifindex == ifidx)
+                       break;
+
+       if (bss == NULL) {
+               wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
+                          ifidx);
+               return;
+       }
+
+       if (type) {
+               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;
+               }
        }
 
+       os_memset(&data, 0, sizeof(data));
        data.ch_switch.freq = nla_get_u32(freq);
        data.ch_switch.ht_enabled = ht_enabled;
        data.ch_switch.ch_offset = chan_offset;
+       if (bw)
+               data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
+       if (cf1)
+               data.ch_switch.cf1 = nla_get_u32(cf1);
+       if (cf2)
+               data.ch_switch.cf2 = nla_get_u32(cf2);
+
+       bss->freq = data.ch_switch.freq;
 
        wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
 }
@@ -1418,6 +1597,7 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
        union wpa_event_data event;
        u16 fc, stype;
        int ssi_signal = 0;
+       int rx_freq = 0;
 
        wpa_printf(MSG_MSGDUMP, "nl80211: Frame event");
        mgmt = (const struct ieee80211_mgmt *) frame;
@@ -1435,8 +1615,11 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
        os_memset(&event, 0, sizeof(event));
        if (freq) {
                event.rx_action.freq = nla_get_u32(freq);
-               drv->last_mgmt_freq = event.rx_action.freq;
+               rx_freq = drv->last_mgmt_freq = event.rx_action.freq;
        }
+       wpa_printf(MSG_DEBUG,
+                  "nl80211: RX frame freq=%d ssi_signal=%d stype=%u len=%u",
+                  rx_freq, ssi_signal, stype, (unsigned int) len);
        if (stype == WLAN_FC_STYPE_ACTION) {
                event.rx_action.da = mgmt->da;
                event.rx_action.sa = mgmt->sa;
@@ -1551,7 +1734,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
 
        if (type == EVENT_DISASSOC) {
                event.disassoc_info.locally_generated =
-                       !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
+                       !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
                event.disassoc_info.addr = bssid;
                event.disassoc_info.reason_code = reason_code;
                if (frame + len > mgmt->u.disassoc.variable) {
@@ -1561,7 +1744,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
                }
        } else {
                event.deauth_info.locally_generated =
-                       !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
+                       !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
                event.deauth_info.addr = bssid;
                event.deauth_info.reason_code = reason_code;
                if (frame + len > mgmt->u.deauth.variable) {
@@ -1740,6 +1923,7 @@ static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
                return;
        }
        os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
        drv->associated = 1;
        wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
                   MAC2STR(drv->bssid));
@@ -1853,21 +2037,36 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
                                &info->ssids[info->num_ssids];
                        s->ssid = nla_data(nl);
                        s->ssid_len = nla_len(nl);
+                       wpa_printf(MSG_DEBUG, "nl80211: Scan probed for SSID '%s'",
+                                  wpa_ssid_txt(s->ssid, s->ssid_len));
                        info->num_ssids++;
                        if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
                                break;
                }
        }
        if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
+               char msg[200], *pos, *end;
+               int res;
+
+               pos = msg;
+               end = pos + sizeof(msg);
+               *pos = '\0';
+
                nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
                {
                        freqs[num_freqs] = nla_get_u32(nl);
+                       res = os_snprintf(pos, end - pos, " %d",
+                                         freqs[num_freqs]);
+                       if (res > 0 && end - pos > res)
+                               pos += res;
                        num_freqs++;
                        if (num_freqs == MAX_REPORT_FREQS - 1)
                                break;
                }
                info->freqs = freqs;
                info->num_freqs = num_freqs;
+               wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s",
+                          msg);
        }
        wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
 }
@@ -2351,6 +2550,13 @@ static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv,
+                           struct nlattr **tb)
+{
+       wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL);
+}
+
+
 static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
                                         struct nlattr **tb)
 {
@@ -2398,11 +2604,43 @@ static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
                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]);
+       data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+       event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
+
+       /* Check HT params */
+       if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+               data.dfs_event.ht_enabled = 1;
+               data.dfs_event.chan_offset = 0;
+
+               switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
+               case NL80211_CHAN_NO_HT:
+                       data.dfs_event.ht_enabled = 0;
+                       break;
+               case NL80211_CHAN_HT20:
+                       break;
+               case NL80211_CHAN_HT40PLUS:
+                       data.dfs_event.chan_offset = 1;
+                       break;
+               case NL80211_CHAN_HT40MINUS:
+                       data.dfs_event.chan_offset = -1;
+                       break;
+               }
+       }
+
+       /* Get VHT params */
+       if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+               data.dfs_event.chan_width =
+                       convert2width(nla_get_u32(
+                                             tb[NL80211_ATTR_CHANNEL_WIDTH]));
+       if (tb[NL80211_ATTR_CENTER_FREQ1])
+               data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+       if (tb[NL80211_ATTR_CENTER_FREQ2])
+               data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
 
-       wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz",
-                  data.dfs_event.freq);
+       wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz",
+                  data.dfs_event.freq, data.dfs_event.ht_enabled,
+                  data.dfs_event.chan_offset, data.dfs_event.chan_width,
+                  data.dfs_event.cf1, data.dfs_event.cf2);
 
        switch (event_type) {
        case NL80211_RADAR_DETECTED:
@@ -2447,6 +2685,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
                                 struct nlattr **tb)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
+       union wpa_event_data data;
 
        wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
                   cmd, nl80211_command_to_string(cmd), bss->ifname);
@@ -2454,7 +2693,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
        if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
            (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
             cmd == NL80211_CMD_SCAN_ABORTED)) {
-               wpa_driver_nl80211_set_mode(&drv->first_bss,
+               wpa_driver_nl80211_set_mode(drv->first_bss,
                                            drv->ap_scan_as_station);
                drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
        }
@@ -2462,17 +2701,22 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
        switch (cmd) {
        case NL80211_CMD_TRIGGER_SCAN:
                wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
+               drv->scan_state = SCAN_STARTED;
+               wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
                break;
        case NL80211_CMD_START_SCHED_SCAN:
                wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
+               drv->scan_state = SCHED_SCAN_STARTED;
                break;
        case NL80211_CMD_SCHED_SCAN_STOPPED:
                wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
+               drv->scan_state = SCHED_SCAN_STOPPED;
                wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
                break;
        case NL80211_CMD_NEW_SCAN_RESULTS:
                wpa_dbg(drv->ctx, MSG_DEBUG,
                        "nl80211: New scan results available");
+               drv->scan_state = SCAN_COMPLETED;
                drv->scan_complete_events = 1;
                eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
                                     drv->ctx);
@@ -2481,10 +2725,12 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
        case NL80211_CMD_SCHED_SCAN_RESULTS:
                wpa_dbg(drv->ctx, MSG_DEBUG,
                        "nl80211: New sched scan results available");
+               drv->scan_state = SCHED_SCAN_RESULTS;
                send_scan_event(drv, 0, tb);
                break;
        case NL80211_CMD_SCAN_ABORTED:
                wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
+               drv->scan_state = SCAN_ABORTED;
                /*
                 * Need to indicate that scan results are available in order
                 * not to make wpa_supplicant stop its scanning.
@@ -2515,8 +2761,13 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
                                   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]);
+               mlme_event_ch_switch(drv,
+                                    tb[NL80211_ATTR_IFINDEX],
+                                    tb[NL80211_ATTR_WIPHY_FREQ],
+                                    tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
+                                    tb[NL80211_ATTR_CHANNEL_WIDTH],
+                                    tb[NL80211_ATTR_CENTER_FREQ1],
+                                    tb[NL80211_ATTR_CENTER_FREQ2]);
                break;
        case NL80211_CMD_DISCONNECT:
                mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
@@ -2540,8 +2791,33 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
                break;
        case NL80211_CMD_REG_CHANGE:
                wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
+               if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
+                       break;
+               os_memset(&data, 0, sizeof(data));
+               switch (nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])) {
+               case NL80211_REGDOM_SET_BY_CORE:
+                       data.channel_list_changed.initiator =
+                               REGDOM_SET_BY_CORE;
+                       break;
+               case NL80211_REGDOM_SET_BY_USER:
+                       data.channel_list_changed.initiator =
+                               REGDOM_SET_BY_USER;
+                       break;
+               case NL80211_REGDOM_SET_BY_DRIVER:
+                       data.channel_list_changed.initiator =
+                               REGDOM_SET_BY_DRIVER;
+                       break;
+               case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+                       data.channel_list_changed.initiator =
+                               REGDOM_SET_BY_COUNTRY_IE;
+                       break;
+               default:
+                       wpa_printf(MSG_DEBUG, "nl80211: Unknown reg change initiator %d received",
+                                  nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]));
+                       break;
+               }
                wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
-                                    NULL);
+                                    &data);
                break;
        case NL80211_CMD_REG_BEACON_HINT:
                wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
@@ -2575,6 +2851,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
        case NL80211_CMD_RADAR_DETECT:
                nl80211_radar_event(drv, tb);
                break;
+       case NL80211_CMD_STOP_AP:
+               nl80211_stop_ap(drv, tb);
+               break;
        default:
                wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
                        "(cmd=%d)", cmd);
@@ -2594,19 +2873,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;
 }
 
@@ -2619,17 +2910,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 = 0;
+       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) {
+               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;
                        }
@@ -2682,10 +2982,15 @@ static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
                                             void *handle)
 {
        struct nl_cb *cb = eloop_ctx;
+       int res;
 
        wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
 
-       nl_recvmsgs(handle, cb);
+       res = nl_recvmsgs(handle, cb);
+       if (res) {
+               wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
+                          __func__, res);
+       }
 }
 
 
@@ -2725,6 +3030,44 @@ nla_put_failure:
 }
 
 
+static int nl80211_get_country(struct nl_msg *msg, void *arg)
+{
+       char *alpha2 = 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_REG_ALPHA2]) {
+               wpa_printf(MSG_DEBUG, "nl80211: No country information available");
+               return NL_SKIP;
+       }
+       os_strlcpy(alpha2, nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), 3);
+       return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_get_country(void *priv, char *alpha2)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+       alpha2[0] = '\0';
+       ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2);
+       if (!alpha2[0])
+               ret = -1;
+
+       return ret;
+}
+
+
 static int protocol_feature_handler(struct nl_msg *msg, void *arg)
 {
        u32 *feat = arg;
@@ -2765,6 +3108,8 @@ struct wiphy_info_data {
        struct wpa_driver_nl80211_data *drv;
        struct wpa_driver_capa *capa;
 
+       unsigned int num_multichan_concurrent;
+
        unsigned int error:1;
        unsigned int device_ap_sme:1;
        unsigned int poll_command_supported:1;
@@ -2775,7 +3120,8 @@ struct wiphy_info_data {
        unsigned int p2p_go_supported:1;
        unsigned int p2p_client_supported:1;
        unsigned int p2p_concurrent:1;
-       unsigned int p2p_multichan_concurrent:1;
+       unsigned int channel_switch_supported:1;
+       unsigned int set_qos_map_supported:1;
 };
 
 
@@ -2813,6 +3159,10 @@ static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
                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;
@@ -2881,8 +3231,8 @@ static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
 
        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;
+               info->num_multichan_concurrent =
+                       nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]);
                return 1;
        }
 
@@ -2929,6 +3279,68 @@ static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
                case NL80211_CMD_PROBE_CLIENT:
                        info->poll_command_supported = 1;
                        break;
+               case NL80211_CMD_CHANNEL_SWITCH:
+                       info->channel_switch_supported = 1;
+                       break;
+               case NL80211_CMD_SET_QOS_MAP:
+                       info->set_qos_map_supported = 1;
+                       break;
+               }
+       }
+}
+
+
+static void wiphy_info_cipher_suites(struct wiphy_info_data *info,
+                                    struct nlattr *tb)
+{
+       int i, num;
+       u32 *ciphers;
+
+       if (tb == NULL)
+               return;
+
+       num = nla_len(tb) / sizeof(u32);
+       ciphers = nla_data(tb);
+       for (i = 0; i < num; i++) {
+               u32 c = ciphers[i];
+
+               wpa_printf(MSG_DEBUG, "nl80211: Supported cipher %02x-%02x-%02x:%d",
+                          c >> 24, (c >> 16) & 0xff,
+                          (c >> 8) & 0xff, c & 0xff);
+               switch (c) {
+               case WLAN_CIPHER_SUITE_CCMP_256:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256;
+                       break;
+               case WLAN_CIPHER_SUITE_GCMP_256:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256;
+                       break;
+               case WLAN_CIPHER_SUITE_CCMP:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+                       break;
+               case WLAN_CIPHER_SUITE_GCMP:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP;
+                       break;
+               case WLAN_CIPHER_SUITE_TKIP:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+                       break;
+               case WLAN_CIPHER_SUITE_WEP104:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104;
+                       break;
+               case WLAN_CIPHER_SUITE_WEP40:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40;
+                       break;
+               case WLAN_CIPHER_SUITE_AES_CMAC:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP;
+                       break;
+               case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128;
+                       break;
+               case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256;
+                       break;
+               case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256;
+                       break;
                }
        }
 }
@@ -3010,6 +3422,10 @@ static int wiphy_info_handler(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_WIPHY_NAME])
+               os_strlcpy(drv->phyname,
+                          nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
+                          sizeof(drv->phyname));
        if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
                capa->max_scan_ssids =
                        nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
@@ -3029,6 +3445,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
        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]);
+       wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]);
 
        if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
                wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
@@ -3106,7 +3523,8 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
                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 (nl80211_set_iface_id(msg, drv->first_bss) < 0)
+               goto nla_put_failure;
 
        if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
                return -1;
@@ -3127,10 +3545,11 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
                drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
                drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
        }
-       if (info->p2p_multichan_concurrent) {
+       if (info->num_multichan_concurrent > 1) {
                wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
                           "concurrent (driver advertised support)");
-               drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
+               drv->capa.num_multichan_concurrent =
+                       info->num_multichan_concurrent;
        }
 
        /* default to 5000 since early versions of mac80211 don't set it */
@@ -3154,15 +3573,10 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
                return -1;
 
        drv->has_capability = 1;
-       /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
        drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
                WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
                WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
                WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
-       drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
-               WPA_DRIVER_CAPA_ENC_WEP104 |
-               WPA_DRIVER_CAPA_ENC_TKIP |
-               WPA_DRIVER_CAPA_ENC_CCMP;
        drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
                WPA_DRIVER_AUTH_SHARED |
                WPA_DRIVER_AUTH_LEAP;
@@ -3184,6 +3598,9 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
        drv->device_ap_sme = info.device_ap_sme;
        drv->poll_command_supported = info.poll_command_supported;
        drv->data_tx_status = info.data_tx_status;
+       drv->channel_switch_supported = info.channel_switch_supported;
+       if (info.set_qos_map_supported)
+               drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING;
 
        /*
         * If poll command and tx status are supported, mac80211 is new enough
@@ -3314,9 +3731,9 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
        nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
                  process_global_event, global);
 
-       eloop_register_read_sock(nl_socket_get_fd(global->nl_event),
-                                wpa_driver_nl80211_event_receive,
-                                global->nl_cb, global->nl_event);
+       nl80211_register_eloop_read(&global->nl_event,
+                                   wpa_driver_nl80211_event_receive,
+                                   global->nl_cb);
 
        return 0;
 
@@ -3360,8 +3777,7 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
 {
        struct wpa_driver_nl80211_data *drv = ctx;
        wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
-       if (linux_set_iface_flags(drv->global->ioctl_sock,
-                                 drv->first_bss.ifname, 1)) {
+       if (i802_set_iface_flags(drv->first_bss, 1)) {
                wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
                           "after rfkill unblock");
                return;
@@ -3370,39 +3786,6 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
 }
 
 
-static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv)
-{
-       /* Find phy (radio) to which this interface belongs */
-       char buf[90], *pos;
-       int f, rv;
-
-       drv->phyname[0] = '\0';
-       snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
-                drv->first_bss.ifname);
-       f = open(buf, O_RDONLY);
-       if (f < 0) {
-               wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
-                          buf, strerror(errno));
-               return;
-       }
-
-       rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
-       close(f);
-       if (rv < 0) {
-               wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
-                          buf, strerror(errno));
-               return;
-       }
-
-       drv->phyname[rv] = '\0';
-       pos = os_strchr(drv->phyname, '\n');
-       if (pos)
-               *pos = '\0';
-       wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
-                  drv->first_bss.ifname, drv->phyname);
-}
-
-
 static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
                                                      void *eloop_ctx,
                                                      void *handle)
@@ -3484,16 +3867,9 @@ static void nl80211_destroy_bss(struct i802_bss *bss)
 }
 
 
-/**
- * wpa_driver_nl80211_init - Initialize nl80211 driver interface
- * @ctx: context to be used when calling wpa_supplicant functions,
- * e.g., wpa_supplicant_event()
- * @ifname: interface name, e.g., wlan0
- * @global_priv: private driver global data from global_init()
- * Returns: Pointer to private data, %NULL on failure
- */
-static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
-                                     void *global_priv)
+static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
+                                         void *global_priv, int hostapd,
+                                         const u8 *set_addr)
 {
        struct wpa_driver_nl80211_data *drv;
        struct rfkill_config *rcfg;
@@ -3506,11 +3882,21 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
                return NULL;
        drv->global = global_priv;
        drv->ctx = ctx;
-       bss = &drv->first_bss;
-       bss->drv = drv;
-       bss->ctx = ctx;
+       drv->hostapd = !!hostapd;
+       drv->eapol_sock = -1;
+       drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
+       drv->if_indices = drv->default_if_indices;
 
-       os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
+       drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
+       if (!drv->first_bss) {
+               os_free(drv);
+               return NULL;
+       }
+       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;
        drv->eapol_tx_sock = -1;
@@ -3524,8 +3910,6 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
        if (nl80211_init_bss(bss))
                goto failed;
 
-       nl80211_get_phy_name(drv);
-
        rcfg = os_zalloc(sizeof(*rcfg));
        if (rcfg == NULL)
                goto failed;
@@ -3539,7 +3923,10 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
                os_free(rcfg);
        }
 
-       if (wpa_driver_nl80211_finish_drv_init(drv))
+       if (linux_iface_up(drv->global->ioctl_sock, ifname) > 0)
+               drv->start_iface_up = 1;
+
+       if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1))
                goto failed;
 
        drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
@@ -3577,6 +3964,21 @@ failed:
 }
 
 
+/**
+ * wpa_driver_nl80211_init - Initialize nl80211 driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * @global_priv: private driver global data from global_init()
+ * Returns: Pointer to private data, %NULL on failure
+ */
+static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
+                                     void *global_priv)
+{
+       return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL);
+}
+
+
 static int nl80211_register_frame(struct i802_bss *bss,
                                  struct nl_handle *nl_handle,
                                  u16 type, const u8 *match, size_t match_len)
@@ -3596,7 +3998,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) < 0)
+               goto nla_put_failure;
+
        NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
        NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
 
@@ -3631,14 +4035,18 @@ static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
        if (bss->nl_mgmt == NULL)
                return -1;
 
-       eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt),
-                                wpa_driver_nl80211_event_receive, bss->nl_cb,
-                                bss->nl_mgmt);
-
        return 0;
 }
 
 
+static void nl80211_mgmt_handle_register_eloop(struct i802_bss *bss)
+{
+       nl80211_register_eloop_read(&bss->nl_mgmt,
+                                   wpa_driver_nl80211_event_receive,
+                                   bss->nl_cb);
+}
+
+
 static int nl80211_register_action_frame(struct i802_bss *bss,
                                         const u8 *match, size_t match_len)
 {
@@ -3657,6 +4065,18 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
        wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
                   "handle %p", bss->nl_mgmt);
 
+       if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
+               u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
+
+               /* register for any AUTH message */
+               nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0);
+       }
+
+#ifdef CONFIG_INTERWORKING
+       /* QoS Map Configure */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)
+               return -1;
+#endif /* CONFIG_INTERWORKING */
 #if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
        /* GAS Initial Request */
        if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
@@ -3711,6 +4131,8 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
        if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
                return -1;
 
+       nl80211_mgmt_handle_register_eloop(bss);
+
        return 0;
 }
 
@@ -3768,7 +4190,7 @@ static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
        wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
                   "handle %p", bss->nl_mgmt);
 
-       for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) {
+       for (i = 0; i < ARRAY_SIZE(stypes); i++) {
                if (nl80211_register_frame(bss, bss->nl_mgmt,
                                           (WLAN_FC_TYPE_MGMT << 2) |
                                           (stypes[i] << 4),
@@ -3783,10 +4205,10 @@ static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
        if (nl80211_get_wiphy_data_ap(bss) == NULL)
                goto out_err;
 
+       nl80211_mgmt_handle_register_eloop(bss);
        return 0;
 
 out_err:
-       eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
        nl_destroy_handles(&bss->nl_mgmt);
        return -1;
 }
@@ -3805,10 +4227,10 @@ static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
                                   NULL, 0) < 0)
                goto out_err;
 
+       nl80211_mgmt_handle_register_eloop(bss);
        return 0;
 
 out_err:
-       eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
        nl_destroy_handles(&bss->nl_mgmt);
        return -1;
 }
@@ -3820,8 +4242,7 @@ static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
                return;
        wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
                   "(%s)", bss->nl_mgmt, reason);
-       eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
-       nl_destroy_handles(&bss->nl_mgmt);
+       nl80211_destroy_eloop_handle(&bss->nl_mgmt);
 
        nl80211_put_wiphy_data_ap(bss);
 }
@@ -3833,26 +4254,127 @@ static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+static void nl80211_del_p2pdev(struct i802_bss *bss)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
+       NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
+                  bss->ifname, (long long unsigned int) bss->wdev_id,
+                  strerror(-ret));
+
+nla_put_failure:
+       nlmsg_free(msg);
+}
+
+
+static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret = -1;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       if (start)
+               nl80211_cmd(drv, msg, 0, NL80211_CMD_START_P2P_DEVICE);
+       else
+               nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_P2P_DEVICE);
+
+       NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+
+       wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
+                  start ? "Start" : "Stop",
+                  bss->ifname, (long long unsigned int) bss->wdev_id,
+                  strerror(-ret));
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return ret;
+}
+
+
+static int i802_set_iface_flags(struct i802_bss *bss, int up)
+{
+       enum nl80211_iftype nlmode;
+
+       nlmode = nl80211_get_ifmode(bss);
+       if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+               return linux_set_iface_flags(bss->drv->global->ioctl_sock,
+                                            bss->ifname, up);
+       }
+
+       /* P2P Device has start/stop which is equivalent */
+       return nl80211_set_p2pdev(bss, up);
+}
+
+
 static int
-wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
+                                  const u8 *set_addr, int first)
 {
-       struct i802_bss *bss = &drv->first_bss;
+       struct i802_bss *bss = drv->first_bss;
        int send_rfkill_event = 0;
+       enum nl80211_iftype nlmode;
 
        drv->ifindex = if_nametoindex(bss->ifname);
-       drv->first_bss.ifindex = drv->ifindex;
+       bss->ifindex = drv->ifindex;
+       bss->wdev_id = drv->global->if_add_wdevid;
+       bss->wdev_id_set = drv->global->if_add_wdevid_set;
 
-#ifndef HOSTAPD
-       /*
-        * Make sure the interface starts up in station mode unless this is a
-        * dynamically added interface (e.g., P2P) that was already configured
-        * with proper iftype.
-        */
-       if (drv->ifindex != drv->global->if_add_ifindex &&
-           wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION) < 0) {
-               wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to "
-                          "use managed mode");
+       bss->if_dynamic = drv->ifindex == drv->global->if_add_ifindex;
+       bss->if_dynamic = bss->if_dynamic || drv->global->if_add_wdevid_set;
+       drv->global->if_add_wdevid_set = 0;
+
+       if (wpa_driver_nl80211_capa(drv))
+               return -1;
+
+       wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
+                  bss->ifname, drv->phyname);
+
+       if (set_addr &&
+           (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) ||
+            linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+                               set_addr)))
                return -1;
+
+       if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
+               drv->start_mode_ap = 1;
+
+       if (drv->hostapd)
+               nlmode = NL80211_IFTYPE_AP;
+       else if (bss->if_dynamic)
+               nlmode = nl80211_get_ifmode(bss);
+       else
+               nlmode = NL80211_IFTYPE_STATION;
+
+       if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
+               wpa_printf(MSG_ERROR, "nl80211: Could not configure driver mode");
+               return -1;
+       }
+
+       if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+               int ret = nl80211_set_p2pdev(bss, 1);
+               if (ret < 0)
+                       wpa_printf(MSG_ERROR, "nl80211: Could not start P2P device");
+               nl80211_get_macaddr(bss);
+               return ret;
        }
 
        if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
@@ -3869,12 +4391,9 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
                }
        }
 
-       netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
-                              1, IF_OPER_DORMANT);
-#endif /* HOSTAPD */
-
-       if (wpa_driver_nl80211_capa(drv))
-               return -1;
+       if (!drv->hostapd)
+               netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
+                                      1, IF_OPER_DORMANT);
 
        if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
                               bss->addr))
@@ -3897,6 +4416,8 @@ static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
        if (!msg)
                return -ENOMEM;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
+                  drv->ifindex);
        nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
@@ -3945,15 +4466,6 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
        if (is_ap_interface(drv->nlmode))
                wpa_driver_nl80211_del_beacon(drv);
 
-#ifdef HOSTAPD
-       if (drv->last_freq_ht) {
-               /* Clear HT flags from the driver */
-               struct hostapd_freq_params freq;
-               os_memset(&freq, 0, sizeof(freq));
-               freq.freq = drv->last_freq;
-               wpa_driver_nl80211_set_freq(bss, &freq);
-       }
-
        if (drv->eapol_sock >= 0) {
                eloop_unregister_read_sock(drv->eapol_sock);
                close(drv->eapol_sock);
@@ -3961,7 +4473,6 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
 
        if (drv->if_indices != drv->default_if_indices)
                os_free(drv->if_indices);
-#endif /* HOSTAPD */
 
        if (drv->disabled_11b_rates)
                nl80211_disable_11b_rates(drv, drv->ifindex, 0);
@@ -3972,13 +4483,20 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
 
        eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
 
-       (void) linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
-       wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
-       nl80211_mgmt_unsubscribe(bss, "deinit");
-
+       if (!drv->start_iface_up)
+               (void) i802_set_iface_flags(bss, 0);
+       if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+               if (!drv->hostapd || !drv->start_mode_ap)
+                       wpa_driver_nl80211_set_mode(bss,
+                                                   NL80211_IFTYPE_STATION);
+               nl80211_mgmt_unsubscribe(bss, "deinit");
+       } else {
+               nl80211_mgmt_unsubscribe(bss, "deinit");
+               nl80211_del_p2pdev(bss);
+       }
        nl_cb_put(drv->nl_cb);
 
-       nl80211_destroy_bss(&drv->first_bss);
+       nl80211_destroy_bss(drv->first_bss);
 
        os_free(drv->filter_ssids);
 
@@ -3989,6 +4507,7 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
 
        os_free(drv->extended_capa);
        os_free(drv->extended_capa_mask);
+       os_free(drv->first_bss);
        os_free(drv);
 }
 
@@ -4005,7 +4524,7 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_driver_nl80211_data *drv = eloop_ctx;
        if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
-               wpa_driver_nl80211_set_mode(&drv->first_bss,
+               wpa_driver_nl80211_set_mode(drv->first_bss,
                                            drv->ap_scan_as_station);
                drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
        }
@@ -4016,7 +4535,7 @@ 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;
        size_t i;
@@ -4027,8 +4546,10 @@ 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 nlattr *ssids;
@@ -4077,6 +4598,7 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
        return msg;
 
 fail:
+nla_put_failure:
        nlmsg_free(msg);
        return NULL;
 }
@@ -4098,7 +4620,8 @@ static int wpa_driver_nl80211_scan(struct i802_bss *bss,
        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;
 
@@ -4129,8 +4652,7 @@ static int wpa_driver_nl80211_scan(struct i802_bss *bss,
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
                           "(%s)", ret, strerror(-ret));
-#ifdef HOSTAPD
-               if (is_ap_interface(drv->nlmode)) {
+               if (drv->hostapd && is_ap_interface(drv->nlmode)) {
                        /*
                         * mac80211 does not allow scan requests in AP mode, so
                         * try to do this in station mode.
@@ -4149,11 +4671,9 @@ static int wpa_driver_nl80211_scan(struct i802_bss *bss,
                        ret = 0;
                } else
                        goto nla_put_failure;
-#else /* HOSTAPD */
-               goto nla_put_failure;
-#endif /* HOSTAPD */
        }
 
+       drv->scan_state = SCAN_REQUESTED;
        /* Not all drivers generate "scan completed" wireless event, so try to
         * read results after a timeout. */
        timeout = 10;
@@ -4201,7 +4721,8 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
                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;
 
@@ -4604,7 +5125,8 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
                goto nla_put_failure;
 
        nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
+               goto nla_put_failure;
 
        arg.drv = drv;
        arg.res = res;
@@ -4675,17 +5197,25 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
                                      const u8 *key, size_t key_len)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       int ifindex = if_nametoindex(ifname);
+       int ifindex;
        struct nl_msg *msg;
        int ret;
+       int tdls = 0;
+
+       /* Ignore for P2P Device */
+       if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+               return 0;
 
+       ifindex = if_nametoindex(ifname);
        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, ifname, alg, addr, key_idx, set_tx,
                   (unsigned long) seq_len, (unsigned long) key_len);
 #ifdef CONFIG_TDLS
-       if (key_idx == -1)
+       if (key_idx == -1) {
                key_idx = 0;
+               tdls = 1;
+       }
 #endif /* CONFIG_TDLS */
 
        msg = nlmsg_alloc();
@@ -4718,10 +5248,30 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
                        NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
                                    WLAN_CIPHER_SUITE_GCMP);
                        break;
+               case WPA_ALG_CCMP_256:
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+                                   WLAN_CIPHER_SUITE_CCMP_256);
+                       break;
+               case WPA_ALG_GCMP_256:
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+                                   WLAN_CIPHER_SUITE_GCMP_256);
+                       break;
                case WPA_ALG_IGTK:
                        NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
                                    WLAN_CIPHER_SUITE_AES_CMAC);
                        break;
+               case WPA_ALG_BIP_GMAC_128:
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+                                   WLAN_CIPHER_SUITE_BIP_GMAC_128);
+                       break;
+               case WPA_ALG_BIP_GMAC_256:
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+                                   WLAN_CIPHER_SUITE_BIP_GMAC_256);
+                       break;
+               case WPA_ALG_BIP_CMAC_256:
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+                                   WLAN_CIPHER_SUITE_BIP_CMAC_256);
+                       break;
                case WPA_ALG_SMS4:
                        NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
                                    WLAN_CIPHER_SUITE_SMS4);
@@ -4775,7 +5325,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
         * If we failed or don't need to set the default TX key (below),
         * we're done here.
         */
-       if (ret || !set_tx || alg == WPA_ALG_NONE)
+       if (ret || !set_tx || alg == WPA_ALG_NONE || tdls)
                return ret;
        if (is_ap_interface(drv->nlmode) && addr &&
            !is_broadcast_ether_addr(addr))
@@ -4858,10 +5408,30 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
        case WPA_ALG_GCMP:
                NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_GCMP);
                break;
+       case WPA_ALG_CCMP_256:
+               NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+                           WLAN_CIPHER_SUITE_CCMP_256);
+               break;
+       case WPA_ALG_GCMP_256:
+               NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+                           WLAN_CIPHER_SUITE_GCMP_256);
+               break;
        case WPA_ALG_IGTK:
                NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
                            WLAN_CIPHER_SUITE_AES_CMAC);
                break;
+       case WPA_ALG_BIP_GMAC_128:
+               NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+                           WLAN_CIPHER_SUITE_BIP_GMAC_128);
+               break;
+       case WPA_ALG_BIP_GMAC_256:
+               NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+                           WLAN_CIPHER_SUITE_BIP_GMAC_256);
+               break;
+       case WPA_ALG_BIP_CMAC_256:
+               NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+                           WLAN_CIPHER_SUITE_BIP_CMAC_256);
+               break;
        default:
                wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
                           "algorithm %d", __func__, alg);
@@ -4980,12 +5550,20 @@ nla_put_failure:
 static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
                                         int reason_code)
 {
+       int ret;
+
        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);
+       ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
+                                     reason_code, 0);
+       /*
+        * For locally generated disconnect, supplicant already generates a
+        * DEAUTH event, so ignore the event from NL80211.
+        */
+       drv->ignore_next_local_disconnect = ret == 0;
+
+       return ret;
 }
 
 
@@ -5230,7 +5808,7 @@ static int wpa_driver_nl80211_authenticate_retry(
        struct wpa_driver_nl80211_data *drv)
 {
        struct wpa_driver_auth_params params;
-       struct i802_bss *bss = &drv->first_bss;
+       struct i802_bss *bss = drv->first_bss;
        int i;
 
        wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
@@ -5320,17 +5898,11 @@ static void phy_info_freq(struct hostapd_hw_modes *mode,
 
        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_NO_IR])
+               chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN | 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]);
@@ -5356,8 +5928,7 @@ static int phy_info_freqs(struct phy_info_arg *phy_info,
        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 },
-               [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
-               [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
+               [NL80211_FREQUENCY_ATTR_NO_IR] = { .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 },
@@ -5465,7 +6036,20 @@ static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
                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;
+               mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN |
+                       HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN;
+
+               /*
+                * Unsupported VHT MCS stream is defined as value 3, so the VHT
+                * MCS RX/TX map must be initialized with 0xffff to mark all 8
+                * possible streams as unsupported. This will be overridden if
+                * driver advertises VHT support.
+                */
+               mode->vht_mcs_set[0] = 0xff;
+               mode->vht_mcs_set[1] = 0xff;
+               mode->vht_mcs_set[4] = 0xff;
+               mode->vht_mcs_set[5] = 0xff;
+
                *(phy_info->num_modes) += 1;
                phy_info->last_mode = nl_band->nla_type;
                phy_info->last_chan_idx = 0;
@@ -5640,6 +6224,38 @@ static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
 }
 
 
+static void nl80211_reg_rule_max_eirp(struct nlattr *tb[],
+                                     struct phy_info_arg *results)
+{
+       u32 start, end, max_eirp;
+       u16 m;
+
+       if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+           tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+           tb[NL80211_ATTR_POWER_RULE_MAX_EIRP] == NULL)
+               return;
+
+       start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+       end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+       max_eirp = nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100;
+
+       wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u mBm",
+                  start, end, max_eirp);
+
+       for (m = 0; m < *results->num_modes; m++) {
+               int c;
+               struct hostapd_hw_modes *mode = &results->modes[m];
+
+               for (c = 0; c < mode->num_channels; c++) {
+                       struct hostapd_channel_data *chan = &mode->channels[c];
+                       if ((u32) chan->freq - 10 >= start &&
+                           (u32) chan->freq + 10 <= end)
+                               chan->max_tx_power = max_eirp;
+               }
+       }
+}
+
+
 static void nl80211_reg_rule_ht40(struct nlattr *tb[],
                                  struct phy_info_arg *results)
 {
@@ -5696,6 +6312,59 @@ static void nl80211_reg_rule_sec(struct nlattr *tb[],
 }
 
 
+static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
+                                int end)
+{
+       int c;
+
+       for (c = 0; c < mode->num_channels; c++) {
+               struct hostapd_channel_data *chan = &mode->channels[c];
+               if (chan->freq - 10 >= start && chan->freq + 70 <= end)
+                       chan->flag |= HOSTAPD_CHAN_VHT_10_70;
+
+               if (chan->freq - 30 >= start && chan->freq + 50 <= end)
+                       chan->flag |= HOSTAPD_CHAN_VHT_30_50;
+
+               if (chan->freq - 50 >= start && chan->freq + 30 <= end)
+                       chan->flag |= HOSTAPD_CHAN_VHT_50_30;
+
+               if (chan->freq - 70 >= start && chan->freq + 10 <= end)
+                       chan->flag |= HOSTAPD_CHAN_VHT_70_10;
+       }
+}
+
+
+static void nl80211_reg_rule_vht(struct nlattr *tb[],
+                                struct phy_info_arg *results)
+{
+       u32 start, end, max_bw;
+       u16 m;
+
+       if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+           tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+           tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+               return;
+
+       start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+       end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+       max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+       if (max_bw < 80)
+               return;
+
+       for (m = 0; m < *results->num_modes; m++) {
+               if (!(results->modes[m].ht_capab &
+                     HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+                       continue;
+               /* TODO: use a real VHT support indication */
+               if (!results->modes[m].vht_capab)
+                       continue;
+
+               nl80211_set_vht_mode(&results->modes[m], start, end);
+       }
+}
+
+
 static int nl80211_get_reg(struct nl_msg *msg, void *arg)
 {
        struct phy_info_arg *results = arg;
@@ -5730,6 +6399,7 @@ static int nl80211_get_reg(struct nl_msg *msg, void *arg)
                nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
                          nla_data(nl_rule), nla_len(nl_rule), reg_policy);
                nl80211_reg_rule_ht40(tb_rule, results);
+               nl80211_reg_rule_max_eirp(tb_rule, results);
        }
 
        nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
@@ -5739,12 +6409,19 @@ static int nl80211_get_reg(struct nl_msg *msg, void *arg)
                nl80211_reg_rule_sec(tb_rule, results);
        }
 
+       nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+       {
+               nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+                         nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+               nl80211_reg_rule_vht(tb_rule, results);
+       }
+
        return NL_SKIP;
 }
 
 
-static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv,
-                                 struct phy_info_arg *results)
+static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
+                                       struct phy_info_arg *results)
 {
        struct nl_msg *msg;
 
@@ -5787,7 +6464,7 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
        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);
+               nl80211_set_regulatory_flags(drv, &result);
                return wpa_driver_nl80211_postprocess_modes(result.modes,
                                                            num_modes);
        }
@@ -5863,16 +6540,42 @@ static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
        u64 cookie;
+       int res;
 
-       if (freq == 0)
+       if (freq == 0) {
+               wpa_printf(MSG_DEBUG, "nl80211: send_frame - Use bss->freq=%u",
+                          bss->freq);
                freq = bss->freq;
+       }
 
-       if (drv->use_monitor)
+       if (drv->use_monitor) {
+               wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_mntr",
+                          freq, bss->freq);
                return wpa_driver_nl80211_send_mntr(drv, data, len,
                                                    encrypt, noack);
+       }
+
+       wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd");
+       res = nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
+                                    &cookie, no_cck, noack, offchanok);
+       if (res == 0 && !noack) {
+               const struct ieee80211_mgmt *mgmt;
+               u16 fc;
+
+               mgmt = (const struct ieee80211_mgmt *) data;
+               fc = le_to_host16(mgmt->frame_control);
+               if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+                   WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
+                       wpa_printf(MSG_MSGDUMP,
+                                  "nl80211: Update send_action_cookie from 0x%llx to 0x%llx",
+                                  (long long unsigned int)
+                                  drv->send_action_cookie,
+                                  (long long unsigned int) cookie);
+                       drv->send_action_cookie = cookie;
+               }
+       }
 
-       return nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
-                                     &cookie, no_cck, noack, offchanok);
+       return res;
 }
 
 
@@ -5889,8 +6592,11 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
 
        mgmt = (struct ieee80211_mgmt *) data;
        fc = le_to_host16(mgmt->frame_control);
+       wpa_printf(MSG_DEBUG, "nl80211: send_mlme - noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u fc=0x%x nlmode=%d",
+                  noack, freq, no_cck, offchanok, wait_time, fc, drv->nlmode);
 
-       if (is_sta_interface(drv->nlmode) &&
+       if ((is_sta_interface(drv->nlmode) ||
+            drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
            WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
            WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
                /*
@@ -5898,16 +6604,22 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
                 * but it works due to the single-threaded nature
                 * of wpa_supplicant.
                 */
-               if (freq == 0)
+               if (freq == 0) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Use last_mgmt_freq=%d",
+                                  drv->last_mgmt_freq);
                        freq = drv->last_mgmt_freq;
+               }
                return nl80211_send_frame_cmd(bss, freq, 0,
                                              data, data_len, NULL, 1, noack,
                                              1);
        }
 
        if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
-               if (freq == 0)
+               if (freq == 0) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Use bss->freq=%d",
+                                  bss->freq);
                        freq = bss->freq;
+               }
                return nl80211_send_frame_cmd(bss, freq,
                                              (int) freq == bss->freq ? 0 :
                                              wait_time,
@@ -5930,6 +6642,7 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
                        encrypt = 0;
        }
 
+       wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame");
        return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
                                             noack, freq, no_cck, offchanok,
                                             wait_time);
@@ -6142,6 +6855,10 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
                   params->pairwise_ciphers);
        num_suites = 0;
+       if (params->pairwise_ciphers & WPA_CIPHER_CCMP_256)
+               suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP_256;
+       if (params->pairwise_ciphers & WPA_CIPHER_GCMP_256)
+               suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP_256;
        if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
                suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
        if (params->pairwise_ciphers & WPA_CIPHER_GCMP)
@@ -6160,6 +6877,14 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
                   params->group_cipher);
        switch (params->group_cipher) {
+       case WPA_CIPHER_CCMP_256:
+               NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+                           WLAN_CIPHER_SUITE_CCMP_256);
+               break;
+       case WPA_CIPHER_GCMP_256:
+               NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+                           WLAN_CIPHER_SUITE_GCMP_256);
+               break;
        case WPA_CIPHER_CCMP:
                NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
                            WLAN_CIPHER_SUITE_CCMP);
@@ -6227,24 +6952,9 @@ static int wpa_driver_nl80211_set_ap(void *priv,
 }
 
 
-static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
-                                      struct hostapd_freq_params *freq)
+static int nl80211_put_freq_params(struct nl_msg *msg,
+                                  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, 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;
-
-       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->freq);
        if (freq->vht_enabled) {
                switch (freq->bandwidth) {
@@ -6269,7 +6979,7 @@ static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
                                    NL80211_CHAN_WIDTH_160);
                        break;
                default:
-                       return -1;
+                       return -EINVAL;
                }
                NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
                if (freq->center_freq2)
@@ -6291,12 +7001,39 @@ static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
                        break;
                }
        }
+       return 0;
 
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-       msg = NULL;
-       if (ret == 0) {
-               bss->freq = freq->freq;
-               return 0;
+nla_put_failure:
+       return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
+                                      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, 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;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_put_freq_params(msg, freq) < 0)
+               goto nla_put_failure;
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+       if (ret == 0) {
+               bss->freq = freq->freq;
+               return 0;
        }
        wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
                   "%d (%s)", freq->freq, ret, strerror(-ret));
@@ -6455,6 +7192,9 @@ static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr)
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
+                  " --> %d (%s)",
+                  bss->ifname, MAC2STR(addr), ret, strerror(-ret));
        if (ret == -ENOENT)
                return 0;
        return ret;
@@ -6511,6 +7251,8 @@ static const char * nl80211_iftype_str(enum nl80211_iftype mode)
                return "P2P_CLIENT";
        case NL80211_IFTYPE_P2P_GO:
                return "P2P_GO";
+       case NL80211_IFTYPE_P2P_DEVICE:
+               return "P2P_DEVICE";
        default:
                return "unknown";
        }
@@ -6520,7 +7262,9 @@ 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;
        int ifidx;
@@ -6534,7 +7278,8 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                return -1;
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
+               goto nla_put_failure;
        NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
        NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
 
@@ -6552,7 +7297,7 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                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:
@@ -6562,6 +7307,9 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                return ret;
        }
 
+       if (iftype == NL80211_IFTYPE_P2P_DEVICE)
+               return 0;
+
        ifidx = if_nametoindex(ifname);
        wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
                   ifname, ifidx);
@@ -6584,14 +7332,22 @@ 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 use_existing)
 {
        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)) {
+               if (use_existing) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Continue using existing interface %s",
+                                  ifname);
+                       return -ENFILE;
+               }
                wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
 
                /* Try to remove the interface that was already there. */
@@ -6599,10 +7355,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;
@@ -6693,12 +7449,13 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
 
        len = recv(sock, buf, sizeof(buf), 0);
        if (len < 0) {
-               perror("recv");
+               wpa_printf(MSG_ERROR, "nl80211: Monitor socket recv failed: %s",
+                          strerror(errno));
                return;
        }
 
        if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
-               printf("received invalid radiotap frame\n");
+               wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
                return;
        }
 
@@ -6707,7 +7464,8 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
                if (ret == -ENOENT)
                        break;
                if (ret) {
-                       printf("received invalid radiotap frame (%d)\n", ret);
+                       wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame (%d)",
+                                  ret);
                        return;
                }
                switch (iter.this_arg_index) {
@@ -6857,7 +7615,7 @@ static struct sock_filter msock_filter_insns[] = {
 };
 
 static struct sock_fprog msock_filter = {
-       .len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]),
+       .len = ARRAY_SIZE(msock_filter_insns),
        .filter = msock_filter_insns,
 };
 
@@ -6892,7 +7650,8 @@ static int add_monitor_filter(int s)
 
        if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
                       &msock_filter, sizeof(msock_filter))) {
-               perror("SO_ATTACH_FILTER");
+               wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s",
+                          strerror(errno));
                return -1;
        }
 
@@ -6903,7 +7662,10 @@ static int add_monitor_filter(int s)
 static void nl80211_remove_monitor_interface(
        struct wpa_driver_nl80211_data *drv)
 {
-       drv->monitor_refcount--;
+       if (drv->monitor_refcount > 0)
+               drv->monitor_refcount--;
+       wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface: refcount=%d",
+                  drv->monitor_refcount);
        if (drv->monitor_refcount > 0)
                return;
 
@@ -6929,27 +7691,29 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
 
        if (drv->monitor_ifidx >= 0) {
                drv->monitor_refcount++;
+               wpa_printf(MSG_DEBUG, "nl80211: Re-use existing monitor interface: refcount=%d",
+                          drv->monitor_refcount);
                return 0;
        }
 
-       if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) {
+       if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) {
                /*
                 * P2P interface name is of the format p2p-%s-%d. For monitor
                 * interface name corresponding to P2P GO, replace "p2p-" with
                 * "mon-" to retain the same interface name length and to
                 * indicate that it is a monitor interface.
                 */
-               snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4);
+               snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
        } else {
                /* Non-P2P interface with AP functionality. */
-               snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
+               snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname);
        }
 
        buf[IFNAMSIZ - 1] = '\0';
 
        drv->monitor_ifidx =
                nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
-                                    0);
+                                    0, NULL, NULL, 0);
 
        if (drv->monitor_ifidx == -EOPNOTSUPP) {
                /*
@@ -6974,7 +7738,8 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
        ll.sll_ifindex = drv->monitor_ifidx;
        drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
        if (drv->monitor_sock < 0) {
-               perror("socket[PF_PACKET,SOCK_RAW]");
+               wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s",
+                          strerror(errno));
                goto error;
        }
 
@@ -6985,7 +7750,8 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
        }
 
        if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
-               perror("monitor socket bind");
+               wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s",
+                          strerror(errno));
                goto error;
        }
 
@@ -6993,16 +7759,18 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
        optval = 20;
        if (setsockopt
            (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
-               perror("Failed to set socket priority");
+               wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s",
+                          strerror(errno));
                goto error;
        }
 
        if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
                                     drv, NULL)) {
-               printf("Could not register monitor read socket\n");
+               wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket");
                goto error;
        }
 
+       drv->monitor_refcount++;
        return 0;
  error:
        nl80211_remove_monitor_interface(drv);
@@ -7014,8 +7782,8 @@ static int nl80211_setup_ap(struct i802_bss *bss)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
 
-       wpa_printf(MSG_DEBUG, "nl80211: Setup AP - device_ap_sme=%d "
-                  "use_monitor=%d", drv->device_ap_sme, drv->use_monitor);
+       wpa_printf(MSG_DEBUG, "nl80211: Setup AP(%s) - device_ap_sme=%d use_monitor=%d",
+                  bss->ifname, drv->device_ap_sme, drv->use_monitor);
 
        /*
         * Disable Probe Request reporting unless we need it in this way for
@@ -7053,6 +7821,8 @@ static void nl80211_teardown_ap(struct i802_bss *bss)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) - device_ap_sme=%d use_monitor=%d",
+                  bss->ifname, drv->device_ap_sme, drv->use_monitor);
        if (drv->device_ap_sme) {
                wpa_driver_nl80211_probe_req_report(bss, 0);
                if (!drv->use_monitor)
@@ -7115,8 +7885,8 @@ static int wpa_driver_nl80211_hapd_send_eapol(
                data_len;
        hdr = os_zalloc(len);
        if (hdr == NULL) {
-               printf("malloc() failed for i802_send_data(len=%lu)\n",
-                      (unsigned long) len);
+               wpa_printf(MSG_INFO, "nl80211: Failed to allocate EAPOL buffer(len=%lu)",
+                          (unsigned long) len);
                return -1;
        }
 
@@ -7233,14 +8003,14 @@ static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
                nlmode = NL80211_IFTYPE_AP;
 
        old_mode = drv->nlmode;
-       if (wpa_driver_nl80211_set_mode(&drv->first_bss, 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 (wpa_driver_nl80211_set_freq(drv->first_bss, &freq)) {
                if (old_mode != nlmode)
-                       wpa_driver_nl80211_set_mode(&drv->first_bss, old_mode);
+                       wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
                nl80211_remove_monitor_interface(drv);
                return -1;
        }
@@ -7272,6 +8042,12 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
        wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully");
 
 nla_put_failure:
+       if (wpa_driver_nl80211_set_mode(drv->first_bss,
+                                       NL80211_IFTYPE_STATION)) {
+               wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
+                          "station mode");
+       }
+
        nlmsg_free(msg);
        return ret;
 }
@@ -7286,7 +8062,7 @@ static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
 
        wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
 
-       if (wpa_driver_nl80211_set_mode(&drv->first_bss,
+       if (wpa_driver_nl80211_set_mode(drv->first_bss,
                                        NL80211_IFTYPE_ADHOC)) {
                wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
                           "IBSS mode");
@@ -7390,7 +8166,9 @@ static int wpa_driver_nl80211_try_connect(
        if (params->freq) {
                wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
                NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
-       }
+               drv->assoc_freq = params->freq;
+       } else
+               drv->assoc_freq = 0;
        if (params->bg_scan_period >= 0) {
                wpa_printf(MSG_DEBUG, "  * bg scan period=%d",
                           params->bg_scan_period);
@@ -7471,6 +8249,12 @@ skip_auth_type:
                case CIPHER_GCMP:
                        cipher = WLAN_CIPHER_SUITE_GCMP;
                        break;
+               case CIPHER_CCMP_256:
+                       cipher = WLAN_CIPHER_SUITE_CCMP_256;
+                       break;
+               case CIPHER_GCMP_256:
+                       cipher = WLAN_CIPHER_SUITE_GCMP_256;
+                       break;
                case CIPHER_TKIP:
                default:
                        cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -7498,6 +8282,12 @@ skip_auth_type:
                case CIPHER_GCMP:
                        cipher = WLAN_CIPHER_SUITE_GCMP;
                        break;
+               case CIPHER_CCMP_256:
+                       cipher = WLAN_CIPHER_SUITE_CCMP_256;
+                       break;
+               case CIPHER_GCMP_256:
+                       cipher = WLAN_CIPHER_SUITE_GCMP_256;
+                       break;
                case CIPHER_TKIP:
                default:
                        cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -7601,8 +8391,6 @@ static int wpa_driver_nl80211_connect(
                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;
@@ -7691,6 +8479,12 @@ static int wpa_driver_nl80211_associate(
                case CIPHER_GCMP:
                        cipher = WLAN_CIPHER_SUITE_GCMP;
                        break;
+               case CIPHER_CCMP_256:
+                       cipher = WLAN_CIPHER_SUITE_CCMP_256;
+                       break;
+               case CIPHER_GCMP_256:
+                       cipher = WLAN_CIPHER_SUITE_GCMP_256;
+                       break;
                case CIPHER_TKIP:
                default:
                        cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -7716,6 +8510,12 @@ static int wpa_driver_nl80211_associate(
                case CIPHER_GCMP:
                        cipher = WLAN_CIPHER_SUITE_GCMP;
                        break;
+               case CIPHER_CCMP_256:
+                       cipher = WLAN_CIPHER_SUITE_CCMP_256;
+                       break;
+               case CIPHER_GCMP_256:
+                       cipher = WLAN_CIPHER_SUITE_GCMP_256;
+                       break;
                case CIPHER_TKIP:
                default:
                        cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -7799,7 +8599,8 @@ static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
                return -ENOMEM;
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+       if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
+               goto nla_put_failure;
        NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -7824,6 +8625,9 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
        int res;
 
        res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+       if (res && nlmode == nl80211_get_ifmode(bss))
+               res = 0;
+
        if (res == 0) {
                drv->nlmode = nlmode;
                ret = 0;
@@ -7847,8 +8651,7 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
        wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
                   "interface down");
        for (i = 0; i < 10; i++) {
-               res = linux_set_iface_flags(drv->global->ioctl_sock,
-                                           bss->ifname, 0);
+               res = i802_set_iface_flags(bss, 0);
                if (res == -EACCES || res == -ENODEV)
                        break;
                if (res == 0) {
@@ -7857,8 +8660,7 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
                        ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
                        if (ret == -EACCES)
                                break;
-                       res = linux_set_iface_flags(drv->global->ioctl_sock,
-                                                   bss->ifname, 1);
+                       res = i802_set_iface_flags(bss, 1);
                        if (res && !ret)
                                ret = -1;
                        else if (ret != -EBUSY)
@@ -7883,7 +8685,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);
@@ -7922,6 +8724,13 @@ static int wpa_driver_nl80211_get_capa(void *priv,
                capa->extended_capa_mask = drv->extended_capa_mask;
                capa->extended_capa_len = drv->extended_capa_len;
        }
+
+       if ((capa->flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+           !drv->allow_p2p_device) {
+               wpa_printf(MSG_DEBUG, "nl80211: Do not indicate P2P_DEVICE support (p2p_device=1 driver param not specified)");
+               capa->flags &= ~WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+       }
+
        return 0;
 }
 
@@ -7980,8 +8789,6 @@ static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
 }
 
 
-#if defined(HOSTAPD) || defined(CONFIG_AP)
-
 static inline int min_int(int a, int b)
 {
        if (a < b)
@@ -8115,6 +8922,8 @@ static int i802_flush(void *priv)
        if (!msg)
                return -1;
 
+       wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)",
+                  bss->ifname);
        nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
 
        /*
@@ -8134,8 +8943,6 @@ static int i802_flush(void *priv)
        return -ENOBUFS;
 }
 
-#endif /* HOSTAPD || CONFIG_AP */
-
 
 static int get_sta_handler(struct nl_msg *msg, void *arg)
 {
@@ -8216,8 +9023,6 @@ static int i802_read_sta_data(struct i802_bss *bss,
 }
 
 
-#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)
 {
@@ -8288,6 +9093,10 @@ static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
        if (!msg)
                return -ENOMEM;
 
+       wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR
+                  ", ifname=%s[%d], vlan_id=%d)",
+                  bss->ifname, if_nametoindex(bss->ifname),
+                  MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
        nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
@@ -8379,9 +9188,6 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
                                            0);
 }
 
-#endif /* HOSTAPD || CONFIG_AP */
-
-#ifdef HOSTAPD
 
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 {
@@ -8447,20 +9253,24 @@ static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 
 
 static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
-                            const char *bridge_ifname)
+                            const char *bridge_ifname, char *ifname_wds)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        char name[IFNAMSIZ + 1];
 
        os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+       if (ifname_wds)
+               os_strlcpy(ifname_wds, name, IFNAMSIZ + 1);
+
        wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
                   " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
        if (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) <
+                           0)
                                return -1;
                        if (bridge_ifname &&
                            linux_br_add_if(drv->global->ioctl_sock,
@@ -8495,7 +9305,8 @@ static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
        len = recvfrom(sock, buf, sizeof(buf), 0,
                       (struct sockaddr *)&lladdr, &fromlen);
        if (len < 0) {
-               perror("recv");
+               wpa_printf(MSG_ERROR, "nl80211: EAPOL recv failed: %s",
+                          strerror(errno));
                return;
        }
 
@@ -8568,14 +9379,13 @@ static void *i802_init(struct hostapd_data *hapd,
        int ifindex, br_ifindex;
        int br_added = 0;
 
-       bss = wpa_driver_nl80211_init(hapd, params->ifname,
-                                     params->global_priv);
+       bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
+                                         params->global_priv, 1,
+                                         params->bssid);
        if (bss == NULL)
                return NULL;
 
        drv = bss->drv;
-       drv->nlmode = NL80211_IFTYPE_AP;
-       drv->eapol_sock = -1;
 
        if (linux_br_get(brname, params->ifname) == 0) {
                wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
@@ -8586,8 +9396,6 @@ static void *i802_init(struct hostapd_data *hapd,
                br_ifindex = 0;
        }
 
-       drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
-       drv->if_indices = drv->default_if_indices;
        for (i = 0; i < params->num_bridge; i++) {
                if (params->bridge[i]) {
                        ifindex = if_nametoindex(params->bridge[i]);
@@ -8604,37 +9412,20 @@ static void *i802_init(struct hostapd_data *hapd,
        /* start listening for EAPOL on the default AP interface */
        add_ifidx(drv, drv->ifindex);
 
-       if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0))
-               goto failed;
-
-       if (params->bssid) {
-               if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-                                      params->bssid))
-                       goto failed;
-       }
-
-       if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
-                          "into AP mode", bss->ifname);
-               goto failed;
-       }
-
        if (params->num_bridge && params->bridge[0] &&
            i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
                goto failed;
 
-       if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1))
-               goto failed;
-
        drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
        if (drv->eapol_sock < 0) {
-               perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)");
+               wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
+                          strerror(errno));
                goto failed;
        }
 
        if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
        {
-               printf("Could not register read socket for eapol\n");
+               wpa_printf(MSG_INFO, "nl80211: Could not register read socket for eapol");
                goto failed;
        }
 
@@ -8658,8 +9449,6 @@ static void i802_deinit(void *priv)
        wpa_driver_nl80211_deinit(bss);
 }
 
-#endif /* HOSTAPD */
-
 
 static enum nl80211_iftype wpa_driver_nl80211_if_type(
        enum wpa_driver_if_type type)
@@ -8676,6 +9465,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;
 }
@@ -8688,7 +9479,7 @@ static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
        struct wpa_driver_nl80211_data *drv;
        dl_list_for_each(drv, &global->interfaces,
                         struct wpa_driver_nl80211_data, list) {
-               if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0)
+               if (os_memcmp(addr, drv->first_bss->addr, ETH_ALEN) == 0)
                        return 1;
        }
        return 0;
@@ -8703,9 +9494,9 @@ static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
        if (!drv->global)
                return -1;
 
-       os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN);
+       os_memcpy(new_addr, drv->first_bss->addr, ETH_ALEN);
        for (idx = 0; idx < 64; idx++) {
-               new_addr[0] = drv->first_bss.addr[0] | 0x02;
+               new_addr[0] = drv->first_bss->addr[0] | 0x02;
                new_addr[0] ^= idx << 2;
                if (!nl80211_addr_in_use(drv->global, new_addr))
                        break;
@@ -8722,42 +9513,88 @@ static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
 #endif /* CONFIG_P2P */
 
 
+struct wdev_info {
+       u64 wdev_id;
+       int wdev_id_set;
+       u8 macaddr[ETH_ALEN];
+};
+
+static int nl80211_wdev_handler(struct nl_msg *msg, void *arg)
+{
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct wdev_info *wi = arg;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+       if (tb[NL80211_ATTR_WDEV]) {
+               wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+               wi->wdev_id_set = 1;
+       }
+
+       if (tb[NL80211_ATTR_MAC])
+               os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
+                         ETH_ALEN);
+
+       return NL_SKIP;
+}
+
+
 static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                                     const char *ifname, const u8 *addr,
                                     void *bss_ctx, void **drv_priv,
                                     char *force_ifname, u8 *if_addr,
-                                    const char *bridge)
+                                    const char *bridge, int use_existing)
 {
+       enum nl80211_iftype nlmode;
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ifidx;
-#ifdef HOSTAPD
-       struct i802_bss *new_bss = NULL;
-
-       if (type == WPA_IF_AP_BSS) {
-               new_bss = os_zalloc(sizeof(*new_bss));
-               if (new_bss == NULL)
-                       return -1;
-       }
-#endif /* HOSTAPD */
+       int added = 1;
 
        if (addr)
                os_memcpy(if_addr, addr, ETH_ALEN);
-       ifidx = nl80211_create_iface(drv, ifname,
-                                    wpa_driver_nl80211_if_type(type), addr,
-                                    0);
-       if (ifidx < 0) {
-#ifdef HOSTAPD
-               os_free(new_bss);
-#endif /* HOSTAPD */
-               return -1;
+       nlmode = wpa_driver_nl80211_if_type(type);
+       if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+               struct wdev_info p2pdev_info;
+
+               os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
+               ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
+                                            0, nl80211_wdev_handler,
+                                            &p2pdev_info, use_existing);
+               if (!p2pdev_info.wdev_id_set || ifidx != 0) {
+                       wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
+                                  ifname);
+                       return -1;
+               }
+
+               drv->global->if_add_wdevid = p2pdev_info.wdev_id;
+               drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
+               if (!is_zero_ether_addr(p2pdev_info.macaddr))
+                       os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
+               wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
+                          ifname,
+                          (long long unsigned int) p2pdev_info.wdev_id);
+       } else {
+               ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
+                                            0, NULL, NULL, use_existing);
+               if (use_existing && ifidx == -ENFILE) {
+                       added = 0;
+                       ifidx = if_nametoindex(ifname);
+               } else if (ifidx < 0) {
+                       return -1;
+               }
        }
 
-       if (!addr &&
-           linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-                              if_addr) < 0) {
-               nl80211_remove_iface(drv, ifidx);
-               return -1;
+       if (!addr) {
+               if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+                       os_memcpy(if_addr, bss->addr, ETH_ALEN);
+               else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
+                                           bss->ifname, if_addr) < 0) {
+                       if (added)
+                               nl80211_remove_iface(drv, ifidx);
+                       return -1;
+               }
        }
 
 #ifdef CONFIG_P2P
@@ -8765,16 +9602,14 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
            (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
             type == WPA_IF_P2P_GO)) {
                /* Enforce unique P2P Interface Address */
-               u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN];
+               u8 new_addr[ETH_ALEN];
 
-               if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-                                      own_addr) < 0 ||
-                   linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
+               if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
                                       new_addr) < 0) {
                        nl80211_remove_iface(drv, ifidx);
                        return -1;
                }
-               if (os_memcmp(own_addr, new_addr, ETH_ALEN) == 0) {
+               if (nl80211_addr_in_use(drv->global, new_addr)) {
                        wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
                                   "for P2P group interface");
                        if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
@@ -8791,17 +9626,25 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
        }
 #endif /* CONFIG_P2P */
 
-#ifdef HOSTAPD
-       if (bridge &&
-           i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
-                          "interface %s to a bridge %s", ifname, bridge);
-               nl80211_remove_iface(drv, ifidx);
-               os_free(new_bss);
-               return -1;
-       }
-
        if (type == WPA_IF_AP_BSS) {
+               struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
+               if (new_bss == NULL) {
+                       if (added)
+                               nl80211_remove_iface(drv, ifidx);
+                       return -1;
+               }
+
+               if (bridge &&
+                   i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
+                       wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
+                                  "interface %s to a bridge %s",
+                                  ifname, bridge);
+                       if (added)
+                               nl80211_remove_iface(drv, ifidx);
+                       os_free(new_bss);
+                       return -1;
+               }
+
                if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
                {
                        nl80211_remove_iface(drv, ifidx);
@@ -8812,10 +9655,11 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
                new_bss->ifindex = ifidx;
                new_bss->drv = drv;
-               new_bss->next = drv->first_bss.next;
-               new_bss->freq = drv->first_bss.freq;
+               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;
+               new_bss->added_if = added;
+               drv->first_bss->next = new_bss;
                if (drv_priv)
                        *drv_priv = new_bss;
                nl80211_init_bss(new_bss);
@@ -8824,7 +9668,6 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                if (nl80211_setup_ap(new_bss))
                        return -1;
        }
-#endif /* HOSTAPD */
 
        if (drv->global)
                drv->global->if_add_ifindex = ifidx;
@@ -8840,14 +9683,11 @@ static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ifindex = if_nametoindex(ifname);
 
-       wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d",
-                  __func__, type, ifname, ifindex);
-       if (ifindex <= 0)
-               return -1;
-
-       nl80211_remove_iface(drv, ifindex);
+       wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d",
+                  __func__, type, ifname, ifindex, bss->added_if);
+       if (ifindex > 0 && (bss->added_if || bss->ifindex != ifindex))
+               nl80211_remove_iface(drv, ifindex);
 
-#ifdef HOSTAPD
        if (type != WPA_IF_AP_BSS)
                return 0;
 
@@ -8865,10 +9705,11 @@ static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
                                   bss->brname, strerror(errno));
        }
 
-       if (bss != &drv->first_bss) {
+       if (bss != drv->first_bss) {
                struct i802_bss *tbss;
 
-               for (tbss = &drv->first_bss; tbss; tbss = tbss->next) {
+               wpa_printf(MSG_DEBUG, "nl80211: Not the first BSS - remove it");
+               for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
                        if (tbss->next == bss) {
                                tbss->next = bss->next;
                                /* Unsubscribe management frames */
@@ -8882,8 +9723,22 @@ static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
                if (bss)
                        wpa_printf(MSG_INFO, "nl80211: %s - could not find "
                                   "BSS %p in the list", __func__, bss);
+       } else {
+               wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
+               nl80211_teardown_ap(bss);
+               if (!bss->added_if && !drv->first_bss->next)
+                       wpa_driver_nl80211_del_beacon(drv);
+               nl80211_destroy_bss(bss);
+               if (!bss->added_if)
+                       i802_set_iface_flags(bss, 0);
+               if (drv->first_bss->next) {
+                       drv->first_bss = drv->first_bss->next;
+                       drv->ctx = drv->first_bss->ctx;
+                       os_free(bss);
+               } else {
+                       wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");
+               }
        }
-#endif /* HOSTAPD */
 
        return 0;
 }
@@ -8920,10 +9775,13 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
        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);
+       wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len);
        nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
-       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
+       if (freq)
+               NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
        if (wait)
                NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
        if (offchanok && (drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX))
@@ -8985,7 +9843,10 @@ static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
        os_memcpy(hdr->addr2, src, ETH_ALEN);
        os_memcpy(hdr->addr3, bssid, ETH_ALEN);
 
-       if (is_ap_interface(drv->nlmode))
+       if (is_ap_interface(drv->nlmode) &&
+           (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
+            (int) freq == bss->freq || drv->device_ap_sme ||
+            !drv->use_monitor))
                ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
                                                   0, freq, no_cck, 1,
                                                   wait_time);
@@ -9015,7 +9876,8 @@ static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
                   (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);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
        NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -9044,7 +9906,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) < 0)
+               goto nla_put_failure;
+
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
        NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
 
@@ -9091,7 +9955,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) < 0)
+               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);
@@ -9123,9 +9989,7 @@ static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
                } else if (bss->nl_preq) {
                        wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
                                   "reporting nl_preq=%p", bss->nl_preq);
-                       eloop_unregister_read_sock(
-                               nl_socket_get_fd(bss->nl_preq));
-                       nl_destroy_handles(&bss->nl_preq);
+                       nl80211_destroy_eloop_handle(&bss->nl_preq);
                }
                return 0;
        }
@@ -9148,9 +10012,9 @@ static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
                                   NULL, 0) < 0)
                goto out_err;
 
-       eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq),
-                                wpa_driver_nl80211_event_receive, bss->nl_cb,
-                                bss->nl_preq);
+       nl80211_register_eloop_read(&bss->nl_preq,
+                                   wpa_driver_nl80211_event_receive,
+                                   bss->nl_cb);
 
        return 0;
 
@@ -9217,6 +10081,14 @@ static int wpa_driver_nl80211_deinit_ap(void *priv)
        if (!is_ap_interface(drv->nlmode))
                return -1;
        wpa_driver_nl80211_del_beacon(drv);
+
+       /*
+        * If the P2P GO interface was dynamically added, then it is
+        * possible that the interface change to station is not possible.
+        */
+       if (drv->nlmode == NL80211_IFTYPE_P2P_GO && bss->if_dynamic)
+               return 0;
+
        return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
 }
 
@@ -9239,6 +10111,14 @@ static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
        struct wpa_driver_nl80211_data *drv = bss->drv;
        if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
                return -1;
+
+       /*
+        * If the P2P Client interface was dynamically added, then it is
+        * possible that the interface change to station is not possible.
+        */
+       if (bss->if_dynamic)
+               return 0;
+
        return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
 }
 
@@ -9246,11 +10126,9 @@ static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
 static void wpa_driver_nl80211_resume(void *priv)
 {
        struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
-               wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
-                          "resume event");
-       }
+
+       if (i802_set_iface_flags(bss, 1))
+               wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on resume event");
 }
 
 
@@ -9337,27 +10215,6 @@ nla_put_failure:
 }
 
 
-/* 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];
@@ -9448,10 +10305,10 @@ static int wpa_driver_nl80211_shared_freq(void *priv)
 
                wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
                           MACSTR,
-                          driver->phyname, driver->first_bss.ifname,
-                          MAC2STR(driver->first_bss.addr));
+                          driver->phyname, driver->first_bss->ifname,
+                          MAC2STR(driver->first_bss->addr));
                if (is_ap_interface(driver->nlmode))
-                       freq = driver->first_bss.freq;
+                       freq = driver->first_bss->freq;
                else
                        freq = nl80211_get_assoc_freq(driver);
                wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
@@ -9491,6 +10348,12 @@ static int nl80211_set_param(void *priv, const char *param)
                drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
                drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
        }
+
+       if (os_strstr(param, "p2p_device=1")) {
+               struct i802_bss *bss = priv;
+               struct wpa_driver_nl80211_data *drv = bss->drv;
+               drv->allow_p2p_device = 1;
+       }
 #endif /* CONFIG_P2P */
 
        return 0;
@@ -9527,7 +10390,8 @@ static void * nl80211_global_init(void)
 
        global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
        if (global->ioctl_sock < 0) {
-               perror("socket(PF_INET,SOCK_DGRAM)");
+               wpa_printf(MSG_ERROR, "nl80211: socket(PF_INET,SOCK_DGRAM) failed: %s",
+                          strerror(errno));
                goto err;
        }
 
@@ -9555,11 +10419,8 @@ static void nl80211_global_deinit(void *priv)
 
        nl_destroy_handles(&global->nl);
 
-       if (global->nl_event) {
-               eloop_unregister_read_sock(
-                       nl_socket_get_fd(global->nl_event));
-               nl_destroy_handles(&global->nl_event);
-       }
+       if (global->nl_event)
+               nl80211_destroy_eloop_handle(&global->nl_event);
 
        nl_cb_put(global->nl_cb);
 
@@ -9627,6 +10488,185 @@ static int nl80211_flush_pmkid(void *priv)
 }
 
 
+static void clean_survey_results(struct survey_results *survey_results)
+{
+       struct freq_survey *survey, *tmp;
+
+       if (dl_list_empty(&survey_results->survey_list))
+               return;
+
+       dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
+                             struct freq_survey, list) {
+               dl_list_del(&survey->list);
+               os_free(survey);
+       }
+}
+
+
+static void add_survey(struct nlattr **sinfo, u32 ifidx,
+                      struct dl_list *survey_list)
+{
+       struct freq_survey *survey;
+
+       survey = os_zalloc(sizeof(struct freq_survey));
+       if  (!survey)
+               return;
+
+       survey->ifidx = ifidx;
+       survey->freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
+       survey->filled = 0;
+
+       if (sinfo[NL80211_SURVEY_INFO_NOISE]) {
+               survey->nf = (int8_t)
+                       nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+               survey->filled |= SURVEY_HAS_NF;
+       }
+
+       if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]) {
+               survey->channel_time =
+                       nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]);
+               survey->filled |= SURVEY_HAS_CHAN_TIME;
+       }
+
+       if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) {
+               survey->channel_time_busy =
+                       nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
+               survey->filled |= SURVEY_HAS_CHAN_TIME_BUSY;
+       }
+
+       if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]) {
+               survey->channel_time_rx =
+                       nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]);
+               survey->filled |= SURVEY_HAS_CHAN_TIME_RX;
+       }
+
+       if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]) {
+               survey->channel_time_tx =
+                       nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]);
+               survey->filled |= SURVEY_HAS_CHAN_TIME_TX;
+       }
+
+       wpa_printf(MSG_DEBUG, "nl80211: Freq survey dump event (freq=%d MHz noise=%d channel_time=%ld busy_time=%ld tx_time=%ld rx_time=%ld filled=%04x)",
+                  survey->freq,
+                  survey->nf,
+                  (unsigned long int) survey->channel_time,
+                  (unsigned long int) survey->channel_time_busy,
+                  (unsigned long int) survey->channel_time_tx,
+                  (unsigned long int) survey->channel_time_rx,
+                  survey->filled);
+
+       dl_list_add_tail(survey_list, &survey->list);
+}
+
+
+static int check_survey_ok(struct nlattr **sinfo, u32 surveyed_freq,
+                          unsigned int freq_filter)
+{
+       if (!freq_filter)
+               return 1;
+
+       return freq_filter == surveyed_freq;
+}
+
+
+static int survey_handler(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+       struct survey_results *survey_results;
+       u32 surveyed_freq = 0;
+       u32 ifidx;
+
+       static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+               [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+               [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+       };
+
+       survey_results = (struct survey_results *) arg;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+
+       if (!tb[NL80211_ATTR_SURVEY_INFO])
+               return NL_SKIP;
+
+       if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+                            tb[NL80211_ATTR_SURVEY_INFO],
+                            survey_policy))
+               return NL_SKIP;
+
+       if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) {
+               wpa_printf(MSG_ERROR, "nl80211: Invalid survey data");
+               return NL_SKIP;
+       }
+
+       surveyed_freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
+
+       if (!check_survey_ok(sinfo, surveyed_freq,
+                            survey_results->freq_filter))
+               return NL_SKIP;
+
+       if (survey_results->freq_filter &&
+           survey_results->freq_filter != surveyed_freq) {
+               wpa_printf(MSG_EXCESSIVE, "nl80211: Ignoring survey data for freq %d MHz",
+                          surveyed_freq);
+               return NL_SKIP;
+       }
+
+       add_survey(sinfo, ifidx, &survey_results->survey_list);
+
+       return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int err = -ENOBUFS;
+       union wpa_event_data data;
+       struct survey_results *survey_results;
+
+       os_memset(&data, 0, sizeof(data));
+       survey_results = &data.survey_results;
+
+       dl_list_init(&survey_results->survey_list);
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               goto nla_put_failure;
+
+       nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+       if (freq)
+               data.survey_results.freq_filter = freq;
+
+       do {
+               wpa_printf(MSG_DEBUG, "nl80211: Fetch survey data");
+               err = send_and_recv_msgs(drv, msg, survey_handler,
+                                        survey_results);
+       } while (err > 0);
+
+       if (err) {
+               wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
+               goto out_clean;
+       }
+
+       wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
+
+out_clean:
+       clean_survey_results(survey_results);
+nla_put_failure:
+       return err;
+}
+
+
 static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
                                   const u8 *replay_ctr)
 {
@@ -9754,8 +10794,13 @@ static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
        wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
                   "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
 
-       if (opp_ps != -1 || ctwindow != -1)
+       if (opp_ps != -1 || ctwindow != -1) {
+#ifdef ANDROID_P2P
+               wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
+#else /* ANDROID_P2P */
                return -1; /* Not yet supported */
+#endif /* ANDROID_P2P */
+       }
 
        if (legacy_ps == -1)
                return 0;
@@ -9766,14 +10811,18 @@ static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
 }
 
 
-static int nl80211_start_radar_detection(void *priv, int freq)
+static int nl80211_start_radar_detection(void *priv,
+                                        struct hostapd_freq_params *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)");
+       wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC) %d MHz (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);
+
        if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
                wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
                           "detection");
@@ -9786,10 +10835,53 @@ static int nl80211_start_radar_detection(void *priv, int freq)
 
        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);
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
 
-       /* only HT20 is supported at this point */
-       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
+       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);
+                       break;
+               case 1:
+                       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+                                   NL80211_CHAN_HT40PLUS);
+                       break;
+               default:
+                       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+                                   NL80211_CHAN_HT20);
+                       break;
+               }
+       }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        if (ret == 0)
@@ -9992,7 +11084,7 @@ static int android_pno_start(struct i802_bss *bss,
 
        memset(&ifr, 0, sizeof(ifr));
        memset(&priv_cmd, 0, sizeof(priv_cmd));
-       os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+       os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
 
        priv_cmd.buf = buf;
        priv_cmd.used_len = bp;
@@ -10089,14 +11181,12 @@ static int driver_nl80211_sta_remove(void *priv, const u8 *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,
@@ -10161,6 +11251,330 @@ nla_put_failure:
 }
 
 
+const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+
+       if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE)
+               return NULL;
+
+       return bss->addr;
+}
+
+
+static const char * scan_state_str(enum scan_states scan_state)
+{
+       switch (scan_state) {
+       case NO_SCAN:
+               return "NO_SCAN";
+       case SCAN_REQUESTED:
+               return "SCAN_REQUESTED";
+       case SCAN_STARTED:
+               return "SCAN_STARTED";
+       case SCAN_COMPLETED:
+               return "SCAN_COMPLETED";
+       case SCAN_ABORTED:
+               return "SCAN_ABORTED";
+       case SCHED_SCAN_STARTED:
+               return "SCHED_SCAN_STARTED";
+       case SCHED_SCAN_STOPPED:
+               return "SCHED_SCAN_STOPPED";
+       case SCHED_SCAN_RESULTS:
+               return "SCHED_SCAN_RESULTS";
+       }
+
+       return "??";
+}
+
+
+static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       int res;
+       char *pos, *end;
+
+       pos = buf;
+       end = buf + buflen;
+
+       res = os_snprintf(pos, end - pos,
+                         "ifindex=%d\n"
+                         "ifname=%s\n"
+                         "brname=%s\n"
+                         "addr=" MACSTR "\n"
+                         "freq=%d\n"
+                         "%s%s%s%s%s",
+                         bss->ifindex,
+                         bss->ifname,
+                         bss->brname,
+                         MAC2STR(bss->addr),
+                         bss->freq,
+                         bss->beacon_set ? "beacon_set=1\n" : "",
+                         bss->added_if_into_bridge ?
+                         "added_if_into_bridge=1\n" : "",
+                         bss->added_bridge ? "added_bridge=1\n" : "",
+                         bss->in_deinit ? "in_deinit=1\n" : "",
+                         bss->if_dynamic ? "if_dynamic=1\n" : "");
+       if (res < 0 || res >= end - pos)
+               return pos - buf;
+       pos += res;
+
+       if (bss->wdev_id_set) {
+               res = os_snprintf(pos, end - pos, "wdev_id=%llu\n",
+                                 (unsigned long long) bss->wdev_id);
+               if (res < 0 || res >= end - pos)
+                       return pos - buf;
+               pos += res;
+       }
+
+       res = os_snprintf(pos, end - pos,
+                         "phyname=%s\n"
+                         "drv_ifindex=%d\n"
+                         "operstate=%d\n"
+                         "scan_state=%s\n"
+                         "auth_bssid=" MACSTR "\n"
+                         "auth_attempt_bssid=" MACSTR "\n"
+                         "bssid=" MACSTR "\n"
+                         "prev_bssid=" MACSTR "\n"
+                         "associated=%d\n"
+                         "assoc_freq=%u\n"
+                         "monitor_sock=%d\n"
+                         "monitor_ifidx=%d\n"
+                         "monitor_refcount=%d\n"
+                         "last_mgmt_freq=%u\n"
+                         "eapol_tx_sock=%d\n"
+                         "%s%s%s%s%s%s%s%s%s%s%s%s%s",
+                         drv->phyname,
+                         drv->ifindex,
+                         drv->operstate,
+                         scan_state_str(drv->scan_state),
+                         MAC2STR(drv->auth_bssid),
+                         MAC2STR(drv->auth_attempt_bssid),
+                         MAC2STR(drv->bssid),
+                         MAC2STR(drv->prev_bssid),
+                         drv->associated,
+                         drv->assoc_freq,
+                         drv->monitor_sock,
+                         drv->monitor_ifidx,
+                         drv->monitor_refcount,
+                         drv->last_mgmt_freq,
+                         drv->eapol_tx_sock,
+                         drv->ignore_if_down_event ?
+                         "ignore_if_down_event=1\n" : "",
+                         drv->scan_complete_events ?
+                         "scan_complete_events=1\n" : "",
+                         drv->disabled_11b_rates ?
+                         "disabled_11b_rates=1\n" : "",
+                         drv->pending_remain_on_chan ?
+                         "pending_remain_on_chan=1\n" : "",
+                         drv->in_interface_list ? "in_interface_list=1\n" : "",
+                         drv->device_ap_sme ? "device_ap_sme=1\n" : "",
+                         drv->poll_command_supported ?
+                         "poll_command_supported=1\n" : "",
+                         drv->data_tx_status ? "data_tx_status=1\n" : "",
+                         drv->scan_for_auth ? "scan_for_auth=1\n" : "",
+                         drv->retry_auth ? "retry_auth=1\n" : "",
+                         drv->use_monitor ? "use_monitor=1\n" : "",
+                         drv->ignore_next_local_disconnect ?
+                         "ignore_next_local_disconnect=1\n" : "",
+                         drv->allow_p2p_device ? "allow_p2p_device=1\n" : "");
+       if (res < 0 || res >= end - pos)
+               return pos - buf;
+       pos += res;
+
+       if (drv->has_capability) {
+               res = os_snprintf(pos, end - pos,
+                                 "capa.key_mgmt=0x%x\n"
+                                 "capa.enc=0x%x\n"
+                                 "capa.auth=0x%x\n"
+                                 "capa.flags=0x%x\n"
+                                 "capa.max_scan_ssids=%d\n"
+                                 "capa.max_sched_scan_ssids=%d\n"
+                                 "capa.sched_scan_supported=%d\n"
+                                 "capa.max_match_sets=%d\n"
+                                 "capa.max_remain_on_chan=%u\n"
+                                 "capa.max_stations=%u\n"
+                                 "capa.probe_resp_offloads=0x%x\n"
+                                 "capa.max_acl_mac_addrs=%u\n"
+                                 "capa.num_multichan_concurrent=%u\n",
+                                 drv->capa.key_mgmt,
+                                 drv->capa.enc,
+                                 drv->capa.auth,
+                                 drv->capa.flags,
+                                 drv->capa.max_scan_ssids,
+                                 drv->capa.max_sched_scan_ssids,
+                                 drv->capa.sched_scan_supported,
+                                 drv->capa.max_match_sets,
+                                 drv->capa.max_remain_on_chan,
+                                 drv->capa.max_stations,
+                                 drv->capa.probe_resp_offloads,
+                                 drv->capa.max_acl_mac_addrs,
+                                 drv->capa.num_multichan_concurrent);
+               if (res < 0 || res >= end - pos)
+                       return pos - buf;
+               pos += res;
+       }
+
+       return pos - buf;
+}
+
+
+static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
+{
+       if (settings->head)
+               NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD,
+                       settings->head_len, settings->head);
+
+       if (settings->tail)
+               NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL,
+                       settings->tail_len, settings->tail);
+
+       if (settings->beacon_ies)
+               NLA_PUT(msg, NL80211_ATTR_IE,
+                       settings->beacon_ies_len, settings->beacon_ies);
+
+       if (settings->proberesp_ies)
+               NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
+                       settings->proberesp_ies_len, settings->proberesp_ies);
+
+       if (settings->assocresp_ies)
+               NLA_PUT(msg,
+                       NL80211_ATTR_IE_ASSOC_RESP,
+                       settings->assocresp_ies_len, settings->assocresp_ies);
+
+       if (settings->probe_resp)
+               NLA_PUT(msg, NL80211_ATTR_PROBE_RESP,
+                       settings->probe_resp_len, settings->probe_resp);
+
+       return 0;
+
+nla_put_failure:
+       return -ENOBUFS;
+}
+
+
+static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
+{
+       struct nl_msg *msg;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nlattr *beacon_csa;
+       int ret = -ENOBUFS;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d width=%d cf1=%d cf2=%d)",
+                  settings->cs_count, settings->block_tx,
+                  settings->freq_params.freq, settings->freq_params.bandwidth,
+                  settings->freq_params.center_freq1,
+                  settings->freq_params.center_freq2);
+
+       if (!drv->channel_switch_supported) {
+               wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command");
+               return -EOPNOTSUPP;
+       }
+
+       if ((drv->nlmode != NL80211_IFTYPE_AP) &&
+           (drv->nlmode != NL80211_IFTYPE_P2P_GO))
+               return -EOPNOTSUPP;
+
+       /* check settings validity */
+       if (!settings->beacon_csa.tail ||
+           ((settings->beacon_csa.tail_len <=
+             settings->counter_offset_beacon) ||
+            (settings->beacon_csa.tail[settings->counter_offset_beacon] !=
+             settings->cs_count)))
+               return -EINVAL;
+
+       if (settings->beacon_csa.probe_resp &&
+           ((settings->beacon_csa.probe_resp_len <=
+             settings->counter_offset_presp) ||
+            (settings->beacon_csa.probe_resp[settings->counter_offset_presp] !=
+             settings->cs_count)))
+               return -EINVAL;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_CHANNEL_SWITCH);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, settings->cs_count);
+       ret = nl80211_put_freq_params(msg, &settings->freq_params);
+       if (ret)
+               goto error;
+
+       if (settings->block_tx)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX);
+
+       /* beacon_after params */
+       ret = set_beacon_data(msg, &settings->beacon_after);
+       if (ret)
+               goto error;
+
+       /* beacon_csa params */
+       beacon_csa = nla_nest_start(msg, NL80211_ATTR_CSA_IES);
+       if (!beacon_csa)
+               goto nla_put_failure;
+
+       ret = set_beacon_data(msg, &settings->beacon_csa);
+       if (ret)
+               goto error;
+
+       NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
+                   settings->counter_offset_beacon);
+
+       if (settings->beacon_csa.probe_resp)
+               NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
+                           settings->counter_offset_presp);
+
+       nla_nest_end(msg, beacon_csa);
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)",
+                          ret, strerror(-ret));
+       }
+       return ret;
+
+nla_put_failure:
+       ret = -ENOBUFS;
+error:
+       nlmsg_free(msg);
+       wpa_printf(MSG_DEBUG, "nl80211: Could not build channel switch request");
+       return ret;
+}
+
+
+static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set,
+                              u8 qos_map_set_len)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
+                   qos_map_set, qos_map_set_len);
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_QOS_MAP);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (ret)
+               wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
+
+       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",
@@ -10182,6 +11596,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .set_operstate = wpa_driver_nl80211_set_operstate,
        .set_supp_port = wpa_driver_nl80211_set_supp_port,
        .set_country = wpa_driver_nl80211_set_country,
+       .get_country = wpa_driver_nl80211_get_country,
        .set_ap = wpa_driver_nl80211_set_ap,
        .set_acl = wpa_driver_nl80211_set_acl,
        .if_add = wpa_driver_nl80211_if_add,
@@ -10192,12 +11607,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .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
        .hapd_init = i802_init,
        .hapd_deinit = i802_deinit,
        .set_wds_sta = i802_set_wds_sta,
-#endif /* HOSTAPD */
-#if defined(HOSTAPD) || defined(CONFIG_AP)
        .get_seqnum = i802_get_seqnum,
        .flush = i802_flush,
        .get_inact_sec = i802_get_inact_sec,
@@ -10208,7 +11620,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .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 = driver_nl80211_send_action,
@@ -10240,4 +11651,17 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .tdls_oper = nl80211_tdls_oper,
 #endif /* CONFIG_TDLS */
        .update_ft_ies = wpa_driver_nl80211_update_ft_ies,
+       .get_mac_addr = wpa_driver_nl80211_get_macaddr,
+       .get_survey = wpa_driver_nl80211_get_survey,
+       .status = wpa_driver_nl80211_status,
+       .switch_channel = nl80211_switch_channel,
+#ifdef ANDROID_P2P
+       .set_noa = wpa_driver_set_p2p_noa,
+       .get_noa = wpa_driver_get_p2p_noa,
+       .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
+#endif /* ANDROID_P2P */
+#ifdef ANDROID
+       .driver_cmd = wpa_driver_nl80211_driver_cmd,
+#endif /* ANDROID */
+       .set_qos_map = nl80211_set_qos_map,
 };