]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - build-utilities/hostap.git/blobdiff - src/drivers/driver_nl80211.c
nl80211: fix warnings
[build-utilities/hostap.git] / src / drivers / driver_nl80211.c
index f22e847d555c505572271f974e1dc28030b46ee6..4a04402c20e5533c1ea02c197bb78bb3691f6708 100644 (file)
@@ -1,19 +1,13 @@
 /*
  * Driver interaction with Linux nl80211/cfg80211
- * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2003-2004, Instant802 Networks, Inc.
  * Copyright (c) 2005-2006, Devicescape Software, Inc.
  * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
  * Copyright (c) 2009-2010, Atheros Communications
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -28,6 +22,7 @@
 #include <linux/rtnetlink.h>
 #include <netpacket/packet.h>
 #include <linux/filter.h>
+#include <linux/errqueue.h>
 #include "nl80211_copy.h"
 
 #include "common.h"
 #include "rfkill.h"
 #include "driver.h"
 
+#ifndef SO_WIFI_STATUS
+# if defined(__sparc__)
+#  define SO_WIFI_STATUS       0x0025
+# elif defined(__parisc__)
+#  define SO_WIFI_STATUS       0x4022
+# else
+#  define SO_WIFI_STATUS       41
+# endif
+
+# define SCM_WIFI_STATUS       SO_WIFI_STATUS
+#endif
+
+#ifndef SO_EE_ORIGIN_TXSTATUS
+#define SO_EE_ORIGIN_TXSTATUS  4
+#endif
+
+#ifndef PACKET_TX_TIMESTAMP
+#define PACKET_TX_TIMESTAMP    16
+#endif
+
+#ifdef ANDROID
+#include "android_drv.h"
+
+static int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
+                                        size_t buf_len);
+#endif /* ANDROID */
 #ifdef CONFIG_LIBNL20
 /* libnl 2.0 compatibility code */
 #define nl_handle nl_sock
@@ -88,65 +109,37 @@ static void nl80211_handle_destroy(struct nl_handle *handle)
 
        nl_handle_destroy(handle);
 }
-
-static inline int __genl_ctrl_alloc_cache(struct nl_handle *h,
-                                         struct nl_cache **cache)
-{
-       struct nl_cache *tmp = genl_ctrl_alloc_cache(h);
-       if (!tmp)
-               return -ENOMEM;
-       *cache = tmp;
-       return 0;
-}
-#define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache
 #endif /* CONFIG_LIBNL20 */
 
 
-struct nl80211_handles {
-       struct nl_handle *handle;
-       struct nl_cache *cache;
-};
-
-
-static int nl_create_handles(struct nl80211_handles *handles, struct nl_cb *cb,
-                            const char *dbg)
+static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
 {
-       if (!handles)
-               return -1;
+       struct nl_handle *handle;
 
-       handles->handle = nl80211_handle_alloc(cb);
-       if (handles->handle == NULL) {
+       handle = nl80211_handle_alloc(cb);
+       if (handle == NULL) {
                wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
                           "callbacks (%s)", dbg);
-               return -1;
+               return NULL;
        }
 
-       if (genl_connect(handles->handle)) {
+       if (genl_connect(handle)) {
                wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
                           "netlink (%s)", dbg);
-               goto err;
-       }
-
-       if (genl_ctrl_alloc_cache(handles->handle, &handles->cache) < 0) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-                          "netlink cache (%s)", dbg);
-               goto err;
+               nl80211_handle_destroy(handle);
+               return NULL;
        }
 
-       return 0;
-err:
-       nl80211_handle_destroy(handles->handle);
-       return -1;
+       return handle;
 }
 
 
-static void nl_destroy_handles(struct nl80211_handles *handles)
+static void nl_destroy_handles(struct nl_handle **handle)
 {
-       if (handles->handle == NULL)
+       if (*handle == NULL)
                return;
-       nl_cache_free(handles->cache);
-       nl80211_handle_destroy(handles->handle);
-       handles->handle = NULL;
+       nl80211_handle_destroy(*handle);
+       *handle = NULL;
 }
 
 
@@ -169,9 +162,22 @@ struct nl80211_global {
        int if_add_ifindex;
        struct netlink_data *netlink;
        struct nl_cb *nl_cb;
-       struct nl80211_handles nl;
-       struct genl_family *nl80211;
+       struct nl_handle *nl;
+       int nl80211_id;
        int ioctl_sock; /* socket for ioctl() use */
+
+       struct nl_handle *nl_event;
+};
+
+struct nl80211_wiphy_data {
+       struct dl_list list;
+       struct dl_list bsss;
+       struct dl_list drvs;
+
+       struct nl_handle *nl_beacons;
+       struct nl_cb *nl_cb;
+
+       int wiphy_idx;
 };
 
 static void nl80211_global_deinit(void *priv);
@@ -186,12 +192,22 @@ struct i802_bss {
        unsigned int beacon_set:1;
        unsigned int added_if_into_bridge:1;
        unsigned int added_bridge:1;
+
+       u8 addr[ETH_ALEN];
+
+       int freq;
+
+       struct nl_handle *nl_preq, *nl_mgmt;
+       struct nl_cb *nl_cb;
+
+       struct nl80211_wiphy_data *wiphy_data;
+       struct dl_list wiphy_list;
 };
 
 struct wpa_driver_nl80211_data {
        struct nl80211_global *global;
        struct dl_list list;
-       u8 addr[ETH_ALEN];
+       struct dl_list wiphy_list;
        char phyname[32];
        void *ctx;
        int ifindex;
@@ -206,7 +222,7 @@ struct wpa_driver_nl80211_data {
 
        int scan_complete_events;
 
-       struct nl80211_handles nl_event, nl_preq;
+       struct nl_cb *nl_cb;
 
        u8 auth_bssid[ETH_ALEN];
        u8 bssid[ETH_ALEN];
@@ -219,26 +235,29 @@ struct wpa_driver_nl80211_data {
 
        int monitor_sock;
        int monitor_ifidx;
-       int no_monitor_iface_capab;
-       int disable_11b_rates;
+       int monitor_refcount;
 
+       unsigned int disabled_11b_rates:1;
        unsigned int pending_remain_on_chan:1;
        unsigned int in_interface_list:1;
+       unsigned int device_ap_sme:1;
+       unsigned int poll_command_supported:1;
+       unsigned int data_tx_status:1;
+       unsigned int scan_for_auth:1;
+       unsigned int retry_auth:1;
+       unsigned int use_monitor:1;
 
        u64 remain_on_chan_cookie;
        u64 send_action_cookie;
 
        unsigned int last_mgmt_freq;
-       unsigned int ap_oper_freq;
 
        struct wpa_driver_scan_filter *filter_ssids;
        size_t num_filter_ssids;
 
        struct i802_bss first_bss;
 
-#ifdef CONFIG_AP
-       struct l2_packet_data *l2;
-#endif /* CONFIG_AP */
+       int eapol_tx_sock;
 
 #ifdef HOSTAPD
        int eapol_sock; /* socket for EAPOL frames */
@@ -250,6 +269,24 @@ struct wpa_driver_nl80211_data {
        int last_freq;
        int last_freq_ht;
 #endif /* HOSTAPD */
+
+       /* From failed authentication command */
+       int auth_freq;
+       u8 auth_bssid_[ETH_ALEN];
+       u8 auth_ssid[32];
+       size_t auth_ssid_len;
+       int auth_alg;
+       u8 *auth_ie;
+       size_t auth_ie_len;
+       u8 auth_wep_key[4][16];
+       size_t auth_wep_key_len[4];
+       int auth_wep_tx_keyidx;
+       int auth_local_state_change;
+       int auth_p2p;
+#ifdef ANDROID
+       u8 wowlan_triggers;
+       u8 wowlan_enabled;
+#endif
 };
 
 
@@ -264,11 +301,21 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
                                   int local_state_change);
 static void nl80211_remove_monitor_interface(
        struct wpa_driver_nl80211_data *drv);
-static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
+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_cck, int no_ack, int offchanok);
 static int wpa_driver_nl80211_probe_req_report(void *priv, 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);
+#endif /* ANDROID */
+#ifdef ANDROID_BRCM_P2P_PATCH
+static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
+                                 enum wpa_event_type type,
+                                 const u8 *frame, size_t len);
+#endif /* ANDROID_BRCM_P2P_PATCH */
 
 #ifdef HOSTAPD
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
@@ -297,6 +344,8 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
                                     int ifindex, int disabled);
 
 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 is_ap_interface(enum nl80211_iftype nlmode)
@@ -313,6 +362,13 @@ static int is_sta_interface(enum nl80211_iftype nlmode)
 }
 
 
+static int is_p2p_interface(enum nl80211_iftype nlmode)
+{
+       return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
+               nlmode == NL80211_IFTYPE_P2P_GO);
+}
+
+
 struct nl80211_bss_info_arg {
        struct wpa_driver_nl80211_data *drv;
        struct wpa_scan_results *res;
@@ -353,7 +409,7 @@ static int no_seq_check(struct nl_msg *msg, void *arg)
 }
 
 
-static int send_and_recv(struct wpa_driver_nl80211_data *drv,
+static int send_and_recv(struct nl80211_global *global,
                         struct nl_handle *nl_handle, struct nl_msg *msg,
                         int (*valid_handler)(struct nl_msg *, void *),
                         void *valid_data)
@@ -361,7 +417,7 @@ static int send_and_recv(struct wpa_driver_nl80211_data *drv,
        struct nl_cb *cb;
        int err = -ENOMEM;
 
-       cb = nl_cb_clone(drv->global->nl_cb);
+       cb = nl_cb_clone(global->nl_cb);
        if (!cb)
                goto out;
 
@@ -388,13 +444,23 @@ static int send_and_recv(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static int send_and_recv_msgs_global(struct nl80211_global *global,
+                                    struct nl_msg *msg,
+                                    int (*valid_handler)(struct nl_msg *, void *),
+                                    void *valid_data)
+{
+       return send_and_recv(global, global->nl, msg, valid_handler,
+                            valid_data);
+}
+
+
 static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
                              struct nl_msg *msg,
                              int (*valid_handler)(struct nl_msg *, void *),
                              void *valid_data)
 {
-       return send_and_recv(drv, drv->global->nl.handle, msg, valid_handler,
-                            valid_data);
+       return send_and_recv(drv->global, drv->global->nl, msg,
+                            valid_handler, valid_data);
 }
 
 
@@ -435,7 +501,7 @@ static int family_handler(struct nl_msg *msg, void *arg)
 }
 
 
-static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv,
+static int nl_get_multicast_id(struct nl80211_global *global,
                               const char *family, const char *group)
 {
        struct nl_msg *msg;
@@ -445,12 +511,11 @@ static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv,
        msg = nlmsg_alloc();
        if (!msg)
                return -ENOMEM;
-       genlmsg_put(msg, 0, 0,
-                   genl_ctrl_resolve(drv->global->nl.handle, "nlctrl"),
+       genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
                    0, 0, CTRL_CMD_GETFAMILY, 0);
        NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
 
-       ret = send_and_recv_msgs(drv, msg, family_handler, &res);
+       ret = send_and_recv_msgs_global(global, msg, family_handler, &res);
        msg = NULL;
        if (ret == 0)
                ret = res.id;
@@ -464,11 +529,232 @@ nla_put_failure:
 static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
                          struct nl_msg *msg, int flags, uint8_t cmd)
 {
-       return genlmsg_put(msg, 0, 0, genl_family_get_id(drv->global->nl80211),
+       return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
                           0, flags, cmd, 0);
 }
 
 
+struct wiphy_idx_data {
+       int wiphy_idx;
+};
+
+
+static int netdev_info_handler(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct wiphy_idx_data *info = arg;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (tb[NL80211_ATTR_WIPHY])
+               info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+
+       return NL_SKIP;
+}
+
+
+static int nl80211_get_wiphy_index(struct i802_bss *bss)
+{
+       struct nl_msg *msg;
+       struct wiphy_idx_data data = {
+               .wiphy_idx = -1,
+       };
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+       if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
+               return data.wiphy_idx;
+       msg = NULL;
+nla_put_failure:
+       nlmsg_free(msg);
+       return -1;
+}
+
+
+static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
+                                   struct nl80211_wiphy_data *w)
+{
+       struct nl_msg *msg;
+       int ret = -1;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx);
+
+       ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL);
+       msg = NULL;
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
+                          "failed: ret=%d (%s)",
+                          ret, strerror(-ret));
+               goto nla_put_failure;
+       }
+       ret = 0;
+nla_put_failure:
+       nlmsg_free(msg);
+       return ret;
+}
+
+
+static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
+{
+       struct nl80211_wiphy_data *w = eloop_ctx;
+
+       wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
+
+       nl_recvmsgs(handle, w->nl_cb);
+}
+
+
+static int process_beacon_event(struct nl_msg *msg, void *arg)
+{
+       struct nl80211_wiphy_data *w = arg;
+       struct wpa_driver_nl80211_data *drv;
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       union wpa_event_data event;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (gnlh->cmd != NL80211_CMD_FRAME) {
+               wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
+                          gnlh->cmd);
+               return NL_SKIP;
+       }
+
+       if (!tb[NL80211_ATTR_FRAME])
+               return NL_SKIP;
+
+       dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
+                        wiphy_list) {
+               os_memset(&event, 0, sizeof(event));
+               event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
+               event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
+               wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+       }
+
+       return NL_SKIP;
+}
+
+
+static struct nl80211_wiphy_data *
+nl80211_get_wiphy_data_ap(struct i802_bss *bss)
+{
+       static DEFINE_DL_LIST(nl80211_wiphys);
+       struct nl80211_wiphy_data *w;
+       int wiphy_idx, found = 0;
+       struct i802_bss *tmp_bss;
+
+       if (bss->wiphy_data != NULL)
+               return bss->wiphy_data;
+
+       wiphy_idx = nl80211_get_wiphy_index(bss);
+
+       dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
+               if (w->wiphy_idx == wiphy_idx)
+                       goto add;
+       }
+
+       /* alloc new one */
+       w = os_zalloc(sizeof(*w));
+       if (w == NULL)
+               return NULL;
+       w->wiphy_idx = wiphy_idx;
+       dl_list_init(&w->bsss);
+       dl_list_init(&w->drvs);
+
+       w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+       if (!w->nl_cb) {
+               os_free(w);
+               return NULL;
+       }
+       nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+       nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_beacon_event,
+                 w);
+
+       w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
+                                        "wiphy beacons");
+       if (w->nl_beacons == NULL) {
+               os_free(w);
+               return NULL;
+       }
+
+       if (nl80211_register_beacons(bss->drv, w)) {
+               nl_destroy_handles(&w->nl_beacons);
+               os_free(w);
+               return NULL;
+       }
+
+       eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons),
+                                nl80211_recv_beacons, w, w->nl_beacons);
+
+       dl_list_add(&nl80211_wiphys, &w->list);
+
+add:
+       /* drv entry for this bss already there? */
+       dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
+               if (tmp_bss->drv == bss->drv) {
+                       found = 1;
+                       break;
+               }
+       }
+       /* if not add it */
+       if (!found)
+               dl_list_add(&w->drvs, &bss->drv->wiphy_list);
+
+       dl_list_add(&w->bsss, &bss->wiphy_list);
+       bss->wiphy_data = w;
+       return w;
+}
+
+
+static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
+{
+       struct nl80211_wiphy_data *w = bss->wiphy_data;
+       struct i802_bss *tmp_bss;
+       int found = 0;
+
+       if (w == NULL)
+               return;
+       bss->wiphy_data = NULL;
+       dl_list_del(&bss->wiphy_list);
+
+       /* still any for this drv present? */
+       dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
+               if (tmp_bss->drv == bss->drv) {
+                       found = 1;
+                       break;
+               }
+       }
+       /* if not remove it */
+       if (!found)
+               dl_list_del(&bss->drv->wiphy_list);
+
+       if (!dl_list_empty(&w->bsss))
+               return;
+
+       eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons));
+
+       nl_cb_put(w->nl_cb);
+       nl_destroy_handles(&w->nl_beacons);
+       dl_list_del(&w->list);
+       os_free(w);
+}
+
+
 static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
 {
        struct i802_bss *bss = priv;
@@ -509,10 +795,28 @@ static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
                   del ? "removed" : "added");
 
        if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
