nl80211: Always register management frames handler
[mech_eap.git] / src / drivers / driver_nl80211.c
index 991dc4e..096779d 100644 (file)
@@ -157,34 +157,25 @@ static int
 wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
                                   const u8 *set_addr, int first,
                                   const char *driver_params);
-static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
-                                  const u8 *addr, int cmd, u16 reason_code,
-                                  int local_state_change);
 static int nl80211_send_frame_cmd(struct i802_bss *bss,
                                  unsigned int freq, unsigned int wait,
                                  const u8 *buf, size_t buf_len, u64 *cookie,
                                  int no_cck, int no_ack, int offchanok);
-static int nl80211_register_frame(struct i802_bss *bss,
-                                 struct nl_handle *hl_handle,
-                                 u16 type, const u8 *match, size_t match_len);
 static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
                                               int report);
 
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
-static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
-                                       enum wpa_driver_if_type type,
-                                       const char *ifname);
 
 static int nl80211_set_channel(struct i802_bss *bss,
                               struct hostapd_freq_params *freq, int set_chan);
 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 nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
+                             int reset_mode);
 
-static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
 static int i802_set_iface_flags(struct i802_bss *bss, int up);
 static int nl80211_set_param(void *priv, const char *param);
 
@@ -217,7 +208,7 @@ int is_ap_interface(enum nl80211_iftype nlmode)
 }
 
 
-static int is_sta_interface(enum nl80211_iftype nlmode)
+int is_sta_interface(enum nl80211_iftype nlmode)
 {
        return nlmode == NL80211_IFTYPE_STATION ||
                nlmode == NL80211_IFTYPE_P2P_CLIENT;
@@ -260,17 +251,6 @@ void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
 }
 
 
-struct nl80211_bss_info_arg {
-       struct wpa_driver_nl80211_data *drv;
-       struct wpa_scan_results *res;
-       unsigned int assoc_freq;
-       unsigned int ibss_freq;
-       u8 assoc_bssid[ETH_ALEN];
-};
-
-static int bss_info_handler(struct nl_msg *msg, void *arg);
-
-
 /* nl80211 code */
 static int ack_handler(struct nl_msg *msg, void *arg)
 {
@@ -301,6 +281,22 @@ static int no_seq_check(struct nl_msg *msg, void *arg)
 }
 
 
+static void nl80211_nlmsg_clear(struct nl_msg *msg)
+{
+       /*
+        * Clear nlmsg data, e.g., to make sure key material is not left in
+        * heap memory for unnecessarily long time.
+        */
+       if (msg) {
+               struct nlmsghdr *hdr = nlmsg_hdr(msg);
+               void *data = nlmsg_data(hdr);
+               int len = nlmsg_datalen(hdr);
+
+               os_memset(data, 0, len);
+       }
+}
+
+
 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 *),
@@ -340,21 +336,13 @@ static int send_and_recv(struct nl80211_global *global,
        }
  out:
        nl_cb_put(cb);
+       if (!valid_handler && valid_data == (void *) -1)
+               nl80211_nlmsg_clear(msg);
        nlmsg_free(msg);
        return err;
 }
 
 
-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);
-}
-
-
 int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
                       struct nl_msg *msg,
                       int (*valid_handler)(struct nl_msg *, void *),
@@ -419,7 +407,7 @@ static int nl_get_multicast_id(struct nl80211_global *global,
                return -1;
        }
 
-       ret = send_and_recv_msgs_global(global, msg, family_handler, &res);
+       ret = send_and_recv(global, global->nl, msg, family_handler, &res);
        if (ret == 0)
                ret = res.id;
        return ret;
@@ -770,7 +758,7 @@ static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
 
 
 static void wpa_driver_nl80211_event_newlink(
-       struct wpa_driver_nl80211_data *drv, char *ifname)
+       struct wpa_driver_nl80211_data *drv, const char *ifname)
 {
        union wpa_event_data event;
 
@@ -796,7 +784,7 @@ static void wpa_driver_nl80211_event_newlink(
 
 
 static void wpa_driver_nl80211_event_dellink(
-       struct wpa_driver_nl80211_data *drv, char *ifname)
+       struct wpa_driver_nl80211_data *drv, const char *ifname)
 {
        union wpa_event_data event;
 
@@ -1038,7 +1026,12 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                struct i802_bss *bss;
 
                /* device has been added to bridge */
-               if_indextoname(brid, namebuf);
+               if (!if_indextoname(brid, namebuf)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Could not find bridge ifname for ifindex %u",
+                                  brid);
+                       return;
+               }
                wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
                           brid, namebuf);
                add_ifidx(drv, brid);
@@ -1118,9 +1111,16 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
        if (ifi->ifi_family == AF_BRIDGE && brid) {
                /* device has been removed from bridge */
                char namebuf[IFNAMSIZ];
-               if_indextoname(brid, namebuf);
-               wpa_printf(MSG_DEBUG, "nl80211: Remove ifindex %u for bridge "
-                          "%s", brid, namebuf);
+
+               if (!if_indextoname(brid, namebuf)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Could not find bridge ifname for ifindex %u",
+                                  brid);
+               } else {
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Remove ifindex %u for bridge %s",
+                                  brid, namebuf);
+               }
                del_ifidx(drv, brid);
        }
 }
@@ -1280,71 +1280,6 @@ int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
 }
 
 
-static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
-{
-       struct nlattr *tb[NL80211_ATTR_MAX + 1];
-       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-       struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
-       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 wpa_scan_results *scan_results = arg;
-       struct wpa_scan_res *scan_res;
-       size_t i;
-
-       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;
-       }
-
-       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 = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
-       return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
-                                 scan_res);
-}
-
-
 static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
                                             void *handle)
 {
@@ -1520,23 +1455,6 @@ err:
 }
 
 
-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");
@@ -1677,11 +1595,6 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
        drv->eapol_tx_sock = -1;
        drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
 
-       if (wpa_driver_nl80211_init_nl(drv)) {
-               os_free(drv);
-               return NULL;
-       }
-
        if (nl80211_init_bss(bss))
                goto failed;
 
@@ -1790,15 +1703,13 @@ static int nl80211_register_frame(struct i802_bss *bss,
 
 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");
+       bss->nl_mgmt = nl_create_handle(bss->nl_cb, "mgmt");
        if (bss->nl_mgmt == NULL)
                return -1;
 
@@ -1919,11 +1830,11 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
 
        /* WMM-AC ADDTS Response */
        if (nl80211_register_action_frame(bss, (u8 *) "\x11\x01", 2) < 0)
-               return -1;
+               ret = -1;
 
        /* WMM-AC DELTS */
        if (nl80211_register_action_frame(bss, (u8 *) "\x11\x02", 2) < 0)
-               return -1;
+               ret = -1;
 
        /* Radio Measurement - Neighbor Report Response */
        if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
@@ -1976,21 +1887,11 @@ static int nl80211_mgmt_subscribe_mesh(struct i802_bss *bss)
 
 static int nl80211_register_spurious_class3(struct i802_bss *bss)
 {
-       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret;
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -1;
-
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_UNEXPECTED_FRAME) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex)) {
-               nlmsg_free(msg);
-               return -1;
-       }
-
-       ret = send_and_recv(drv->global, bss->nl_mgmt, msg, NULL, NULL);
+       msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UNEXPECTED_FRAME);
+       ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL);
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
                           "failed: ret=%d (%s)",
