]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/drivers/driver_nl80211.c
nl80211: Missing sysctl flags aren't fatal
[thirdparty/hostap.git] / src / drivers / driver_nl80211.c
index 6ecb810d623be141e77a4948b5c7fb6b8b2f5d89..7ed1878ad93b973afaa30c8d3b7b327ee668af48 100644 (file)
 #include "driver_nl80211.h"
 
 
+#ifndef NETLINK_CAP_ACK
+#define NETLINK_CAP_ACK 10
+#endif /* NETLINK_CAP_ACK */
+/* support for extack if compilation headers are too old */
+#ifndef NETLINK_EXT_ACK
+#define NETLINK_EXT_ACK 11
+enum nlmsgerr_attrs {
+       NLMSGERR_ATTR_UNUSED,
+       NLMSGERR_ATTR_MSG,
+       NLMSGERR_ATTR_OFFS,
+       NLMSGERR_ATTR_COOKIE,
+
+       __NLMSGERR_ATTR_MAX,
+       NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
+};
+#endif
+#ifndef NLM_F_CAPPED
+#define NLM_F_CAPPED 0x100
+#endif
+#ifndef NLM_F_ACK_TLVS
+#define NLM_F_ACK_TLVS 0x200
+#endif
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
+
 #ifndef CONFIG_LIBNL20
 /*
  * libnl 1.1 has a bug, it tries to allocate socket numbers densely
@@ -130,7 +156,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 +177,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);
 }
@@ -206,7 +236,7 @@ static int nl80211_put_mesh_config(struct nl_msg *msg,
                                   struct wpa_driver_mesh_bss_params *params);
 #endif /* CONFIG_MESH */
 static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
-                            int reason);
+                            u16 reason);
 
 
 /* Converts nl80211_chan_width to a common format */
@@ -277,6 +307,7 @@ void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
                os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
        drv->associated = 0;
        os_memset(drv->bssid, 0, ETH_ALEN);
+       drv->first_bss->freq = 0;
 }
 
 
@@ -298,8 +329,35 @@ static int finish_handler(struct nl_msg *msg, void *arg)
 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
                         void *arg)
 {
+       struct nlmsghdr *nlh = (struct nlmsghdr *) err - 1;
+       int len = nlh->nlmsg_len;
+       struct nlattr *attrs;
+       struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
        int *ret = arg;
+       int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh);
+
        *ret = err->error;
+
+       if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
+               return NL_SKIP;
+
+       if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
+               ack_len += err->msg.nlmsg_len - sizeof(*nlh);
+
+       if (len <= ack_len)
+               return NL_STOP;
+
+       attrs = (void *) ((unsigned char *) nlh + ack_len);
+       len -= ack_len;
+
+       nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, len, NULL);
+       if (tb[NLMSGERR_ATTR_MSG]) {
+               len = strnlen((char *) nla_data(tb[NLMSGERR_ATTR_MSG]),
+                             nla_len(tb[NLMSGERR_ATTR_MSG]));
+               wpa_printf(MSG_ERROR, "nl80211: kernel reports: %*s",
+                          len, (char *) nla_data(tb[NLMSGERR_ATTR_MSG]));
+       }
+
        return NL_SKIP;
 }
 
@@ -338,7 +396,7 @@ static int send_and_recv(struct nl80211_global *global,
                         void *valid_data)
 {
        struct nl_cb *cb;
-       int err = -ENOMEM;
+       int err = -ENOMEM, opt;
 
        if (!msg)
                return -ENOMEM;
@@ -347,6 +405,16 @@ static int send_and_recv(struct nl80211_global *global,
        if (!cb)
                goto out;
 
+       /* try to set NETLINK_EXT_ACK to 1, ignoring errors */
+       opt = 1;
+       setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
+                  NETLINK_EXT_ACK, &opt, sizeof(opt));
+
+       /* try to set NETLINK_CAP_ACK to 1, ignoring errors */
+       opt = 1;
+       setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
+                  NETLINK_CAP_ACK, &opt, sizeof(opt));
+
        err = nl_send_auto_complete(nl_handle, msg);
        if (err < 0)
                goto out;
@@ -723,7 +791,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 +840,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 +979,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 +989,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 +1053,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 +1098,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 +1111,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,18 +1136,27 @@ 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;
                }
        }
 
        if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
+               namebuf[0] = '\0';
                if (if_indextoname(ifi->ifi_index, namebuf) &&
                    linux_iface_up(drv->global->ioctl_sock, namebuf) == 0) {
                        wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
                                   "event since interface %s is down",
                                   namebuf);
+                       return;
+               }
+               wpa_printf(MSG_DEBUG, "nl80211: Interface up (%s/%s)",
+                          namebuf, ifname);
+               if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Not the main interface (%s) - do not indicate interface up",
+                                  drv->first_bss->ifname);
                } else if (if_nametoindex(drv->first_bss->ifname) == 0) {
                        wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
                                   "event since interface %s does not exist",
@@ -1044,29 +1166,9 @@ 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;
                        wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
                                             NULL);
@@ -1168,7 +1270,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 */
@@ -1376,7 +1478,7 @@ int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
 {
        struct nl_msg *msg;
 
-       sig->current_signal = -9999;
+       sig->current_signal = -WPA_INVALID_NOISE;
        sig->current_txrate = 0;
 
        if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) ||