-               if (del)
+               if (del) {
+                       if (drv->if_removed) {
+                               wpa_printf(MSG_DEBUG, "nl80211: if_removed "
+                                          "already set - ignore event");
+                               return;
+                       }
                        drv->if_removed = 1;
-               else
+               } else {
+                       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);
+                               return;
+                       }
+                       if (!drv->if_removed) {
+                               wpa_printf(MSG_DEBUG, "nl80211: if_removed "
+                                          "already cleared - ignore event");
+                               return;
+                       }
                        drv->if_removed = 0;
+               }
        }
 
        wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
@@ -585,6 +889,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
        int attrlen, rta_len;
        struct rtattr *attr;
        u32 brid = 0;
+       char namebuf[IFNAMSIZ];
 
        drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
        if (!drv) {
@@ -602,7 +907,6 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
 
        if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
-               char namebuf[IFNAMSIZ];
                if (if_indextoname(ifi->ifi_index, namebuf) &&
                    linux_iface_up(drv->global->ioctl_sock,
                                   drv->first_bss.ifname) > 0) {
@@ -623,9 +927,26 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
        }
 
        if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
-               wpa_printf(MSG_DEBUG, "nl80211: Interface up");
-               drv->if_disabled = 0;
-               wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
+               if (if_indextoname(ifi->ifi_index, namebuf) &&
+                   linux_iface_up(drv->global->ioctl_sock,
+                                  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) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
+                                  "event since interface %s does not exist",
+                                  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);
+               } else {
+                       wpa_printf(MSG_DEBUG, "nl80211: Interface up");
+                       drv->if_disabled = 0;
+                       wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+                                            NULL);
+               }
        }
 
        /*
@@ -656,7 +977,6 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
 
        if (ifi->ifi_family == AF_BRIDGE && brid) {
                /* device has been added to bridge */
-               char namebuf[IFNAMSIZ];
                if_indextoname(brid, namebuf);
                wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
                           brid, namebuf);
@@ -774,6 +1094,20 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
        u16 status;
 
        mgmt = (const struct ieee80211_mgmt *) frame;
+#if (defined (CONFIG_AP) || defined (HOSTAPD) ) && defined (ANDROID_BRCM_P2P_PATCH)
+       if (drv->nlmode == NL80211_IFTYPE_AP || drv->nlmode == NL80211_IFTYPE_P2P_GO) {
+               if (len < 24 + sizeof(mgmt->u.assoc_req)) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
+                          "frame");
+                       return;
+               }
+               os_memset(&event, 0, sizeof(event));
+               event.assoc_info.freq = drv->assoc_freq;
+               event.assoc_info.req_ies = (u8 *) mgmt->u.assoc_req.variable;
+               event.assoc_info.req_ies_len = len - 24 - sizeof(mgmt->u.assoc_req);
+               event.assoc_info.addr = mgmt->sa;
+       } else {
+#endif
        if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
                wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
                           "frame");
@@ -807,6 +1141,9 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
        }
 
        event.assoc_info.freq = drv->assoc_freq;
+#if (defined (CONFIG_AP) || defined(HOSTAPD)) && defined (ANDROID_BRCM_P2P_PATCH)
+       }
+#endif
 
        wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
 }
@@ -863,7 +1200,8 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
 
 
 static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
-                                 struct nlattr *reason, struct nlattr *addr)
+                                 struct nlattr *reason, struct nlattr *addr,
+                                 struct nlattr *by_ap)
 {
        union wpa_event_data data;
 
@@ -881,6 +1219,7 @@ static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
        os_memset(&data, 0, sizeof(data));
        if (reason)
                data.disassoc_info.reason_code = nla_get_u16(reason);
+       data.disassoc_info.locally_generated = by_ap == NULL;
        wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data);
 }
 
@@ -939,6 +1278,14 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
                event.rx_action.data = &mgmt->u.action.category + 1;
                event.rx_action.len = frame + len - event.rx_action.data;
                wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
+#ifdef ANDROID_BRCM_P2P_PATCH
+       } else if (stype == WLAN_FC_STYPE_ASSOC_REQ) {
+               mlme_event_assoc(drv, frame, len);
+       } else if (stype == WLAN_FC_STYPE_DISASSOC) {
+               mlme_event_deauth_disassoc(drv, EVENT_DISASSOC, frame, len);
+       } else if (stype == WLAN_FC_STYPE_DEAUTH) {
+               mlme_event_deauth_disassoc(drv, EVENT_DEAUTH, frame, len);
+#endif /* ANDROID_BRCM_P2P_PATCH */
        } else {
                event.rx_mgmt.frame = frame;
                event.rx_mgmt.frame_len = len;
@@ -947,26 +1294,29 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
 }
 
 
-static void mlme_event_action_tx_status(struct wpa_driver_nl80211_data *drv,
-                                       struct nlattr *cookie, const u8 *frame,
-                                       size_t len, struct nlattr *ack)
+static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
+                                     struct nlattr *cookie, const u8 *frame,
+                                     size_t len, struct nlattr *ack)
 {
        union wpa_event_data event;
        const struct ieee80211_hdr *hdr;
        u16 fc;
-       u64 cookie_val;
 
-       if (!cookie)
-               return;
+       if (!is_ap_interface(drv->nlmode)) {
+               u64 cookie_val;
 
-       cookie_val = nla_get_u64(cookie);
-       wpa_printf(MSG_DEBUG, "nl80211: Action TX status: cookie=0%llx%s "
-                  "(ack=%d)",
-                  (long long unsigned int) cookie_val,
-                  cookie_val == drv->send_action_cookie ?
-                  " (match)" : " (unknown)", ack != NULL);
-       if (cookie_val != drv->send_action_cookie)
-               return;
+               if (!cookie)
+                       return;
+
+               cookie_val = nla_get_u64(cookie);
+               wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
+                          " cookie=0%llx%s (ack=%d)",
+                          (long long unsigned int) cookie_val,
+                          cookie_val == drv->send_action_cookie ?
+                          " (match)" : " (unknown)", ack != NULL);
+               if (cookie_val != drv->send_action_cookie)
+                       return;
+       }
 
        hdr = (const struct ieee80211_hdr *) frame;
        fc = le_to_host16(hdr->frame_control);
@@ -1018,6 +1368,13 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
                reason_code = le_to_host16(mgmt->u.deauth.reason_code);
 
        if (type == EVENT_DISASSOC) {
+               event.disassoc_info.locally_generated =
+                       !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
+#ifdef ANDROID_BRCM_P2P_PATCH
+               if (is_ap_interface(drv->nlmode)) {
+                       event.disassoc_info.addr = mgmt->sa;
+               } else
+#endif /* ANDROID_BRCM_P2P_PATCH */
                event.disassoc_info.addr = bssid;
                event.disassoc_info.reason_code = reason_code;
                if (frame + len > mgmt->u.disassoc.variable) {
@@ -1026,6 +1383,13 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
                                mgmt->u.disassoc.variable;
                }
        } else {
+               event.deauth_info.locally_generated =
+                       !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
+#ifdef ANDROID_BRCM_P2P_PATCH
+               if (is_ap_interface(drv->nlmode)) {
+                       event.deauth_info.addr = mgmt->sa;
+               } else
+#endif /* ANDROID_BRCM_P2P_PATCH */
                event.deauth_info.addr = bssid;
                event.deauth_info.reason_code = reason_code;
                if (frame + len > mgmt->u.deauth.variable) {
@@ -1111,8 +1475,8 @@ static void mlme_event(struct wpa_driver_nl80211_data *drv,
                mlme_event_mgmt(drv, freq, nla_data(frame), nla_len(frame));
                break;
        case NL80211_CMD_FRAME_TX_STATUS:
-               mlme_event_action_tx_status(drv, cookie, nla_data(frame),
-                                           nla_len(frame), ack);
+               mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
+                                         nla_len(frame), ack);
                break;
        case NL80211_CMD_UNPROT_DEAUTHENTICATE:
                mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
@@ -1240,6 +1604,14 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
        int freqs[MAX_REPORT_FREQS];
        int num_freqs = 0;
 
+       if (drv->scan_for_auth) {
+               drv->scan_for_auth = 0;
+               wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
+                          "cfg80211 BSS entry");
+               wpa_driver_nl80211_authenticate_retry(drv);
+               return;
+       }
+
        os_memset(&event, 0, sizeof(event));
        info = &event.scan_info;
        info->aborted = aborted;
@@ -1336,6 +1708,7 @@ static int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
 
        return send_and_recv_msgs(drv, msg, get_link_signal, sig);
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
@@ -1402,33 +1775,109 @@ static int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
 
        return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
 
-static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
-                             struct nlattr *tb[])
+static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
 {
-       static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
-               [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
-               [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
-               [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
-               [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+       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 },
        };
-       struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
-       enum nl80211_cqm_rssi_threshold_event event;
-       union wpa_event_data ed;
-       struct wpa_signal_info sig;
-       int res;
+       struct wpa_scan_results *scan_results = arg;
+       struct wpa_scan_res *scan_res;
+       size_t i;
 
-       if (tb[NL80211_ATTR_CQM] == NULL ||
-           nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
-                            cqm_policy)) {
-               wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event");
-               return;
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (!tb[NL80211_ATTR_SURVEY_INFO]) {
+               wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
+               return NL_SKIP;
        }
 
-       os_memset(&ed, 0, sizeof(ed));
+       if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+                            tb[NL80211_ATTR_SURVEY_INFO],
+                            survey_policy)) {
+               wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
+                          "attributes");
+               return NL_SKIP;
+       }
+
+       if (!sinfo[NL80211_SURVEY_INFO_NOISE])
+               return NL_SKIP;
+
+       if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
+               return NL_SKIP;
+
+       for (i = 0; i < scan_results->num; ++i) {
+               scan_res = scan_results->res[i];
+               if (!scan_res)
+                       continue;
+               if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
+                   scan_res->freq)
+                       continue;
+               if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
+                       continue;
+               scan_res->noise = (s8)
+                       nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+               scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
+       }
+
+       return NL_SKIP;
+}
+
+
+static int nl80211_get_noise_for_scan_results(
+       struct wpa_driver_nl80211_data *drv,
+       struct wpa_scan_results *scan_res)
+{
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+       return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
+                                 scan_res);
+ nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+
+static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
+                             struct nlattr *tb[])
+{
+       static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
+               [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
+               [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
+               [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
+               [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
+       };
+       struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
+       enum nl80211_cqm_rssi_threshold_event event;
+       union wpa_event_data ed;
+       struct wpa_signal_info sig;
+       int res;
+
+       if (tb[NL80211_ATTR_CQM] == NULL ||
+           nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
+                            cqm_policy)) {
+               wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event");
+               return;
+       }
+
+       os_memset(&ed, 0, sizeof(ed));
 
        if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
                if (!tb[NL80211_ATTR_MAC])
@@ -1451,6 +1900,10 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
                wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
                           "event: RSSI low");
                ed.signal_change.above_threshold = 0;
+       } else if (event == NL80211_CQM_RSSI_BEACON_LOSS) {
+               wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
+                          "event: beacon loss!");
+               wpa_supplicant_event(drv->ctx, EVENT_START_ROAMING, &ed);
        } else
                return;
 
@@ -1473,6 +1926,25 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static void nl80211_roaming_support_event(struct wpa_driver_nl80211_data *drv,
+                                         struct nlattr *tb[])
+{
+       int enabled;
+       enum wpa_event_type event;
+
+       enabled = (tb[NL80211_ATTR_ROAMING_DISABLED] == NULL);
+
+       if (enabled)
+               event = EVENT_ROAMING_ENABLED;
+       else
+               event = EVENT_ROAMING_DISABLED;
+
+       wpa_printf(MSG_DEBUG, "nl80211: roaming %s",
+                  enabled ? "enabled" : "disabled");
+
+       wpa_supplicant_event(drv->ctx, event, NULL);
+}
+
 static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
                                      struct nlattr **tb)
 {
@@ -1484,7 +1956,7 @@ static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
        addr = nla_data(tb[NL80211_ATTR_MAC]);
        wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
 
-       if (is_ap_interface(drv->nlmode) && drv->no_monitor_iface_capab) {
+       if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
                u8 *ies = NULL;
                size_t ies_len = 0;
                if (tb[NL80211_ATTR_IE]) {
@@ -1517,7 +1989,7 @@ static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
        wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
                   MAC2STR(addr));
 
-       if (is_ap_interface(drv->nlmode) && drv->no_monitor_iface_capab) {
+       if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
                drv_event_disassoc(drv->ctx, addr);
                return;
        }
@@ -1607,34 +2079,52 @@ static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
 }
 
 
-static int process_event(struct nl_msg *msg, void *arg)
+static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
+                                      struct nlattr **tb)
 {
-       struct wpa_driver_nl80211_data *drv = arg;
-       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       union wpa_event_data data;
 
-       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-                 genlmsg_attrlen(gnlh, 0), NULL);
+       if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
+               return;
 
-       if (tb[NL80211_ATTR_IFINDEX]) {
-               int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
-               if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) {
-                       wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
-                                  " for foreign interface (ifindex %d)",
-                                  gnlh->cmd, ifindex);
-                       return NL_SKIP;
-               }
-       }
+       os_memset(&data, 0, sizeof(data));
+       os_memcpy(data.client_poll.addr,
+                 nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+       wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
+}
+
+
+static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
+                                  int wds)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       union wpa_event_data event;
+
+       if (!tb[NL80211_ATTR_MAC])
+               return;
+
+       os_memset(&event, 0, sizeof(event));
+       event.rx_from_unknown.bssid = bss->addr;
+       event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]);
+       event.rx_from_unknown.wds = wds;
+
+       wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
+}
 