@@ -2090,21 +1991,11 @@ static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
 
 static void nl80211_del_p2pdev(struct i802_bss *bss)
 {
-       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret;
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return;
-
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE) ||
-           nla_put_u64(msg, NL80211_ATTR_WDEV, bss->wdev_id)) {
-               nlmsg_free(msg);
-               return;
-       }
-
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_INTERFACE);
+       ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
 
        wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
                   bss->ifname, (long long unsigned int) bss->wdev_id,
@@ -2114,22 +2005,12 @@ static void nl80211_del_p2pdev(struct i802_bss *bss)
 
 static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
 {
-       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret;
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -1;
-
-       if (!nl80211_cmd(drv, msg, 0, start ? NL80211_CMD_START_P2P_DEVICE :
-                        NL80211_CMD_STOP_P2P_DEVICE) ||
-           nla_put_u64(msg, NL80211_ATTR_WDEV, bss->wdev_id)) {
-               nlmsg_free(msg);
-               return -1;
-       }
-
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = nl80211_cmd_msg(bss, 0, start ? NL80211_CMD_START_P2P_DEVICE :
+                             NL80211_CMD_STOP_P2P_DEVICE);
+       ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
 
        wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
                   start ? "Start" : "Stop",
@@ -2266,6 +2147,9 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
 
+       wpa_printf(MSG_INFO, "nl80211: deinit ifname=%s disabled_11b_rates=%d",
+                  bss->ifname, drv->disabled_11b_rates);
+
        bss->in_deinit = 1;
        if (drv->data_tx_status)
                eloop_unregister_read_sock(drv->eapol_tx_sock);
@@ -2284,779 +2168,79 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
                        nl80211_handle_destroy(drv->rtnl_sk);
        }
        if (bss->added_bridge) {
+               if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
+                                         0) < 0)
+                       wpa_printf(MSG_INFO,
+                                  "nl80211: Could not set bridge %s down",
+                                  bss->brname);
                if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
                        wpa_printf(MSG_INFO, "nl80211: Failed to remove "
                                   "bridge %s: %s",
                                   bss->brname, strerror(errno));
        }
 