@@ -1438,7 +1540,7 @@ int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
 {
        struct nl_msg *msg;
 
-       sig_change->current_noise = 9999;
+       sig_change->current_noise = WPA_INVALID_NOISE;
        sig_change->frequency = drv->assoc_freq;
 
        msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
@@ -1446,6 +1548,70 @@ int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static int get_channel_info(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb[NL80211_ATTR_MAX + 1] = { 0 };
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct wpa_channel_info *chan_info = arg;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       os_memset(chan_info, 0, sizeof(struct wpa_channel_info));
+       chan_info->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+       if (tb[NL80211_ATTR_WIPHY_FREQ])
+               chan_info->frequency =
+                       nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+       if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+               chan_info->chanwidth = convert2width(
+                       nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
+       if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+               enum nl80211_channel_type ct =
+                       nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+
+               switch (ct) {
+               case NL80211_CHAN_HT40MINUS:
+                       chan_info->sec_channel = -1;
+                       break;
+               case NL80211_CHAN_HT40PLUS:
+                       chan_info->sec_channel = 1;
+                       break;
+               default:
+                       chan_info->sec_channel = 0;
+                       break;
+               }
+       }
+       if (tb[NL80211_ATTR_CENTER_FREQ1])
+               chan_info->center_frq1 =
+                       nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+       if (tb[NL80211_ATTR_CENTER_FREQ2])
+               chan_info->center_frq2 =
+                       nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+
+       if (chan_info->center_frq2) {
+               u8 seg1_idx = 0;
+
+               if (ieee80211_freq_to_chan(chan_info->center_frq2, &seg1_idx) !=
+                   NUM_HOSTAPD_MODES)
+                       chan_info->seg1_idx = seg1_idx;
+       }
+
+       return NL_SKIP;
+}
+
+
+static int nl80211_channel_info(void *priv, struct wpa_channel_info *ci)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+
+       msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
+       return send_and_recv_msgs(drv, msg, get_channel_info, ci);
+}
+
+
 static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
                                             void *handle)
 {
@@ -1608,7 +1774,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;
 
@@ -1844,9 +2010,8 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
         */
        drv->set_rekey_offload = 1;
 
-       drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
+       drv->num_if_indices = ARRAY_SIZE(drv->default_if_indices);
        drv->if_indices = drv->default_if_indices;
-       drv->if_indices_reason = drv->default_if_indices_reason;
 
        drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
        if (!drv->first_bss) {
@@ -1974,7 +2139,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 +2152,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 +2181,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 +2195,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 +2220,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,7 +2233,19 @@ 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
+#ifdef CONFIG_OCV
+       /* SA Query Request */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x08\x00", 2) < 0)
+               ret = -1;
+#endif /* CONFIG_OCV */
        /* SA Query Response */
        if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
                ret = -1;
@@ -2079,6 +2277,11 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
        /* WNM-Sleep Mode Response */
        if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
                ret = -1;
+#ifdef CONFIG_WNM
+       /* WNM - Collocated Interference Request */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x0b", 2) < 0)
+               ret = -1;
+#endif /* CONFIG_WNM */
 
 #ifdef CONFIG_HS20
        /* WNM-Notification */
@@ -2266,6 +2469,16 @@ static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
        if (nl80211_action_subscribe_ap(bss))
                goto out_err;
 
+       if (bss->drv->device_ap_sme) {
+               u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
+
+               /* Register for all Authentication frames */
+               if (nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0)
+                   < 0)
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Failed to subscribe to handle Authentication frames - SAE offload may not work");
+       }
+
        nl80211_mgmt_handle_register_eloop(bss);
        return 0;
 
@@ -2281,7 +2494,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 +2710,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;
 }
 
@@ -2543,9 +2758,11 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
                        wpa_printf(MSG_INFO, "nl80211: Failed to remove "
                                   "interface %s from bridge %s: %s",
                                   bss->ifname, bss->brname, strerror(errno));
-               if (drv->rtnl_sk)
-                       nl80211_handle_destroy(drv->rtnl_sk);
        }
+
+       if (drv->rtnl_sk)
+               nl80211_handle_destroy(drv->rtnl_sk);
+
        if (bss->added_bridge) {
                if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
                                          0) < 0)
@@ -2571,9 +2788,6 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
        if (drv->if_indices != drv->default_if_indices)
                os_free(drv->if_indices);
 
-       if (drv->if_indices_reason != drv->default_if_indices_reason)
-               os_free(drv->if_indices_reason);
-
        if (drv->disabled_11b_rates)
                nl80211_disable_11b_rates(drv, drv->ifindex, 0);
 
@@ -2610,6 +2824,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 +2969,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 +3045,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_8021X))
+               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)
@@ -2990,7 +3249,8 @@ static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
 
 int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
                            const u8 *addr, int cmd, u16 reason_code,
-                           int local_state_change)
+                           int local_state_change,
+                           struct nl_handle *nl_connect)
 {
        int ret;
        struct nl_msg *msg;
@@ -3004,7 +3264,10 @@ int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
                return -1;
        }
 
-       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);
        if (ret) {
                wpa_dbg(drv->ctx, MSG_DEBUG,
                        "nl80211: MLME command failed: reason=%u ret=%d (%s)",
@@ -3015,47 +3278,57 @@ int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
 
 
 static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
-                                        int reason_code)
+                                        u16 reason_code,
+                                        struct nl_handle *nl_connect)
 {
        int ret;
+       int drv_associated = drv->associated;
 
        wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
        nl80211_mark_disconnected(drv);
        /* Disconnect command doesn't need BSSID - it uses cached value */
        ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
-                                     reason_code, 0);
+                                     reason_code, 0, nl_connect);
        /*
         * For locally generated disconnect, supplicant already generates a
         * DEAUTH event, so ignore the event from NL80211.
         */