+
+static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
+                                int cmd, struct nlattr **tb)
+{
        if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
-           (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
-            gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) {
+           (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
+            cmd == NL80211_CMD_SCAN_ABORTED)) {
                wpa_driver_nl80211_set_mode(&drv->first_bss,
                                            drv->ap_scan_as_station);
                drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
        }
 
-       switch (gnlh->cmd) {
+       switch (cmd) {
        case NL80211_CMD_TRIGGER_SCAN:
                wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
                break;
@@ -1671,18 +2161,17 @@ static int process_event(struct nl_msg *msg, void *arg)
        case NL80211_CMD_ASSOCIATE:
        case NL80211_CMD_DEAUTHENTICATE:
        case NL80211_CMD_DISASSOCIATE:
-       case NL80211_CMD_FRAME:
        case NL80211_CMD_FRAME_TX_STATUS:
        case NL80211_CMD_UNPROT_DEAUTHENTICATE:
        case NL80211_CMD_UNPROT_DISASSOCIATE:
-               mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+               mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME],
                           tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
                           tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
                           tb[NL80211_ATTR_COOKIE]);
                break;
        case NL80211_CMD_CONNECT:
        case NL80211_CMD_ROAM:
-               mlme_event_connect(drv, gnlh->cmd,
+               mlme_event_connect(drv, cmd,
                                   tb[NL80211_ATTR_STATUS_CODE],
                                   tb[NL80211_ATTR_MAC],
                                   tb[NL80211_ATTR_REQ_IE],
@@ -1690,7 +2179,8 @@ static int process_event(struct nl_msg *msg, void *arg)
                break;
        case NL80211_CMD_DISCONNECT:
                mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
-                                     tb[NL80211_ATTR_MAC]);
+                                     tb[NL80211_ATTR_MAC],
+                                     tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
                break;
        case NL80211_CMD_MICHAEL_MIC_FAILURE:
                mlme_event_michael_mic_failure(drv, tb);
@@ -1707,6 +2197,9 @@ static int process_event(struct nl_msg *msg, void *arg)
        case NL80211_CMD_NOTIFY_CQM:
                nl80211_cqm_event(drv, tb);
                break;
+       case NL80211_CMD_ROAMING_SUPPORT:
+               nl80211_roaming_support_event(drv, tb);
+               break;
        case NL80211_CMD_REG_CHANGE:
                wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
                wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
@@ -1729,6 +2222,89 @@ static int process_event(struct nl_msg *msg, void *arg)
        case NL80211_CMD_PMKSA_CANDIDATE:
                nl80211_pmksa_candidate_event(drv, tb);
                break;
+       case NL80211_CMD_PROBE_CLIENT:
+               nl80211_client_probe_event(drv, tb);
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
+                          "(cmd=%d)", cmd);
+               break;
+       }
+}
+
+
+static int process_drv_event(struct nl_msg *msg, void *arg)
+{
+       struct wpa_driver_nl80211_data *drv = arg;
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (tb[NL80211_ATTR_IFINDEX]) {
+               int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+               if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
+                                  " for foreign interface (ifindex %d)",
+                                  gnlh->cmd, ifindex);
+                       return NL_SKIP;
+               }
+       }
+
+       do_process_drv_event(drv, gnlh->cmd, tb);
+       return NL_SKIP;
+}
+
+
+static int process_global_event(struct nl_msg *msg, void *arg)
+{
+       struct nl80211_global *global = arg;
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct wpa_driver_nl80211_data *drv;
+       int ifidx = -1;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (tb[NL80211_ATTR_IFINDEX])
+               ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+
+       dl_list_for_each(drv, &global->interfaces,
+                        struct wpa_driver_nl80211_data, list) {
+               if (ifidx == -1 || ifidx == drv->ifindex ||
+                   have_ifidx(drv, ifidx))
+                       do_process_drv_event(drv, gnlh->cmd, tb);
+       }
+
+       return NL_SKIP;
+}
+
+
+static int process_bss_event(struct nl_msg *msg, void *arg)
+{
+       struct i802_bss *bss = arg;
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       switch (gnlh->cmd) {
+       case NL80211_CMD_FRAME:
+       case NL80211_CMD_FRAME_TX_STATUS:
+               mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+                          tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
+                          tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
+                          tb[NL80211_ATTR_COOKIE]);
+               break;
+       case NL80211_CMD_UNEXPECTED_FRAME:
+               nl80211_spurious_frame(bss, tb, 0);
+               break;
+       case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
+               nl80211_spurious_frame(bss, tb, 1);
+               break;
        default:
                wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
                           "(cmd=%d)", gnlh->cmd);
@@ -1742,18 +2318,11 @@ static int process_event(struct nl_msg *msg, void *arg)
 static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
                                             void *handle)
 {
-       struct nl_cb *cb;
-       struct wpa_driver_nl80211_data *drv = eloop_ctx;
+       struct nl_cb *cb = eloop_ctx;
 
        wpa_printf(MSG_DEBUG, "nl80211: Event message available");
 
-       cb = nl_cb_clone(drv->global->nl_cb);
-       if (!cb)
-               return;
-       nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
-       nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv);
        nl_recvmsgs(handle, cb);
-       nl_cb_put(cb);
 }
 
 
@@ -1788,6 +2357,7 @@ static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
                return -EINVAL;
        return 0;
 nla_put_failure:
+       nlmsg_free(msg);
        return -EINVAL;
 }
 
@@ -1796,9 +2366,30 @@ struct wiphy_info_data {
        struct wpa_driver_capa *capa;
 
        unsigned int error:1;
+       unsigned int device_ap_sme:1;
+       unsigned int poll_command_supported:1;
+       unsigned int data_tx_status:1;
+       unsigned int monitor_supported:1;
 };
 
 
+static unsigned int probe_resp_offload_support(int supp_protocols)
+{
+       unsigned int prot = 0;
+
+       if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
+               prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
+       if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
+               prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
+       if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
+               prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
+       if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
+               prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
+
+       return prot;
+}
+
+
 static int wiphy_info_handler(struct nl_msg *msg, void *arg)
 {
        struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -1850,6 +2441,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
                        case NL80211_IFTYPE_P2P_CLIENT:
                                p2p_client_supported = 1;
                                break;
+                       case NL80211_IFTYPE_MONITOR:
+                               info->monitor_supported = 1;
+                               break;
                        }
                }
        }
@@ -1927,6 +2521,9 @@ broken_combination:
                        case NL80211_CMD_START_SCHED_SCAN:
                                capa->sched_scan_supported = 1;
                                break;
+                       case NL80211_CMD_PROBE_CLIENT:
+                               info->poll_command_supported = 1;
+                               break;
                        }
                }
        }
@@ -1945,6 +2542,15 @@ broken_combination:
        /* default to 5000 since early versions of mac80211 don't set it */
        capa->max_remain_on_chan = 5000;
 
+       if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
+               capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
+
+       if (tb[NL80211_ATTR_FEATURE_FLAGS]) {
+               int features = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]);
+               if (features & NL80211_FEATURE_SCHED_SCAN_INTERVALS)
+                       capa->sched_scan_intervals_supported = 1;
+       }
+
        if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION])
                capa->max_remain_on_chan =
                        nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
@@ -1977,6 +2583,26 @@ broken_combination:
                }
        }
 
+       if (tb[NL80211_ATTR_DEVICE_AP_SME])
+               info->device_ap_sme = 1;
+
+       if (tb[NL80211_ATTR_FEATURE_FLAGS]) {
+               u32 flags = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]);
+
+               if (flags & NL80211_FEATURE_SK_TX_STATUS)
+                       info->data_tx_status = 1;
+       }
+
+       if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) {
+               int protocols =
+                       nla_get_u32(tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
+               wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response "
+                          "offload in AP mode");
+               capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
+               capa->probe_resp_offloads =
+                       probe_resp_offload_support(protocols);
+       }
+
        return NL_SKIP;
 }
 
@@ -2034,12 +2660,82 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
        drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
        drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
 
+       drv->device_ap_sme = info.device_ap_sme;
+       drv->poll_command_supported = info.poll_command_supported;
+       drv->data_tx_status = info.data_tx_status;
+
+       /*
+        * If poll command is supported mac80211 is new enough to
+        * have everything we need to not need monitor interfaces.
+        */
+       drv->use_monitor = !info.poll_command_supported;
+
+       if (drv->device_ap_sme && drv->use_monitor) {
+               /*
+                * Non-mac80211 drivers may not support monitor interface.
+                * Make sure we do not get stuck with incorrect capability here
+                * by explicitly testing this.
+                */
+               if (!info.monitor_supported) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
+                                  "with device_ap_sme since no monitor mode "
+                                  "support detected");
+                       drv->use_monitor = 0;
+               }
+       }
+
+       /*
+        * If we aren't going to use monitor interfaces, but the
+        * driver doesn't support data TX status, we won't get TX
+        * status for EAPOL frames.
+        */
+       if (!drv->use_monitor && !info.data_tx_status)
+               drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+
        return 0;
 }
 
 
+#ifdef ANDROID
+static int android_genl_ctrl_resolve(struct nl_handle *handle,
+                                    const char *name)
+{
+       /*
+        * Android ICS has very minimal genl_ctrl_resolve() implementation, so
+        * need to work around that.
+        */
+       struct nl_cache *cache = NULL;
+       struct genl_family *nl80211 = NULL;
+       int id = -1;
+
+       if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
+               wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
+                          "netlink cache");
+               goto fail;
+       }
+
+       nl80211 = genl_ctrl_search_by_name(cache, name);
+       if (nl80211 == NULL)
+               goto fail;
+
+       id = genl_family_get_id(nl80211);
+
+fail:
+       if (nl80211)
+               genl_family_put(nl80211);
+       if (cache)
+               nl_cache_free(cache);
+
+       return id;
+}
+#define genl_ctrl_resolve android_genl_ctrl_resolve
+#endif /* ANDROID */
+
+
 static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
 {
+       int ret;
+
        global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
        if (global->nl_cb == NULL) {
                wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
@@ -2047,54 +2743,44 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
                return -1;
        }
 
-       if (nl_create_handles(&global->nl, global->nl_cb, "nl"))
-               return -1;
+       global->nl = nl_create_handle(global->nl_cb, "nl");
+       if (global->nl == NULL)
+               goto err;
 
-       global->nl80211 = genl_ctrl_search_by_name(global->nl.cache,
-                                                  "nl80211");
-       if (global->nl80211 == NULL) {
+       global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
+       if (global->nl80211_id < 0) {
                wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
                           "found");
-               return -1;
+               goto err;
        }
 
-       return 0;
-}
-
-
-static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
-{
-       struct nl80211_global *global = drv->global;
-       int ret;
-
-       /* Initialize generic netlink and nl80211 */
-
-       if (nl_create_handles(&drv->nl_event, global->nl_cb, "event"))
-               goto err3;
+       global->nl_event = nl_create_handle(global->nl_cb, "event");
+       if (global->nl_event == NULL)
+               goto err;
 
-       ret = nl_get_multicast_id(drv, "nl80211", "scan");
+       ret = nl_get_multicast_id(global, "nl80211", "scan");
        if (ret >= 0)
-               ret = nl_socket_add_membership(drv->nl_event.handle, ret);
+               ret = nl_socket_add_membership(global->nl_event, ret);
        if (ret < 0) {
                wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
                           "membership for scan events: %d (%s)",
                           ret, strerror(-ret));
-               goto err4;
+               goto err;
        }
 
-       ret = nl_get_multicast_id(drv, "nl80211", "mlme");
+       ret = nl_get_multicast_id(global, "nl80211", "mlme");
        if (ret >= 0)
-               ret = nl_socket_add_membership(drv->nl_event.handle, ret);
+               ret = nl_socket_add_membership(global->nl_event, ret);
        if (ret < 0) {
                wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
                           "membership for mlme events: %d (%s)",
                           ret, strerror(-ret));
-               goto err4;
+               goto err;
        }
 
-       ret = nl_get_multicast_id(drv, "nl80211", "regulatory");
+       ret = nl_get_multicast_id(global, "nl80211", "regulatory");
        if (ret >= 0)
-               ret = nl_socket_add_membership(drv->nl_event.handle, ret);
+               ret = nl_socket_add_membership(global->nl_event, ret);
        if (ret < 0) {
                wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
                           "membership for regulatory events: %d (%s)",
@@ -2102,19 +2788,43 @@ static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
                /* Continue without regulatory events */
        }
 
-       eloop_register_read_sock(nl_socket_get_fd(drv->nl_event.handle),
-                                wpa_driver_nl80211_event_receive, drv,
-                                drv->nl_event.handle);
+       nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+                 no_seq_check, NULL);
+       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);
 
        return 0;
 
-err4:
-       nl_destroy_handles(&drv->nl_event);
-err3:
+err:
+       nl_destroy_handles(&global->nl_event);
+       nl_destroy_handles(&global->nl);
+       nl_cb_put(global->nl_cb);
+       global->nl_cb = NULL;
        return -1;
 }
 
 
+static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
+{
+       drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+       if (!drv->nl_cb) {
+               wpa_printf(MSG_ERROR, "nl80211: Failed to alloc cb struct");
+               return -1;
+       }
+
+       nl_cb_set(drv->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+                 no_seq_check, NULL);
+       nl_cb_set(drv->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+                 process_drv_event, drv);
+
+       return 0;
+}
+
+
 static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
 {
        wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
@@ -2172,21 +2882,95 @@ static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv)
 }
 
 
-#ifdef CONFIG_AP
-static void nl80211_l2_read(void *ctx, const u8 *src_addr, const u8 *buf,
-                           size_t len)
+static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
+                                                     void *eloop_ctx,
+                                                     void *handle)
 {
-       wpa_printf(MSG_DEBUG, "nl80211: l2_packet read %u",
-                  (unsigned int) len);
-}
-#endif /* CONFIG_AP */
+       struct wpa_driver_nl80211_data *drv = eloop_ctx;
+       u8 data[2048];
+       struct msghdr msg;
+       struct iovec entry;
+       struct {
+               struct cmsghdr cm;
+               char control[512];
+       } control;
+       struct cmsghdr *cmsg;
+       int res, found_ee = 0, found_wifi = 0, acked = 0;
+       union wpa_event_data event;
 
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_iov = &entry;
+       msg.msg_iovlen = 1;
+       entry.iov_base = data;
+       entry.iov_len = sizeof(data);
+       msg.msg_control = &control;
+       msg.msg_controllen = sizeof(control);
+
+       res = recvmsg(sock, &msg, MSG_ERRQUEUE);
+       /* if error or not fitting 802.3 header, return */
+       if (res < 14)
+               return;
 
-/**
- * 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
+       for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
+       {
+               if (cmsg->cmsg_level == SOL_SOCKET &&
+                   cmsg->cmsg_type == SCM_WIFI_STATUS) {
+                       int *ack;
+
+                       found_wifi = 1;
+                       ack = (void *)CMSG_DATA(cmsg);
+                       acked = *ack;
+               }
+
+               if (cmsg->cmsg_level == SOL_PACKET &&
+                   cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
+                       struct sock_extended_err *err =
+                               (struct sock_extended_err *)CMSG_DATA(cmsg);
+
+                       if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
+                               found_ee = 1;
+               }
+       }
+
+       if (!found_ee || !found_wifi)
+               return;
+
+       memset(&event, 0, sizeof(event));
+       event.eapol_tx_status.dst = data;
+       event.eapol_tx_status.data = data + 14;
+       event.eapol_tx_status.data_len = res - 14;
+       event.eapol_tx_status.ack = acked;
+       wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
+}
+
+
+static int nl80211_init_bss(struct i802_bss *bss)
+{
+       bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+       if (!bss->nl_cb)
+               return -1;
+
+       nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+                 no_seq_check, NULL);
+       nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+                 process_bss_event, bss);
+
+       return 0;
+}
+
+
+static void nl80211_destroy_bss(struct i802_bss *bss)
+{
+       nl_cb_put(bss->nl_cb);
+       bss->nl_cb = NULL;
+}
+
+
+/**
+ * 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
  */
@@ -2197,6 +2981,8 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
        struct rfkill_config *rcfg;
        struct i802_bss *bss;
 
+       if (global_priv == NULL)
+               return NULL;
        drv = os_zalloc(sizeof(*drv));
        if (drv == NULL)
                return NULL;
@@ -2207,6 +2993,7 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
        os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
        drv->monitor_ifidx = -1;
        drv->monitor_sock = -1;
+       drv->eapol_tx_sock = -1;
        drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
 
        if (wpa_driver_nl80211_init_nl(drv)) {
@@ -2214,6 +3001,9 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
                return NULL;
        }
 
+       if (nl80211_init_bss(bss))
+               goto failed;
+
        nl80211_get_phy_name(drv);
 
        rcfg = os_zalloc(sizeof(*rcfg));
@@ -2232,10 +3022,27 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
        if (wpa_driver_nl80211_finish_drv_init(drv))
                goto failed;
 
-#ifdef CONFIG_AP
-       drv->l2 = l2_packet_init(ifname, NULL, ETH_P_EAPOL,
-                                nl80211_l2_read, drv, 0);
-#endif /* CONFIG_AP */
+       drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+       if (drv->eapol_tx_sock < 0)
+               goto failed;
+
+       if (drv->data_tx_status) {
+               int enabled = 1;
+
+               if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
+                              &enabled, sizeof(enabled)) < 0) {
+                       wpa_printf(MSG_DEBUG,
+                               "nl80211: wifi status sockopt failed\n");
+                       drv->data_tx_status = 0;
+                       if (!drv->use_monitor)
+                               drv->capa.flags &=
+                                       ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+               } else {
+                       eloop_register_read_sock(drv->eapol_tx_sock,
+                               wpa_driver_nl80211_handle_eapol_tx_status,
+                               drv, NULL);
+               }
+       }
 
        if (drv->global) {
                dl_list_add(&drv->global->interfaces, &drv->list);
@@ -2250,10 +3057,11 @@ failed:
 }
 
 