-       nl80211_remove_monitor_interface(drv);
-
-       if (is_ap_interface(drv->nlmode))
-               wpa_driver_nl80211_del_beacon(drv);
-
-       if (drv->eapol_sock >= 0) {
-               eloop_unregister_read_sock(drv->eapol_sock);
-               close(drv->eapol_sock);
-       }
-
-       if (drv->if_indices != drv->default_if_indices)
-               os_free(drv->if_indices);
-
-       if (drv->disabled_11b_rates)
-               nl80211_disable_11b_rates(drv, drv->ifindex, 0);
-
-       netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
-                              IF_OPER_UP);
-       eloop_cancel_timeout(wpa_driver_nl80211_send_rfkill, drv, drv->ctx);
-       rfkill_deinit(drv->rfkill);
-
-       eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
-
-       if (!drv->start_iface_up)
-               (void) i802_set_iface_flags(bss, 0);
-
-       if (drv->addr_changed) {
-               if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
-                                         0) < 0) {
-                       wpa_printf(MSG_DEBUG,
-                                  "nl80211: Could not set interface down to restore permanent MAC address");
-               }
-               if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-                                      drv->perm_addr) < 0) {
-                       wpa_printf(MSG_DEBUG,
-                                  "nl80211: Could not restore permanent MAC address");
-               }
-       }
-
-       if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
-               if (!drv->hostapd || !drv->start_mode_ap)
-                       wpa_driver_nl80211_set_mode(bss,
-                                                   NL80211_IFTYPE_STATION);
-               nl80211_mgmt_unsubscribe(bss, "deinit");
-       } else {
-               nl80211_mgmt_unsubscribe(bss, "deinit");
-               nl80211_del_p2pdev(bss);
-       }
-       nl_cb_put(drv->nl_cb);
-
-       nl80211_destroy_bss(drv->first_bss);
-
-       os_free(drv->filter_ssids);
-
-       os_free(drv->auth_ie);
-
-       if (drv->in_interface_list)
-               dl_list_del(&drv->list);
-
-       os_free(drv->extended_capa);
-       os_free(drv->extended_capa_mask);
-       os_free(drv->first_bss);
-       os_free(drv);
-}
-
-
-/**
- * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
- * @eloop_ctx: Driver private data
- * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
- *
- * This function can be used as registered timeout when starting a scan to
- * generate a scan completed event if the driver does not report this.
- */
-void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-       struct wpa_driver_nl80211_data *drv = eloop_ctx;
-       if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
-               wpa_driver_nl80211_set_mode(drv->first_bss,
-                                           drv->ap_scan_as_station);
-               drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
-       }
-       wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
-       wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-static struct nl_msg *
-nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
-                   struct wpa_driver_scan_params *params, u64 *wdev_id)
-{
-       struct nl_msg *msg;
-       size_t i;
-       u32 scan_flags = 0;
-       int res;
-
-       msg = nlmsg_alloc();
-       if (!msg)
-               return NULL;
-
-       nl80211_cmd(drv, msg, 0, cmd);
-
-       if (!wdev_id)
-               res = nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-       else
-               res = nla_put_u64(msg, NL80211_ATTR_WDEV, *wdev_id);
-       if (res < 0)
-               goto fail;
-
-       if (params->num_ssids) {
-               struct nlattr *ssids;
-
-               ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
-               if (ssids == NULL)
-                       goto fail;
-               for (i = 0; i < params->num_ssids; i++) {
-                       wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
-                                         params->ssids[i].ssid,
-                                         params->ssids[i].ssid_len);
-                       if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
-                                   params->ssids[i].ssid))
-                               goto fail;
-               }
-               nla_nest_end(msg, ssids);
-       }
-
-       if (params->extra_ies) {
-               wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
-                           params->extra_ies, params->extra_ies_len);
-               if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
-                           params->extra_ies))
-                       goto fail;
-       }
-
-       if (params->freqs) {
-               struct nlattr *freqs;
-               freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
-               if (freqs == NULL)
-                       goto fail;
-               for (i = 0; params->freqs[i]; i++) {
-                       wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
-                                  "MHz", params->freqs[i]);
-                       if (nla_put_u32(msg, i + 1, params->freqs[i]))
-                               goto fail;
-               }
-               nla_nest_end(msg, freqs);
-       }
-
-       os_free(drv->filter_ssids);
-       drv->filter_ssids = params->filter_ssids;
-       params->filter_ssids = NULL;
-       drv->num_filter_ssids = params->num_filter_ssids;
-
-       if (params->only_new_results) {
-               wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
-               scan_flags |= NL80211_SCAN_FLAG_FLUSH;
-       }
-
-       if (params->low_priority && drv->have_low_prio_scan) {
-               wpa_printf(MSG_DEBUG,
-                          "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY");
-               scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
-       }
-
-       if (scan_flags &&
-           nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
-               goto fail;
-
-       return msg;
-
-fail:
-       nlmsg_free(msg);
-       return NULL;
-}
-
-
-/**
- * wpa_driver_nl80211_scan - Request the driver to initiate scan
- * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
- * @params: Scan parameters
- * Returns: 0 on success, -1 on failure
- */
-static int wpa_driver_nl80211_scan(struct i802_bss *bss,
-                                  struct wpa_driver_scan_params *params)
-{
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       int ret = -1, timeout;
-       struct nl_msg *msg = NULL;
-
-       wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
-       drv->scan_for_auth = 0;
-
-       msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params,
-                                 bss->wdev_id_set ? &bss->wdev_id : NULL);
-       if (!msg)
-               return -1;
-
-       if (params->p2p_probe) {
-               struct nlattr *rates;
-
-               wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
-
-               rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
-               if (rates == NULL)
-                       goto fail;
-
-               /*
-                * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
-                * by masking out everything else apart from the OFDM rates 6,
-                * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
-                * rates are left enabled.
-                */
-               if (nla_put(msg, NL80211_BAND_2GHZ, 8,
-                           "\x0c\x12\x18\x24\x30\x48\x60\x6c"))
-                       goto fail;
-               nla_nest_end(msg, rates);
-
-               if (nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE))
-                       goto fail;
-       }
-
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-       msg = NULL;
-       if (ret) {
-               wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
-                          "(%s)", ret, strerror(-ret));
-               if (drv->hostapd && is_ap_interface(drv->nlmode)) {
-                       enum nl80211_iftype old_mode = drv->nlmode;
-
-                       /*
-                        * mac80211 does not allow scan requests in AP mode, so
-                        * try to do this in station mode.
-                        */
-                       if (wpa_driver_nl80211_set_mode(
-                                   bss, NL80211_IFTYPE_STATION))
-                               goto fail;
-
-                       if (wpa_driver_nl80211_scan(bss, params)) {
-                               wpa_driver_nl80211_set_mode(bss, drv->nlmode);
-                               goto fail;
-                       }
-
-                       /* Restore AP mode when processing scan results */
-                       drv->ap_scan_as_station = old_mode;
-                       ret = 0;
-               } else
-                       goto fail;
-       }
-
-       drv->scan_state = SCAN_REQUESTED;
-       /* Not all drivers generate "scan completed" wireless event, so try to
-        * read results after a timeout. */
-       timeout = 10;
-       if (drv->scan_complete_events) {
-               /*
-                * The driver seems to deliver events to notify when scan is
-                * complete, so use longer timeout to avoid race conditions
-                * with scanning and following association request.
-                */
-               timeout = 30;
-       }
-       wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
-                  "seconds", ret, timeout);
-       eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
-       eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
-                              drv, drv->ctx);
-
-fail:
-       nlmsg_free(msg);
-       return ret;
-}
-
-
-/**
- * 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
- * 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)
-{
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       int ret = -1;
-       struct nl_msg *msg;
-       size_t i;
-
-       wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
-
-#ifdef ANDROID
-       if (!drv->capa.sched_scan_supported)
-               return android_pno_start(bss, params);
-#endif /* ANDROID */
-
-       msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params,
-                                 bss->wdev_id_set ? &bss->wdev_id : NULL);
-       if (!msg ||
-           nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval))
-               goto fail;
-
-       if ((drv->num_filter_ssids &&
-           (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
-           params->filter_rssi) {
-               struct nlattr *match_sets;
-               match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
-               if (match_sets == NULL)
-                       goto fail;
-
-               for (i = 0; i < drv->num_filter_ssids; i++) {
-                       struct nlattr *match_set_ssid;
-                       wpa_hexdump_ascii(MSG_MSGDUMP,
-                                         "nl80211: Sched scan filter SSID",
-                                         drv->filter_ssids[i].ssid,
-                                         drv->filter_ssids[i].ssid_len);
-
-                       match_set_ssid = nla_nest_start(msg, i + 1);
-                       if (match_set_ssid == NULL ||
-                           nla_put(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
-                                   drv->filter_ssids[i].ssid_len,
-                                   drv->filter_ssids[i].ssid) ||
-                           (params->filter_rssi &&
-                            nla_put_u32(msg,
-                                        NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
-                                        params->filter_rssi)))
-                               goto fail;
-
-                       nla_nest_end(msg, match_set_ssid);
-               }
-
-               /*
-                * Due to backward compatibility code, newer kernels treat this
-                * matchset (with only an RSSI filter) as the default for all
-                * other matchsets, unless it's the only one, in which case the
-                * matchset will actually allow all SSIDs above the RSSI.
-                */
-               if (params->filter_rssi) {
-                       struct nlattr *match_set_rssi;
-                       match_set_rssi = nla_nest_start(msg, 0);
-                       if (match_set_rssi == NULL ||
-                           nla_put_u32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
-                                       params->filter_rssi))
-                               goto fail;
-                       wpa_printf(MSG_MSGDUMP,
-                                  "nl80211: Sched scan RSSI filter %d dBm",
-                                  params->filter_rssi);
-                       nla_nest_end(msg, match_set_rssi);
-               }
-
-               nla_nest_end(msg, match_sets);
-       }
-
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-
-       /* TODO: if we get an error here, we should fall back to normal scan */
-
-       msg = NULL;
-       if (ret) {
-               wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
-                          "ret=%d (%s)", ret, strerror(-ret));
-               goto fail;
-       }
-
-       wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
-                  "scan interval %d msec", ret, interval);
-
-fail:
-       nlmsg_free(msg);
-       return ret;
-}
-
-
-/**
- * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
- * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
- * Returns: 0 on success, -1 on failure or if not supported
- */
-static int wpa_driver_nl80211_stop_sched_scan(void *priv)
-{
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       int ret;
-       struct nl_msg *msg;
-
-#ifdef ANDROID
-       if (!drv->capa.sched_scan_supported)
-               return android_pno_stop(bss);
-#endif /* ANDROID */
-
-       msg = nl80211_drv_msg(drv, 0, NL80211_CMD_STOP_SCHED_SCAN);
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-       if (ret) {
-               wpa_printf(MSG_DEBUG,
-                          "nl80211: Sched scan stop failed: ret=%d (%s)",
-                          ret, strerror(-ret));
-       } else {
-               wpa_printf(MSG_DEBUG,
-                          "nl80211: Sched scan stop sent");
-       }
-
-       return ret;
-}
-
-
-static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
-{
-       const u8 *end, *pos;
-
-       if (ies == NULL)
-               return NULL;
-
-       pos = ies;
-       end = ies + ies_len;
-
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
-                       break;
-               if (pos[0] == ie)
-                       return pos;
-               pos += 2 + pos[1];
-       }
-
-       return NULL;
-}
-
-
-static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
-                                const u8 *ie, size_t ie_len)
-{
-       const u8 *ssid;
-       size_t i;
-
-       if (drv->filter_ssids == NULL)
-               return 0;
-
-       ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
-       if (ssid == NULL)
-               return 1;
-
-       for (i = 0; i < drv->num_filter_ssids; i++) {
-               if (ssid[1] == drv->filter_ssids[i].ssid_len &&
-                   os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
-                   0)
-                       return 0;
-       }
-
-       return 1;
-}
-
-
-static int bss_info_handler(struct nl_msg *msg, void *arg)
-{
-       struct nlattr *tb[NL80211_ATTR_MAX + 1];
-       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-       struct nlattr *bss[NL80211_BSS_MAX + 1];
-       static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
-               [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
-               [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
-               [NL80211_BSS_TSF] = { .type = NLA_U64 },
-               [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
-               [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
-               [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
-               [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
-               [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
-               [NL80211_BSS_STATUS] = { .type = NLA_U32 },
-               [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
-               [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
-       };
-       struct nl80211_bss_info_arg *_arg = arg;
-       struct wpa_scan_results *res = _arg->res;
-       struct wpa_scan_res **tmp;
-       struct wpa_scan_res *r;
-       const u8 *ie, *beacon_ie;
-       size_t ie_len, beacon_ie_len;
-       u8 *pos;
-       size_t i;
-
-       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-                 genlmsg_attrlen(gnlh, 0), NULL);
-       if (!tb[NL80211_ATTR_BSS])
-               return NL_SKIP;
-       if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
-                            bss_policy))
-               return NL_SKIP;
-       if (bss[NL80211_BSS_STATUS]) {
-               enum nl80211_bss_status status;
-               status = nla_get_u32(bss[NL80211_BSS_STATUS]);
-               if (status == NL80211_BSS_STATUS_ASSOCIATED &&
-                   bss[NL80211_BSS_FREQUENCY]) {
-                       _arg->assoc_freq =
-                               nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
-                       wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
-                                  _arg->assoc_freq);
-               }
-               if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
-                   bss[NL80211_BSS_FREQUENCY]) {
-                       _arg->ibss_freq =
-                               nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
-                       wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
-                                  _arg->ibss_freq);
-               }
-               if (status == NL80211_BSS_STATUS_ASSOCIATED &&
-                   bss[NL80211_BSS_BSSID]) {
-                       os_memcpy(_arg->assoc_bssid,
-                                 nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
-                       wpa_printf(MSG_DEBUG, "nl80211: Associated with "
-                                  MACSTR, MAC2STR(_arg->assoc_bssid));
-               }
-       }
-       if (!res)
-               return NL_SKIP;
-       if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
-               ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
-               ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
-       } else {
-               ie = NULL;
-               ie_len = 0;
-       }
-       if (bss[NL80211_BSS_BEACON_IES]) {
-               beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]);
-               beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]);
-       } else {
-               beacon_ie = NULL;
-               beacon_ie_len = 0;
-       }
-
-       if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
-                                 ie ? ie_len : beacon_ie_len))
-               return NL_SKIP;
-
-       r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
-       if (r == NULL)
-               return NL_SKIP;
-       if (bss[NL80211_BSS_BSSID])
-               os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
-                         ETH_ALEN);
-       if (bss[NL80211_BSS_FREQUENCY])
-               r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
-       if (bss[NL80211_BSS_BEACON_INTERVAL])
-               r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
-       if (bss[NL80211_BSS_CAPABILITY])
-               r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
-       r->flags |= WPA_SCAN_NOISE_INVALID;
-       if (bss[NL80211_BSS_SIGNAL_MBM]) {
-               r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
-               r->level /= 100; /* mBm to dBm */
-               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_QUAL_INVALID;
-       } else
-               r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
-       if (bss[NL80211_BSS_TSF])
-               r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
-       if (bss[NL80211_BSS_SEEN_MS_AGO])
-               r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
-       r->ie_len = ie_len;
-       pos = (u8 *) (r + 1);
-       if (ie) {
-               os_memcpy(pos, ie, ie_len);
-               pos += ie_len;
-       }
-       r->beacon_ie_len = beacon_ie_len;
-       if (beacon_ie)
-               os_memcpy(pos, beacon_ie, beacon_ie_len);
-
-       if (bss[NL80211_BSS_STATUS]) {
-               enum nl80211_bss_status status;
-               status = nla_get_u32(bss[NL80211_BSS_STATUS]);
-               switch (status) {
-               case NL80211_BSS_STATUS_AUTHENTICATED:
-                       r->flags |= WPA_SCAN_AUTHENTICATED;
-                       break;
-               case NL80211_BSS_STATUS_ASSOCIATED:
-                       r->flags |= WPA_SCAN_ASSOCIATED;
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       /*
-        * cfg80211 maintains separate BSS table entries for APs if the same
-        * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
-        * not use frequency as a separate key in the BSS table, so filter out
-        * duplicated entries. Prefer associated BSS entry in such a case in
-        * order to get the correct frequency into the BSS table. Similarly,
-        * prefer newer entries over older.
-        */
-       for (i = 0; i < res->num; i++) {
-               const u8 *s1, *s2;
-               if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
-                       continue;
-
-               s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
-                                   res->res[i]->ie_len, WLAN_EID_SSID);
-               s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
-               if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
-                   os_memcmp(s1, s2, 2 + s1[1]) != 0)
-                       continue;
-
-               /* Same BSSID,SSID was already included in scan results */
-               wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
-                          "for " MACSTR, MAC2STR(r->bssid));
-
-               if (((r->flags & WPA_SCAN_ASSOCIATED) &&
-                    !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) ||
-                   r->age < res->res[i]->age) {
-                       os_free(res->res[i]);
-                       res->res[i] = r;
-               } else
-                       os_free(r);
-               return NL_SKIP;
-       }
-
-       tmp = os_realloc_array(res->res, res->num + 1,
-                              sizeof(struct wpa_scan_res *));
-       if (tmp == NULL) {
-               os_free(r);
-               return NL_SKIP;
-       }
-       tmp[res->num++] = r;
-       res->res = tmp;
-
-       return NL_SKIP;
-}
+       nl80211_remove_monitor_interface(drv);
 