-       drv->ignore_next_local_disconnect = ret == 0;
+       drv->ignore_next_local_disconnect = drv_associated && (ret == 0);
 
        return ret;
 }
 
 
 static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
-                                            const u8 *addr, int reason_code)
+                                            const u8 *addr, u16 reason_code)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ret;
+       int drv_associated = drv->associated;
 
        if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
                nl80211_mark_disconnected(drv);
                return nl80211_leave_ibss(drv, 1);
        }
-       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
-               return wpa_driver_nl80211_disconnect(drv, reason_code);
+       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+               struct nl_handle *nl_connect = NULL;
+
+               if (bss->use_nl_connect)
+                       nl_connect = bss->nl_connect;
+               return wpa_driver_nl80211_disconnect(drv, reason_code,
+                                                    nl_connect);
+       }
        wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
                   __func__, MAC2STR(addr), reason_code);
        nl80211_mark_disconnected(drv);
        ret = wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
-                                     reason_code, 0);
+                                     reason_code, 0, NULL);
        /*
         * For locally generated deauthenticate, supplicant already generates a
         * DEAUTH event, so ignore the event from NL80211.
         */
-       drv->ignore_next_local_deauth = ret == 0;
+       drv->ignore_next_local_deauth = drv_associated && (ret == 0);
+
        return ret;
 }
 
@@ -3125,6 +3398,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)
 {
@@ -3190,8 +3484,8 @@ retry:
                        goto fail;
        }
        if (params->ssid) {
-               wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
-                                 params->ssid, params->ssid_len);
+               wpa_printf(MSG_DEBUG, "  * SSID=%s",
+                          wpa_ssid_txt(params->ssid, params->ssid_len));
                if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
                            params->ssid))
                        goto fail;
@@ -3207,24 +3501,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 +3516,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
@@ -3772,7 +4052,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        u8 cmd = NL80211_CMD_NEW_BEACON;
-       int ret;
+       int ret = -ENOBUFS;
        int beacon_set;
        int num_suites;
        int smps_mode;
@@ -3801,8 +4081,8 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        wpa_printf(MSG_DEBUG, "nl80211: beacon_rate=%u", params->beacon_rate);
        wpa_printf(MSG_DEBUG, "nl80211: rate_type=%d", params->rate_type);
        wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
-       wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
-                         params->ssid, params->ssid_len);
+       wpa_printf(MSG_DEBUG, "nl80211: ssid=%s",
+                  wpa_ssid_txt(params->ssid, params->ssid_len));
        if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
            nla_put(msg, NL80211_ATTR_BEACON_HEAD, params->head_len,
                    params->head) ||
@@ -3887,6 +4167,11 @@ static int wpa_driver_nl80211_set_ap(void *priv,
             nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
                goto fail;
 
+       if (drv->device_ap_sme &&
+           (params->key_mgmt_suites & WPA_KEY_MGMT_SAE) &&
+           nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
+               goto fail;
+
        wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
                   params->pairwise_ciphers);
        num_suites = wpa_cipher_to_cipher_suites(params->pairwise_ciphers,
@@ -3920,7 +4205,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;
        }
 
@@ -3978,6 +4263,29 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                        goto fail;
        }
 
+       if (params->ftm_responder) {
+               struct nlattr *ftm;
+
+               if (!(drv->capa.flags & WPA_DRIVER_FLAGS_FTM_RESPONDER)) {
+                       ret = -ENOTSUP;
+                       goto fail;
+               }
+
+               ftm = nla_nest_start(msg, NL80211_ATTR_FTM_RESPONDER);
+               if (!ftm ||
+                   nla_put_flag(msg, NL80211_FTM_RESP_ATTR_ENABLED) ||
+                   (params->lci &&
+                    nla_put(msg, NL80211_FTM_RESP_ATTR_LCI,
+                            wpabuf_len(params->lci),
+                            wpabuf_head(params->lci))) ||
+                   (params->civic &&
+                    nla_put(msg, NL80211_FTM_RESP_ATTR_CIVICLOC,
+                            wpabuf_len(params->civic),
+                            wpabuf_head(params->civic))))
+                       goto fail;
+               nla_nest_end(msg, ftm);
+       }
+
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
@@ -4029,7 +4337,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        return ret;
 fail:
        nlmsg_free(msg);
-       return -ENOBUFS;
+       return ret;
 }
 
 
@@ -4040,10 +4348,11 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
        if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
                return -ENOBUFS;
 
+       wpa_printf(MSG_DEBUG, "  * he_enabled=%d", freq->he_enabled);
        wpa_printf(MSG_DEBUG, "  * vht_enabled=%d", freq->vht_enabled);
        wpa_printf(MSG_DEBUG, "  * ht_enabled=%d", freq->ht_enabled);
 
