]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/drivers/driver_nl80211.c
hostapd: Add ctrl iface indications for WDS STA interface
[thirdparty/hostap.git] / src / drivers / driver_nl80211.c
index 6ecb810d623be141e77a4948b5c7fb6b8b2f5d89..0c5c6bb6f7981098a518de044382f49b12c40d8b 100644 (file)
@@ -130,7 +130,7 @@ static void nl_destroy_handles(struct nl_handle **handle)
 
 static void nl80211_register_eloop_read(struct nl_handle **handle,
                                        eloop_sock_handler handler,
-                                       void *eloop_data)
+                                       void *eloop_data, int persist)
 {
 #ifdef CONFIG_LIBNL20
        /*
@@ -151,13 +151,17 @@ static void nl80211_register_eloop_read(struct nl_handle **handle,
        nl_socket_set_nonblocking(*handle);
        eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
                                 eloop_data, *handle);
-       *handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+       if (!persist)
+               *handle = (void *) (((intptr_t) *handle) ^
+                                   ELOOP_SOCKET_INVALID);
 }
 
 
-static void nl80211_destroy_eloop_handle(struct nl_handle **handle)
+static void nl80211_destroy_eloop_handle(struct nl_handle **handle, int persist)
 {
-       *handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+       if (!persist)
+               *handle = (void *) (((intptr_t) *handle) ^
+                                   ELOOP_SOCKET_INVALID);
        eloop_unregister_read_sock(nl_socket_get_fd(*handle));
        nl_destroy_handles(handle);
 }
@@ -723,7 +727,7 @@ nl80211_get_wiphy_data_ap(struct i802_bss *bss)
                }
 
                nl80211_register_eloop_read(&w->nl_beacons,
-                                           nl80211_recv_beacons, w);
+                                           nl80211_recv_beacons, w, 0);
        }
 
        dl_list_add(&nl80211_wiphys, &w->list);
@@ -772,7 +776,7 @@ static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
                return;
 
        if (w->nl_beacons)
-               nl80211_destroy_eloop_handle(&w->nl_beacons);
+               nl80211_destroy_eloop_handle(&w->nl_beacons, 0);
 
        nl_cb_put(w->nl_cb);
        dl_list_del(&w->list);
@@ -911,7 +915,8 @@ static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
                nl80211_check_global(drv->global);
                wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
                           "interface");
-               wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL);
+               if (wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL) < 0)
+                       return -1;
                return 1;
        }
 
@@ -920,19 +925,58 @@ static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
 
 
 static struct wpa_driver_nl80211_data *
-nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len)
+nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len,
+                int *init_failed)
 {
        struct wpa_driver_nl80211_data *drv;
+       int res;
+
+       if (init_failed)
+               *init_failed = 0;
        dl_list_for_each(drv, &global->interfaces,
                         struct wpa_driver_nl80211_data, list) {
-               if (wpa_driver_nl80211_own_ifindex(drv, idx, buf, len) ||
-                   have_ifidx(drv, idx, IFIDX_ANY))
+               res = wpa_driver_nl80211_own_ifindex(drv, idx, buf, len);
+               if (res < 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Found matching own interface, but failed to complete reinitialization");
+                       if (init_failed)
+                               *init_failed = 1;
+                       return drv;
+               }
+               if (res > 0 || have_ifidx(drv, idx, IFIDX_ANY))
                        return drv;
        }
        return NULL;
 }
 
 
+static void nl80211_refresh_mac(struct wpa_driver_nl80211_data *drv,
+                               int ifindex, int notify)
+{
+       struct i802_bss *bss;
+       u8 addr[ETH_ALEN];
+
+       bss = get_bss_ifindex(drv, ifindex);
+       if (bss &&
+           linux_get_ifhwaddr(drv->global->ioctl_sock,
+                              bss->ifname, addr) < 0) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: %s: failed to re-read MAC address",
+                          bss->ifname);
+       } else if (bss && os_memcmp(addr, bss->addr, ETH_ALEN) != 0) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Own MAC address on ifindex %d (%s) changed from "
+                          MACSTR " to " MACSTR,
+                          ifindex, bss->ifname,
+                          MAC2STR(bss->addr), MAC2STR(addr));
+               os_memcpy(bss->addr, addr, ETH_ALEN);
+               if (notify)
+                       wpa_supplicant_event(drv->ctx,
+                                            EVENT_INTERFACE_MAC_CHANGED, NULL);
+       }
+}
+
+
 static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                                                 struct ifinfomsg *ifi,
                                                 u8 *buf, size_t len)
@@ -945,6 +989,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
        char namebuf[IFNAMSIZ];
        char ifname[IFNAMSIZ + 1];
        char extra[100], *pos, *end;
+       int init_failed;
 
        extra[0] = '\0';
        pos = extra;
@@ -989,9 +1034,11 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
                   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
 
-       drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+       drv = nl80211_find_drv(global, ifi->ifi_index, buf, len, &init_failed);
        if (!drv)
                goto event_newlink;
+       if (init_failed)
+               return; /* do not update interface state */
 
        if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
                namebuf[0] = '\0';
@@ -1000,6 +1047,8 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                        wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
                                   "event since interface %s is up", namebuf);
                        drv->ignore_if_down_event = 0;