-static int nl80211_register_frame(struct wpa_driver_nl80211_data *drv,
+static int nl80211_register_frame(struct i802_bss *bss,
                                  struct nl_handle *nl_handle,
                                  u16 type, const u8 *match, size_t match_len)
 {
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret = -1;
 
@@ -2261,13 +3069,18 @@ static int nl80211_register_frame(struct wpa_driver_nl80211_data *drv,
        if (!msg)
                return -1;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p",
+                  type, nl_handle);
+       wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
+                   match, match_len);
+
        nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
        NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
        NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
 
-       ret = send_and_recv(drv, nl_handle, msg, NULL, NULL);
+       ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
@@ -2284,69 +3097,210 @@ nla_put_failure:
 }
 
 
-static int nl80211_register_action_frame(struct wpa_driver_nl80211_data *drv,
+static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+
+       if (bss->nl_mgmt) {
+               wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
+                          "already on! (nl_mgmt=%p)", bss->nl_mgmt);
+               return -1;
+       }
+
+       bss->nl_mgmt = nl_create_handle(drv->nl_cb, "mgmt");
+       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 int nl80211_register_action_frame(struct i802_bss *bss,
                                         const u8 *match, size_t match_len)
 {
        u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
-       return nl80211_register_frame(drv, drv->nl_event.handle,
+       return nl80211_register_frame(bss, bss->nl_mgmt,
                                      type, match, match_len);
 }
 
 
-static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv)
+static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
 {
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+
+       if (nl80211_alloc_mgmt_handle(bss))
+               return -1;
+       wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
+                  "handle %p", bss->nl_mgmt);
+
 #if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
        /* GAS Initial Request */
-       if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0a", 2) < 0)
+       if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
                return -1;
        /* GAS Initial Response */
-       if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0b", 2) < 0)
+       if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
                return -1;
        /* GAS Comeback Request */
-       if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0c", 2) < 0)
+       if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
                return -1;
        /* GAS Comeback Response */
-       if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0d", 2) < 0)
+       if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
                return -1;
 #endif /* CONFIG_P2P || CONFIG_INTERWORKING */
 #ifdef CONFIG_P2P
        /* P2P Public Action */
-       if (nl80211_register_action_frame(drv,
+       if (nl80211_register_action_frame(bss,
                                          (u8 *) "\x04\x09\x50\x6f\x9a\x09",
                                          6) < 0)
                return -1;
        /* P2P Action */
-       if (nl80211_register_action_frame(drv,
+       if (nl80211_register_action_frame(bss,
                                          (u8 *) "\x7f\x50\x6f\x9a\x09",
                                          5) < 0)
                return -1;
 #endif /* CONFIG_P2P */
 #ifdef CONFIG_IEEE80211W
        /* SA Query Response */
-       if (nl80211_register_action_frame(drv, (u8 *) "\x08\x01", 2) < 0)
+       if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
                return -1;
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_TDLS
        if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
                /* TDLS Discovery Response */
-               if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0e", 2) <
+               if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
                    0)
                        return -1;
        }
 #endif /* CONFIG_TDLS */
 
        /* FT Action frames */
-       if (nl80211_register_action_frame(drv, (u8 *) "\x06", 1) < 0)
+       if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
                return -1;
        else
                drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
                        WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
 
        /* WNM - BSS Transition Management Request */
-       if (nl80211_register_action_frame(drv, (u8 *) "\x0a\x07", 2) < 0)
+       if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
+               return -1;
+
+       return 0;
+}
+
+
+static int nl80211_register_spurious_class3(struct i802_bss *bss)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret = -1;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_UNEXPECTED_FRAME);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+       ret = send_and_recv(drv->global, bss->nl_mgmt, msg, NULL, NULL);
+       msg = NULL;
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
+                          "failed: ret=%d (%s)",
+                          ret, strerror(-ret));
+               goto nla_put_failure;
+       }
+       ret = 0;
+nla_put_failure:
+       nlmsg_free(msg);
+       return ret;
+}
+
+
+static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
+{
+       static const int stypes[] = {
+               WLAN_FC_STYPE_AUTH,
+               WLAN_FC_STYPE_ASSOC_REQ,
+               WLAN_FC_STYPE_REASSOC_REQ,
+               WLAN_FC_STYPE_DISASSOC,
+               WLAN_FC_STYPE_DEAUTH,
+               WLAN_FC_STYPE_ACTION,
+               WLAN_FC_STYPE_PROBE_REQ,
+/* Beacon doesn't work as mac80211 doesn't currently allow
+ * it, but it wouldn't really be the right thing anyway as
+ * it isn't per interface ... maybe just dump the scan
+ * results periodically for OLBC?
+ */
+//             WLAN_FC_STYPE_BEACON,
+       };
+       unsigned int i;
+
+       if (nl80211_alloc_mgmt_handle(bss))
+               return -1;
+       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++) {
+               if (nl80211_register_frame(bss, bss->nl_mgmt,
+                                          (WLAN_FC_TYPE_MGMT << 2) |
+                                          (stypes[i] << 4),
+                                          NULL, 0) < 0) {
+                       goto out_err;
+               }
+       }
+
+       if (nl80211_register_spurious_class3(bss))
+               goto out_err;
+
+       if (nl80211_get_wiphy_data_ap(bss) == NULL)
+               goto out_err;
+
+       return 0;
+
+out_err:
+       eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
+       nl_destroy_handles(&bss->nl_mgmt);
+       return -1;
+}
+
+
+static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
+{
+       if (nl80211_alloc_mgmt_handle(bss))
                return -1;
+       wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
+                  "handle %p (device SME)", bss->nl_mgmt);
+
+       if (nl80211_register_frame(bss, bss->nl_mgmt,
+                                  (WLAN_FC_TYPE_MGMT << 2) |
+                                  (WLAN_FC_STYPE_ACTION << 4),
+                                  NULL, 0) < 0)
+               goto out_err;
 
        return 0;
+
+out_err:
+       eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
+       nl_destroy_handles(&bss->nl_mgmt);
+       return -1;
+}
+
+
+static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
+{
+       if (bss->nl_mgmt == NULL)
+               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_put_wiphy_data_ap(bss);
 }
 
 
@@ -2371,8 +3325,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
         * dynamically added interface (e.g., P2P) that was already configured
         * with proper iftype.
         */
-       if ((drv->global == NULL ||
-            drv->ifindex != drv->global->if_add_ifindex) &&
+       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");
@@ -2401,19 +3354,9 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
                return -1;
 
        if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-                              drv->addr))
+                              bss->addr))
                return -1;
 
-       if (nl80211_register_action_frames(drv) < 0) {
-               wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
-                          "frame processing - ignore for now");
-               /*
-                * Older kernel versions did not support this, so ignore the
-                * error for now. Some functionality may not be available
-                * because of this.
-                */
-       }
-
        if (send_rfkill_event) {
                eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
                                       drv, drv->ctx);
@@ -2436,6 +3379,7 @@ static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
 
        return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
@@ -2452,12 +3396,12 @@ static void wpa_driver_nl80211_deinit(void *priv)
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
 
-#ifdef CONFIG_AP
-       if (drv->l2)
-               l2_packet_deinit(drv->l2);
-#endif /* CONFIG_AP */
+       if (drv->data_tx_status)
+               eloop_unregister_read_sock(drv->eapol_tx_sock);
+       if (drv->eapol_tx_sock >= 0)
+               close(drv->eapol_tx_sock);
 
-       if (drv->nl_preq.handle)
+       if (bss->nl_preq)
                wpa_driver_nl80211_probe_req_report(bss, 0);
        if (bss->added_if_into_bridge) {
                if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
@@ -2496,7 +3440,7 @@ static void wpa_driver_nl80211_deinit(void *priv)
                os_free(drv->if_indices);
 #endif /* HOSTAPD */
 
-       if (drv->disable_11b_rates)
+       if (drv->disabled_11b_rates)
                nl80211_disable_11b_rates(drv, drv->ifindex, 0);
 
        netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
@@ -2507,12 +3451,16 @@ static void wpa_driver_nl80211_deinit(void *priv)
 
        (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");
+
+       nl_cb_put(drv->nl_cb);
 
-       eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_event.handle));
-       nl_destroy_handles(&drv->nl_event);
+       nl80211_destroy_bss(&drv->first_bss);
 
        os_free(drv->filter_ssids);
 
+       os_free(drv->auth_ie);
+
        if (drv->in_interface_list)
                dl_list_del(&drv->list);
 
@@ -2556,6 +3504,8 @@ static int wpa_driver_nl80211_scan(void *priv,
        struct nl_msg *msg, *ssids, *freqs, *rates;
        size_t i;
 
+       drv->scan_for_auth = 0;
+
        msg = nlmsg_alloc();
        ssids = nlmsg_alloc();
        freqs = nlmsg_alloc();
@@ -2588,8 +3538,8 @@ static int wpa_driver_nl80211_scan(void *priv,
                nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
 
        if (params->extra_ies) {
-               wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan extra IEs",
-                                 params->extra_ies, params->extra_ies_len);
+               wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
+                           params->extra_ies, params->extra_ies_len);
                NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
                        params->extra_ies);
        }
@@ -2604,6 +3554,8 @@ static int wpa_driver_nl80211_scan(void *priv,
        }
 
        if (params->p2p_probe) {
+               wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
+
                /*
                 * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
                 * by masking out everything else apart from the OFDM rates 6,
@@ -2677,12 +3629,16 @@ nla_put_failure:
  * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
  * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
  * @params: Scan parameters
- * @interval: Interval between scan cycles in milliseconds
+ * @long_interval: interval between scan cycles after end of short cycles
+ * @short_interval: interval between initial short scan cycles
+ * @num_short_intervals: number of interval short scan intervals
  * Returns: 0 on success, -1 on failure or if not supported
  */
 static int wpa_driver_nl80211_sched_scan(void *priv,
                                         struct wpa_driver_scan_params *params,
-                                        u32 interval)
+                                        u32 long_interval,
+                                        u32 short_interval,
+                                        u8 num_short_intervals)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -2690,6 +3646,11 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
        struct nl_msg *msg, *ssids, *freqs, *match_set_ssid, *match_sets;
        size_t i;
 
+#ifdef ANDROID
+       if (!drv->capa.sched_scan_supported)
+               return android_pno_start(bss, params);
+#endif /* ANDROID */
+
        msg = nlmsg_alloc();
        ssids = nlmsg_alloc();
        freqs = nlmsg_alloc();
@@ -2709,9 +3670,20 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval);
+       NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, long_interval);
+
+       if (drv->capa.sched_scan_intervals_supported) {
+               NLA_PUT_U32(msg,
+                           NL80211_ATTR_SCHED_SCAN_SHORT_INTERVAL,
+                           short_interval);
+
+               NLA_PUT_U8(msg,
+                          NL80211_ATTR_SCHED_SCAN_NUM_SHORT_INTERVALS,
+                          num_short_intervals);
+       }
 
-       if (drv->num_filter_ssids) {
+       if (drv->num_filter_ssids &&
+           (int) drv->num_filter_ssids <= drv->capa.max_match_sets) {
                match_sets = nlmsg_alloc();
 
                for (i = 0; i < drv->num_filter_ssids; i++) {
@@ -2773,8 +3745,9 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
                goto nla_put_failure;
        }
 
-       wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
-                  "scan interval %d msec", ret, interval);
+       wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) "
+                  "intervals: short=%d ms long=%d ms num_short_intervals=%d"
+                  , ret, short_interval, long_interval, num_short_intervals);
 
 nla_put_failure:
        nlmsg_free(ssids);
@@ -2796,6 +3769,11 @@ static int wpa_driver_nl80211_stop_sched_scan(void *priv)
        int ret = 0;
        struct nl_msg *msg;
 
+#ifdef ANDROID
+       if (!drv->capa.sched_scan_supported)
+               return android_pno_stop(bss);
+#endif /* ANDROID */
+
        msg = nlmsg_alloc();
        if (!msg)
                return -1;
@@ -2958,7 +3936,7 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
                r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
        } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
                r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
-               r->flags |= WPA_SCAN_LEVEL_INVALID;
+               r->flags |= WPA_SCAN_QUAL_INVALID;
        } else
                r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
        if (bss[NL80211_BSS_TSF])
@@ -3122,8 +4100,9 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
        ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
        msg = NULL;
        if (ret == 0) {
-               wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)",
-                          (unsigned long) res->num);
+               wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
+                          "BSSes)", (unsigned long) res->num);
+               nl80211_get_noise_for_scan_results(drv, res);
                return res;
        }
        wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
@@ -3329,6 +4308,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
        return ret;
 
 nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
@@ -3469,8 +4449,9 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
-               wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-                          "(%s)", ret, strerror(-ret));
+               wpa_dbg(drv->ctx, MSG_DEBUG,
+                       "nl80211: MLME command failed: reason=%u ret=%d (%s)",
+                       reason_code, ret, strerror(-ret));
                goto nla_put_failure;
        }
        ret = 0;
@@ -3523,6 +4504,52 @@ static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
 }
 
 
+static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
+                                    struct wpa_driver_auth_params *params)
+{
+       int i;
+
+       drv->auth_freq = params->freq;
+       drv->auth_alg = params->auth_alg;
+       drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
+       drv->auth_local_state_change = params->local_state_change;
+       drv->auth_p2p = params->p2p;
+
+       if (params->bssid)
+               os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
+       else
+               os_memset(drv->auth_bssid_, 0, ETH_ALEN);
+
+       if (params->ssid) {
+               os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
+               drv->auth_ssid_len = params->ssid_len;
+       } else
+               drv->auth_ssid_len = 0;
+
+
+       os_free(drv->auth_ie);
+       drv->auth_ie = NULL;
+       drv->auth_ie_len = 0;
+       if (params->ie) {
+               drv->auth_ie = os_malloc(params->ie_len);
+               if (drv->auth_ie) {
+                       os_memcpy(drv->auth_ie, params->ie, params->ie_len);
+                       drv->auth_ie_len = params->ie_len;
+               }
+       }
+
+       for (i = 0; i < 4; i++) {
+               if (params->wep_key[i] && params->wep_key_len[i] &&
+                   params->wep_key_len[i] <= 16) {
+                       os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
+                                 params->wep_key_len[i]);
+                       drv->auth_wep_key_len[i] = params->wep_key_len[i];
+               } else
+                       drv->auth_wep_key_len[i] = 0;
+       }
+}
+
+
 static int wpa_driver_nl80211_authenticate(
        void *priv, struct wpa_driver_auth_params *params)
 {
@@ -3533,6 +4560,10 @@ static int wpa_driver_nl80211_authenticate(
        enum nl80211_auth_type type;
        enum nl80211_iftype nlmode;
        int count = 0;
+       int is_retry;
+
+       is_retry = drv->retry_auth;
+       drv->retry_auth = 0;
 
        drv->associated = 0;
        os_memset(drv->auth_bssid, 0, ETH_ALEN);
@@ -3609,8 +4640,9 @@ retry:
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
-               wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-                          "(%s)", ret, strerror(-ret));
+               wpa_dbg(drv->ctx, MSG_DEBUG,
+                       "nl80211: MLME command failed (auth): ret=%d (%s)",
+                       ret, strerror(-ret));
                count++;
                if (ret == -EALREADY && count == 1 && params->bssid &&
                    !params->local_state_change) {
@@ -3627,6 +4659,49 @@ retry:
                        nlmsg_free(msg);
                        goto retry;
                }
+
+               if (ret == -ENOENT && params->freq && !is_retry) {
+                       /*
+                        * cfg80211 has likely expired the BSS entry even
+                        * though it was previously available in our internal
+                        * BSS table. To recover quickly, start a single
+                        * channel scan on the specified channel.
+                        */
+                       struct wpa_driver_scan_params scan;
+                       int freqs[2];
+
+                       os_memset(&scan, 0, sizeof(scan));
+                       scan.num_ssids = 1;
+                       if (params->ssid) {
+                               scan.ssids[0].ssid = params->ssid;
+                               scan.ssids[0].ssid_len = params->ssid_len;
+                       }
+                       freqs[0] = params->freq;
+                       freqs[1] = 0;
+                       scan.freqs = freqs;
+                       wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
+                                  "channel scan to refresh cfg80211 BSS "
+                                  "entry");
+                       ret = wpa_driver_nl80211_scan(bss, &scan);
+                       if (ret == 0) {
+                               nl80211_copy_auth_params(drv, params);
+                               drv->scan_for_auth = 1;
+                       }
+               } else if (is_retry) {
+                       /*
+                        * Need to indicate this with an event since the return
+                        * value from the retry is not delivered to core code.
+                        */
+                       union wpa_event_data event;
+                       wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
+                                  "failed");
+                       os_memset(&event, 0, sizeof(event));
+                       os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
+                                 ETH_ALEN);
+                       wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
+                                            &event);
+               }
+
                goto nla_put_failure;
        }
        ret = 0;