-       if (freq->vht_enabled) {
+       if (freq->vht_enabled || freq->he_enabled) {
                enum nl80211_chan_width cw;
 
                wpa_printf(MSG_DEBUG, "  * bandwidth=%d", freq->bandwidth);
@@ -4118,8 +4427,8 @@ static int nl80211_set_channel(struct i802_bss *bss,
        int ret;
 
        wpa_printf(MSG_DEBUG,
-                  "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
-                  freq->freq, freq->ht_enabled, freq->vht_enabled,
+                  "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
+                  freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
                   freq->bandwidth, freq->center_freq1, freq->center_freq2);
 
        msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
@@ -4251,6 +4560,14 @@ static int wpa_driver_nl80211_sta_add(void *priv,
                                goto fail;
                }
 
+               if (params->he_capab) {
+                       wpa_hexdump(MSG_DEBUG, "  * he_capab",
+                                   params->he_capab, params->he_capab_len);
+                       if (nla_put(msg, NL80211_ATTR_HE_CAPABILITY,
+                                   params->he_capab_len, params->he_capab))
+                               goto fail;
+               }
+
                if (params->ext_capab) {
                        wpa_hexdump(MSG_DEBUG, "  * ext_capab",
                                    params->ext_capab, params->ext_capab_len);
@@ -4383,7 +4700,9 @@ static int wpa_driver_nl80211_sta_add(void *priv,
                goto fail;
 #endif /* CONFIG_MESH */
 
-       if (params->flags & WPA_STA_WMM) {
+       if ((!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
+            FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) &&
+            (params->flags & WPA_STA_WMM)) {
                struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
 
                wpa_printf(MSG_DEBUG, "  * qosinfo=0x%x", params->qosinfo);
@@ -4874,6 +5193,28 @@ fail:
 }
 
 
+static int driver_nl80211_sta_set_airtime_weight(void *priv, const u8 *addr,
+                                                unsigned int weight)
+{
+       struct i802_bss *bss = priv;
+       struct nl_msg *msg;
+
+       wpa_printf(MSG_DEBUG,
+                  "nl80211: Set STA airtime weight - ifname=%s addr=" MACSTR
+                  " weight=%u", bss->ifname, MAC2STR(addr), weight);
+
+       if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
+           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+           nla_put_u16(msg, NL80211_ATTR_AIRTIME_WEIGHT, weight))
+               goto fail;
+
+       return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+fail:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+
 static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
                                 struct wpa_driver_associate_params *params)
 {
@@ -4993,8 +5334,8 @@ retry:
            params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
                goto fail;
 
-       wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
-                         params->ssid, params->ssid_len);
+       wpa_printf(MSG_DEBUG, "  * SSID=%s",
+                  wpa_ssid_txt(params->ssid, params->ssid_len));
        if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
                goto fail;
        os_memcpy(drv->ssid, params->ssid, params->ssid_len);
@@ -5155,8 +5496,8 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
        }
 
        if (params->ssid) {
-               wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
-                                 params->ssid, params->ssid_len);
+               wpa_printf(MSG_DEBUG, "  * SSID=%s",
+                          wpa_ssid_txt(params->ssid, params->ssid_len));
                if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
                            params->ssid))
                        return -1;
@@ -5214,12 +5555,17 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
            params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
            params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
            params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
+           params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+           params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE ||
            params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
            params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ||
+           params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 ||
            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) {
@@ -5244,12 +5590,21 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
                case WPA_KEY_MGMT_OSEN:
                        mgmt = RSN_AUTH_KEY_MGMT_OSEN;
                        break;
+               case WPA_KEY_MGMT_SAE:
+                       mgmt = RSN_AUTH_KEY_MGMT_SAE;
+                       break;
+               case WPA_KEY_MGMT_FT_SAE:
+                       mgmt = RSN_AUTH_KEY_MGMT_FT_SAE;
+                       break;
                case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
                        mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
                        break;
                case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
                        mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
                        break;
+               case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+                       mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
+                       break;
                case WPA_KEY_MGMT_FILS_SHA256:
                        mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA256;
                        break;
@@ -5262,6 +5617,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 +5633,21 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
                        return -1;
        }
 
+       if (params->req_key_mgmt_offload &&
+           (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)) {
+                   wpa_printf(MSG_DEBUG, "  * WANT_1X_4WAY_HS");
+                   if (nla_put_flag(msg, NL80211_ATTR_WANT_1X_4WAY_HS))
+                           return -1;
+           }
+
+       /* Add PSK in case of 4-way handshake offload */
+       if (params->psk &&
+           (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) {
+               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 +5659,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 +5695,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 +5735,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 +5751,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 +5772,12 @@ 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, (void *) -1);
+       else
+               ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+
        msg = NULL;
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
@@ -5403,6 +5788,7 @@ skip_auth_type:
        }
 
 fail:
+       nl80211_nlmsg_clear(msg);
        nlmsg_free(msg);
        return ret;
 
@@ -5411,7 +5797,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 +5808,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
@@ -5432,9 +5819,9 @@ static int wpa_driver_nl80211_connect(
                           "disconnecting before reassociation "
                           "attempt");
                if (wpa_driver_nl80211_disconnect(
-                           drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
+                           drv, WLAN_REASON_PREV_AUTH_NOT_VALID, nl_connect))
                        return -1;
-               ret = wpa_driver_nl80211_try_connect(drv, params);
+               ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
        }
        return ret;
 }
@@ -5459,10 +5846,18 @@ 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;
+                       bss->use_nl_connect = 1;
+               } else {
+                       bss->use_nl_connect = 0;
+               }
+
+               return wpa_driver_nl80211_connect(drv, params, nl_connect);
        }
 
        nl80211_mark_disconnected(drv);
@@ -5477,6 +5872,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);
@@ -5790,6 +6189,7 @@ static int get_key_handler(struct nl_msg *msg, void *arg)
        if (tb[NL80211_ATTR_KEY_SEQ])
                memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
                       min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
+       nl80211_nlmsg_clear(msg);
        return NL_SKIP;
 }
 
@@ -5824,7 +6224,7 @@ static int i802_set_rts(void *priv, int rts)
        int ret;
        u32 val;
 
-       if (rts >= 2347)
+       if (rts >= 2347 || rts == -1)
                val = (u32) -1;
        else
                val = rts;
@@ -5852,7 +6252,7 @@ static int i802_set_frag(void *priv, int frag)
        int ret;
        u32 val;
 