+                       /* Re-read MAC address as it may have changed */
+                       nl80211_refresh_mac(drv, ifi->ifi_index, 1);
                        return;
                }
                wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)",
@@ -1023,7 +1072,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                         * dynamic interfaces
                         */
                        drv = nl80211_find_drv(global, ifi->ifi_index,
-                                              buf, len);
+                                              buf, len, NULL);
                        if (!drv)
                                return;
                }
@@ -1044,27 +1093,8 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                                   "event since interface %s is marked "
                                   "removed", drv->first_bss->ifname);
                } else {
-                       struct i802_bss *bss;
-                       u8 addr[ETH_ALEN];
-
                        /* Re-read MAC address as it may have changed */
-                       bss = get_bss_ifindex(drv, ifi->ifi_index);
-                       if (bss &&
-                           linux_get_ifhwaddr(drv->global->ioctl_sock,
-                                              bss->ifname, addr) < 0) {
-                               wpa_printf(MSG_DEBUG,
-                                          "nl80211: %s: failed to re-read MAC address",
-                                          bss->ifname);
-                       } else if (bss &&
-                                  os_memcmp(addr, bss->addr, ETH_ALEN) != 0) {
-                               wpa_printf(MSG_DEBUG,
-                                          "nl80211: Own MAC address on ifindex %d (%s) changed from "
-                                          MACSTR " to " MACSTR,
-                                          ifi->ifi_index, bss->ifname,
-                                          MAC2STR(bss->addr),
-                                          MAC2STR(addr));
-                               os_memcpy(bss->addr, addr, ETH_ALEN);
-                       }
+                       nl80211_refresh_mac(drv, ifi->ifi_index, 0);
 
                        wpa_printf(MSG_DEBUG, "nl80211: Interface up");
                        drv->if_disabled = 0;
@@ -1168,7 +1198,7 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
                   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
                   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
 
-       drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+       drv = nl80211_find_drv(global, ifi->ifi_index, buf, len, NULL);
 
        if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
                /* device has been removed from bridge */
@@ -1608,7 +1638,7 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
 
        nl80211_register_eloop_read(&global->nl_event,
                                    wpa_driver_nl80211_event_receive,
-                                   global->nl_cb);
+                                   global->nl_cb, 0);
 
        return 0;
 
@@ -1974,7 +2004,7 @@ static void nl80211_mgmt_handle_register_eloop(struct i802_bss *bss)
 {
        nl80211_register_eloop_read(&bss->nl_mgmt,
                                    wpa_driver_nl80211_event_receive,
-                                   bss->nl_cb);
+                                   bss->nl_cb, 0);
 }
 
 
@@ -1987,6 +2017,25 @@ static int nl80211_register_action_frame(struct i802_bss *bss,
 }
 
 
+static int nl80211_init_connect_handle(struct i802_bss *bss)
+{
+       if (bss->nl_connect) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Connect handle already created (nl_connect=%p)",
+                          bss->nl_connect);
+               return -1;
+       }
+
+       bss->nl_connect = nl_create_handle(bss->nl_cb, "connect");
+       if (!bss->nl_connect)
+               return -1;
+       nl80211_register_eloop_read(&bss->nl_connect,
+                                   wpa_driver_nl80211_event_receive,
+                                   bss->nl_cb, 1);
+       return 0;
+}
+
+
 static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -1997,7 +2046,9 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
        wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
                   "handle %p", bss->nl_mgmt);
 
-       if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
+       if (drv->nlmode == NL80211_IFTYPE_ADHOC ||
+           ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
+            !(drv->capa.flags & WPA_DRIVER_FLAGS_SME))) {
                u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
 
                /* register for any AUTH message */
@@ -2009,7 +2060,7 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
        if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)
                ret = -1;
 #endif /* CONFIG_INTERWORKING */
-#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
+#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING) || defined(CONFIG_DPP)
        /* GAS Initial Request */
        if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
                ret = -1;
@@ -2034,7 +2085,7 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
        /* Protected GAS Comeback Response */
        if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0d", 2) < 0)
                ret = -1;
-#endif /* CONFIG_P2P || CONFIG_INTERWORKING */
+#endif /* CONFIG_P2P || CONFIG_INTERWORKING || CONFIG_DPP */
 #ifdef CONFIG_P2P
        /* P2P Public Action */
        if (nl80211_register_action_frame(bss,
@@ -2047,6 +2098,13 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
                                          5) < 0)
                ret = -1;
 #endif /* CONFIG_P2P */