+       if (is_ap_interface(drv->nlmode))
+               wpa_driver_nl80211_del_beacon(drv);
 
-static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
-                                const u8 *addr)
-{
-       if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
-               wpa_printf(MSG_DEBUG, "nl80211: Clear possible state "
-                          "mismatch (" MACSTR ")", MAC2STR(addr));
-               wpa_driver_nl80211_mlme(drv, addr,
-                                       NL80211_CMD_DEAUTHENTICATE,
-                                       WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
+       if (drv->eapol_sock >= 0) {
+               eloop_unregister_read_sock(drv->eapol_sock);
+               close(drv->eapol_sock);
        }
-}
 
+       if (drv->if_indices != drv->default_if_indices)
+               os_free(drv->if_indices);
 
-static void wpa_driver_nl80211_check_bss_status(
-       struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
-{
-       size_t i;
-
-       for (i = 0; i < res->num; i++) {
-               struct wpa_scan_res *r = res->res[i];
-               if (r->flags & WPA_SCAN_AUTHENTICATED) {
-                       wpa_printf(MSG_DEBUG, "nl80211: Scan results "
-                                  "indicates BSS status with " MACSTR
-                                  " as authenticated",
-                                  MAC2STR(r->bssid));
-                       if (is_sta_interface(drv->nlmode) &&
-                           os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 &&
-                           os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) !=
-                           0) {
-                               wpa_printf(MSG_DEBUG, "nl80211: Unknown BSSID"
-                                          " in local state (auth=" MACSTR
-                                          " assoc=" MACSTR ")",
-                                          MAC2STR(drv->auth_bssid),
-                                          MAC2STR(drv->bssid));
-                               clear_state_mismatch(drv, r->bssid);
-                       }
-               }
+       if (drv->disabled_11b_rates)
+               nl80211_disable_11b_rates(drv, drv->ifindex, 0);
 
-               if (r->flags & WPA_SCAN_ASSOCIATED) {
-                       wpa_printf(MSG_DEBUG, "nl80211: Scan results "
-                                  "indicate BSS status with " MACSTR
-                                  " as associated",
-                                  MAC2STR(r->bssid));
-                       if (is_sta_interface(drv->nlmode) &&
-                           !drv->associated) {
-                               wpa_printf(MSG_DEBUG, "nl80211: Local state "
-                                          "(not associated) does not match "
-                                          "with BSS state");
-                               clear_state_mismatch(drv, r->bssid);
-                       } else if (is_sta_interface(drv->nlmode) &&
-                                  os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
-                                  0) {
-                               wpa_printf(MSG_DEBUG, "nl80211: Local state "
-                                          "(associated with " MACSTR ") does "
-                                          "not match with BSS state",
-                                          MAC2STR(drv->bssid));
-                               clear_state_mismatch(drv, r->bssid);
-                               clear_state_mismatch(drv, drv->bssid);
-                       }
-               }
-       }
-}
+       netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
+                              IF_OPER_UP);
+       eloop_cancel_timeout(wpa_driver_nl80211_send_rfkill, drv, drv->ctx);
+       rfkill_deinit(drv->rfkill);
 