-       if (frag >= 2346)
+       if (frag >= 2346 || frag == -1)
                val = (u32) -1;
        else
                val = frag;
@@ -5894,6 +6294,36 @@ static int i802_flush(void *priv)
 }
 
 
+static void get_sta_tid_stats(struct hostap_sta_driver_data *data,
+                             struct nlattr *attr)
+{
+       struct nlattr *tid_stats[NL80211_TID_STATS_MAX + 1], *tidattr;
+       struct nlattr *txq_stats[NL80211_TXQ_STATS_MAX + 1];
+       static struct nla_policy txq_stats_policy[NL80211_TXQ_STATS_MAX + 1] = {
+               [NL80211_TXQ_STATS_BACKLOG_BYTES] = { .type = NLA_U32 },
+               [NL80211_TXQ_STATS_BACKLOG_PACKETS] = { .type = NLA_U32 },
+       };
+       int rem;
+
+       nla_for_each_nested(tidattr, attr, rem) {
+               if (nla_parse_nested(tid_stats, NL80211_TID_STATS_MAX,
+                                    tidattr, NULL) != 0 ||
+                   !tid_stats[NL80211_TID_STATS_TXQ_STATS] ||
+                   nla_parse_nested(txq_stats, NL80211_TXQ_STATS_MAX,
+                                    tid_stats[NL80211_TID_STATS_TXQ_STATS],
+                                    txq_stats_policy) != 0)
+                       continue;
+               /* sum the backlogs over all TIDs for station */
+               if (txq_stats[NL80211_TXQ_STATS_BACKLOG_BYTES])
+                       data->backlog_bytes += nla_get_u32(
+                               txq_stats[NL80211_TXQ_STATS_BACKLOG_BYTES]);
+               if (txq_stats[NL80211_TXQ_STATS_BACKLOG_PACKETS])
+                       data->backlog_bytes += nla_get_u32(
+                               txq_stats[NL80211_TXQ_STATS_BACKLOG_PACKETS]);
+       }
+}
+
+
 static int get_sta_handler(struct nl_msg *msg, void *arg)
 {
        struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -5909,6 +6339,19 @@ 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 },
+               [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 },
+               [NL80211_STA_INFO_TX_DURATION] = { .type = NLA_U64 },
+       };
+       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),
@@ -5957,9 +6400,84 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
        if (stats[NL80211_STA_INFO_TX_PACKETS])
                data->tx_packets =
                        nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
+       if (stats[NL80211_STA_INFO_RX_DURATION])
+               data->rx_airtime =
+                       nla_get_u64(stats[NL80211_STA_INFO_RX_DURATION]);
+       if (stats[NL80211_STA_INFO_TX_DURATION])
+               data->tx_airtime =
+                       nla_get_u64(stats[NL80211_STA_INFO_TX_DURATION]);
        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;
+               }
+       }
+
+       if (stats[NL80211_STA_INFO_TID_STATS])
+               get_sta_tid_stats(data, stats[NL80211_STA_INFO_TID_STATS]);
 
        return NL_SKIP;
 }
@@ -5987,6 +6505,7 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        struct nlattr *txq, *params;
+       int res;
 
        msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY);
        if (!msg)
@@ -6032,7 +6551,11 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
 
        nla_nest_end(msg, txq);
 
-       if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+       res = send_and_recv_msgs(drv, msg, NULL, NULL);
+       wpa_printf(MSG_DEBUG,
+                  "nl80211: TX queue param set: queue=%d aifs=%d cw_min=%d cw_max=%d burst_time=%d --> res=%d",
+                  queue, aifs, cw_min, cw_max, burst_time, res);
+       if (res == 0)
                return 0;
        msg = NULL;
 fail:
@@ -6096,7 +6619,7 @@ static int i802_sta_clear_stats(void *priv, const u8 *addr)
 
 
 static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
-                          int reason)
+                          u16 reason)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -6131,7 +6654,7 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
 
 
 static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
-                            int reason)
+                            u16 reason)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -6166,11 +6689,11 @@ static void dump_ifidx(struct wpa_driver_nl80211_data *drv)
        end = pos + sizeof(buf);
 
        for (i = 0; i < drv->num_if_indices; i++) {
-               if (!drv->if_indices[i])
+               if (!drv->if_indices[i].ifindex)
                        continue;
                res = os_snprintf(pos, end - pos, " %d(%d)",
-                                 drv->if_indices[i],
-                                 drv->if_indices_reason[i]);
+                                 drv->if_indices[i].ifindex,
+                                 drv->if_indices[i].reason);
                if (os_snprintf_error(end - pos, res))
                        break;
                pos += res;