+#ifdef CONFIG_DPP
+       /* DPP Public Action */
+       if (nl80211_register_action_frame(bss,
+                                         (u8 *) "\x04\x09\x50\x6f\x9a\x1a",
+                                         6) < 0)
+               ret = -1;
+#endif /* CONFIG_DPP */
 #ifdef CONFIG_IEEE80211W
        /* SA Query Response */
        if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
@@ -2281,7 +2339,7 @@ static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
                return;
        wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
                   "(%s)", bss->nl_mgmt, reason);
-       nl80211_destroy_eloop_handle(&bss->nl_mgmt);
+       nl80211_destroy_eloop_handle(&bss->nl_mgmt, 0);
 
        nl80211_put_wiphy_data_ap(bss);
 }
@@ -2497,6 +2555,8 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
        if (drv->vendor_cmd_test_avail)
                qca_vendor_test(drv);
 
+       nl80211_init_connect_handle(bss);
+
        return 0;
 }
 
@@ -2610,6 +2670,9 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
                nl80211_del_p2pdev(bss);
        }
 
+       if (bss->nl_connect)
+               nl80211_destroy_eloop_handle(&bss->nl_connect, 1);
+
        nl80211_destroy_bss(drv->first_bss);
 
        os_free(drv->filter_ssids);
@@ -2752,6 +2815,44 @@ static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
 
+static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
+                          const u8 *key, size_t key_len,
+                          const u8 *addr)
+{
+       struct nl_msg *msg = NULL;
+       int ret;
+
+       /*
+        * If the authenticator address is not set, assume it is
+        * the current BSSID.
+        */
+       if (!addr && drv->associated)
+               addr = drv->bssid;
+       else if (!addr)
+               return -1;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Set PMK to the driver for " MACSTR,
+                  MAC2STR(addr));
+       wpa_hexdump_key(MSG_DEBUG, "nl80211: PMK", key, key_len);
+       msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_PMK);
+       if (!msg ||
+           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+           nla_put(msg, NL80211_ATTR_PMK, key_len, key)) {
+               nl80211_nlmsg_clear(msg);
+               nlmsg_free(msg);
+               return -ENOBUFS;
+       }
+
+       ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: Set PMK failed: ret=%d (%s)",
+                          ret, strerror(-ret));
+       }
+
+       return ret;
+}
+
+
 static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
                                      enum wpa_alg alg, const u8 *addr,
                                      int key_idx, int set_tx,
@@ -2790,6 +2891,10 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
        }
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
+       if (alg == WPA_ALG_PMK &&
+           (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+               return nl80211_set_pmk(drv, key, key_len, addr);
+
        if (alg == WPA_ALG_NONE) {
                msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
                if (!msg)
@@ -3125,6 +3230,27 @@ static void nl80211_unmask_11b_rates(struct i802_bss *bss)
 }
 
 
+static enum nl80211_auth_type get_nl_auth_type(int wpa_auth_alg)
+{
+       if (wpa_auth_alg & WPA_AUTH_ALG_OPEN)
+               return NL80211_AUTHTYPE_OPEN_SYSTEM;
+       if (wpa_auth_alg & WPA_AUTH_ALG_SHARED)
+               return NL80211_AUTHTYPE_SHARED_KEY;
+       if (wpa_auth_alg & WPA_AUTH_ALG_LEAP)
+               return NL80211_AUTHTYPE_NETWORK_EAP;
+       if (wpa_auth_alg & WPA_AUTH_ALG_FT)
+               return NL80211_AUTHTYPE_FT;
+       if (wpa_auth_alg & WPA_AUTH_ALG_SAE)
+               return NL80211_AUTHTYPE_SAE;
+       if (wpa_auth_alg & WPA_AUTH_ALG_FILS)
+               return NL80211_AUTHTYPE_FILS_SK;
+       if (wpa_auth_alg & WPA_AUTH_ALG_FILS_SK_PFS)
+               return NL80211_AUTHTYPE_FILS_SK_PFS;
+
+       return NL80211_AUTHTYPE_MAX;
+}
+
+
 static int wpa_driver_nl80211_authenticate(
        struct i802_bss *bss, struct wpa_driver_auth_params *params)
 {
@@ -3207,24 +3333,10 @@ retry:
                            params->auth_data))
                        goto fail;
        }
-       if (params->auth_alg & WPA_AUTH_ALG_OPEN)
-               type = NL80211_AUTHTYPE_OPEN_SYSTEM;
-       else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
-               type = NL80211_AUTHTYPE_SHARED_KEY;
-       else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
-               type = NL80211_AUTHTYPE_NETWORK_EAP;
-       else if (params->auth_alg & WPA_AUTH_ALG_FT)
-               type = NL80211_AUTHTYPE_FT;
-       else if (params->auth_alg & WPA_AUTH_ALG_SAE)
-               type = NL80211_AUTHTYPE_SAE;
-       else if (params->auth_alg & WPA_AUTH_ALG_FILS)
-               type = NL80211_AUTHTYPE_FILS_SK;
-       else if (params->auth_alg & WPA_AUTH_ALG_FILS_SK_PFS)
-               type = NL80211_AUTHTYPE_FILS_SK_PFS;
-       else
-               goto fail;
+       type = get_nl_auth_type(params->auth_alg);
        wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