+       eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
 
-static struct wpa_scan_results *
-nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
-{
-       struct nl_msg *msg;
-       struct wpa_scan_results *res;
-       int ret;
-       struct nl80211_bss_info_arg arg;
+       if (!drv->start_iface_up)
+               (void) i802_set_iface_flags(bss, 0);
 
-       res = os_zalloc(sizeof(*res));
-       if (res == NULL)
-               return NULL;
-       if (!(msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP,
-                                   NL80211_CMD_GET_SCAN))) {
-               wpa_scan_results_free(res);
-               return NULL;
+       if (drv->addr_changed) {
+               if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
+                                         0) < 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Could not set interface down to restore permanent MAC address");
+               }
+               if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+                                      drv->perm_addr) < 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Could not restore permanent MAC address");
+               }
        }
 
-       arg.drv = drv;
-       arg.res = res;
-       ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
-       if (ret == 0) {
-               wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
-                          "BSSes)", (unsigned long) res->num);
-               nl80211_get_noise_for_scan_results(drv, res);
-               return res;
+       if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+               if (!drv->hostapd || !drv->start_mode_ap)
+                       wpa_driver_nl80211_set_mode(bss,
+                                                   NL80211_IFTYPE_STATION);
+               nl80211_mgmt_unsubscribe(bss, "deinit");
+       } else {
+               nl80211_mgmt_unsubscribe(bss, "deinit");
+               nl80211_del_p2pdev(bss);
        }
-       wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
-                  "(%s)", ret, strerror(-ret));
-       wpa_scan_results_free(res);
-       return NULL;
-}
-
-
-/**
- * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
- * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
- * Returns: Scan results on success, -1 on failure
- */
-static struct wpa_scan_results *
-wpa_driver_nl80211_get_scan_results(void *priv)
-{
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct wpa_scan_results *res;
-
-       res = nl80211_get_scan_results(drv);
-       if (res)
-               wpa_driver_nl80211_check_bss_status(drv, res);
-       return res;
-}
 
+       nl80211_destroy_bss(drv->first_bss);
 
-static void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
-{
-       struct wpa_scan_results *res;
-       size_t i;
+       os_free(drv->filter_ssids);
 
-       res = nl80211_get_scan_results(drv);
-       if (res == NULL) {
-               wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
-               return;
-       }
+       os_free(drv->auth_ie);
 
-       wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
-       for (i = 0; i < res->num; i++) {
-               struct wpa_scan_res *r = res->res[i];
-               wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s%s",
-                          (int) i, (int) res->num, MAC2STR(r->bssid),
-                          r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "",
-                          r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
-       }
+       if (drv->in_interface_list)
+               dl_list_del(&drv->list);
 
-       wpa_scan_results_free(res);
+       os_free(drv->extended_capa);
+       os_free(drv->extended_capa_mask);
+       os_free(drv->first_bss);
+       os_free(drv);
 }
 
 
@@ -3157,7 +2341,7 @@ static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
        struct nl_msg *msg;
        int ret;
 
-       if (!drv->key_mgmt_set_key_vendor_cmd_avail)
+       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
                return 0;
 
        if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
@@ -3165,10 +2349,11 @@ static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
            nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
                        QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY) ||
            nla_put(msg, NL80211_ATTR_VENDOR_DATA, key_len, key)) {
+               nl80211_nlmsg_clear(msg);
                nlmsg_free(msg);
                return -1;
        }
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
        if (ret) {
                wpa_printf(MSG_DEBUG,
                           "nl80211: Key management set key failed: ret=%d (%s)",
@@ -3207,22 +2392,21 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
        }
 #endif /* CONFIG_TDLS */
 
-       if (alg == WPA_ALG_PMK && drv->key_mgmt_set_key_vendor_cmd_avail) {
+       if (alg == WPA_ALG_PMK &&
+           (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
                wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
                           __func__);
                ret = issue_key_mgmt_set_key(drv, key, key_len);
                return ret;
        }
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
        if (alg == WPA_ALG_NONE) {
-               if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY))
-                       goto fail;
+               msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
+               if (!msg)
+                       return -ENOBUFS;
        } else {
-               if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY) ||
+               msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
+               if (!msg ||
                    nla_put(msg, NL80211_ATTR_KEY_DATA, key_len, key) ||
                    nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER,
                                wpa_alg_to_cipher_suite(alg, key_len)))
@@ -3258,11 +2442,10 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
                        goto fail;
                nla_nest_end(msg, types);
        }
-       if (nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex))
+       if (nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
                goto fail;
 
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL);
        if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
                ret = 0;
        if (ret)
@@ -3279,13 +2462,9 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
            !is_broadcast_ether_addr(addr))
                return ret;
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_KEY) ||
+       msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
+       if (!msg ||
            nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex) ||
            nla_put_flag(msg, alg == WPA_ALG_IGTK ?
                         NL80211_ATTR_KEY_DEFAULT_MGMT :
                         NL80211_ATTR_KEY_DEFAULT))
@@ -3317,6 +2496,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
        return ret;
 
 fail:
+       nl80211_nlmsg_clear(msg);
        nlmsg_free(msg);
        return -ENOBUFS;
 }
@@ -3406,9 +2586,9 @@ static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
 }
 
 
-static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
-                                  const u8 *addr, int cmd, u16 reason_code,
-                                  int local_state_change)
+int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
+                           const u8 *addr, int cmd, u16 reason_code,
+                           int local_state_change)
 {
        int ret;
        struct nl_msg *msg;
@@ -3460,7 +2640,7 @@ static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
 
        if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
                nl80211_mark_disconnected(drv);
-               return nl80211_leave_ibss(drv);
+               return nl80211_leave_ibss(drv, 1);
        }
        if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
                return wpa_driver_nl80211_disconnect(drv, reason_code);