@@ -6186,7 +6709,7 @@ static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
                      int ifidx_reason)
 {
        int i;
-       int *old, *old_reason;
+       struct drv_nl80211_if_info *old;
 
        wpa_printf(MSG_DEBUG,
                   "nl80211: Add own interface ifindex %d (ifidx_reason %d)",
@@ -6197,9 +6720,9 @@ static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
                return;
        }
        for (i = 0; i < drv->num_if_indices; i++) {
-               if (drv->if_indices[i] == 0) {
-                       drv->if_indices[i] = ifidx;
-                       drv->if_indices_reason[i] = ifidx_reason;
+               if (drv->if_indices[i].ifindex == 0) {
+                       drv->if_indices[i].ifindex = ifidx;
+                       drv->if_indices[i].reason = ifidx_reason;
                        dump_ifidx(drv);
                        return;
                }
@@ -6210,29 +6733,13 @@ static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
        else
                old = NULL;
 
-       if (drv->if_indices_reason != drv->default_if_indices_reason)
-               old_reason = drv->if_indices_reason;
-       else
-               old_reason = NULL;
-
        drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
-                                          sizeof(int));
-       drv->if_indices_reason = os_realloc_array(old_reason,
-                                                 drv->num_if_indices + 1,
-                                                 sizeof(int));
+                                          sizeof(*old));
        if (!drv->if_indices) {
                if (!old)
                        drv->if_indices = drv->default_if_indices;
                else
                        drv->if_indices = old;
-       }
-       if (!drv->if_indices_reason) {
-               if (!old_reason)
-                       drv->if_indices_reason = drv->default_if_indices_reason;
-               else
-                       drv->if_indices_reason = old_reason;
-       }
-       if (!drv->if_indices || !drv->if_indices_reason) {
                wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
                           "interfaces");
                wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
@@ -6241,12 +6748,8 @@ static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
        if (!old)
                os_memcpy(drv->if_indices, drv->default_if_indices,
                          sizeof(drv->default_if_indices));
-       if (!old_reason)
-               os_memcpy(drv->if_indices_reason,
-                         drv->default_if_indices_reason,
-                         sizeof(drv->default_if_indices_reason));
-       drv->if_indices[drv->num_if_indices] = ifidx;
-       drv->if_indices_reason[drv->num_if_indices] = ifidx_reason;
+       drv->if_indices[drv->num_if_indices].ifindex = ifidx;
+       drv->if_indices[drv->num_if_indices].reason = ifidx_reason;
        drv->num_if_indices++;
        dump_ifidx(drv);
 }
@@ -6258,10 +6761,12 @@ static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
        int i;
 
        for (i = 0; i < drv->num_if_indices; i++) {
-               if ((drv->if_indices[i] == ifidx || ifidx == IFIDX_ANY) &&
-                   (drv->if_indices_reason[i] == ifidx_reason ||
+               if ((drv->if_indices[i].ifindex == ifidx ||
+                    ifidx == IFIDX_ANY) &&
+                   (drv->if_indices[i].reason == ifidx_reason ||
                     ifidx_reason == IFIDX_ANY)) {
-                       drv->if_indices[i] = 0;
+                       drv->if_indices[i].ifindex = 0;
+                       drv->if_indices[i].reason = 0;
                        break;
                }
        }
@@ -6275,8 +6780,8 @@ static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
        int i;
 
        for (i = 0; i < drv->num_if_indices; i++)
-               if (drv->if_indices[i] == ifidx &&
-                   (drv->if_indices_reason[i] == ifidx_reason ||
+               if (drv->if_indices[i].ifindex == ifidx &&
+                   (drv->if_indices[i].reason == ifidx_reason ||
                     ifidx_reason == IFIDX_ANY))
                        return 1;
 
@@ -6290,8 +6795,16 @@ 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;
+       int ret;
+
+       ret = os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+       if (ret >= (int) sizeof(name))
+               wpa_printf(MSG_WARNING,
+                          "nl80211: WDS interface name was truncated");
+       else if (ret < 0)
+               return ret;
 
-       os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
        if (ifname_wds)
                os_strlcpy(ifname_wds, name, IFNAMSIZ + 1);
 
@@ -6308,6 +6821,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(bss->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 "
@@ -6315,12 +6836,21 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
                }
                return i802_set_sta_vlan(priv, addr, name, 0);
        } else {
-               if (bridge_ifname)
-                       linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
-                                       name);
+               if (bridge_ifname &&
+                   linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
+                                   name) < 0)
+                       wpa_printf(MSG_INFO,
+                                  "nl80211: Failed to remove interface %s from bridge %s: %s",
+                                  name, bridge_ifname, strerror(errno));
 
                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(bss->ctx, EVENT_WDS_STA_INTERFACE_STATUS,
+                                    &event);
                return 0;
        }
 }
@@ -6374,8 +6904,10 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
        bss->br_ifindex = br_ifindex;
 
        if (linux_br_get(in_br, ifname) == 0) {
-               if (os_strcmp(in_br, brname) == 0)
+               if (os_strcmp(in_br, brname) == 0) {
+                       bss->already_in_bridge = 1;
                        return 0; /* already in the bridge */
+               }
 
                wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
                           "bridge %s", ifname, in_br);
@@ -6384,7 +6916,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;
                }
        }
@@ -6472,7 +7004,7 @@ static void *i802_init(struct hostapd_data *hapd,
                add_ifidx(drv, br_ifindex, drv->ifindex);
 
 #ifdef CONFIG_LIBNL3_ROUTE
-       if (bss->added_if_into_bridge) {
+       if (bss->added_if_into_bridge || bss->already_in_bridge) {
                drv->rtnl_sk = nl_socket_alloc();
                if (drv->rtnl_sk == NULL) {
                        wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
@@ -7101,7 +7633,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 +7658,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 +7973,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 +7996,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,19 +8008,22 @@ 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 &&
+           (cmd != NL80211_CMD_DEL_PMKSA &&
+            params->pmk_len && params->pmk_len <= PMK_MAX_LEN &&
             nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) {
+               nl80211_nlmsg_clear(msg);
                nlmsg_free(msg);
                return -ENOBUFS;
        }
 
-       return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+       return send_and_recv_msgs(bss->drv, msg, NULL, (void *) -1);
 }
 
 
 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 +8035,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 +8061,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 +8276,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);
@@ -7788,6 +8339,7 @@ static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
+       u64 cookie;
        int ret;
 
        if (!drv->poll_command_supported) {
@@ -7801,11 +8353,16 @@ static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
                return;
        }
 
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
        if (ret < 0) {
                wpa_printf(MSG_DEBUG, "nl80211: Client probe request for "
                           MACSTR " failed: ret=%d (%s)",
                           MAC2STR(addr), ret, strerror(-ret));
+       } else {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Client probe request addr=" MACSTR
+                          " cookie=%llu", MAC2STR(addr),
+                          (long long unsigned int) cookie);
        }
 }
 