-       if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
+       if (type == NL80211_AUTHTYPE_MAX ||
+           nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
                goto fail;
        if (params->local_state_change) {
                wpa_printf(MSG_DEBUG, "  * Local state change only");
@@ -3236,11 +3348,11 @@ retry:
        msg = NULL;
        if (ret) {
                wpa_dbg(drv->ctx, MSG_DEBUG,
-                       "nl80211: MLME command failed (auth): ret=%d (%s)",
-                       ret, strerror(-ret));
+                       "nl80211: MLME command failed (auth): count=%d ret=%d (%s)",
+                       count, ret, strerror(-ret));
                count++;
-               if (ret == -EALREADY && count == 1 && params->bssid &&
-                   !params->local_state_change) {
+               if ((ret == -EALREADY || ret == -EEXIST) && count == 1 &&
+                   params->bssid && !params->local_state_change) {
                        /*
                         * mac80211 does not currently accept new
                         * authentication if we are already authenticated. As a
@@ -3920,7 +4032,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                        smps_mode = NL80211_SMPS_OFF;
                        break;
                }
-               if (nla_put_u32(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
+               if (nla_put_u8(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
                        goto fail;
        }
 
@@ -5219,7 +5331,9 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
            params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA256 ||
            params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA384 ||
            params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA256 ||
-           params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384) {
+           params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384 ||
+           params->key_mgmt_suite == WPA_KEY_MGMT_OWE ||
+           params->key_mgmt_suite == WPA_KEY_MGMT_DPP) {
                int mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
 
                switch (params->key_mgmt_suite) {
@@ -5262,6 +5376,12 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
                case WPA_KEY_MGMT_FT_FILS_SHA384:
                        mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
                        break;
+               case WPA_KEY_MGMT_OWE:
+                       mgmt = RSN_AUTH_KEY_MGMT_OWE;
+                       break;
+               case WPA_KEY_MGMT_DPP:
+                       mgmt = RSN_AUTH_KEY_MGMT_DPP;
+                       break;
                case WPA_KEY_MGMT_PSK:
                default:
                        mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
@@ -5272,6 +5392,14 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
                        return -1;
        }
 
+       /* Add PSK in case of 4-way handshake offload */
+       if (params->psk &&
+           (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)) {
+               wpa_hexdump_key(MSG_DEBUG, "  * PSK", params->psk, 32);
+               if (nla_put(msg, NL80211_ATTR_PMK, 32, params->psk))
+                       return -1;
+       }
+
        if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
                return -1;
 
@@ -5283,10 +5411,6 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
             nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
                return -1;
 
-       if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
-           nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
-               return -1;
-
        if (params->rrm_used) {
                u32 drv_rrm_flags = drv->capa.rrm_flags;
                if ((!((drv_rrm_flags &
@@ -5323,13 +5447,19 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
            nl80211_put_fils_connect_params(drv, params, msg) != 0)
                return -1;
 
+       if ((params->auth_alg & WPA_AUTH_ALG_SAE) &&
+           (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
+           nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
+               return -1;
+
        return 0;
 }
 
 
 static int wpa_driver_nl80211_try_connect(
        struct wpa_driver_nl80211_data *drv,
-       struct wpa_driver_associate_params *params)
+       struct wpa_driver_associate_params *params,
+       struct nl_handle *nl_connect)
 {
        struct nl_msg *msg;
        enum nl80211_auth_type type;
@@ -5357,6 +5487,15 @@ static int wpa_driver_nl80211_try_connect(
        if (ret)
                goto fail;
 
+       if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
+           nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
+               goto fail;
+
+       if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_OPTIONAL &&
+           (drv->capa.flags & WPA_DRIVER_FLAGS_MFP_OPTIONAL) &&
+           nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_OPTIONAL))
+               goto fail;
+
        algs = 0;
        if (params->auth_alg & WPA_AUTH_ALG_OPEN)
                algs++;
@@ -5364,27 +5503,20 @@ static int wpa_driver_nl80211_try_connect(
                algs++;
        if (params->auth_alg & WPA_AUTH_ALG_LEAP)
                algs++;
+       if (params->auth_alg & WPA_AUTH_ALG_FILS)
+               algs++;
+       if (params->auth_alg & WPA_AUTH_ALG_FT)
+               algs++;
        if (algs > 1) {
                wpa_printf(MSG_DEBUG, "  * Leave out Auth Type for automatic "
                           "selection");
                goto skip_auth_type;
        }
 
-       if (params->auth_alg & WPA_AUTH_ALG_OPEN)
-               type = NL80211_AUTHTYPE_OPEN_SYSTEM;
-       else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
-               type = NL80211_AUTHTYPE_SHARED_KEY;
-       else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
-               type = NL80211_AUTHTYPE_NETWORK_EAP;
-       else if (params->auth_alg & WPA_AUTH_ALG_FT)
-               type = NL80211_AUTHTYPE_FT;
-       else if (params->auth_alg & WPA_AUTH_ALG_FILS)
-               type = NL80211_AUTHTYPE_FILS_SK;
-       else
-               goto fail;
-
+       type = get_nl_auth_type(params->auth_alg);
        wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
-       if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
+       if (type == NL80211_AUTHTYPE_MAX ||
+           nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
                goto fail;
 
 skip_auth_type:
@@ -5392,7 +5524,11 @@ skip_auth_type:
        if (ret)
                goto fail;
 
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (nl_connect)
+               ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL);
+       else
+               ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+
        msg = NULL;
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
@@ -5411,7 +5547,8 @@ fail:
 
 static int wpa_driver_nl80211_connect(
        struct wpa_driver_nl80211_data *drv,
-       struct wpa_driver_associate_params *params)
+       struct wpa_driver_associate_params *params,
+       struct nl_handle *nl_connect)
 {
        int ret;
 
@@ -5421,7 +5558,7 @@ static int wpa_driver_nl80211_connect(
        else
                os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
 
-       ret = wpa_driver_nl80211_try_connect(drv, params);
+       ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
        if (ret == -EALREADY) {
                /*
                 * cfg80211 does not currently accept new connections if
@@ -5434,7 +5571,7 @@ static int wpa_driver_nl80211_connect(
                if (wpa_driver_nl80211_disconnect(
                            drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
                        return -1;
-               ret = wpa_driver_nl80211_try_connect(drv, params);
+               ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
        }
        return ret;
 }
@@ -5459,10 +5596,13 @@ static int wpa_driver_nl80211_associate(
        if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
                enum nl80211_iftype nlmode = params->p2p ?
                        NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
+               struct nl_handle *nl_connect = NULL;
 
                if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
                        return -1;
-               return wpa_driver_nl80211_connect(drv, params);
+               if (params->auth_alg & WPA_AUTH_ALG_SAE)
+                       nl_connect = bss->nl_connect;
+               return wpa_driver_nl80211_connect(drv, params, nl_connect);
        }
 
        nl80211_mark_disconnected(drv);
@@ -5477,6 +5617,10 @@ static int wpa_driver_nl80211_associate(
        if (ret)
                goto fail;
 
+       if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
+           nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
+               goto fail;
+
        if (params->fils_kek) {
                wpa_printf(MSG_DEBUG, "  * FILS KEK (len=%u)",
                           (unsigned int) params->fils_kek_len);
@@ -5909,6 +6053,17 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
                [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
                [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
                [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
+               [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
+               [NL80211_STA_INFO_ACK_SIGNAL] = { .type = NLA_U8 },
+       };
+       struct nlattr *rate[NL80211_RATE_INFO_MAX + 1];
+       static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
+               [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
+               [NL80211_RATE_INFO_BITRATE32] = { .type = NLA_U32 },
+               [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
+               [NL80211_RATE_INFO_VHT_MCS] = { .type = NLA_U8 },
+               [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
+               [NL80211_RATE_INFO_VHT_NSS] = { .type = NLA_U8 },
        };
 
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
@@ -5960,6 +6115,72 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
        if (stats[NL80211_STA_INFO_TX_FAILED])
                data->tx_retry_failed =
                        nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
+       if (stats[NL80211_STA_INFO_SIGNAL])
+               data->signal = nla_get_u8(stats[NL80211_STA_INFO_SIGNAL]);
+       if (stats[NL80211_STA_INFO_ACK_SIGNAL]) {
+               data->last_ack_rssi =
+                       nla_get_u8(stats[NL80211_STA_INFO_ACK_SIGNAL]);
+               data->flags |= STA_DRV_DATA_LAST_ACK_RSSI;
+       }
+
+       if (stats[NL80211_STA_INFO_TX_BITRATE] &&
+           nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
+                            stats[NL80211_STA_INFO_TX_BITRATE],
+                            rate_policy) == 0) {
+               if (rate[NL80211_RATE_INFO_BITRATE32])
+                       data->current_tx_rate =
+                               nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
+               else if (rate[NL80211_RATE_INFO_BITRATE])
+                       data->current_tx_rate =
+                               nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
+
+               if (rate[NL80211_RATE_INFO_MCS]) {
+                       data->tx_mcs = nla_get_u8(rate[NL80211_RATE_INFO_MCS]);
+                       data->flags |= STA_DRV_DATA_TX_MCS;
+               }
+               if (rate[NL80211_RATE_INFO_VHT_MCS]) {
+                       data->tx_vhtmcs =
+                               nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
+                       data->flags |= STA_DRV_DATA_TX_VHT_MCS;
+               }
+               if (rate[NL80211_RATE_INFO_SHORT_GI])
+                       data->flags |= STA_DRV_DATA_TX_SHORT_GI;
+               if (rate[NL80211_RATE_INFO_VHT_NSS]) {
+                       data->tx_vht_nss =
+                               nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
+                       data->flags |= STA_DRV_DATA_TX_VHT_NSS;
+               }
+       }
+
+       if (stats[NL80211_STA_INFO_RX_BITRATE] &&
+           nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
+                            stats[NL80211_STA_INFO_RX_BITRATE],
+                            rate_policy) == 0) {
+               if (rate[NL80211_RATE_INFO_BITRATE32])
+                       data->current_rx_rate =
+                               nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
+               else if (rate[NL80211_RATE_INFO_BITRATE])
+                       data->current_rx_rate =
+                               nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
+
+               if (rate[NL80211_RATE_INFO_MCS]) {
+                       data->rx_mcs =
+                               nla_get_u8(rate[NL80211_RATE_INFO_MCS]);
+                       data->flags |= STA_DRV_DATA_RX_MCS;
+               }
+               if (rate[NL80211_RATE_INFO_VHT_MCS]) {
+                       data->rx_vhtmcs =
+                               nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
+                       data->flags |= STA_DRV_DATA_RX_VHT_MCS;
+               }
+               if (rate[NL80211_RATE_INFO_SHORT_GI])
+                       data->flags |= STA_DRV_DATA_RX_SHORT_GI;
+               if (rate[NL80211_RATE_INFO_VHT_NSS]) {
+                       data->rx_vht_nss =
+                               nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
+                       data->flags |= STA_DRV_DATA_RX_VHT_NSS;
+               }
+       }
 
        return NL_SKIP;
 }
@@ -6290,6 +6511,7 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        char name[IFNAMSIZ + 1];
+       union wpa_event_data event;
 
        os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
        if (ifname_wds)
@@ -6308,6 +6530,14 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
                            linux_br_add_if(drv->global->ioctl_sock,
                                            bridge_ifname, name) < 0)
                                return -1;
+
+                       os_memset(&event, 0, sizeof(event));
+                       event.wds_sta_interface.sta_addr = addr;
+                       event.wds_sta_interface.ifname = name;
+                       event.wds_sta_interface.istatus = INTERFACE_ADDED;
+                       wpa_supplicant_event(drv->ctx,
+                                            EVENT_WDS_STA_INTERFACE_STATUS,
+                                            &event);
                }
                if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
                        wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
@@ -6321,6 +6551,12 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
 
                i802_set_sta_vlan(priv, addr, bss->ifname, 0);
                nl80211_remove_iface(drv, if_nametoindex(name));
+               os_memset(&event, 0, sizeof(event));
+               event.wds_sta_interface.sta_addr = addr;
+               event.wds_sta_interface.ifname = name;
+               event.wds_sta_interface.istatus = INTERFACE_REMOVED;
+               wpa_supplicant_event(drv->ctx, EVENT_WDS_STA_INTERFACE_STATUS,
+                                    &event);
                return 0;
        }
 }
@@ -6384,7 +6620,7 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
                        wpa_printf(MSG_ERROR, "nl80211: Failed to "
                                   "remove interface %s from bridge "
                                   "%s: %s",
-                                  ifname, brname, strerror(errno));
+                                  ifname, in_br, strerror(errno));
                        return -1;
                }
        }
@@ -7101,7 +7337,7 @@ static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
                } else if (bss->nl_preq) {
                        wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
                                   "reporting nl_preq=%p", bss->nl_preq);
-                       nl80211_destroy_eloop_handle(&bss->nl_preq);
+                       nl80211_destroy_eloop_handle(&bss->nl_preq, 0);
                }
                return 0;
        }
@@ -7126,7 +7362,7 @@ static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
 
        nl80211_register_eloop_read(&bss->nl_preq,
                                    wpa_driver_nl80211_event_receive,
-                                   bss->nl_cb);
+                                   bss->nl_cb, 0);
 
        return 0;
 
@@ -7441,7 +7677,7 @@ static void nl80211_global_deinit(void *priv)
        nl_destroy_handles(&global->nl);
 
        if (global->nl_event)
-               nl80211_destroy_eloop_handle(&global->nl_event);
+               nl80211_destroy_eloop_handle(&global->nl_event, 0);
 
        nl_cb_put(global->nl_cb);
 
@@ -7464,6 +7700,7 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd,
                         struct wpa_pmkid_params *params)
 {
        struct nl_msg *msg;
+       const size_t PMK_MAX_LEN = 48; /* current cfg80211 limit */
 
        if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
            (params->pmkid &&
@@ -7475,7 +7712,7 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd,
            (params->fils_cache_id &&
             nla_put(msg, NL80211_ATTR_FILS_CACHE_ID, 2,
                     params->fils_cache_id)) ||
-           (params->pmk_len &&
+           (params->pmk_len && params->pmk_len <= PMK_MAX_LEN &&
             nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) {
                nlmsg_free(msg);
                return -ENOBUFS;
@@ -7488,6 +7725,7 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd,
 static int nl80211_add_pmkid(void *priv, struct wpa_pmkid_params *params)
 {
        struct i802_bss *bss = priv;
+       int ret;
 
        if (params->bssid)
                wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR,
@@ -7499,13 +7737,21 @@ static int nl80211_add_pmkid(void *priv, struct wpa_pmkid_params *params)
                           wpa_ssid_txt(params->ssid, params->ssid_len));
        }
 
-       return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params);
+       ret = nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params);
+       if (ret < 0) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: NL80211_CMD_SET_PMKSA failed: %d (%s)",
+                          ret, strerror(-ret));
+       }
+
+       return ret;
 }
 
 
 static int nl80211_remove_pmkid(void *priv, struct wpa_pmkid_params *params)
 {
        struct i802_bss *bss = priv;
+       int ret;
 
        if (params->bssid)
                wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
@@ -7517,7 +7763,14 @@ static int nl80211_remove_pmkid(void *priv, struct wpa_pmkid_params *params)
                           wpa_ssid_txt(params->ssid, params->ssid_len));
        }
 
-       return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, params);
+       ret = nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, params);
+       if (ret < 0) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: NL80211_CMD_DEL_PMKSA failed: %d (%s)",
+                          ret, strerror(-ret));
+       }
+
+       return ret;
 }
 
 
@@ -7725,7 +7978,7 @@ static void nl80211_set_rekey_info(void *priv, const u8 *kek, size_t kek_len,
        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, kek_len, kek) ||
-           nla_put(msg, NL80211_REKEY_DATA_KCK, kck_len, kck) ||
+           (kck_len && nla_put(msg, NL80211_REKEY_DATA_KCK, kck_len, kck)) ||
            nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
                    replay_ctr)) {
                nl80211_nlmsg_clear(msg);
@@ -7813,6 +8066,7 @@ static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
 static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
 {
        struct nl_msg *msg;
+       int ret;
 
        if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_POWER_SAVE)) ||
            nla_put_u32(msg, NL80211_ATTR_PS_STATE,
@@ -7820,7 +8074,15 @@ static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
                nlmsg_free(msg);
                return -ENOBUFS;
        }