@@ -3639,6 +4714,45 @@ nla_put_failure:
 }
 
 
+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;
+       int i;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
+
+       os_memset(&params, 0, sizeof(params));
+       params.freq = drv->auth_freq;
+       params.auth_alg = drv->auth_alg;
+       params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
+       params.local_state_change = drv->auth_local_state_change;
+       params.p2p = drv->auth_p2p;
+
+       if (!is_zero_ether_addr(drv->auth_bssid_))
+               params.bssid = drv->auth_bssid_;
+
+       if (drv->auth_ssid_len) {
+               params.ssid = drv->auth_ssid;
+               params.ssid_len = drv->auth_ssid_len;
+       }
+
+       params.ie = drv->auth_ie;
+       params.ie_len = drv->auth_ie_len;
+
+       for (i = 0; i < 4; i++) {
+               if (drv->auth_wep_key_len[i]) {
+                       params.wep_key[i] = drv->auth_wep_key[i];
+                       params.wep_key_len[i] = drv->auth_wep_key_len[i];
+               }
+       }
+
+       drv->retry_auth = 1;
+       return wpa_driver_nl80211_authenticate(bss, &params);
+}
+
+
 struct phy_info_arg {
        u16 *num_modes;
        struct hostapd_hw_modes *modes;
@@ -4063,14 +5177,16 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
                nl80211_set_ht40_flags(drv, &result);
                return wpa_driver_nl80211_add_11b(result.modes, num_modes);
        }
+       msg = NULL;
  nla_put_failure:
+       nlmsg_free(msg);
        return NULL;
 }
 
 
-static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
-                                        const void *data, size_t len,
-                                        int encrypt)
+static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv,
+                                       const void *data, size_t len,
+                                       int encrypt, int noack)
 {
        __u8 rtap_hdr[] = {
                0x00, 0x00, /* radiotap version */
@@ -4101,6 +5217,7 @@ static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
                .msg_flags = 0,
        };
        int res;
+       u16 txflags = 0;
 
        if (encrypt)
                rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
@@ -4111,6 +5228,10 @@ static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
                return -1;
        }
 
+       if (noack)
+               txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
+       *(le16 *) &rtap_hdr[12] = host_to_le16(txflags);
+
        res = sendmsg(drv->monitor_sock, &msg, 0);
        if (res < 0) {
                wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
@@ -4120,10 +5241,34 @@ static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
 }
 
 
-static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
-                                       size_t data_len)
+static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
+                                        const void *data, size_t len,
+                                        int encrypt, int noack,
+                                        unsigned int freq, int no_cck,
+                                        int offchanok, unsigned int wait_time)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       u64 cookie;
+
+       if (freq == 0)
+               freq = bss->freq;
+
+       if (drv->use_monitor)
+               return wpa_driver_nl80211_send_mntr(drv, data, len,
+                                                   encrypt, noack);
+
+       return nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
+                                     &cookie, no_cck, noack, offchanok);
+}
+
+
+static int wpa_driver_nl80211_send_mlme_freq(struct i802_bss *bss,
+                                            const u8 *data,
+                                            size_t data_len, int noack,
+                                            unsigned int freq, int no_cck,
+                                            int offchanok,
+                                            unsigned int wait_time)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct ieee80211_mgmt *mgmt;
        int encrypt = 1;
@@ -4140,14 +5285,33 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
                 * but it works due to the single-threaded nature
                 * of wpa_supplicant.
                 */
-               return nl80211_send_frame_cmd(drv, drv->last_mgmt_freq, 0,
-                                             data, data_len, NULL, 1);
-       }
-
-       if (drv->no_monitor_iface_capab && is_ap_interface(drv->nlmode)) {
-               return nl80211_send_frame_cmd(drv, drv->ap_oper_freq, 0,
-                                             data, data_len, NULL, 0);
-       }
+               if (freq == 0)
+                       freq = drv->last_mgmt_freq;
+               return nl80211_send_frame_cmd(bss, freq, 0,
+                                             data, data_len, NULL, 1, noack,
+                                             1);
+       }
+
+#ifdef ANDROID_BRCM_P2P_PATCH
+       if (is_ap_interface(drv->nlmode)) {
+               wpa_printf(MSG_DEBUG, "%s: Sending frame on bss freq %d "
+                          "using nl80211_send_frame_cmd", __func__,
+                          bss->freq);
+               return nl80211_send_frame_cmd(bss, bss->freq, 0,
+                                             data, data_len,
+                                             &drv->send_action_cookie, 0,
+                                             noack, 0);
+       }
+#else /* ANDROID_BRCM_P2P_PATCH */
+       if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
+               if (freq == 0)
+                       freq = bss->freq;
+               return nl80211_send_frame_cmd(bss, freq, 0,
+                                             data, data_len,
+                                             &drv->send_action_cookie,
+                                             no_cck, noack, offchanok);
+       }
+#endif /* ANDROID_BRCM_P2P_PATCH */
 
        if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
            WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
@@ -4163,32 +5327,26 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
                        encrypt = 0;
        }
 
-       return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
+       wpa_printf(MSG_DEBUG, "%s: Sending frame using monitor interface/"
+                  "l2 socket", __func__);
+       return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
+                                            noack, freq, no_cck, offchanok,
+                                            wait_time);
 }
 
 
-static int nl80211_set_ap_isolate(struct i802_bss *bss, int enabled)
+static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
+                                       size_t data_len, int noack)
 {
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct nl_msg *msg;
-
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
-       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_BSS);
-
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-       NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, enabled);
-
-       return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
-       return -ENOBUFS;
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_send_mlme_freq(bss, data, data_len, noack,
+                                                0, 0, 0, 0);
 }
 
 
 static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
-                          int slot, int ht_opmode)
+                          int slot, int ht_opmode, int ap_isolate,
+                          int *basic_rates)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
@@ -4207,10 +5365,26 @@ static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
                NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
        if (ht_opmode >= 0)
                NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode);
+       if (ap_isolate >= 0)
+               NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate);
+
+       if (basic_rates) {
+               u8 rates[NL80211_MAX_SUPP_RATES];
+               u8 rates_len = 0;
+               int i;
+
+               for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0;
+                    i++)
+                       rates[rates_len++] = basic_rates[i] / 5;
+
+               NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+       }
+
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
 
        return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
@@ -4248,6 +5422,9 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period);
        NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
                params->ssid);
+       if (params->proberesp && params->proberesp_len)
+               NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
+                       params->proberesp);
        switch (params->hide_ssid) {
        case NO_SSID_HIDING:
                NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
@@ -4292,6 +5469,10 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                        num_suites * sizeof(u32), suites);
        }
 
+       if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X &&
+           params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
+               NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
+
        num_suites = 0;
        if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
                suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
@@ -4346,27 +5527,25 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                           ret, strerror(-ret));
        } else {
                bss->beacon_set = 1;
-               ret = nl80211_set_ap_isolate(bss, params->isolate);
-               if (!params->isolate && ret) {
-                       wpa_printf(MSG_DEBUG, "nl80211: Ignore AP isolation "
-                                  "configuration error since isolation is "
-                                  "not used");
-                       ret = 0;
-               }
-
                nl80211_set_bss(bss, params->cts_protect, params->preamble,
-                               params->short_slot_time, params->ht_opmode);
+                               params->short_slot_time, params->ht_opmode,
+                               params->isolate, params->basic_rates);
        }
+#if defined(ANDROID_BRCM_P2P_PATCH) && defined(HOSTAPD)
+       wpa_driver_nl80211_probe_req_report(priv, 1);
+#endif
        return ret;
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
 
-static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv,
+static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
                                       int freq, int ht_enabled,
                                       int sec_channel_offset)
 {
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret;
 
@@ -4392,18 +5571,29 @@ static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv,
                                    NL80211_CHAN_HT40PLUS);
                        break;
                default:
+#ifdef ANDROID_BRCM_P2P_PATCH
+                       /* Should be changed to HT20 as a default value because
+                        * P2P firmware does not support 11n for BCM4329 */
+                       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+                                   NL80211_CHAN_NO_HT);
+#else /* ANDROID_BRCM_P2P_PATCH */
                        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
                                    NL80211_CHAN_HT20);
+#endif /* ANDROID_BRCM_P2P_PATCH */
                        break;
                }
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-       if (ret == 0)
+       msg = NULL;
+       if (ret == 0) {
+               bss->freq = freq;
                return 0;
+       }
        wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
                   "%d (%s)", freq, ret, strerror(-ret));
 nla_put_failure:
+       nlmsg_free(msg);
        return -1;
 }
 
@@ -4432,7 +5622,7 @@ static int wpa_driver_nl80211_sta_add(void *priv,
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct nl_msg *msg;
+       struct nl_msg *msg, *wme = NULL;
        struct nl80211_sta_flag_update upd;
        int ret = -ENOBUFS;
 
@@ -4467,7 +5657,21 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        upd.set = upd.mask;
        NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
 
+       if (params->flags & WPA_STA_WMM) {
+               wme = nlmsg_alloc();
+               if (!wme)
+                       goto nla_put_failure;
+
+               NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
+                               params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
+               NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
+                               (params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) &
+                               WMM_QOSINFO_STA_SP_MASK);
+               nla_put_nested(msg, NL80211_ATTR_STA_WME, wme);
+       }
+
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
        if (ret)
                wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
                           "result: %d (%s)", params->set ? "SET" : "NEW", ret,
@@ -4475,6 +5679,8 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        if (ret == -EEXIST)
                ret = 0;
  nla_put_failure:
+       nlmsg_free(wme);
+       nlmsg_free(msg);
        return ret;
 }
 
@@ -4501,6 +5707,7 @@ static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
                return 0;
        return ret;
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
@@ -4524,7 +5731,9 @@ static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
 
        if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
                return;
+       msg = NULL;
  nla_put_failure:
+       nlmsg_free(msg);
        wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
 }
 
@@ -4591,8 +5800,10 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
        if (ret) {
  nla_put_failure:
+               nlmsg_free(msg);
                wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
                           ifname, ret, strerror(-ret));
                return ret;
@@ -4638,7 +5849,7 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
                                                wds);
        }
 
-       if (ret >= 0 && drv->disable_11b_rates)
+       if (ret >= 0 && is_p2p_interface(iftype))
                nl80211_disable_11b_rates(drv, ret, 1);
 
        return ret;
@@ -4939,6 +6150,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)
+               return;
+
        if (drv->monitor_ifidx >= 0) {
                nl80211_remove_iface(drv, drv->monitor_ifidx);
                drv->monitor_ifidx = -1;
@@ -4959,6 +6174,11 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
        int optval;
        socklen_t optlen;
 
+       if (drv->monitor_ifidx >= 0) {
+               drv->monitor_refcount++;
+               return 0;
+       }
+
        if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) {
                /*
                 * P2P interface name is of the format p2p-%s-%d. For monitor
@@ -4979,9 +6199,15 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
                                     0);
 
        if (drv->monitor_ifidx == -EOPNOTSUPP) {
+               /*
+                * This is backward compatibility for a few versions of
+                * the kernel only that didn't advertise the right
+                * attributes for the only driver that then supported
+                * AP mode w/o monitor -- ath6kl.
+                */
                wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
                           "monitor interface type - try to run without it");
-               drv->no_monitor_iface_capab = 1;
+               drv->device_ap_sme = 1;
        }
 
        if (drv->monitor_ifidx < 0)
@@ -5031,22 +6257,88 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
 }
 
 
-#ifdef CONFIG_AP
+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);
+
+       /*
+        * Disable Probe Request reporting unless we need it in this way for
+        * devices that include the AP SME, in the other case (unless using
+        * monitor iface) we'll get it through the nl_mgmt socket instead.
+        */
+       if (!drv->device_ap_sme)
+               wpa_driver_nl80211_probe_req_report(bss, 0);
+
+       if (!drv->device_ap_sme && !drv->use_monitor)
+               if (nl80211_mgmt_subscribe_ap(bss))
+                       return -1;
+
+       if (drv->device_ap_sme && !drv->use_monitor)
+               if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
+                       return -1;
+
+       if (!drv->device_ap_sme && drv->use_monitor &&
+           nl80211_create_monitor_interface(drv) &&
+           !drv->device_ap_sme)
+               return -1;
+
+       if (drv->device_ap_sme &&
+           wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
+               wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
+                          "Probe Request frame reporting in AP mode");
+               /* Try to survive without this */
+       }
+
+       return 0;
+}
+
+
+static void nl80211_teardown_ap(struct i802_bss *bss)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+
+       if (drv->device_ap_sme) {
+               wpa_driver_nl80211_probe_req_report(bss, 0);
+               if (!drv->use_monitor)
+                       nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
+       } else if (drv->use_monitor)
+               nl80211_remove_monitor_interface(drv);
+       else
+               nl80211_mgmt_unsubscribe(bss, "AP teardown");
+
+       bss->beacon_set = 0;
+}
+
+
 static int nl80211_send_eapol_data(struct i802_bss *bss,
                                   const u8 *addr, const u8 *data,
-                                  size_t data_len, const u8 *own_addr)
+                                  size_t data_len)
 {
-       if (bss->drv->l2 == NULL) {
-               wpa_printf(MSG_DEBUG, "nl80211: No l2_packet to send EAPOL");
+       struct sockaddr_ll ll;
+       int ret;
+
+       if (bss->drv->eapol_tx_sock < 0) {
+               wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
                return -1;
        }
 
-       if (l2_packet_send(bss->drv->l2, addr, ETH_P_EAPOL, data, data_len) <
-           0)
-               return -1;
-       return 0;
+       os_memset(&ll, 0, sizeof(ll));
+       ll.sll_family = AF_PACKET;
+       ll.sll_ifindex = bss->ifindex;
+       ll.sll_protocol = htons(ETH_P_PAE);
+       ll.sll_halen = ETH_ALEN;
+       os_memcpy(ll.sll_addr, addr, ETH_ALEN);
+       ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
+                    (struct sockaddr *) &ll, sizeof(ll));
+       if (ret < 0)
+               wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
+                          strerror(errno));
+
+       return ret;
 }
-#endif /* CONFIG_AP */
 
 
 static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
@@ -5063,11 +6355,8 @@ static int wpa_driver_nl80211_hapd_send_eapol(
        int res;
        int qos = flags & WPA_STA_WMM;
 
-#ifdef CONFIG_AP
-       if (drv->no_monitor_iface_capab)
-               return nl80211_send_eapol_data(bss, addr, data, data_len,
-                                              own_addr);
-#endif /* CONFIG_AP */
+       if (drv->device_ap_sme || !drv->use_monitor)
+               return nl80211_send_eapol_data(bss, addr, data, data_len);
 
        len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
                data_len;
@@ -5106,7 +6395,8 @@ static int wpa_driver_nl80211_hapd_send_eapol(
        pos += 2;
        memcpy(pos, data, data_len);
 
-       res = wpa_driver_nl80211_send_frame(drv, (u8 *) hdr, len, encrypt);
+       res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0,
+                                           0, 0, 0, 0);
        if (res < 0) {
                wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
                           "failed: %d (%s)",
@@ -5174,6 +6464,7 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
 
        return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
+       nlmsg_free(msg);
        nlmsg_free(flags);
        return -ENOBUFS;
 }
@@ -5192,22 +6483,11 @@ static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
                nlmode = NL80211_IFTYPE_AP;
 
        if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode) ||