@@ -7813,6 +8370,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 +8378,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;
 }
 
 
@@ -7857,8 +8423,8 @@ static int nl80211_start_radar_detection(void *priv,
        struct nl_msg *msg;
        int ret;
 
-       wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC) %d MHz (ht_enabled=%d, vht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
-                  freq->freq, freq->ht_enabled, freq->vht_enabled,
+       wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC) %d MHz (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
+                  freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
                   freq->bandwidth, freq->center_freq1, freq->center_freq2);
 
        if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
@@ -8070,7 +8636,7 @@ static int driver_nl80211_scan2(void *priv,
 
 
 static int driver_nl80211_deauthenticate(void *priv, const u8 *addr,
-                                        int reason_code)
+                                        u16 reason_code)
 {
        struct i802_bss *bss = priv;
        return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code);
@@ -8185,6 +8751,35 @@ static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
 }
 
 
+static int nl80211_update_dh_ie(void *priv, const u8 *peer_mac,
+                               u16 reason_code, const u8 *ie, size_t ie_len)
+{
+       int ret;
+       struct nl_msg *msg;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Updating DH IE peer: " MACSTR
+                  " reason %u", MAC2STR(peer_mac), reason_code);
+       if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UPDATE_OWE_INFO)) ||
+           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer_mac) ||
+           nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, reason_code) ||
+           (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie))) {
+               nlmsg_free(msg);
+               return -ENOBUFS;
+       }
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (ret) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: update_dh_ie failed err=%d (%s)",
+                          ret, strerror(-ret));
+       }
+
+       return ret;
+}
+
+
 static const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
 {
        struct i802_bss *bss = priv;
@@ -8228,6 +8823,8 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int res;
        char *pos, *end;
+       struct nl_msg *msg;
+       char alpha2[3] = { 0, 0, 0 };
 
        pos = buf;
        end = buf + buflen;
@@ -8238,7 +8835,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
                          "brname=%s\n"
                          "addr=" MACSTR "\n"
                          "freq=%d\n"
-                         "%s%s%s%s%s",
+                         "%s%s%s%s%s%s",
                          bss->ifindex,
                          bss->ifname,
                          bss->brname,
@@ -8247,6 +8844,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
                          bss->beacon_set ? "beacon_set=1\n" : "",
                          bss->added_if_into_bridge ?
                          "added_if_into_bridge=1\n" : "",
+                         bss->already_in_bridge ? "already_in_bridge=1\n" : "",
                          bss->added_bridge ? "added_bridge=1\n" : "",
                          bss->in_deinit ? "in_deinit=1\n" : "",
                          bss->if_dynamic ? "if_dynamic=1\n" : "");
@@ -8371,6 +8969,23 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
                pos += res;
        }
 
+       msg = nlmsg_alloc();
+       if (msg &&
+           nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG) &&
+           nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx) == 0) {
+               if (send_and_recv_msgs(drv, msg, nl80211_get_country,
+                                      alpha2) == 0 &&
+                   alpha2[0]) {
+                       res = os_snprintf(pos, end - pos, "country=%s\n",
+                                         alpha2);
+                       if (os_snprintf_error(end - pos, res))
+                               return pos - buf;
+                       pos += res;
+               }
+       } else {
+               nlmsg_free(msg);
+       }
+
        return pos - buf;
 }
 
@@ -8422,8 +9037,9 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
                return -EOPNOTSUPP;
        }
 
-       if ((drv->nlmode != NL80211_IFTYPE_AP) &&
-           (drv->nlmode != NL80211_IFTYPE_P2P_GO))
+       if (drv->nlmode != NL80211_IFTYPE_AP &&
+           drv->nlmode != NL80211_IFTYPE_P2P_GO &&
+           drv->nlmode != NL80211_IFTYPE_MESH_POINT)
                return -EOPNOTSUPP;
 
        /*
@@ -8784,6 +9400,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 */
 
 
@@ -8847,8 +9552,8 @@ static int nl80211_put_mesh_id(struct nl_msg *msg, const u8 *mesh_id,
                               size_t mesh_id_len)
 {
        if (mesh_id) {
-               wpa_hexdump_ascii(MSG_DEBUG, "  * Mesh ID (SSID)",
-                                 mesh_id, mesh_id_len);
+               wpa_printf(MSG_DEBUG, "  * Mesh ID (SSID)=%s",
+                          wpa_ssid_txt(mesh_id, mesh_id_len));
                return nla_put(msg, NL80211_ATTR_MESH_ID, mesh_id_len, mesh_id);
        }
 
@@ -8866,11 +9571,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;
 
        /*
@@ -9020,6 +9728,36 @@ static int wpa_driver_nl80211_leave_mesh(void *priv)
        return ret;
 }
 
+
+static int nl80211_probe_mesh_link(void *priv, const u8 *addr, const u8 *eth,
+                                  size_t len)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret;
+
+       msg = nl80211_drv_msg(drv, 0, NL80211_CMD_PROBE_MESH_LINK);
+       if (!msg ||
+           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+           nla_put(msg, NL80211_ATTR_FRAME, len, eth)) {
+               nlmsg_free(msg);
+               return -ENOBUFS;
+       }
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: mesh link probe to " MACSTR
+                          " failed: ret=%d (%s)",
+                          MAC2STR(addr), ret, strerror(-ret));
+       } else {
+               wpa_printf(MSG_DEBUG, "nl80211: Mesh link to " MACSTR
+                          " probed successfully", MAC2STR(addr));
+       }
+
+       return ret;
+}
+
 #endif /* CONFIG_MESH */
 
 
@@ -9949,6 +10687,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 */
@@ -9958,22 +10746,37 @@ static int nl80211_write_to_file(const char *name, unsigned int val)
 {
        int fd, len;
        char tmp[128];
+       int ret = 0;
 
        fd = open(name, O_RDWR);
        if (fd < 0) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to open %s: %s",
+               int level;
+               /*
+                * Flags may not exist on older kernels, or while we're tearing
+                * down a disappearing device.
+                */
+               if (errno == ENOENT) {
+                       ret = 0;
+                       level = MSG_DEBUG;
+               } else {
+                       ret = -1;
+                       level = MSG_ERROR;
+               }
+               wpa_printf(level, "nl80211: Failed to open %s: %s",
                           name, strerror(errno));
-               return fd;
+               return ret;
        }
 
        len = os_snprintf(tmp, sizeof(tmp), "%u\n", val);
        len = write(fd, tmp, len);
-       if (len < 0)
+       if (len < 0) {
+               ret = -1;
                wpa_printf(MSG_ERROR, "nl80211: Failed to write to %s: %s",
                           name, strerror(errno));
+       }
        close(fd);
 
-       return 0;
+       return ret;
 }
 
 