-       return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+
+       ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+       if (ret < 0) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Setting PS state %s failed: %d (%s)",
+                          enabled ? "enabled" : "disabled",
+                          ret, strerror(-ret));
+       }
+       return ret;
 }
 
 
@@ -8784,6 +9046,95 @@ static int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
 
        return send_and_recv_msgs(drv, msg, NULL, NULL);
 }
+
+
+static int nl80211_disable_fils(void *priv, int disable)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       struct nlattr *params;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Disable FILS=%d", disable);
+
+       if (!drv->set_wifi_conf_vendor_cmd_avail)
+               return -1;
+
+       if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+           nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+           nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+                       QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION) ||
+           !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+           nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS,
+                      disable)) {
+               nlmsg_free(msg);
+               return -1;
+       }
+       nla_nest_end(msg, params);
+
+       return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
+
+/* Reserved QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID value for wpa_supplicant */
+#define WPA_SUPPLICANT_CLIENT_ID 1
+
+static int nl80211_set_bssid_blacklist(void *priv, unsigned int num_bssid,
+                                      const u8 *bssid)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       struct nlattr *params, *nlbssids, *attr;
+       unsigned int i;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Set blacklist BSSID (num=%u)",
+                  num_bssid);
+
+       if (!drv->roam_vendor_cmd_avail)
+               return -1;
+
+       if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+           nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+           nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+                       QCA_NL80211_VENDOR_SUBCMD_ROAM) ||
+           !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+           nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD,
+                       QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID) ||
+           nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID,
+                       WPA_SUPPLICANT_CLIENT_ID) ||
+           nla_put_u32(msg,
+                       QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID,
+                       num_bssid))
+               goto fail;
+
+       nlbssids = nla_nest_start(
+               msg, QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS);
+       if (!nlbssids)
+               goto fail;
+
+       for (i = 0; i < num_bssid; i++) {
+               attr = nla_nest_start(msg, i);
+               if (!attr)
+                       goto fail;
+               if (nla_put(msg,
+                           QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID,
+                           ETH_ALEN, &bssid[i * ETH_ALEN]))
+                       goto fail;
+               wpa_printf(MSG_DEBUG, "nl80211:   BSSID[%u]: " MACSTR, i,
+                          MAC2STR(&bssid[i * ETH_ALEN]));
+               nla_nest_end(msg, attr);
+       }
+       nla_nest_end(msg, nlbssids);
+       nla_nest_end(msg, params);
+
+       return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+fail:
+       nlmsg_free(msg);
+       return -1;
+}
+
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
 