-           wpa_driver_nl80211_set_freq(drv, params->freq, 0, 0)) {
+           wpa_driver_nl80211_set_freq(&drv->first_bss, params->freq, 0, 0)) {
                nl80211_remove_monitor_interface(drv);
                return -1;
        }
 
-       if (drv->no_monitor_iface_capab) {
-               if (wpa_driver_nl80211_probe_req_report(&drv->first_bss, 1) < 0)
-               {
-                       wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
-                                  "Probe Request frame reporting in AP mode");
-                       /* Try to survive without this */
-               }
-       }
-
-       drv->ap_oper_freq = params->freq;
-
        return 0;
 }
 
@@ -5281,6 +6561,20 @@ retry:
        if (ret)
                goto nla_put_failure;
 
+       if (params->bssid && params->fixed_bssid) {
+               wpa_printf(MSG_DEBUG, "  * BSSID=" MACSTR,
+                          MAC2STR(params->bssid));
+               NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
+       }
+
+       if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+           params->key_mgmt_suite == KEY_MGMT_PSK ||
+           params->key_mgmt_suite == KEY_MGMT_802_1X_SHA256 ||
+           params->key_mgmt_suite == KEY_MGMT_PSK_SHA256) {
+               wpa_printf(MSG_DEBUG, "  * control port");
+               NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
+       }
+
        if (params->wpa_ie) {
                wpa_hexdump(MSG_DEBUG,
                            "  * Extra IEs for Beacon/Probe Response frames",
@@ -5502,6 +6796,16 @@ skip_auth_type:
                NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
        }
 
+       if (params->disable_ht)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
+
+       if (params->htcaps && params->htcaps_mask) {
+               int sz = sizeof(struct ieee80211_ht_capabilities);
+               NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
+               NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
+                       params->htcaps_mask);
+       }
+
        ret = nl80211_set_conn_keys(params, msg);
        if (ret)
                goto nla_put_failure;
@@ -5649,14 +6953,25 @@ static int wpa_driver_nl80211_associate(
                        params->prev_bssid);
        }
 
+       if (params->disable_ht)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
+
+       if (params->htcaps && params->htcaps_mask) {
+               int sz = sizeof(struct ieee80211_ht_capabilities);
+               NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
+               NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
+                       params->htcaps_mask);
+       }
+
        if (params->p2p)
                wpa_printf(MSG_DEBUG, "  * P2P group");
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
-               wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-                          "(%s)", ret, strerror(-ret));
+               wpa_dbg(drv->ctx, MSG_DEBUG,
+                       "nl80211: MLME command failed (assoc): ret=%d (%s)",
+                       ret, strerror(-ret));
                nl80211_dump_scan(drv);
                goto nla_put_failure;
        }
@@ -5688,9 +7003,11 @@ static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
        NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
        if (!ret)
                return 0;
 nla_put_failure:
+       nlmsg_free(msg);
        wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
                   " %d (%s)", ifindex, mode, ret, strerror(-ret));
        return ret;
@@ -5704,13 +7021,18 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
        int ret = -1;
        int i;
        int was_ap = is_ap_interface(drv->nlmode);
+       int res;
 
-       if (nl80211_set_mode(drv, drv->ifindex, nlmode) == 0) {
+       res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+       if (res == 0) {
                drv->nlmode = nlmode;
                ret = 0;
                goto done;
        }
 
+       if (res == -ENODEV)
+               return -1;
+
        if (nlmode == drv->nlmode) {
                wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
                           "requested mode - ignore error");
@@ -5725,7 +7047,6 @@ 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++) {
-               int res;
                res = linux_set_iface_flags(drv->global->ioctl_sock,
                                            bss->ifname, 0);
                if (res == -EACCES || res == -ENODEV)
@@ -5756,25 +7077,30 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
        }
 
 done:
-       if (!ret && is_ap_interface(nlmode)) {
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
+                          "from %d failed", nlmode, drv->nlmode);
+               return ret;
+       }
+
+       if (is_ap_interface(nlmode)) {
+               nl80211_mgmt_unsubscribe(bss, "start AP");
                /* Setup additional AP mode functionality if needed */
-               if (!drv->no_monitor_iface_capab && drv->monitor_ifidx < 0 &&
-                   nl80211_create_monitor_interface(drv) &&
-                   !drv->no_monitor_iface_capab)
+               if (nl80211_setup_ap(bss))
                        return -1;
-       } else if (!ret && !is_ap_interface(nlmode)) {
+       } else if (was_ap) {
                /* Remove additional AP mode functionality */
-               if (was_ap && drv->no_monitor_iface_capab)
-                       wpa_driver_nl80211_probe_req_report(bss, 0);
-               nl80211_remove_monitor_interface(drv);
-               bss->beacon_set = 0;
+               nl80211_teardown_ap(bss);
+       } else {
+               nl80211_mgmt_unsubscribe(bss, "mode change");
        }
 
-       if (ret)
-               wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
-                          "from %d failed", nlmode, drv->nlmode);
+       if (!is_ap_interface(nlmode) &&
+           nl80211_mgmt_subscribe_non_ap(bss) < 0)
+               wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
+                          "frame processing - ignore for now");
 
-       return ret;
+       return 0;
 }
 
 
@@ -5828,6 +7154,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
 
        return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
@@ -5836,8 +7163,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
 static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
 {
        struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled,
+       return wpa_driver_nl80211_set_freq(bss, freq->freq, freq->ht_enabled,
                                           freq->sec_channel_offset);
 }
 
@@ -5895,35 +7221,7 @@ static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
 
        return send_and_recv_msgs(drv, msg, get_key_handler, seq);
  nla_put_failure:
-       return -ENOBUFS;
-}
-
-
-static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates,
-                             int mode)
-{
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct nl_msg *msg;
-       u8 rates[NL80211_MAX_SUPP_RATES];
-       u8 rates_len = 0;
-       int i;
-
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
-       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_BSS);
-
-       for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
-               rates[rates_len++] = basic_rates[i] / 5;
-
-       NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
-
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
-       return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
@@ -5950,9 +7248,11 @@ static int i802_set_rts(void *priv, int rts)
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
        if (!ret)
                return 0;
 nla_put_failure:
+       nlmsg_free(msg);
        wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
                   "%d (%s)", rts, ret, strerror(-ret));
        return ret;
@@ -5981,9 +7281,11 @@ static int i802_set_frag(void *priv, int frag)
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
        if (!ret)
                return 0;
 nla_put_failure:
+       nlmsg_free(msg);
        wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
                   "%d: %d (%s)", frag, ret, strerror(-ret));
        return ret;
@@ -5995,6 +7297,7 @@ static int i802_flush(void *priv)
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
+       int res;
 
        msg = nlmsg_alloc();
        if (!msg)
@@ -6008,8 +7311,14 @@ static int i802_flush(void *priv)
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
                    if_nametoindex(bss->ifname));
 
-       return send_and_recv_msgs(drv, msg, NULL, NULL);
+       res = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (res) {
+               wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
+                          "(%s)", res, strerror(-res));
+       }
+       return res;
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
@@ -6084,6 +7393,7 @@ static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
 
        return send_and_recv_msgs(drv, msg, get_sta_handler, data);
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
@@ -6140,7 +7450,9 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
 
        if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
                return 0;
+       msg = NULL;
  nla_put_failure:
+       nlmsg_free(msg);
        return -1;
 }
 
@@ -6166,6 +7478,7 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr,
                    if_nametoindex(ifname));
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
        if (ret < 0) {
                wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
                           MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
@@ -6173,6 +7486,7 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr,
                           strerror(-ret));
        }
  nla_put_failure:
+       nlmsg_free(msg);
        return ret;
 }
 
@@ -6214,7 +7528,7 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
        mgmt.u.deauth.reason_code = host_to_le16(reason);
        return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
                                            IEEE80211_HDRLEN +
-                                           sizeof(mgmt.u.deauth));
+                                           sizeof(mgmt.u.deauth), 0);
 }
 
 
@@ -6233,7 +7547,7 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
        mgmt.u.disassoc.reason_code = host_to_le16(reason);
        return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
                                            IEEE80211_HDRLEN +
-                                           sizeof(mgmt.u.disassoc));
+                                           sizeof(mgmt.u.disassoc), 0);
 }
 
 #endif /* HOSTAPD || CONFIG_AP */
@@ -6492,6 +7806,8 @@ static void *i802_init(struct hostapd_data *hapd,
                               params->own_addr))
                goto failed;
 
+       memcpy(bss->addr, params->own_addr, ETH_ALEN);
+
        return bss;
 
 failed:
@@ -6535,7 +7851,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->addr, ETH_ALEN) == 0)
+               if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0)
                        return 1;
        }
        return 0;
@@ -6550,9 +7866,9 @@ static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
        if (!drv->global)
                return -1;
 
-       os_memcpy(new_addr, drv->addr, ETH_ALEN);
+       os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN);
        for (idx = 0; idx < 64; idx++) {
-               new_addr[0] = drv->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;
@@ -6656,12 +7972,19 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                        return -1;
                }
                os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
+               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;
                drv->first_bss.next = new_bss;
                if (drv_priv)
                        *drv_priv = new_bss;
+               nl80211_init_bss(new_bss);
+
+               /* Subscribe management frames for this WPA_IF_AP_BSS */
+               if (nl80211_setup_ap(new_bss))
+                       return -1;
        }
 #endif /* HOSTAPD */
 
@@ -6713,6 +8036,9 @@ static int wpa_driver_nl80211_if_remove(void *priv,
                for (tbss = &drv->first_bss; tbss; tbss = tbss->next) {
                        if (tbss->next == bss) {
                                tbss->next = bss->next;
+                               /* Unsubscribe management frames */
+                               nl80211_teardown_ap(bss);
+                               nl80211_destroy_bss(bss);
                                os_free(bss);
                                bss = NULL;
                                break;
@@ -6741,11 +8067,13 @@ static int cookie_handler(struct nl_msg *msg, void *arg)
 }
 
 
-static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
+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_out, int no_cck)
+                                 u64 *cookie_out, int no_cck, int no_ack,
+                                 int offchanok)
 {
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        u64 cookie;
        int ret = -1;
@@ -6756,13 +8084,18 @@ static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+#ifndef ANDROID_BRCM_P2P_PATCH
        if (wait)
                NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
-       NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
+#endif /* ANDROID_BRCM_P2P_PATCH */
+       if (offchanok && (drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX))
+               NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
        if (no_cck)
                NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
+       if (no_ack)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK);
 
        NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf);
 
@@ -6775,11 +8108,12 @@ static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
                           freq, wait);
                goto nla_put_failure;
        }
-       wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted; "
-                  "cookie 0x%llx", (long long unsigned int) cookie);
+       wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted%s; "
+                  "cookie 0x%llx", no_ack ? " (no ACK)" : "",
+                  (long long unsigned int) cookie);
 
        if (cookie_out)
-               *cookie_out = cookie;
+               *cookie_out = no_ack ? (u64) -1 : cookie;
 
 nla_put_failure:
        nlmsg_free(msg);
@@ -6801,7 +8135,8 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
        struct ieee80211_hdr *hdr;
 
        wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
-                  "wait=%d ms no_cck=%d)", drv->ifindex, wait_time, no_cck);
+                  "freq=%u MHz wait=%d ms no_cck=%d)",
+                  drv->ifindex, freq, wait_time, no_cck);
 
        buf = os_zalloc(24 + data_len);
        if (buf == NULL)
@@ -6815,12 +8150,15 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
        os_memcpy(hdr->addr3, bssid, ETH_ALEN);
 
        if (is_ap_interface(drv->nlmode))
-               ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len);
+               ret = wpa_driver_nl80211_send_mlme_freq(priv, buf,
+                                                       24 + data_len,
+                                                       0, freq, no_cck, 1,
+                                                       wait_time);
        else
-               ret = nl80211_send_frame_cmd(drv, freq, wait_time, buf,
+               ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
                                             24 + data_len,
                                             &drv->send_action_cookie,
-                                            no_cck);
+                                            no_cck, 0, 1);
 
        os_free(buf);
        return ret;
@@ -6875,6 +8213,7 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
 
        cookie = 0;
        ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+       msg = NULL;
        if (ret == 0) {
                wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
                           "0x%llx for freq=%u MHz duration=%u",
@@ -6887,6 +8226,7 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
                   "(freq=%d duration=%u): %d (%s)",
                   freq, duration, ret, strerror(-ret));
 nla_put_failure:
+       nlmsg_free(msg);
        return -1;
 }
 
@@ -6918,11 +8258,13 @@ static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
        NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
        if (ret == 0)
                return 0;
        wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
                   "%d (%s)", ret, strerror(-ret));
 nla_put_failure:
+       nlmsg_free(msg);
        return -1;
 }
 
@@ -6932,38 +8274,89 @@ static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
 
+       if (drv->nlmode != NL80211_IFTYPE_STATION) {
+               wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only "
+                          "allowed in station mode (iftype=%d)",
+                          drv->nlmode);
+               return -1;
+       }
+
        if (!report) {
-               if (drv->nl_preq.handle) {
+               if (bss->nl_preq && drv->device_ap_sme &&
+                   is_ap_interface(drv->nlmode)) {
+                       /*
+                        * Do not disable Probe Request reporting that was
+                        * enabled in nl80211_setup_ap().
+                        */
+                       wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of "
+                                  "Probe Request reporting nl_preq=%p while "
+                                  "in AP mode", bss->nl_preq);
+               } 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(drv->nl_preq.handle));
-                       nl_destroy_handles(&drv->nl_preq);
+                               nl_socket_get_fd(bss->nl_preq));
+                       nl_destroy_handles(&bss->nl_preq);
                }
                return 0;
        }
 
-       if (drv->nl_preq.handle) {
+       if (bss->nl_preq) {
                wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
-                          "already on!");
+                          "already on! nl_preq=%p", bss->nl_preq);
                return 0;
        }
 
-       if (nl_create_handles(&drv->nl_preq, drv->global->nl_cb, "preq"))
+       bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
+       if (bss->nl_preq == NULL)
                return -1;
+       wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request "
+                  "reporting nl_preq=%p", bss->nl_preq);
 
-       if (nl80211_register_frame(drv, drv->nl_preq.handle,
+       if (nl80211_register_frame(bss, bss->nl_preq,
                                   (WLAN_FC_TYPE_MGMT << 2) |
                                   (WLAN_FC_STYPE_PROBE_REQ << 4),
                                   NULL, 0) < 0)
                goto out_err;
 
-       eloop_register_read_sock(nl_socket_get_fd(drv->nl_preq.handle),
-                                wpa_driver_nl80211_event_receive, drv,
-                                drv->nl_preq.handle);
+#ifdef ANDROID_BRCM_P2P_PATCH
+       if (nl80211_register_frame(bss, bss->nl_preq,
+                                  (WLAN_FC_TYPE_MGMT << 2) |
+                                  (WLAN_FC_STYPE_ASSOC_REQ << 4),
+                                  NULL, 0) < 0) {
+               goto out_err;
+       }
+
+       if (nl80211_register_frame(bss, bss->nl_preq,
+                                  (WLAN_FC_TYPE_MGMT << 2) |
+                                  (WLAN_FC_STYPE_REASSOC_REQ << 4),
+                                  NULL, 0) < 0) {
+               goto out_err;
+       }
+
+       if (nl80211_register_frame(bss, bss->nl_preq,
+                                  (WLAN_FC_TYPE_MGMT << 2) |
+                                  (WLAN_FC_STYPE_DISASSOC << 4),
+                                  NULL, 0) < 0) {
+               goto out_err;
+       }
+
+       if (nl80211_register_frame(bss, bss->nl_preq,
+                                  (WLAN_FC_TYPE_MGMT << 2) |
+                                  (WLAN_FC_STYPE_DEAUTH << 4),
+                                  NULL, 0) < 0) {
+               goto out_err;
+       }
+#endif /* ANDROID_BRCM_P2P_PATCH */
+
+       eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq),
+                                wpa_driver_nl80211_event_receive, bss->nl_cb,
+                                bss->nl_preq);
 
        return 0;
 
  out_err:
-       nl_destroy_handles(&drv->nl_preq);
+       nl_destroy_handles(&bss->nl_preq);
        return -1;
 }
 
@@ -6994,8 +8387,10 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
        band = nla_nest_start(msg, NL80211_BAND_2GHZ);
        if (!band)
                goto nla_put_failure;
-       NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
-               "\x0c\x12\x18\x24\x30\x48\x60\x6c");
+       if (disabled) {
+               NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
+                       "\x0c\x12\x18\x24\x30\x48\x60\x6c");
+       }
        nla_nest_end(msg, band);
 
        nla_nest_end(msg, bands);
@@ -7015,26 +8410,25 @@ nla_put_failure:
 }
 
 
-static int wpa_driver_nl80211_disable_11b_rates(void *priv, int disabled)
+static int wpa_driver_nl80211_deinit_ap(void *priv)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       drv->disable_11b_rates = disabled;
-       return nl80211_disable_11b_rates(drv, drv->ifindex, disabled);
+       if (!is_ap_interface(drv->nlmode))
+               return -1;
+       wpa_driver_nl80211_del_beacon(drv);
+       return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
 }
 
-
-static int wpa_driver_nl80211_deinit_ap(void *priv)
+static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       if (!is_ap_interface(drv->nlmode))
+       if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
                return -1;
-       wpa_driver_nl80211_del_beacon(drv);
        return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
 }
 
-
 static void wpa_driver_nl80211_resume(void *priv)
 {
        struct i802_bss *bss = priv;
@@ -7054,11 +8448,7 @@ static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
        int ret;
        u8 *data, *pos;
        size_t data_len;
-       u8 own_addr[ETH_ALEN];
-
-       if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-                              own_addr) < 0)
-               return -1;
+       const u8 *own_addr = bss->addr;
 
        if (action != 1) {
                wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
@@ -7127,8 +8517,7 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
        msg = NULL;
 
 nla_put_failure:
-       if (cqm)
-               nlmsg_free(cqm);
+       nlmsg_free(cqm);
        nlmsg_free(msg);
        return -1;
 }
@@ -7149,12 +8538,50 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
 }
 
 
+static int wpa_driver_nl80211_shared_freq(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct wpa_driver_nl80211_data *driver;
+       int freq = 0;
+
+       /*
+        * If the same PHY is in connected state with some other interface,
+        * then retrieve the assoc freq.
+        */
+       wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s",
+                  drv->phyname);
+
+       dl_list_for_each(driver, &drv->global->interfaces,
+                        struct wpa_driver_nl80211_data, list) {
+               if (drv == driver ||
+                   os_strcmp(drv->phyname, driver->phyname) != 0 ||
+                   !driver->associated)
+                       continue;
+
+               wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
+                          MACSTR,
+                          driver->phyname, driver->first_bss.ifname,
+                          MAC2STR(driver->first_bss.addr));
+               freq = nl80211_get_assoc_freq(driver);
+               wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
+                          drv->phyname, freq);
+       }
+
+       if (!freq)
+               wpa_printf(MSG_DEBUG, "nl80211: No shared interface for "
+                          "PHY (%s) in associated state", drv->phyname);
+
+       return freq;
+}
+
+
 static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
                              int encrypt)
 {
        struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
+       return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0,
+                                            0, 0, 0, 0);
 }
 
 
@@ -7236,12 +8663,15 @@ static void nl80211_global_deinit(void *priv)
        if (global->netlink)
                netlink_deinit(global->netlink);
 
-       if (global->nl80211)
-               genl_family_put(global->nl80211);
        nl_destroy_handles(&global->nl);
 
-       if (global->nl_cb)
-               nl_cb_put(global->nl_cb);
+       if (global->nl_event) {
+               eloop_unregister_read_sock(
+                       nl_socket_get_fd(global->nl_event));
+               nl_destroy_handles(&global->nl_event);
+       }
+
+       nl_cb_put(global->nl_cb);
 
        if (global->ioctl_sock >= 0)
                close(global->ioctl_sock);
@@ -7277,57 +8707,376 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid,
 
        return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
  nla_put_failure:
+       nlmsg_free(msg);
        return -ENOBUFS;
 }
 
+#ifdef ANDROID
 
-static int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
-{
-       struct i802_bss *bss = priv;
-       wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR, MAC2STR(bssid));
-       return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid);
-}
+#define MAX_PATTERN_SIZE        256
+#define MAX_MASK_SIZE           (MAX_PATTERN_SIZE/8)
 
+/* Describes a single RX filter configuration */
+struct rx_filter {
+       /* name - A human recongmizable name for the filter */
+       char *name;
 
-static int nl80211_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
+       /* get_pattern_handler - A handler which enables the user to configure
+        * the pattern dynamically (For example filter according to the HW addr).
+        * If NULL the static pattern configured will be used.
+        * buf - the pattern will be copied to buf
+        * buflen - the size of buf
+        * arg - A generic input argumet which can be passed to the handler
+        */
+       int (* get_pattern_handler) (u8 *buf, int buflen, void* arg);
+
+       /* pattern - A static pattern to filter
+        * This array contains the bytes of the pattern. The mask field
+        * indicates which bytes should be used in the filter and which
+        * can be discarded
+        */
+       u8 pattern[MAX_PATTERN_SIZE];
+
+       /* pattern_len - The number of bytes used in pattern */
+       u8 pattern_len;
+
+       /* mask - A bit mask indicating which bytes in pattern should be
+        * used for filtering. Each bit here corresponds to a byte in pattern
+        */
+       u8 mask[MAX_MASK_SIZE];
+
+       /* mask_len - The number of bytes used in mask */
+       u8 mask_len;
+};
+
+static u8 *nl80211_rx_filter_get_pattern(struct rx_filter *filter, void *arg)
 {
-       struct i802_bss *bss = priv;
-       wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
-                  MAC2STR(bssid));
-       return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid);
-}
+       if (filter->get_pattern_handler) {
+               if (filter->get_pattern_handler(filter->pattern,
+                                               filter->pattern_len, arg)) {
+                       return NULL;
+               }
+       }
 
+       return filter->pattern;
+}
 
-static int nl80211_flush_pmkid(void *priv)
+static int
+nl80211_self_filter_get_pattern_handler(u8 *buf, int buflen, void *arg)
 {
-       struct i802_bss *bss = priv;
-       wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
-       return nl80211_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL);
+       int ret;
+       struct i802_bss *bss = (struct i802_bss *)arg;
+
+       ret = linux_get_ifhwaddr(bss->drv->global->ioctl_sock,
+                                bss->ifname, buf);
+       if (ret) {
+               wpa_printf(MSG_ERROR, "Failed to get own HW addr (%d)", ret);
+               return -1;
+       }
+       return 0;
 }
 
+static struct rx_filter rx_filters[] = {
+       /* ID 0 */
+       {.name = "self",
+        .pattern = {},
+        .pattern_len = 6,
+        .mask = { BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) },
+        .mask_len = 1,
+        .get_pattern_handler = nl80211_self_filter_get_pattern_handler,
+       },
 
-static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
-                                  const u8 *replay_ctr)
+       /* ID 1 */
+       {.name = "bcast",
+        .pattern = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
+        .pattern_len = 6,
+        .mask = { BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) },
+        .mask_len = 1,
+       },
+
+       /* ID 2 */
+       {.name = "ipv4mc",
+        .pattern = {0x01,0x00,0x5E},
+        .pattern_len = 3,
+        .mask = { BIT(0) | BIT(1) | BIT(2) },
+        .mask_len = 1,
+       },
+
+       /* ID 3 */
+       {.name = "ipv6mc",
+        .pattern = {0x33,0x33},
+        .pattern_len = 2,
+        .mask = { BIT(0) | BIT(1) },
+        .mask_len = 1,
+       },
+
+       /* ID 4 */
+       {.name = "dhcp",
+        .pattern = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0   , 0   ,
+                    0   , 0   , 0   , 0   , 0   , 0   , 0x45, 0   ,
+                    0   , 0   , 0   , 0   , 0   , 0   , 0   , 0x11,
+                    0   , 0   , 0   , 0   , 0   , 0   , 0   , 0   ,
+                    0   , 0   , 0   , 0   , 0x00, 0x44},
+        .pattern_len = 38,
+        .mask = { BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5),
+                  BIT(6),                               /* OCTET 2 */
+                  BIT(7),                               /* OCTET 3 */
+                  0,                                    /* OCTET 4 */
+                  BIT(4) | BIT(5) },                    /* OCTET 5 */
+        .mask_len = 5,
+       },
+
+       /* ID 5 */
+       {.name = "arp",
+        .pattern = {0   , 0   , 0   , 0   , 0   , 0   , 0   , 0   ,
+                    0   , 0   , 0   , 0   , 0x08, 0x06},
+        .pattern_len = 14,
+        .mask = { 0,                                    /* OCTET 1 */
+                  BIT(4) | BIT(5) },                    /* OCTET 2 */
+        .mask_len = 2,
+       },
+
+       /* ID 6 */
+       {.name = "ssdp",
+        .pattern = {0x01, 0x00, 0x5E, 0   , 0   , 0   , 0   , 0   ,
+                    0   , 0   , 0   , 0   , 0   , 0   , 0x45, 0   ,
+                    0   , 0   , 0   , 0   , 0   , 0   , 0   , 0x11,
+                    0   , 0   , 0   , 0   , 0   , 0   , 0xEF, 0xFF,
+                    0xFF, 0xFA, 0   , 0   , 0x07, 0x6C},
+        .pattern_len = 38,
+        .mask = { BIT(0) | BIT(1) | BIT(2),             /* OCTET 1 */
+                  BIT(6),                               /* OCTET 2 */
+                  BIT(7),                               /* OCTET 3 */
+                  BIT(6) | BIT(7),                      /* OCTET 4 */
+                  BIT(0) | BIT(1) | BIT(4) | BIT(5) },  /* OCTET 5 */
+        .mask_len = 5,
+       },
+};
+
+#define NR_RX_FILTERS  (int)(sizeof(rx_filters) / sizeof(struct rx_filter))
+
+static int nl80211_set_wowlan_triggers(struct i802_bss *bss, int enable)
 {
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct nlattr *replay_nested;
-       struct nl_msg *msg;
+       struct nl_msg *msg, *pats = NULL;
+       struct nlattr *wowtrig, *pat;
+       int i, ret = -1;
+       int filters;
+
+       bss->drv->wowlan_enabled = !!enable;
 
        msg = nlmsg_alloc();
        if (!msg)
-               return;
+               return -ENOMEM;
 
-       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
+       genlmsg_put(msg, 0, 0, bss->drv->global->nl80211_id, 0,
+                   0, NL80211_CMD_SET_WOWLAN, 0);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->drv->first_bss.ifindex);
+       wowtrig = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
 
-       replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
-       if (!replay_nested)
+       if (!wowtrig) {
+               ret = -ENOBUFS;
                goto nla_put_failure;
+       }
 
-       NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek);
-       NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck);
+       if (!enable) {
+               NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY);
+       } else {
+               pats = nlmsg_alloc();
+               if (!pats) {
+                       ret = -ENOMEM;
+                       goto nla_put_failure;
+               }
+
+               /*
+                * In GB filters 0 and 1 are always set but in ICS they
+                * were completely removed. Add filter 0 (unicast) by default
+                * so unicast traffic won't be dropped in any case.
+                */
+
+               filters = bss->drv->wowlan_triggers |= 1;
+
+               for (i = 0; i < NR_RX_FILTERS; i++) {
+                       struct rx_filter *rx_filter = &rx_filters[i];
+                       int patnr = 1;
+                       u8 *pattern;
+
+                       if (!(filters & (1 << i)))
+                               continue;
+
+                       pattern = nl80211_rx_filter_get_pattern(rx_filter, bss);
+                       if (!pattern)
+                               continue;
+
+                       pat = nla_nest_start(pats, patnr++);
+                       NLA_PUT(pats, NL80211_WOWLAN_PKTPAT_MASK,
+                               rx_filter->mask_len,
+                               rx_filter->mask);
+
+                       NLA_PUT(pats, NL80211_WOWLAN_PKTPAT_PATTERN,
+                               rx_filter->pattern_len,
+                               pattern);
+
+                       nla_nest_end(pats, pat);
+               }
+       }
+
+       if (pats)
+               nla_put_nested(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, pats);
+
+       nla_nest_end(msg, wowtrig);
+
+       ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+
+       if (ret < 0)
+               wpa_printf(MSG_ERROR, "Failed to set WoWLAN trigger:%d\n", ret);
+
+       if (pats)
+               nlmsg_free(pats);
+
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return ret;
+}
+
+static int nl80211_toggle_wowlan_trigger(struct i802_bss *bss, int nr,
+                                        int enabled)
+{
+       if (nr >= NR_RX_FILTERS) {
+               wpa_printf(MSG_ERROR, "Unknown filter: %d\n", nr);
+               return -1;
+       }
+
+       if (enabled)
+               bss->drv->wowlan_triggers |= 1 << nr;
+       else
+               bss->drv->wowlan_triggers &= ~(1 << nr);
+
+       if (bss->drv->wowlan_enabled)
+               nl80211_set_wowlan_triggers(bss, 1);
+
+       return 0;
+}
+
+static int nl80211_parse_wowlan_trigger_nr(char *s)
+{
+       long i;
+       char *endp;
+
+       i = strtol(s, &endp, 10);
+
+       if(endp == s)
+               return -1;
+       return i;
+}
+
+static int nl80211_toggle_dropbcast(int enable)
+{
+       char filename[90];
+       int rv;
+       FILE *f;
+
+       snprintf(filename, sizeof(filename) - 1,
+                "/sys/bus/platform/devices/wl12xx/drop_bcast");
+       f = fopen(filename, "w");
+       if (!f) {
+               wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
+                          filename, strerror(errno));
+               return -1;
+       }
+
+       rv = fprintf(f, "%d", enable);
+       fclose(f);
+       if (rv < 1) {
+               wpa_printf(MSG_DEBUG, "Could not write to file %s: %s",
+                          filename, strerror(errno));
+               return -1;
+       }
+
+       return 0;
+}
+
+static int nl80211_dropbcast_get(char *buf, size_t buf_len)
+{
+       char filename[90], value[10], *pos;
+       int f, rv;
+
+       snprintf(filename, sizeof(filename) - 1,
+                "/sys/bus/platform/devices/wl12xx/drop_bcast");
+       f = open(filename, O_RDONLY);
+       if (f < 0) {
+               wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
+                          filename, strerror(errno));
+               return -1;
+       }
+
+       rv = read(f, value, sizeof(value) - 1);
+       close(f);
+       if (rv < 0) {
+               wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
+                          filename, strerror(errno));
+               return -1;
+       }
+
+       value[rv] = '\0';
+       pos = os_strchr(value, '\n');
+       if (pos)
+               *pos = '\0';
+
+       return snprintf(buf, buf_len, "Drop bcast = %s\n", value);
+}
+
+#endif /* ANDROID */
+
+static int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
+{
+       struct i802_bss *bss = priv;
+       wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR, MAC2STR(bssid));
+       return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid);
+}
+
+
+static int nl80211_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
+{
+       struct i802_bss *bss = priv;
+       wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
+                  MAC2STR(bssid));
+       return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid);
+}
+
+
+static int nl80211_flush_pmkid(void *priv)
+{
+       struct i802_bss *bss = priv;
+       wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
+       return nl80211_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL);
+}
+
+
+static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
+                                  const u8 *replay_ctr)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nlattr *replay_nested;
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+       replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
+       if (!replay_nested)
+               goto nla_put_failure;
+
+       NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek);
+       NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck);
        NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
                replay_ctr);
 
@@ -7340,10 +9089,11 @@ static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
 }
 
 
-static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
-                               int qos)
+static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
+                                   const u8 *addr, int qos)
 {
-       struct i802_bss *bss = priv;
+       /* send data frame to poll STA and check whether
+        * this frame is ACKed */
        struct {
                struct ieee80211_hdr hdr;
                u16 qos_ctl;
@@ -7371,11 +9121,87 @@ static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
        os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
        os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
 
-       if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size) < 0)
+       if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0) < 0)
                wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
                           "send poll frame");
 }
 