@@ -10078,6 +10881,143 @@ 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;
+
+       /* External auth command/status is intended for drivers that implement
+        * intenral SME but want to offload authentication processing (e.g.,
+        * SAE) to hostapd/wpa_supplicant. Do nott send the status to drivers
+        * which do not support AP SME or use wpa_supplicant/hostapd SME.
+        */
+       if ((is_ap_interface(drv->nlmode) && !bss->drv->device_ap_sme) ||
+           (drv->capa.flags & WPA_DRIVER_FLAGS_SME))
+               return -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) ||
+           (params->ssid && params->ssid_len &&
+            nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) ||
+           (params->pmkid &&
+            nla_put(msg, NL80211_ATTR_PMKID, PMKID_LEN, params->pmkid)) ||
+           (params->bssid &&
+            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;
+}
+
+
+static int nl80211_set_4addr_mode(void *priv, const char *bridge_ifname,
+                                 int val)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret = -ENOBUFS;
+
+       wpa_printf(MSG_DEBUG, "nl80211: %s 4addr mode (bridge_ifname: %s)",
+                  val ? "Enable" : "Disable", bridge_ifname);
+
+       msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
+       if (!msg || nla_put_u8(msg, NL80211_ATTR_4ADDR, val))
+               goto fail;
+
+       if (bridge_ifname[0] && bss->added_if_into_bridge && !val) {
+               if (linux_br_del_if(drv->global->ioctl_sock,
+                                   bridge_ifname, bss->ifname)) {
+                       wpa_printf(MSG_ERROR,
+                                  "nl80211: Failed to remove interface %s from bridge %s",
+                                  bss->ifname, bridge_ifname);
+                       return -1;
+               }
+               bss->added_if_into_bridge = 0;
+       }
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+       if (!ret) {
+               if (bridge_ifname[0] && val &&
+                   i802_check_bridge(drv, bss, bridge_ifname, bss->ifname) < 0)
+                       return -1;
+               return 0;
+       }
+
+fail:
+       nlmsg_free(msg);
+       wpa_printf(MSG_ERROR, "nl80211: Failed to enable/disable 4addr");
+
+       return ret;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
@@ -10111,6 +11051,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .sta_remove = driver_nl80211_sta_remove,
        .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
        .sta_set_flags = wpa_driver_nl80211_sta_set_flags,
+       .sta_set_airtime_weight = driver_nl80211_sta_set_airtime_weight,
        .hapd_init = i802_init,
        .hapd_deinit = i802_deinit,
        .set_wds_sta = i802_set_wds_sta,
@@ -10137,6 +11078,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .resume = wpa_driver_nl80211_resume,
        .signal_monitor = nl80211_signal_monitor,
        .signal_poll = nl80211_signal_poll,
+       .channel_info = nl80211_channel_info,
        .send_frame = nl80211_send_frame,
        .set_param = nl80211_set_param,
        .get_radio_name = nl80211_get_radio_name,
@@ -10155,6 +11097,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .tdls_disable_channel_switch = nl80211_tdls_disable_channel_switch,
 #endif /* CONFIG_TDLS */
        .update_ft_ies = wpa_driver_nl80211_update_ft_ies,
+       .update_dh_ie = nl80211_update_dh_ie,
        .get_mac_addr = wpa_driver_nl80211_get_macaddr,
        .get_survey = wpa_driver_nl80211_get_survey,
        .status = wpa_driver_nl80211_status,
@@ -10177,6 +11120,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .init_mesh = wpa_driver_nl80211_init_mesh,
        .join_mesh = wpa_driver_nl80211_join_mesh,
        .leave_mesh = wpa_driver_nl80211_leave_mesh,
+       .probe_mesh_link = nl80211_probe_mesh_link,
 #endif /* CONFIG_MESH */
        .br_add_ip_neigh = wpa_driver_br_add_ip_neigh,
        .br_delete_ip_neigh = wpa_driver_br_delete_ip_neigh,
@@ -10187,6 +11131,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 +11142,13 @@ 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,
+       .set_4addr_mode = nl80211_set_4addr_mode,
 };