@@ -8866,11 +9217,14 @@ static int nl80211_put_mesh_config(struct nl_msg *msg,
                return -1;
 
        if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
-            nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
-                        params->auto_plinks)) ||
+            nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+                       params->auto_plinks)) ||
            ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) &&
             nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
-                        params->max_peer_links)))
+                        params->max_peer_links)) ||
+           ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD) &&
+            nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
+                        params->rssi_threshold)))
                return -1;
 
        /*
@@ -9949,6 +10303,56 @@ fail:
        return NULL;
 }
 
+
+/**
+ * nl80211_ignore_assoc_disallow - Configure driver to ignore assoc_disallow
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @ignore_assoc_disallow: 0 to not ignore, 1 to ignore
+ * Returns: 0 on success, -1 on failure
+ */
+static int nl80211_ignore_assoc_disallow(void *priv, int ignore_disallow)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       struct nlattr *attr;
+       int ret = -1;
+
+       if (!drv->set_wifi_conf_vendor_cmd_avail)
+               return -1;
+
+       if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+           nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+           nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+                       QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION))
+               goto fail;
+
+       attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+       if (!attr)
+               goto fail;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Set ignore_assoc_disallow %d",
+                  ignore_disallow);
+       if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED,
+                      ignore_disallow))
+               goto fail;
+
+       nla_nest_end(msg, attr);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+       if (ret) {
+               wpa_printf(MSG_ERROR,
+                          "nl80211: Set ignore_assoc_disallow failed: ret=%d (%s)",
+                          ret, strerror(-ret));
+               goto fail;
+       }
+
+fail:
+       nlmsg_free(msg);
+       return ret;
+}
+
 #endif /* CONFIG_MBO */
 
 #endif /* CONFIG_DRIVER_NL80211_QCA */