+static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
+                               int qos)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+
+       if (!drv->poll_command_supported) {
+               nl80211_send_null_frame(bss, own_addr, addr, qos);
+               return;
+       }
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+       send_and_recv_msgs(drv, msg, NULL, NULL);
+       return;
+ nla_put_failure:
+       nlmsg_free(msg);
+}
+
+
+static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
+{
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_SET_POWER_SAVE);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE,
+                   enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED);
+       return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+
+static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
+                                    int ctwindow)
+{
+#ifdef ANDROID_BRCM_P2P_PATCH
+       char buf[MAX_DRV_CMD_SIZE];
+
+       memset(buf, 0, sizeof(buf));
+       wpa_printf(MSG_DEBUG, "%s: Entry", __func__);
+       os_snprintf(buf, sizeof(buf), "P2P_SET_PS %d %d %d", legacy_ps, opp_ps,
+                   ctwindow);
+       return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf) + 1);
+#else /* ANDROID_BRCM_P2P_PATCH */
+       struct i802_bss *bss = priv;
+
+       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)
+               return -1; /* Not yet supported */
+
+       if (legacy_ps == -1)
+               return 0;
+       if (legacy_ps != 0 && legacy_ps != 1)
+               return -1; /* Not yet supported */
+
+       return nl80211_set_power_save(bss, legacy_ps);
+#endif /* ANDROID_BRCM_P2P_PATCH */
+}
+
 
 #ifdef CONFIG_TDLS
 
@@ -7466,6 +9292,385 @@ nla_put_failure:
 #endif /* CONFIG TDLS */
 
 
+#ifdef ANDROID
+
+typedef struct android_wifi_priv_cmd {
+       char *buf;
+       int used_len;
+       int total_len;
+} android_wifi_priv_cmd;
+
+static int drv_errors = 0;
+
+static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
+{
+       drv_errors++;
+       if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+               drv_errors = 0;
+               wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+       }
+}
+
+
+#define WPA_PS_ENABLED         0
+#define WPA_PS_DISABLED                1
+
+static int wpa_driver_set_power_save(void *priv, int state)
+{
+       return nl80211_set_power_save(priv, state == WPA_PS_ENABLED);
+}
+
+
+static int get_power_mode_handler(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       int *state = arg;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (!tb[NL80211_ATTR_PS_STATE])
+               return NL_SKIP;
+
+       if (state) {
+               int s = (int) nla_get_u32(tb[NL80211_ATTR_PS_STATE]);
+               wpa_printf(MSG_DEBUG, "nl80211: Get power mode = %d", s);
+               *state = (s == NL80211_PS_ENABLED) ?
+                       WPA_PS_ENABLED : WPA_PS_DISABLED;
+       }
+
+       return NL_SKIP;
+}
+
+
+static int wpa_driver_get_power_save(void *priv, int *state)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret = -1;
+       enum nl80211_ps_state ps_state;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_POWER_SAVE);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+       ret = send_and_recv_msgs(drv, msg, get_power_mode_handler, state);
+       msg = NULL;
+       if (ret < 0)
+               wpa_printf(MSG_ERROR, "nl80211: Get power mode fail: %d", ret);
+nla_put_failure:
+       nlmsg_free(msg);
+       return ret;
+}
+
+
+static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct ifreq ifr;
+       android_wifi_priv_cmd priv_cmd;
+       char buf[MAX_DRV_CMD_SIZE];
+       int ret;
+
+       os_memset(&ifr, 0, sizeof(ifr));
+       os_memset(&priv_cmd, 0, sizeof(priv_cmd));
+       os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+       os_memset(buf, 0, sizeof(buf));
+       os_strlcpy(buf, cmd, sizeof(buf));
+
+       priv_cmd.buf = buf;
+       priv_cmd.used_len = sizeof(buf);
+       priv_cmd.total_len = sizeof(buf);
+       ifr.ifr_data = &priv_cmd;
+
+       ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+       if (ret < 0) {
+               wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
+                          __func__);
+               wpa_driver_send_hang_msg(drv);
+               return ret;
+       }
+
+       drv_errors = 0;
+       return 0;
+}
+
+
+static int android_pno_start(struct i802_bss *bss,
+                            struct wpa_driver_scan_params *params)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct ifreq ifr;
+       android_wifi_priv_cmd priv_cmd;
+       int ret = 0, i = 0, bp;
+       char buf[WEXT_PNO_MAX_COMMAND_SIZE];
+
+       bp = WEXT_PNOSETUP_HEADER_SIZE;
+       os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
+       buf[bp++] = WEXT_PNO_TLV_PREFIX;
+       buf[bp++] = WEXT_PNO_TLV_VERSION;
+       buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
+       buf[bp++] = WEXT_PNO_TLV_RESERVED;
+
+       while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
+               /* Check that there is enough space needed for 1 more SSID, the
+                * other sections and null termination */
+               if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
+                    WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
+                       break;
+               wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
+                                 params->ssids[i].ssid,
+                                 params->ssids[i].ssid_len);
+               buf[bp++] = WEXT_PNO_SSID_SECTION;
+               buf[bp++] = params->ssids[i].ssid_len;
+               os_memcpy(&buf[bp], params->ssids[i].ssid,
+                         params->ssids[i].ssid_len);
+               bp += params->ssids[i].ssid_len;
+               i++;
+       }
+
+       buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
+       os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
+                   WEXT_PNO_SCAN_INTERVAL);
+       bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
+
+       buf[bp++] = WEXT_PNO_REPEAT_SECTION;
+       os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
+                   WEXT_PNO_REPEAT);
+       bp += WEXT_PNO_REPEAT_LENGTH;
+
+       buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
+       os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
+                   WEXT_PNO_MAX_REPEAT);
+       bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
+
+       memset(&ifr, 0, sizeof(ifr));
+       memset(&priv_cmd, 0, sizeof(priv_cmd));
+       os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+       priv_cmd.buf = buf;
+       priv_cmd.used_len = bp;
+       priv_cmd.total_len = bp;
+       ifr.ifr_data = &priv_cmd;
+
+       ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+
+       if (ret < 0) {
+               wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
+                          ret);
+               wpa_driver_send_hang_msg(drv);
+               return ret;
+       }
+
+       drv_errors = 0;
+
+       return android_priv_cmd(bss, "PNOFORCE 1");
+}
+
+
+static int android_pno_stop(struct i802_bss *bss)
+{
+       return android_priv_cmd(bss, "PNOFORCE 0");
+}
+
+
+static int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
+                                        size_t buf_len)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct ifreq ifr;
+       android_wifi_priv_cmd priv_cmd;
+       int ret = 0;
+
+       if (os_strcasecmp(cmd, "STOP") == 0) {
+               linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
+               wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED");
+       } else if (os_strcasecmp(cmd, "START") == 0) {
+               linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);
+               wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED");
+       } else if (os_strcasecmp(cmd, "MACADDR") == 0) {
+               u8 macaddr[ETH_ALEN] = {};
+
+               ret = linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+                                        macaddr);
+               if (!ret)
+                       ret = os_snprintf(buf, buf_len,
+                                         "Macaddr = " MACSTR "\n",
+                                         MAC2STR(macaddr));
+       } else if (os_strcasecmp(cmd, "RELOAD") == 0) {
+               wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+       } else if (os_strncasecmp(cmd, "POWERMODE ", 10) == 0) {
+               int state = atoi(cmd + 10);
+               ret = wpa_driver_set_power_save(priv, state);
+               if (ret < 0)
+                       wpa_driver_send_hang_msg(drv);
+               else
+                       drv_errors = 0;
+       } else if (os_strncasecmp(cmd, "GETPOWER", 8) == 0) {
+               int state = -1;
+               ret = wpa_driver_get_power_save(priv, &state);
+               if (!ret && (state != -1))
+                       ret = os_snprintf(buf, buf_len, "POWERMODE = %d\n",
+                                         state);
+       } else if( os_strncasecmp(cmd, "RXFILTER-ADD ", 13) == 0 ) {
+               int i = nl80211_parse_wowlan_trigger_nr(cmd + 13);
+               if(i < 0)
+                       return i;
+               return nl80211_toggle_wowlan_trigger(bss, i, 1);
+       } else if( os_strncasecmp(cmd, "RXFILTER-REMOVE ", 16) == 0 ) {
+               int i = nl80211_parse_wowlan_trigger_nr(cmd + 16);
+               if(i < 0)
+                       return i;
+               return nl80211_toggle_wowlan_trigger(bss, i, 0);
+       } else if (os_strcasecmp(cmd, "RXFILTER-START") == 0) {
+               return nl80211_set_wowlan_triggers(bss, 1);
+       } else if (os_strcasecmp(cmd, "RXFILTER-STOP") == 0) {
+               return nl80211_set_wowlan_triggers(bss, 0);
+       } else if (os_strncasecmp(cmd, "DROPBCAST", 9) == 0) {
+               char *value = cmd + 10;
+
+               if (!os_strcasecmp(value, "ENABLE") ||
+                   !os_strcasecmp(value, "1")) {
+                       ret = nl80211_toggle_dropbcast(1);
+               } else if (!os_strcasecmp(value, "DISABLE") ||
+                          !os_strcasecmp(value, "0")) {
+                       ret = nl80211_toggle_dropbcast(0);
+               } else if (!os_strcasecmp(value, "GET") ||
+                          !os_strlen(value)) {
+                       ret = nl80211_dropbcast_get(buf, buf_len);
+               } else {
+                       wpa_printf(MSG_ERROR,
+                                  "Invalid parameter for DROPBCAST: %s",
+                                  value);
+                       ret = -1;
+               }
+       } else if( os_strcasecmp(cmd, "LINKSPEED") == 0 ) {
+               struct wpa_signal_info sig;
+               int linkspeed;
+
+               if (!drv->associated)
+                       return -1;
+
+               ret = nl80211_get_link_signal(drv, &sig);
+               if (ret == 0) {
+                       linkspeed = sig.current_txrate;
+                       ret = os_snprintf(buf, buf_len, "LinkSpeed %d\n",
+                                         linkspeed);
+               }
+       } else if (os_strcasecmp(cmd, "RSSI") == 0 ||
+                  os_strcasecmp(cmd, "RSSI-APPROX") == 0) {
+               struct wpa_signal_info sig;
+               int rssi;
+
+               if (!drv->associated)
+                       return -1;
+
+               ret = nl80211_get_link_signal(drv, &sig);
+               if (ret == 0) {
+                       rssi = sig.current_signal;
+                       ret = os_snprintf(buf, buf_len, "%s rssi %d\n",
+                                         drv->ssid, rssi);
+               }
+       } else {
+               wpa_printf(MSG_ERROR, "Unsupported command: %s", cmd);
+               ret = -1;
+       }
+
+       return ret;
+}
+
+#ifdef ANDROID_BRCM_P2P_PATCH
+
+static int wpa_driver_set_p2p_noa(void *priv, u8 count, int start,
+                                 int duration)
+{
+       char buf[MAX_DRV_CMD_SIZE];
+
+       memset(buf, 0, sizeof(buf));
+       wpa_printf(MSG_DEBUG, "%s: Entry", __func__);
+       os_snprintf(buf, sizeof(buf), "P2P_SET_NOA %d %d %d", count, start,
+                   duration);
+       return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf) + 1);
+}
+
+
+static int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len)
+{
+       char rbuf[MAX_DRV_CMD_SIZE];
+       char *cmd = "P2P_GET_NOA";
+       int ret;
+
+       wpa_printf(MSG_DEBUG, "%s: Entry", __func__);
+       os_memset(buf, 0, len);
+       ret = wpa_driver_nl80211_driver_cmd(priv, cmd, rbuf, sizeof(rbuf));
+       if (ret <= 0)
+               return 0;
+       ret >>= 1;
+       if (ret > (int)len)
+               ret = (int)len;
+       hexstr2bin(rbuf, buf, ret);
+       return ret;
+}
+
+
+static int wpa_driver_set_ap_wps_p2p_ie(void *priv,
+                                       const struct wpabuf *beacon,
+                                       const struct wpabuf *proberesp,
+                                       const struct wpabuf *assocresp)
+{
+       char buf[MAX_WPSP2PIE_CMD_SIZE];
+       struct wpabuf *ap_wps_p2p_ie = NULL;
+       char *_cmd = "SET_AP_WPS_P2P_IE";
+       char *pbuf;
+       int ret = 0;
+       int i;
+       struct cmd_desc {
+               int cmd;
+               const struct wpabuf *src;
+       } cmd_arr[] = {
+               {0x1, beacon},
+               {0x2, proberesp},
+               {0x4, assocresp},
+               {-1, NULL}
+       };
+
+       wpa_printf(MSG_DEBUG, "%s: Entry", __func__);
+       for (i = 0; cmd_arr[i].cmd != -1; i++) {
+               os_memset(buf, 0, sizeof(buf));
+               pbuf = buf;
+               pbuf += sprintf(pbuf, "%s %d", _cmd, cmd_arr[i].cmd);
+               *pbuf++ = '\0';
+               ap_wps_p2p_ie = cmd_arr[i].src ?
+                       wpabuf_dup(cmd_arr[i].src) : NULL;
+               if (ap_wps_p2p_ie) {
+                       os_memcpy(pbuf, wpabuf_head(ap_wps_p2p_ie),
+                                 wpabuf_len(ap_wps_p2p_ie));
+                       ret = wpa_driver_nl80211_driver_cmd(
+                               priv, buf, buf,
+                               os_strlen(_cmd) + 3 +
+                               wpabuf_len(ap_wps_p2p_ie));
+                       wpabuf_free(ap_wps_p2p_ie);
+                       if (ret < 0)
+                               break;
+               }
+       }
+
+       return ret;
+}
+
+#endif /* ANDROID_BRCM_P2P_PATCH */
+
+#endif /* ANDROID */
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
@@ -7512,7 +9717,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .set_frag = i802_set_frag,
        .set_tx_queue_params = i802_set_tx_queue_params,
        .set_sta_vlan = i802_set_sta_vlan,
-       .set_rate_sets = i802_set_rate_sets,
        .sta_deauth = i802_sta_deauth,
        .sta_disassoc = i802_sta_disassoc,
 #endif /* HOSTAPD || CONFIG_AP */
@@ -7523,13 +9727,14 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .cancel_remain_on_channel =
        wpa_driver_nl80211_cancel_remain_on_channel,
        .probe_req_report = wpa_driver_nl80211_probe_req_report,
-       .disable_11b_rates = wpa_driver_nl80211_disable_11b_rates,
        .deinit_ap = wpa_driver_nl80211_deinit_ap,
+       .deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
        .resume = wpa_driver_nl80211_resume,
        .send_ft_action = nl80211_send_ft_action,
        .signal_monitor = nl80211_signal_monitor,
        .signal_poll = nl80211_signal_poll,
        .send_frame = nl80211_send_frame,
+       .shared_freq = wpa_driver_nl80211_shared_freq,
        .set_param = nl80211_set_param,
        .get_radio_name = nl80211_get_radio_name,
        .add_pmkid = nl80211_add_pmkid,
@@ -7537,8 +9742,17 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .flush_pmkid = nl80211_flush_pmkid,
        .set_rekey_info = nl80211_set_rekey_info,
        .poll_client = nl80211_poll_client,
+       .set_p2p_powersave = nl80211_set_p2p_powersave,
 #ifdef CONFIG_TDLS
        .send_tdls_mgmt = nl80211_send_tdls_mgmt,
        .tdls_oper = nl80211_tdls_oper,
 #endif /* CONFIG_TDLS */
+#ifdef ANDROID_BRCM_P2P_PATCH
+       .get_noa = wpa_driver_get_p2p_noa,
+       .set_noa = wpa_driver_set_p2p_noa,
+       .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
+#endif /* ANDROID_BRCM_P2P_PATCH */
+#ifdef ANDROID
+       .driver_cmd = wpa_driver_nl80211_driver_cmd,
+#endif /* ANDROID */
 };