@@ -3524,6 +2704,25 @@ static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static void nl80211_unmask_11b_rates(struct i802_bss *bss)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+
+       if (is_p2p_net_interface(drv->nlmode) || !drv->disabled_11b_rates)
+               return;
+
+       /*
+        * Looks like we failed to unmask 11b rates previously. This could
+        * happen, e.g., if the interface was down at the point in time when a
+        * P2P group was terminated.
+        */
+       wpa_printf(MSG_DEBUG,
+                  "nl80211: Interface %s mode is for non-P2P, but 11b rates were disabled - re-enable them",
+                  bss->ifname);
+       nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+}
+
+
 static int wpa_driver_nl80211_authenticate(
        struct i802_bss *bss, struct wpa_driver_auth_params *params)
 {
@@ -3535,6 +2734,8 @@ static int wpa_driver_nl80211_authenticate(
        int count = 0;
        int is_retry;
 
+       nl80211_unmask_11b_rates(bss);
+
        is_retry = drv->retry_auth;
        drv->retry_auth = 0;
        drv->ignore_deauth_event = 0;
@@ -3870,11 +3071,7 @@ static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_BSS) ||
+       if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_BSS)) ||
            (cts >= 0 &&
             nla_put_u8(msg, NL80211_ATTR_BSS_CTS_PROT, cts)) ||
            (preamble >= 0 &&
@@ -3901,9 +3098,6 @@ static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
                        goto fail;
        }
 
-       if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)))
-               goto fail;
-
        return send_and_recv_msgs(drv, msg, NULL, NULL);
 fail:
        nlmsg_free(msg);
@@ -3967,7 +3161,6 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        u8 cmd = NL80211_CMD_NEW_BEACON;
        int ret;
        int beacon_set;
-       int ifindex = if_nametoindex(bss->ifname);
        int num_suites;
        int smps_mode;
        u32 suites[10], suite;
@@ -3975,10 +3168,6 @@ static int wpa_driver_nl80211_set_ap(void *priv,
 
        beacon_set = bss->beacon_set;
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
        wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
                   beacon_set);
        if (beacon_set)
@@ -3988,17 +3177,16 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                    params->head, params->head_len);
        wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail",
                    params->tail, params->tail_len);
-       wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", ifindex);
+       wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", bss->ifindex);
        wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
        wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
        wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
                          params->ssid, params->ssid_len);
-       if (!nl80211_cmd(drv, msg, 0, cmd) ||
+       if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
            nla_put(msg, NL80211_ATTR_BEACON_HEAD, params->head_len,
                    params->head) ||
            nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
                    params->tail) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex) ||
            nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
                        params->beacon_int) ||
            nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period) ||
@@ -4071,7 +3259,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                    suites))
                goto fail;
 
-       if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X &&
+       if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
            params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40) &&
            nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
                goto fail;
@@ -4334,16 +3522,11 @@ static int wpa_driver_nl80211_sta_add(void *priv,
            !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
                return -EOPNOTSUPP;
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
        wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
                   params->set ? "Set" : "Add", MAC2STR(params->addr));
-       if (!nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
-                        NL80211_CMD_NEW_STATION) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)) ||
-           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
+       msg = nl80211_bss_msg(bss, 0, params->set ? NL80211_CMD_SET_STATION :
+                             NL80211_CMD_NEW_STATION);
+       if (!msg || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
                goto fail;
 
        if (!params->set || (params->flags & WPA_STA_TDLS_PEER)) {
@@ -4523,12 +3706,7 @@ static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr,
        struct nl_msg *msg;
        int ret;
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)) ||
+       if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION)) ||
            nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
            (deauth == 0 &&
             nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
@@ -4568,19 +3746,9 @@ void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
                         struct wpa_driver_nl80211_data, list)
                del_ifidx(drv2, ifidx);
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return;
-
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifidx)) {
-               nlmsg_free(msg);
-               goto fail;
-       }
-
+       msg = nl80211_ifindex_msg(drv, ifidx, 0, NL80211_CMD_DEL_INTERFACE);
        if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
                return;
-fail:
        wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
 }
 
@@ -4735,8 +3903,12 @@ int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
                                                wds, handler, arg);
        }
 
-       if (ret >= 0 && is_p2p_net_interface(iftype))
+       if (ret >= 0 && is_p2p_net_interface(iftype)) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Interface %s created for P2P - disable 11b rates",
+                          ifname);
                nl80211_disable_11b_rates(drv, ret, 1);
+       }
 
        return ret;
 }
@@ -4900,7 +4072,6 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
                                            int flags_or, int flags_and)
 {
        struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        struct nlattr *flags;
        struct nl80211_sta_flag_update upd;
@@ -4910,13 +4081,7 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
                   bss->ifname, MAC2STR(addr), total_flags, flags_or, flags_and,
                   !!(total_flags & WPA_STA_AUTHORIZED));
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX,
-                       if_nametoindex(bss->ifname)) ||
+       if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
            nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
                goto fail;
 
@@ -4946,7 +4111,7 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
        if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
                goto fail;
 
-       return send_and_recv_msgs(drv, msg, NULL, NULL);
+       return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
 fail:
        nlmsg_free(msg);
        return -ENOBUFS;
@@ -4982,7 +4147,8 @@ static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
 }
 
 
-static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
+                             int reset_mode)
 {
        struct nl_msg *msg;
        int ret;
@@ -4997,7 +4163,8 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
                           "nl80211: Leave IBSS request sent successfully");
        }
 
-       if (wpa_driver_nl80211_set_mode(drv->first_bss,
+       if (reset_mode &&
+           wpa_driver_nl80211_set_mode(drv->first_bss,
                                        NL80211_IFTYPE_STATION)) {
                wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
                           "station mode");
@@ -5090,7 +4257,7 @@ retry:
                if (ret == -EALREADY && count == 1) {
                        wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
                                   "forced leave");
-                       nl80211_leave_ibss(drv);
+                       nl80211_leave_ibss(drv, 0);
                        nlmsg_free(msg);
                        goto retry;
                }
@@ -5421,6 +4588,8 @@ static int wpa_driver_nl80211_associate(
        int ret = -1;
        struct nl_msg *msg;
 
+       nl80211_unmask_11b_rates(bss);
+
        if (params->mode == IEEE80211_MODE_AP)
                return wpa_driver_nl80211_ap(drv, params);
 
@@ -5553,7 +4722,7 @@ static int wpa_driver_nl80211_set_mode_impl(
                 * on a frequency that the mode is disallowed in.
                 */
                if (desired_freq_params) {
-                       res = i802_set_freq(bss, desired_freq_params);
+                       res = nl80211_set_channel(bss, desired_freq_params, 0);
                        if (res) {
                                wpa_printf(MSG_DEBUG,
                                           "nl80211: Failed to set frequency on interface");
@@ -5594,10 +4763,17 @@ done:
                return ret;
        }
 
-       if (is_p2p_net_interface(nlmode))
+       if (is_p2p_net_interface(nlmode)) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Interface %s mode change to P2P - disable 11b rates",
+                          bss->ifname);
                nl80211_disable_11b_rates(drv, drv->ifindex, 1);
-       else if (drv->disabled_11b_rates)
+       } else if (drv->disabled_11b_rates) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Interface %s mode changed to non-P2P - re-enable 11b rates",
+                          bss->ifname);
                nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+       }
 
        if (is_ap_interface(nlmode)) {
                nl80211_mgmt_unsubscribe(bss, "start AP");
@@ -5689,18 +4865,12 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
        wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
                   MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
        os_memset(&upd, 0, sizeof(upd));
        upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
        if (authorized)
                upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
 
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX,
-                       if_nametoindex(bss->ifname)) ||
+       if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
            nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid) ||
            nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd)) {
                nlmsg_free(msg);
@@ -5760,14 +4930,11 @@ static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_KEY) ||
+       msg = nl80211_ifindex_msg(drv, if_nametoindex(iface), 0,
+                                 NL80211_CMD_GET_KEY);
+       if (!msg ||
            (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
-           nla_put_u8(msg, NL80211_ATTR_KEY_IDX, idx) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface))) {
+           nla_put_u8(msg, NL80211_ATTR_KEY_IDX, idx)) {
                nlmsg_free(msg);
                return -ENOBUFS;
        }