@@ -10078,6 +10482,88 @@ static int nl80211_get_ext_capab(void *priv, enum wpa_driver_if_type type,
 }
 
 
+static int nl80211_update_connection_params(
+       void *priv, struct wpa_driver_associate_params *params,
+       enum wpa_drv_update_connect_params_mask mask)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret = -1;
+       enum nl80211_auth_type type;
+
+       msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_CONNECT_PARAMS);
+       if (!msg)
+               goto fail;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Update connection params (ifindex=%d)",
+                  drv->ifindex);
+
+       if ((mask & WPA_DRV_UPDATE_ASSOC_IES) && params->wpa_ie) {
+               if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
+                           params->wpa_ie))
+                       goto fail;
+               wpa_hexdump(MSG_DEBUG, "  * IEs", params->wpa_ie,
+                           params->wpa_ie_len);
+       }
+
+       if (mask & WPA_DRV_UPDATE_AUTH_TYPE) {
+               type = get_nl_auth_type(params->auth_alg);
+               if (type == NL80211_AUTHTYPE_MAX ||
+                   nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
+                       goto fail;
+               wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
+       }
+
+       if ((mask & WPA_DRV_UPDATE_FILS_ERP_INFO) &&
+           nl80211_put_fils_connect_params(drv, params, msg))
+               goto fail;
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+       if (ret)
+               wpa_dbg(drv->ctx, MSG_DEBUG,
+                       "nl80211: Update connect params command failed: ret=%d (%s)",
+                       ret, strerror(-ret));
+
+fail:
+       nlmsg_free(msg);
+       return ret;
+}
+
+
+static int nl80211_send_external_auth_status(void *priv,
+                                            struct external_auth *params)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg = NULL;
+       int ret = -1;
+
+       wpa_dbg(drv->ctx, MSG_DEBUG,
+               "nl80211: External auth status: %u", params->status);
+
+       msg = nl80211_drv_msg(drv, 0, NL80211_CMD_EXTERNAL_AUTH);
+       if (!msg ||
+           nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, params->status) ||
+           nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
+                   params->ssid) ||
+           nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid))
+               goto fail;
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+       if (ret) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: External Auth status update failed: ret=%d (%s)",
+                          ret, strerror(-ret));
+               goto fail;
+       }
+fail:
+       nlmsg_free(msg);
+       return ret;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
@@ -10187,6 +10673,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .get_ifindex = nl80211_get_ifindex,
 #ifdef CONFIG_DRIVER_NL80211_QCA
        .roaming = nl80211_roaming,
+       .disable_fils = nl80211_disable_fils,
        .do_acs = wpa_driver_do_acs,
        .set_band = nl80211_set_band,
        .get_pref_freq_list = nl80211_get_pref_freq_list,
@@ -10197,8 +10684,12 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .set_tdls_mode = nl80211_set_tdls_mode,
 #ifdef CONFIG_MBO
        .get_bss_transition_status = nl80211_get_bss_transition_status,
+       .ignore_assoc_disallow = nl80211_ignore_assoc_disallow,
 #endif /* CONFIG_MBO */
+       .set_bssid_blacklist = nl80211_set_bssid_blacklist,
 #endif /* CONFIG_DRIVER_NL80211_QCA */
        .configure_data_frame_filters = nl80211_configure_data_frame_filters,
        .get_ext_capab = nl80211_get_ext_capab,
+       .update_connect_params = nl80211_update_connection_params,
+       .send_external_auth_status = nl80211_send_external_auth_status,
 };