@@ -5837,28 +5004,17 @@ static int i802_set_frag(void *priv, int frag)
 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)
-               return -1;
-
        wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)",
                   bss->ifname);
-       nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
 
        /*
         * XXX: FIX! this needs to flush all VLANs too
         */
-       if (nla_put_u32(msg, NL80211_ATTR_IFINDEX,
-                       if_nametoindex(bss->ifname))) {
-               nlmsg_free(msg);
-               return -ENOBUFS;
-       }
-
-       res = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION);
+       res = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
        if (res) {
                wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
                           "(%s)", res, strerror(-res));
@@ -5926,23 +5082,17 @@ static int i802_read_sta_data(struct i802_bss *bss,
                              struct hostap_sta_driver_data *data,
                              const u8 *addr)
 {
-       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
 
        os_memset(data, 0, sizeof(*data));
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
 
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION) ||
-           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX,
-                       if_nametoindex(bss->ifname))) {
+       if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_STATION)) ||
+           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
                nlmsg_free(msg);
                return -ENOBUFS;
        }
 
-       return send_and_recv_msgs(drv, msg, get_sta_handler, data);
+       return send_and_recv_msgs(bss->drv, msg, get_sta_handler, data);
 }
 
 
@@ -5954,14 +5104,10 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
        struct nl_msg *msg;
        struct nlattr *txq, *params;
 
-       msg = nlmsg_alloc();
+       msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY);
        if (!msg)
                return -1;
 
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)))
-               goto fail;
-
        txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
        if (!txq)
                goto fail;
@@ -6018,17 +5164,11 @@ static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
        struct nl_msg *msg;
        int ret;
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
        wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR
                   ", ifname=%s[%d], vlan_id=%d)",
                   bss->ifname, if_nametoindex(bss->ifname),
                   MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX,
-                       if_nametoindex(bss->ifname)) ||
+       if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
            nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
            nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) {
                nlmsg_free(msg);
@@ -6134,7 +5274,7 @@ static void dump_ifidx(struct wpa_driver_nl80211_data *drv)
                if (!drv->if_indices[i])
                        continue;
                res = os_snprintf(pos, end - pos, " %d", drv->if_indices[i]);
-               if (res < 0 || res >= end - pos)
+               if (os_snprintf_error(end - pos, res))
                        break;
                pos += res;
        }
@@ -6373,16 +5513,21 @@ static void *i802_init(struct hostapd_data *hapd,
                                br_added = 1;
                }
        }
-       if (!br_added && br_ifindex &&
-           (params->num_bridge == 0 || !params->bridge[0]))
-               add_ifidx(drv, br_ifindex);
 
        /* start listening for EAPOL on the default AP interface */
        add_ifidx(drv, drv->ifindex);
 
-       if (params->num_bridge && params->bridge[0] &&
-           i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
-               goto failed;
+       if (params->num_bridge && params->bridge[0]) {
+               if (i802_check_bridge(drv, bss, params->bridge[0],
+                                     params->ifname) < 0)
+                       goto failed;
+               if (os_strcmp(params->bridge[0], brname) != 0)
+                       br_added = 1;
+       }
+
+       if (!br_added && br_ifindex &&
+           (params->num_bridge == 0 || !params->bridge[0]))
+               add_ifidx(drv, br_ifindex);
 
 #ifdef CONFIG_LIBNL3_ROUTE
        if (bss->added_if_into_bridge) {
@@ -6452,12 +5597,14 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type(
                return NL80211_IFTYPE_P2P_GO;
        case WPA_IF_P2P_DEVICE:
                return NL80211_IFTYPE_P2P_DEVICE;
+       case WPA_IF_MESH:
+               return NL80211_IFTYPE_MESH_POINT;
        }
        return -1;
 }
 
 
-#ifdef CONFIG_P2P
+#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
 
 static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
 {
@@ -6471,8 +5618,7 @@ static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
 }
 
 
-static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
-                                     u8 *new_addr)
+static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
 {
        unsigned int idx;
 
@@ -6489,13 +5635,13 @@ static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
        if (idx == 64)
                return -1;
 
-       wpa_printf(MSG_DEBUG, "nl80211: Assigned new P2P Interface Address "
+       wpa_printf(MSG_DEBUG, "nl80211: Assigned new virtual interface address "
                   MACSTR, MAC2STR(new_addr));
 
        return 0;
 }
 
-#endif /* CONFIG_P2P */
+#endif /* CONFIG_P2P || CONFIG_MESH */
 
 
 struct wdev_info {
@@ -6582,10 +5728,10 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                }
        }
 
-#ifdef CONFIG_P2P
+#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
        if (!addr &&
            (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
-            type == WPA_IF_P2P_GO)) {
+            type == WPA_IF_P2P_GO || type == WPA_IF_MESH)) {
                /* Enforce unique P2P Interface Address */
                u8 new_addr[ETH_ALEN];
 
@@ -6597,8 +5743,9 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                }
                if (nl80211_addr_in_use(drv->global, new_addr)) {
                        wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
-                                  "for P2P group interface");
-                       if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
+                                  "for %s interface", type == WPA_IF_MESH ?
+                                  "mesh" : "P2P group");
+                       if (nl80211_vif_addr(drv, new_addr) < 0) {
                                if (added)
                                        nl80211_remove_iface(drv, ifidx);
                                return -1;
@@ -6612,7 +5759,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                }
                os_memcpy(if_addr, new_addr, ETH_ALEN);
        }
-#endif /* CONFIG_P2P */
+#endif /* CONFIG_P2P || CONFIG_MESH */
 
        if (type == WPA_IF_AP_BSS) {
                struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
@@ -7008,14 +6155,16 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
        struct nlattr *bands, *band;
        int ret;
 
-       msg = nlmsg_alloc();
+       wpa_printf(MSG_DEBUG,
+                  "nl80211: NL80211_CMD_SET_TX_BITRATE_MASK (ifindex=%d %s)",
+                  ifindex, disabled ? "NL80211_TXRATE_LEGACY=OFDM-only" :
+                  "no NL80211_TXRATE_LEGACY constraint");
+
+       msg = nl80211_ifindex_msg(drv, ifindex, 0,
+                                 NL80211_CMD_SET_TX_BITRATE_MASK);
        if (!msg)
                return -1;
 
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex))
-               goto fail;
-
        bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
        if (!bands)
                goto fail;
@@ -7108,53 +6257,6 @@ static void wpa_driver_nl80211_resume(void *priv)
 }
 
 
-static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
-                                 const u8 *ies, size_t ies_len)
-{
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       int ret;
-       u8 *data, *pos;
-       size_t data_len;
-       const u8 *own_addr = bss->addr;
-
-       if (action != 1) {
-               wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
-                          "action %d", action);
-               return -1;
-       }
-
-       /*
-        * Action frame payload:
-        * Category[1] = 6 (Fast BSS Transition)
-        * Action[1] = 1 (Fast BSS Transition Request)
-        * STA Address
-        * Target AP Address
-        * FT IEs
-        */
-
-       data_len = 2 + 2 * ETH_ALEN + ies_len;
-       data = os_malloc(data_len);
-       if (data == NULL)
-               return -1;
-       pos = data;
-       *pos++ = 0x06; /* FT Action category */
-       *pos++ = action;
-       os_memcpy(pos, own_addr, ETH_ALEN);
-       pos += ETH_ALEN;
-       os_memcpy(pos, target_ap, ETH_ALEN);
-       pos += ETH_ALEN;
-       os_memcpy(pos, ies, ies_len);
-
-       ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
-                                            drv->bssid, own_addr, drv->bssid,
-                                            data, data_len, 0);
-       os_free(data);
-
-       return ret;
-}
-
-
 static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
 {
        struct i802_bss *bss = priv;
@@ -7165,12 +6267,7 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
        wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
                   "hysteresis=%d", threshold, hysteresis);
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -1;
-
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_CQM) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex) ||
+       if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_CQM)) ||
            !(cqm = nla_nest_start(msg, NL80211_ATTR_CQM)) ||
            nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold) ||
            nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis)) {
@@ -7416,13 +6513,7 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid,
 {
        struct nl_msg *msg;
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
-       if (!nl80211_cmd(bss->drv, msg, 0, cmd) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX,
-                       if_nametoindex(bss->ifname)) ||
+       if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
            (pmkid && nla_put(msg, NL80211_ATTR_PMKID, 16, pmkid)) ||
            (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))) {
                nlmsg_free(msg);
@@ -7640,24 +6731,20 @@ static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
        struct nlattr *replay_nested;
        struct nl_msg *msg;
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return;
-
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex) ||
+       if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_REKEY_OFFLOAD)) ||
            !(replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA)) ||
            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)) {
+               nl80211_nlmsg_clear(msg);
                nlmsg_free(msg);
                return;
        }
 
        nla_nest_end(msg, replay_nested);
 
-       send_and_recv_msgs(drv, msg, NULL, NULL);
+       send_and_recv_msgs(drv, msg, NULL, (void *) -1);
 }
 
 
@@ -7711,12 +6798,7 @@ static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
                return;
        }
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return;
-
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex) ||
+       if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_PROBE_CLIENT)) ||
            nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
                nlmsg_free(msg);
                return;
@@ -7730,12 +6812,7 @@ static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
 {
        struct nl_msg *msg;
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
-       if (!nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_SET_POWER_SAVE) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex) ||
+       if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_POWER_SAVE)) ||
            nla_put_u32(msg, NL80211_ATTR_PS_STATE,
                        enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED)) {
                nlmsg_free(msg);
@@ -8092,14 +7169,14 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
                          bss->added_bridge ? "added_bridge=1\n" : "",
                          bss->in_deinit ? "in_deinit=1\n" : "",
                          bss->if_dynamic ? "if_dynamic=1\n" : "");
-       if (res < 0 || res >= end - pos)
+       if (os_snprintf_error(end - pos, res))
                return pos - buf;
        pos += res;
 
        if (bss->wdev_id_set) {
                res = os_snprintf(pos, end - pos, "wdev_id=%llu\n",
                                  (unsigned long long) bss->wdev_id);
-               if (res < 0 || res >= end - pos)
+               if (os_snprintf_error(end - pos, res))
                        return pos - buf;
                pos += res;
        }
@@ -8158,7 +7235,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
                          "ignore_next_local_disconnect=1\n" : "",
                          drv->ignore_next_local_deauth ?
                          "ignore_next_local_deauth=1\n" : "");
-       if (res < 0 || res >= end - pos)
+       if (os_snprintf_error(end - pos, res))
                return pos - buf;
        pos += res;
 
@@ -8168,6 +7245,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
                                  "capa.enc=0x%x\n"
                                  "capa.auth=0x%x\n"
                                  "capa.flags=0x%llx\n"
+                                 "capa.rrm_flags=0x%x\n"
                                  "capa.max_scan_ssids=%d\n"
                                  "capa.max_sched_scan_ssids=%d\n"
                                  "capa.sched_scan_supported=%d\n"
@@ -8181,6 +7259,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
                                  drv->capa.enc,
                                  drv->capa.auth,
                                  (unsigned long long) drv->capa.flags,
+                                 drv->capa.rrm_flags,
                                  drv->capa.max_scan_ssids,
                                  drv->capa.max_sched_scan_ssids,
                                  drv->capa.sched_scan_supported,
@@ -8190,7 +7269,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
                                  drv->capa.probe_resp_offloads,
                                  drv->capa.max_acl_mac_addrs,
                                  drv->capa.num_multichan_concurrent);
-               if (res < 0 || res >= end - pos)
+               if (os_snprintf_error(end - pos, res))
                        return pos - buf;
                pos += res;
        }
@@ -8263,12 +7342,7 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
              settings->cs_count)))
                return -EINVAL;
 
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
-       if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_CHANNEL_SWITCH) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex) ||
+       if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CHANNEL_SWITCH)) ||
            nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT,
                        settings->cs_count) ||
            (ret = nl80211_put_freq_params(msg, &settings->freq_params)) ||
@@ -8699,6 +7773,13 @@ wpa_driver_nl80211_join_mesh(void *priv,
                        goto fail;
        }
 
+       if (params->beacon_int > 0) {
+               wpa_printf(MSG_DEBUG, "  * beacon_int=%d", params->beacon_int);
+               if (nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
+                               params->beacon_int))
+                       goto fail;
+       }
+
        wpa_printf(MSG_DEBUG, "  * flags=%08X", params->flags);
 
        container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
@@ -8732,6 +7813,10 @@ wpa_driver_nl80211_join_mesh(void *priv,
        if (!(params->conf.flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
            nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, 0))
                goto fail;
+       if ((params->conf.flags & WPA_DRIVER_MESH_FLAG_DRIVER_MPM) &&
+           nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
+                       params->max_peer_links))
+               goto fail;
        nla_nest_end(msg, container);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -8949,7 +8034,7 @@ static int linux_write_system_file(const char *path, unsigned int val)
        int fd, len;
 
        len = os_snprintf(buf, sizeof(buf), "%u\n", val);
-       if (len < 0)
+       if (os_snprintf_error(sizeof(buf), len))
                return -1;
 
        fd = open(path, O_WRONLY);
@@ -9155,7 +8240,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .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,