Revert "Revert "[wpa_supplicant] cumilative patch from commit 3a..."

Revert submission 28102966-revert-26533062-Supplicant_merge_June24-CUATTSRBBR

Reason for revert: Fixed the regression issue (ag/28389573)

Reverted changes: /q/submissionid:28102966-revert-26533062-Supplicant_merge_June24-CUATTSRBBR

Bug: 329004037
Test: Turn ON/OFF SoftAp multiple times

Change-Id: Ibfff2a847be5678f1a6d77e28506a05936812a91
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 7ae7d90..a55e8e3 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -949,6 +949,8 @@
 		const u8 *bssid;
 		const u8 *ies;
 		size_t ies_len;
+		int error;
+		bool disabled;
 	} mld_links[MAX_NUM_MLD_LINKS];
 };
 
@@ -2715,6 +2717,7 @@
  * @counter_offset_beacon: Offset to the count field in beacon's tail
  * @counter_offset_presp: Offset to the count field in probe resp.
  * @punct_bitmap - Preamble puncturing bitmap
+ * @link_id: Link ID to determine the link for MLD; -1 for non-MLD
  */
 struct csa_settings {
 	u8 cs_count;
@@ -2728,6 +2731,7 @@
 	u16 counter_offset_presp[2];
 
 	u16 punct_bitmap;
+	int link_id;
 };
 
 /**
@@ -2819,6 +2823,9 @@
 
 	/* Indicates whether EHT is enabled */
 	bool eht_enabled;
+
+	/* Indicates the link if MLO case; -1 otherwise */
+	int link_id;
 };
 
 struct wpa_bss_trans_info {
@@ -6535,6 +6542,7 @@
 	/**
 	 * struct dfs_event - Data for radar detected events
 	 * @freq: Frequency of the channel in MHz
+	 * @link_id: If >= 0, Link ID of the MLO link
 	 */
 	struct dfs_event {
 		int freq;
@@ -6543,6 +6551,7 @@
 		enum chan_width chan_width;
 		int cf1;
 		int cf2;
+		int link_id;
 	} dfs_event;
 
 	/**
@@ -6561,11 +6570,22 @@
 	 * @initiator: Initiator of the regulatory change
 	 * @type: Regulatory change type
 	 * @alpha2: Country code (or "" if not available)
+	 * @beacon_hint_before: Data for frequency attributes before beacon hint
+	 *	event if initiator == REGDOM_BEACON_HINT
+	 * @beacon_hint_after: Data for frequency attributes after beacon hint
+	 *	event if initiator == REGDOM_BEACON_HINT
 	 */
 	struct channel_list_changed {
 		enum reg_change_initiator initiator;
 		enum reg_type type;
 		char alpha2[3];
+		struct frequency_attrs {
+			unsigned int freq;
+			unsigned int max_tx_power;
+			bool disabled;
+			bool no_ir;
+			bool radar;
+		} beacon_hint_before, beacon_hint_after;
 	} channel_list_changed;
 
 	/**
@@ -6608,7 +6628,9 @@
 	 * @ch_width: Selected Channel width by driver. Driver may choose to
 	 *	change hostapd configured ACS channel width due driver internal
 	 *	channel restrictions.
-	 * hw_mode: Selected band (used with hw_mode=any)
+	 * @hw_mode: Selected band (used with hw_mode=any)
+	 * @puncture_bitmap: Indicate the puncturing channels
+	 * @link_id: Indicate the link id if operating as AP MLD; -1 otherwise
 	 */
 	struct acs_selected_channels {
 		unsigned int pri_freq;
@@ -6619,6 +6641,7 @@
 		u16 ch_width;
 		enum hostapd_hw_mode hw_mode;
 		u16 puncture_bitmap;
+		int link_id;
 	} acs_selected_channels;
 
 	/**
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 59f65b8..ae7f0e5 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -659,7 +659,7 @@
 			 &stats, sizeof(stats))) {
 		wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr "
 			   MACSTR ")", __func__, MAC2STR(addr));
-		if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
+		if (ether_addr_equal(addr, drv->acct_mac)) {
 			os_memcpy(data, &drv->acct_data, sizeof(*data));
 			return 0;
 		}
@@ -892,7 +892,7 @@
 	}
 
 	if (stype == WLAN_FC_STYPE_ACTION &&
-	    (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) == 0 ||
+	    (ether_addr_equal(drv->own_addr, mgmt->bssid) ||
 	     is_broadcast_ether_addr(mgmt->bssid))) {
 		os_memset(&event, 0, sizeof(event));
 		event.rx_mgmt.frame = buf;
@@ -901,7 +901,7 @@
 		return;
 	}
 
-	if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
+	if (!ether_addr_equal(drv->own_addr, mgmt->bssid)) {
 		wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
 			   __func__);
 		return;
@@ -1226,7 +1226,7 @@
 no_ie:
 	drv_event_assoc(hapd, addr, iebuf, ielen, NULL, 0, NULL, -1, 0);
 
-	if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
+	if (ether_addr_equal(addr, drv->acct_mac)) {
 		/* Cached accounting data is not valid anymore. */
 		os_memset(drv->acct_mac, 0, ETH_ALEN);
 		os_memset(&drv->acct_data, 0, sizeof(drv->acct_data));
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index b32e009..0351705 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -1248,7 +1248,7 @@
 	prev = NULL;
 	entry = drv->pmkid;
 	while (entry) {
-		if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0)
+		if (ether_addr_equal(entry->bssid, bssid))
 			break;
 		prev = entry;
 		entry = entry->next;
@@ -1293,7 +1293,7 @@
 	entry = drv->pmkid;
 	prev = NULL;
 	while (entry) {
-		if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 &&
+		if (ether_addr_equal(entry->bssid, bssid) &&
 		    os_memcmp(entry->pmkid, pmkid, 16) == 0) {
 			if (prev)
 				prev->next = entry->next;
@@ -1434,7 +1434,7 @@
 	pos = (char *) &b->Bssid[0];
 	for (i = 0; i < b->NumberOfItems; i++) {
 		NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos;
-		if (os_memcmp(drv->bssid, bss->MacAddress, ETH_ALEN) == 0 &&
+		if (ether_addr_equal(drv->bssid, bss->MacAddress) &&
 		    bss->IELength > sizeof(NDIS_802_11_FIXED_IEs)) {
 			data.assoc_info.beacon_ies =
 				((u8 *) bss->IEs) +
@@ -1477,7 +1477,7 @@
 		}
 	} else {
 		/* Connected */
-		if (os_memcmp(drv->bssid, bssid, ETH_ALEN) != 0) {
+		if (!ether_addr_equal(drv->bssid, bssid)) {
 			os_memcpy(drv->bssid, bssid, ETH_ALEN);
 			wpa_driver_ndis_get_associnfo(drv);
 			wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index ac2f457..9b50b6f 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -12,10 +12,12 @@
 
 #include "includes.h"
 #include <sys/types.h>
+#include <sys/utsname.h>
 #include <fcntl.h>
 #include <net/if.h>
 #include <netlink/genl/genl.h>
 #include <netlink/genl/ctrl.h>
+#include <netlink/genl/family.h>
 #ifdef CONFIG_LIBNL3_ROUTE
 #include <netlink/route/neighbour.h>
 #endif /* CONFIG_LIBNL3_ROUTE */
@@ -170,9 +172,9 @@
 static int nl80211_send_frame_cmd(struct i802_bss *bss,
 				  unsigned int freq, unsigned int wait,
 				  const u8 *buf, size_t buf_len,
-				  int save_cookie,
-				  int no_cck, int no_ack, int offchanok,
-				  const u16 *csa_offs, size_t csa_offs_len);
+				  int save_cookie, int no_cck, int no_ack,
+				  int offchanok, const u16 *csa_offs,
+				  size_t csa_offs_len, int link_id);
 static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
 					       int report);
 
@@ -195,6 +197,7 @@
 
 static int i802_set_iface_flags(struct i802_bss *bss, int up);
 static int nl80211_set_param(void *priv, const char *param);
+static void nl80211_remove_links(struct i802_bss *bss);
 #ifdef CONFIG_MESH
 static int nl80211_put_mesh_config(struct nl_msg *msg,
 				   struct wpa_driver_mesh_bss_params *params);
@@ -345,17 +348,29 @@
 	return NL_SKIP;
 }
 
+struct nl80211_ack_err_args {
+	int err;
+	struct nl_msg *orig_msg;
+	struct nl80211_err_info *err_info;
+};
+
 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
 			 void *arg)
 {
+	struct nl80211_ack_err_args *err_args = arg;
 	struct nlmsghdr *nlh = (struct nlmsghdr *) err - 1;
+	struct nlmsghdr *orig_nlh = nlmsg_hdr(err_args->orig_msg);
 	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);
+	struct nlattr *mlo_links, *link_attr;
+	u32 offset;
+	int rem;
 
-	*ret = err->error;
+	err_args->err = err->error;
+	if (err_args->err_info)
+		err_args->err_info->link_id = -1;
 
 	if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
 		return NL_SKIP;
@@ -377,6 +392,41 @@
 			   len, (char *) nla_data(tb[NLMSGERR_ATTR_MSG]));
 	}
 
+	if (!err_args->err_info)
+		return NL_SKIP;
+
+	/* Check if it was a per-link error report */
+
+	if (!tb[NLMSGERR_ATTR_OFFS] ||
+	    os_memcmp(orig_nlh, &err->msg, sizeof(err->msg)) != 0)
+		return NL_SKIP;
+
+	offset = nla_get_u32(tb[NLMSGERR_ATTR_OFFS]);
+
+	mlo_links = nlmsg_find_attr(orig_nlh, GENL_HDRLEN,
+				    NL80211_ATTR_MLO_LINKS);
+	if (!mlo_links)
+		return NL_SKIP;
+
+	nla_for_each_nested(link_attr, mlo_links, rem) {
+		struct nlattr *link_id;
+		size_t link_offset = (u8 *) link_attr - (u8 *) orig_nlh;
+
+		if (offset < link_offset ||
+		    offset >= link_offset + link_attr->nla_len)
+			continue;
+
+		link_id = nla_find(nla_data(link_attr), nla_len(link_attr),
+				   NL80211_ATTR_MLO_LINK_ID);
+		if (link_id) {
+			err_args->err_info->link_id = nla_get_u8(link_id);
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: kernel reports error for link: %d",
+				   err_args->err_info->link_id);
+			break;
+		}
+	}
+
 	return NL_SKIP;
 }
 
@@ -409,20 +459,61 @@
 }
 
 
-static int send_and_recv(struct nl80211_global *global,
-			 struct nl_sock *nl_handle, struct nl_msg *msg,
-			 int (*valid_handler)(struct nl_msg *, void *),
-			 void *valid_data,
-			 int (*ack_handler_custom)(struct nl_msg *, void *),
-			 void *ack_data)
+static int send_event_marker(struct wpa_driver_nl80211_data *drv)
 {
-	struct nl_cb *cb;
-	int err = -ENOMEM, opt;
+	struct nl_sock *handle;
+	struct nl_msg *msg;
+	struct nlmsghdr *hdr;
+	int res = 0;
+	int err = -NLE_NOMEM;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		goto out;
+
+	/* We only care about the returned sequence number for matching. */
+	if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES))
+		goto out;
+
+	handle = (void *) (((intptr_t) drv->global->nl_event) ^
+			   ELOOP_SOCKET_INVALID);
+
+	err = nl_send_auto_complete(handle, msg);
+	if (err < 0)
+		goto out;
+
+	hdr = nlmsg_hdr(msg);
+	res = hdr->nlmsg_seq;
+
+out:
+	nlmsg_free(msg);
+	if (err)
+		wpa_printf(MSG_INFO, "nl80211: %s failed: %s",
+			   __func__, nl_geterror(err));
+	return res;
+}
+
+
+int send_and_recv(struct nl80211_global *global,
+		  struct nl_sock *nl_handle, struct nl_msg *msg,
+		  int (*valid_handler)(struct nl_msg *, void *),
+		  void *valid_data,
+		  int (*ack_handler_custom)(struct nl_msg *, void *),
+		  void *ack_data,
+		  struct nl80211_err_info *err_info)
+{
+	struct nl_cb *cb, *s_nl_cb;
+	struct nl80211_ack_err_args err;
+	int opt;
 
 	if (!msg)
 		return -ENOMEM;
 
-	cb = nl_cb_clone(global->nl_cb);
+	err.err = -ENOMEM;
+
+	s_nl_cb = nl_socket_get_cb(nl_handle);
+	cb = nl_cb_clone(s_nl_cb);
+	nl_cb_put(s_nl_cb);
 	if (!cb)
 		goto out;
 
@@ -436,26 +527,28 @@
 	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) {
+	err.err = nl_send_auto_complete(nl_handle, msg);
+	if (err.err < 0) {
 		wpa_printf(MSG_INFO,
 			   "nl80211: nl_send_auto_complete() failed: %s",
-			   nl_geterror(err));
+			   nl_geterror(err.err));
 		/* Need to convert libnl error code to an errno value. For now,
 		 * just hardcode this to EBADF; the real error reason is shown
 		 * in that error print above. */
-		err = -EBADF;
+		err.err = -EBADF;
 		goto out;
 	}
 
-	err = 1;
+	err.err = 1;
+	err.orig_msg = msg;
+	err.err_info = err_info;
 
 	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
-	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
+	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err.err);
 	if (ack_handler_custom) {
 		struct nl80211_ack_ext_arg *ext_arg = ack_data;
 
-		ext_arg->err = &err;
+		ext_arg->err = &err.err;
 		nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM,
 			  ack_handler_custom, ack_data);
 	} else {
@@ -466,7 +559,7 @@
 		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
 			  valid_handler, valid_data);
 
-	while (err > 0) {
+	while (err.err > 0) {
 		int res = nl_recvmsgs(nl_handle, cb);
 
 		if (res == -NLE_DUMP_INTR) {
@@ -481,7 +574,7 @@
 			 * will stop and return an error. */
 			wpa_printf(MSG_DEBUG, "nl80211: %s; convert to -EAGAIN",
 				   nl_geterror(res));
-			err = -EAGAIN;
+			err.err = -EAGAIN;
 		} else if (res < 0) {
 			wpa_printf(MSG_INFO,
 				   "nl80211: %s->nl_recvmsgs failed: %d (%s)",
@@ -493,89 +586,20 @@
 	/* Always clear the message as it can potentially contain keys */
 	nl80211_nlmsg_clear(msg);
 	nlmsg_free(msg);
-	return err;
+	return err.err;
 }
 
 
-int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
-		       struct nl_msg *msg,
-		       int (*valid_handler)(struct nl_msg *, void *),
-		       void *valid_data,
-		       int (*ack_handler_custom)(struct nl_msg *, void *),
-		       void *ack_data)
+static int nl80211_put_control_port(struct wpa_driver_nl80211_data *drv,
+				    struct nl_msg *msg)
 {
-	return send_and_recv(drv->global, drv->global->nl, msg,
-			     valid_handler, valid_data,
-			     ack_handler_custom, ack_data);
-}
-
-
-/* Use this method to mark that it is necessary to own the connection/interface
- * for this operation.
- * handle may be set to NULL, to get the same behavior as send_and_recv_msgs().
- * set_owner can be used to mark this socket for receiving control port frames.
- */
-static int send_and_recv_msgs_owner(struct wpa_driver_nl80211_data *drv,
-				    struct nl_msg *msg,
-				    struct nl_sock *handle, int set_owner,
-				    int (*valid_handler)(struct nl_msg *,
-							 void *),
-				    void *valid_data,
-				    int (*ack_handler_custom)(struct nl_msg *,
-							      void *),
-				    void *ack_data)
-{
-	if (!msg)
-		return -ENOMEM;
-
-	/* Control port over nl80211 needs the flags and attributes below.
-	 *
-	 * The Linux kernel has initial checks for them (in nl80211.c) like:
-	 *     validate_pae_over_nl80211(...)
-	 * or final checks like:
-	 *     dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid
-	 *
-	 * Final operations (e.g., disassociate) don't need to set these
-	 * attributes, but they have to be performed on the socket, which has
-	 * the connection owner property set in the kernel.
-	 */
-	if ((drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) &&
-	    handle && set_owner &&
-	    (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_OVER_NL80211) ||
-	     nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER) ||
-	     nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
-	     nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_PREAUTH)))
+	if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT) ||
+	    nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
+	    ((drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) &&
+	     (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_OVER_NL80211) ||
+	      nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_PREAUTH))))
 		return -1;
-
-	return send_and_recv(drv->global, handle ? handle : drv->global->nl,
-			     msg, valid_handler, valid_data,
-			     ack_handler_custom, ack_data);
-}
-
-
-static int
-send_and_recv_msgs_connect_handle(struct wpa_driver_nl80211_data *drv,
-				  struct nl_msg *msg, struct i802_bss *bss,
-				  int set_owner)
-{
-	struct nl_sock *nl_connect = get_connect_handle(bss);
-
-	if (nl_connect)
-		return send_and_recv_msgs_owner(drv, msg, nl_connect, set_owner,
-						process_bss_event, bss, NULL,
-						NULL);
-	else
-		return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
-}
-
-
-struct nl_sock * get_connect_handle(struct i802_bss *bss)
-{
-	if ((bss->drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) ||
-	    bss->use_nl_connect)
-		return bss->nl_connect;
-
-	return NULL;
+	return 0;
 }
 
 
@@ -634,7 +658,7 @@
 	}
 
 	ret = send_and_recv(global, global->nl, msg, family_handler, &res,
-			    NULL, NULL);
+			    NULL, NULL, NULL);
 	if (ret == 0)
 		ret = res.id;
 	return ret;
@@ -762,8 +786,7 @@
 	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
 		return -1;
 
-	if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
-			       NULL, NULL) == 0)
+	if (send_and_recv_resp(bss->drv, msg, netdev_info_handler, &data) == 0)
 		return data.wiphy_idx;
 	return -1;
 }
@@ -780,8 +803,7 @@
 	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
 		return NL80211_IFTYPE_UNSPECIFIED;
 
-	if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
-			       NULL, NULL) == 0)
+	if (send_and_recv_resp(bss->drv, msg, netdev_info_handler, &data) == 0)
 		return data.nlmode;
 	return NL80211_IFTYPE_UNSPECIFIED;
 }
@@ -797,8 +819,7 @@
 	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
 		return -1;
 
-	return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
-				  NULL, NULL);
+	return send_and_recv_resp(bss->drv, msg, netdev_info_handler, &data);
 }
 
 
@@ -810,8 +831,7 @@
 	};
 
 	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)) ||
-	    send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
-			       NULL, NULL))
+	    send_and_recv_resp(bss->drv, msg, netdev_info_handler, &data))
 		return -1;
 	return data.use_4addr;
 }
@@ -834,7 +854,7 @@
 	}
 
 	ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL,
-			    NULL, NULL);
+			    NULL, NULL, NULL);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
 			   "failed: ret=%d (%s)",
@@ -1091,8 +1111,8 @@
 		struct nl_msg *msg;
 
 		msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
-		if (send_and_recv_msgs(drv, msg, get_mlo_info,
-				       &drv->sta_mlo_info, NULL, NULL))
+		if (send_and_recv_resp(drv, msg, get_mlo_info,
+				       &drv->sta_mlo_info))
 			return -1;
 	}
 
@@ -1249,7 +1269,7 @@
 		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) {
+	} else if (bss && !ether_addr_equal(addr, bss->addr)) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Own MAC address on ifindex %d (%s) changed from "
 			   MACSTR " to " MACSTR,
@@ -1637,8 +1657,8 @@
 	msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
 	os_memset(&arg, 0, sizeof(arg));
 	arg.drv = drv;
-	ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
-				 &arg, NULL, NULL);
+	ret = send_and_recv_resp(drv, msg, nl80211_get_assoc_freq_handler,
+				 &arg);
 	if (ret == -EAGAIN) {
 		count++;
 		if (count >= 10) {
@@ -1671,8 +1691,8 @@
 	msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
 	os_memset(&arg, 0, sizeof(arg));
 	arg.drv = drv;
-	ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
-				 &arg, NULL, NULL);
+	ret = send_and_recv_resp(drv, msg, nl80211_get_assoc_freq_handler,
+				 &arg);
 	if (ret == -EAGAIN) {
 		count++;
 		if (count >= 10) {
@@ -1759,8 +1779,7 @@
 	sig_change->frequency = drv->assoc_freq;
 
 	msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
-	return send_and_recv_msgs(drv, msg, get_link_noise, sig_change,
-				  NULL, NULL);
+	return send_and_recv_resp(drv, msg, get_link_noise, sig_change);
 }
 
 
@@ -1824,7 +1843,7 @@
 	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, NULL, NULL);
+	return send_and_recv_resp(drv, msg, get_channel_info, ci);
 }
 
 
@@ -1873,7 +1892,7 @@
 		nlmsg_free(msg);
 		return -EINVAL;
 	}
-	if (send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL))
+	if (send_and_recv_cmd(drv, msg))
 		return -EINVAL;
 	return 0;
 }
@@ -1919,8 +1938,7 @@
 	}
 
 	alpha2[0] = '\0';
-	ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2,
-				 NULL, NULL);
+	ret = send_and_recv_resp(drv, msg, nl80211_get_country, alpha2);
 	if (!alpha2[0])
 		ret = -1;
 
@@ -1930,6 +1948,8 @@
 
 static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
 {
+	struct nl_cache *cache = NULL;
+	struct genl_family *family = NULL;
 	int ret;
 
 	global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
@@ -2001,6 +2021,29 @@
 		/* Continue without vendor events */
 	}
 
+	/* Resolve maxattr for kernel support checks */
+	ret = genl_ctrl_alloc_cache(global->nl, &cache);
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Could not allocate genl cache: %d (%s)",
+			   ret, nl_geterror(ret));
+		goto err;
+	}
+
+	family = genl_ctrl_search(cache, global->nl80211_id);
+	if (!family) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Could not get nl80211 family from cache: %d (%s)",
+			   ret, nl_geterror(ret));
+		goto err;
+	}
+
+	global->nl80211_maxattr = genl_family_get_maxattr(family);
+	wpa_printf(MSG_DEBUG, "nl80211: Maximum supported attribute ID: %u",
+		   global->nl80211_maxattr);
+	genl_family_put(family);
+	nl_cache_free(cache);
+
 	nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
 		  no_seq_check, NULL);
 	nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
@@ -2013,6 +2056,8 @@
 	return 0;
 
 err:
+	genl_family_put(family);
+	nl_cache_free(cache);
 	nl_destroy_handles(&global->nl_event);
 	nl_destroy_handles(&global->nl);
 	nl_cb_put(global->nl_cb);
@@ -2251,6 +2296,26 @@
 	struct wpa_driver_nl80211_data *drv;
 	struct i802_bss *bss;
 	unsigned int i;
+	char path[128], buf[200], *pos;
+	ssize_t len;
+	int ret;
+
+	ret = os_snprintf(path, sizeof(path), "/sys/class/net/%s/device/driver",
+			  ifname);
+	if (!os_snprintf_error(sizeof(path), ret)) {
+		len = readlink(path, buf, sizeof(buf));
+		if (len > 0 && (size_t) len < sizeof(buf)) {
+			buf[len] = '\0';
+			pos = strrchr(buf, '/');
+			if (pos)
+				pos++;
+			else
+				pos = buf;
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Initialize interface %s (driver: %s)",
+				   ifname, pos);
+		}
+	}
 
 	if (global_priv == NULL)
 		return NULL;
@@ -2389,7 +2454,7 @@
 	}
 
 	ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL,
-			    NULL, NULL);
+			    NULL, NULL, NULL);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
 			   "failed (type=%u): ret=%d (%s)",
@@ -2505,6 +2570,13 @@
 					  5) < 0)
 		ret = -1;
 #endif /* CONFIG_P2P */
+#ifdef CONFIG_NAN_USD
+	/* NAN SDF Public Action */
+	if (nl80211_register_action_frame(bss,
+					  (u8 *) "\x04\x09\x50\x6f\x9a\x13",
+					  6) < 0)
+		ret = -1;
+#endif /* CONFIG_NAN_USD */
 #ifdef CONFIG_DPP
 	/* DPP Public Action */
 	if (nl80211_register_action_frame(bss,
@@ -2650,7 +2722,7 @@
 
 	msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UNEXPECTED_FRAME);
 	ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL,
-			    NULL, NULL);
+			    NULL, NULL, NULL);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
 			   "failed: ret=%d (%s)",
@@ -2804,7 +2876,7 @@
 	int ret;
 
 	msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_INTERFACE);
-	ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(bss->drv, msg);
 
 	wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
 		   bss->ifname, (long long unsigned int) bss->wdev_id,
@@ -2819,7 +2891,7 @@
 
 	msg = nl80211_cmd_msg(bss, 0, start ? NL80211_CMD_START_P2P_DEVICE :
 			      NL80211_CMD_STOP_P2P_DEVICE);
-	ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(bss->drv, msg);
 
 	wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
 		   start ? "Start" : "Stop",
@@ -2890,8 +2962,7 @@
 	}
 	nla_nest_end(msg, params);
 
-	ret = send_and_recv_msgs(drv, msg, qca_vendor_test_cmd_handler, drv,
-				 NULL, NULL);
+	ret = send_and_recv_resp(drv, msg, qca_vendor_test_cmd_handler, drv);
 	wpa_printf(MSG_DEBUG,
 		   "nl80211: QCA vendor test command returned %d (%s)",
 		   ret, strerror(-ret));
@@ -3038,7 +3109,7 @@
 		}
 	}
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	return send_and_recv_cmd(drv, msg);
 }
 
 
@@ -3099,8 +3170,10 @@
 
 	nl80211_remove_monitor_interface(drv);
 
-	if (is_ap_interface(drv->nlmode))
+	if (is_ap_interface(drv->nlmode)) {
 		wpa_driver_nl80211_del_beacon_all(bss);
+		nl80211_remove_links(bss);
+	}
 
 	if (drv->eapol_sock >= 0) {
 		eloop_unregister_read_sock(drv->eapol_sock);
@@ -3296,57 +3369,6 @@
 	return num_suites;
 }
 
-#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
-static int wpa_driver_do_broadcom_acs(struct wpa_driver_nl80211_data *drv,
-				      struct drv_acs_params *params)
-{
-	struct nl_msg *msg;
-	struct nlattr *data;
-	int freq_list_len;
-	int ret = -1;
-
-	freq_list_len = int_array_len(params->freq_list);
-	wpa_printf(MSG_DEBUG, "%s: freq_list_len=%d",
-		    __func__, freq_list_len);
-
-	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
-	if (!msg ||
-	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
-	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
-			BRCM_VENDOR_SCMD_ACS) ||
-	    !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
-	    nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HW_MODE, params->hw_mode) ||
-	    nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT_ENABLED,
-		       params->ht_enabled) ||
-	    nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT40_ENABLED,
-		       params->ht40_enabled) ||
-		nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_VHT_ENABLED,
-		       params->vht_enabled) ||
-	    nla_put_u16(msg, BRCM_VENDOR_ATTR_ACS_CHWIDTH, params->ch_width) ||
-	    (freq_list_len > 0 &&
-	     nla_put(msg, BRCM_VENDOR_ATTR_ACS_FREQ_LIST,
-		     sizeof(int) * freq_list_len, params->freq_list)))
-		goto fail;
-	nla_nest_end(msg, data);
-
-	wpa_printf(MSG_DEBUG,
-		   "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d",
-		   params->hw_mode, params->ht_enabled, params->ht40_enabled,
-		   params->vht_enabled, params->ch_width);
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
-	if (ret) {
-		wpa_printf(MSG_ERROR,
-			   "nl80211: BRCM Failed to invoke driver ACS function: %s",
-			   strerror(errno));
-	}
-
-	msg = NULL;
-fail:
-	nlmsg_free(msg);
-	return ret;
-}
-#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
 
 #if (defined(CONFIG_DRIVER_NL80211_BRCM) && !defined(WIFI_BRCM_OPEN_SOURCE_MULTI_AKM)) ||   \
 	defined(CONFIG_DRIVER_NL80211_SYNA)
@@ -3368,6 +3390,7 @@
 #endif /* (CONFIG_DRIVER_NL80211_BRCM && !WIFI_BRCM_OPEN_SOURCE_MULTI_AKM) ||
 	* CONFIG_DRIVER_NL80211_SYNA */
 
+
 #ifdef CONFIG_DRIVER_NL80211_QCA
 static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
 				  const u8 *key, size_t key_len)
@@ -3387,7 +3410,7 @@
 		nlmsg_free(msg);
 		return -1;
 	}
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Key management set key failed: ret=%d (%s)",
@@ -3419,7 +3442,7 @@
 	}
 	nla_nest_end(msg, params);
 
-	ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Key mgmt set key failed: ret=%d (%s)",
 			ret, strerror(-ret));
@@ -3458,7 +3481,7 @@
 		return -ENOBUFS;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Set PMK failed: ret=%d (%s)",
 			   ret, strerror(-ret));
@@ -3639,7 +3662,7 @@
 			goto fail;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
 		ret = 0;
 	if (ret)
@@ -3708,7 +3731,7 @@
 			goto fail;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret)
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: set_key default failed; err=%d %s",
@@ -3821,7 +3844,6 @@
 {
 	int ret;
 	struct nl_msg *msg;
-	struct nl_sock *nl_connect = get_connect_handle(bss);
 
 	if (!(msg = nl80211_drv_msg(drv, 0, cmd)) ||
 	    nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code) ||
@@ -3832,11 +3854,8 @@
 		return -1;
 	}
 
-	if (nl_connect)
-		ret = send_and_recv(drv->global, nl_connect, msg,
-				    process_bss_event, bss, NULL, NULL);
-	else
-		ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv(drv->global, bss->nl_connect, msg,
+			    NULL, NULL, NULL, NULL, NULL);
 	if (ret) {
 		wpa_dbg(drv->ctx, MSG_DEBUG,
 			"nl80211: MLME command failed: reason=%u ret=%d (%s)",
@@ -3851,7 +3870,6 @@
 					 struct i802_bss *bss)
 {
 	int ret;
-	int drv_associated = drv->associated;
 
 	wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
 	nl80211_mark_disconnected(drv);
@@ -3862,7 +3880,8 @@
 	 * For locally generated disconnect, supplicant already generates a
 	 * DEAUTH event, so ignore the event from NL80211.
 	 */
-	drv->ignore_next_local_disconnect = drv_associated && (ret == 0);
+	if (ret == 0)
+		drv->ignore_next_local_disconnect = send_event_marker(drv);
 
 	return ret;
 }
@@ -3873,7 +3892,6 @@
 {
 	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);
@@ -3891,7 +3909,8 @@
 	 * For locally generated deauthenticate, supplicant already generates a
 	 * DEAUTH event, so ignore the event from NL80211.
 	 */
-	drv->ignore_next_local_deauth = drv_associated && (ret == 0);
+	if (ret == 0)
+		drv->ignore_next_local_deauth = send_event_marker(drv);
 
 	return ret;
 }
@@ -4114,7 +4133,7 @@
 			goto fail;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	msg = NULL;
 	if (ret) {
 		wpa_dbg(drv->ctx, MSG_DEBUG,
@@ -4194,6 +4213,7 @@
 {
 	struct wpa_driver_auth_params params;
 	struct i802_bss *bss = drv->first_bss;
+	u8 ap_mld_addr[ETH_ALEN];
 	int i;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
@@ -4219,8 +4239,10 @@
 	params.auth_data_len = drv->auth_data_len;
 	params.mld = drv->auth_mld;
 	params.mld_link_id = drv->auth_mld_link_id;
-	if (drv->auth_mld)
-		params.ap_mld_addr = drv->auth_ap_mld_addr;
+	if (drv->auth_mld) {
+		os_memcpy(ap_mld_addr, drv->auth_ap_mld_addr, ETH_ALEN);
+		params.ap_mld_addr = ap_mld_addr;
+	}
 
 	for (i = 0; i < 4; i++) {
 		if (drv->auth_wep_key_len[i]) {
@@ -4263,7 +4285,7 @@
 	size_t i;
 
 	for (i = 0; i < bss->n_links; i++) {
-		if (os_memcmp(bss->links[i].addr, addr, ETH_ALEN) == 0) {
+		if (ether_addr_equal(bss->links[i].addr, addr)) {
 			wpa_printf(MSG_DEBUG,
 				   "nl80211: Use link freq=%d for address "
 				   MACSTR,
@@ -4299,9 +4321,11 @@
 
 	mgmt = (struct ieee80211_mgmt *) data;
 	fc = le_to_host16(mgmt->frame_control);
-	wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da=" MACSTR
+	wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da=" MACSTR " sa=" MACSTR
+		   " bssid=" MACSTR
 		   " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u no_encrypt=%d fc=0x%x (%s) nlmode=%d",
-		   MAC2STR(mgmt->da), noack, freq, no_cck, offchanok, wait_time,
+		   MAC2STR(mgmt->da), MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid),
+		   noack, freq, no_cck, offchanok, wait_time,
 		   no_encrypt, fc, fc2str(fc), drv->nlmode);
 
 	if ((is_sta_interface(drv->nlmode) ||
@@ -4428,7 +4452,7 @@
 	wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame_cmd");
 	res = nl80211_send_frame_cmd(bss, freq, wait_time, data, data_len,
 				     use_cookie, no_cck, noack, offchanok,
-				     csa_offs, csa_offs_len);
+				     csa_offs, csa_offs_len, link_id);
 	if (!res)
 		drv->send_frame_link_id = link_id;
 
@@ -4454,7 +4478,7 @@
 
 static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
 			   int slot, int ht_opmode, int ap_isolate,
-			   const int *basic_rates)
+			   const int *basic_rates, int link_id)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
@@ -4470,12 +4494,14 @@
 	     nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode)) ||
 	    (ap_isolate >= 0 &&
 	     nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)) ||
-	    nl80211_put_basic_rates(msg, basic_rates)) {
+	    nl80211_put_basic_rates(msg, basic_rates) ||
+	    (link_id != NL80211_DRV_LINK_ID_NA &&
+	     nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id))) {
 		nlmsg_free(msg);
 		return -ENOBUFS;
 	}
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	return send_and_recv_cmd(drv, msg);
 }
 
 
@@ -4534,7 +4560,7 @@
 	}
 	nlmsg_free(acl);
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
 			   ret, strerror(-ret));
@@ -4586,7 +4612,7 @@
 		return ret;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_ERROR,
 			   "nl80211: Mesh config set failed: %d (%s)",
@@ -4732,7 +4758,7 @@
 		return -ENOBUFS;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 
 	switch (ret) {
 	case 0:
@@ -4926,7 +4952,8 @@
 
 #ifdef CONFIG_DRIVER_NL80211_QCA
 static void qca_set_allowed_ap_freqs(struct wpa_driver_nl80211_data *drv,
-				    const int *freqs, int num_freqs)
+				     const int *freqs, int num_freqs,
+				     int link_id)
 {
 	struct nl_msg *msg;
 	struct nlattr *params, *freqs_list;
@@ -4944,6 +4971,10 @@
 	    !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)))
 		goto err;
 
+	if (link_id != NL80211_DRV_LINK_ID_NA &&
+	    nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINK_ID, link_id))
+		goto err;
+
 	freqs_list = nla_nest_start(
 		msg, QCA_WLAN_VENDOR_ATTR_CONFIG_AP_ALLOWED_FREQ_LIST);
 	if (!freqs_list)
@@ -4957,7 +4988,7 @@
 	nla_nest_end(msg, freqs_list);
 	nla_nest_end(msg, params);
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret)
 		wpa_printf(MSG_ERROR,
 			   "nl80211: Failed set AP alllowed frequency list: %d (%s)",
@@ -5225,32 +5256,26 @@
 			 suites))
 		goto fail;
 
-	if ((params->key_mgmt_suites & WPA_KEY_MGMT_PSK) &&
+	if (wpa_key_mgmt_wpa_psk_no_sae(params->key_mgmt_suites) &&
 	    (drv->capa.flags2 & WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK) &&
-	    params->psk_len) {
-		if (nla_put(msg, NL80211_ATTR_PMK, params->psk_len, params->psk)) {
-			wpa_printf(MSG_ERROR, "nl80211: Setting PSK failed");
-			goto fail;
-		} else
-			wpa_printf(MSG_DEBUG, "nl80211: Setting PSK for offload");
-	}
+	    params->psk_len &&
+	    nla_put(msg, NL80211_ATTR_PMK, params->psk_len, params->psk))
+		goto fail;
 
 	if (wpa_key_mgmt_sae(params->key_mgmt_suites) &&
 	    (drv->capa.flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP) &&
-	    params->sae_password) {
-		if (nla_put(msg, NL80211_ATTR_SAE_PASSWORD,
-		    os_strlen(params->sae_password), params->sae_password)) {
-			wpa_printf(MSG_ERROR, "nl80211: Setting SAE password failed");
-			goto fail;
-		} else
-			wpa_printf(MSG_DEBUG, "nl80211: SAE password for offload");
-	}
+	    params->sae_password &&
+	    nla_put(msg, NL80211_ATTR_SAE_PASSWORD,
+		    os_strlen(params->sae_password), params->sae_password))
+		goto fail;
+
+	if (nl80211_put_control_port(drv, msg) < 0)
+		goto fail;
 
 	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
 	    (!params->pairwise_ciphers ||
 	     params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) &&
-	    (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
-	     nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
+	    nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
 		goto fail;
 
 	if (drv->device_ap_sme) {
@@ -5269,7 +5294,9 @@
 
 		flags |= NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT;
 
-		if (nla_put_u32(msg, NL80211_ATTR_AP_SETTINGS_FLAGS, flags))
+		if (nl80211_attr_supported(drv,
+					   NL80211_ATTR_AP_SETTINGS_FLAGS) &&
+		    nla_put_u32(msg, NL80211_ATTR_AP_SETTINGS_FLAGS, flags))
 			goto fail;
 	}
 
@@ -5403,7 +5430,8 @@
 	if (params->freq && nl80211_put_freq_params(msg, params->freq) < 0)
 		goto fail;
 
-	if (params->freq && params->freq->he_enabled) {
+	if (params->freq && params->freq->he_enabled &&
+	    nl80211_attr_supported(drv, NL80211_ATTR_HE_BSS_COLOR)) {
 		struct nlattr *bss_color;
 
 		bss_color = nla_nest_start(msg, NL80211_ATTR_HE_BSS_COLOR);
@@ -5455,10 +5483,15 @@
 #ifdef CONFIG_DRIVER_NL80211_QCA
 	if (cmd == NL80211_CMD_NEW_BEACON && params->allowed_freqs)
 		qca_set_allowed_ap_freqs(drv, params->allowed_freqs,
-					 int_array_len(params->allowed_freqs));
+					 int_array_len(params->allowed_freqs),
+					 params->mld_ap ? params->mld_link_id :
+					 NL80211_DRV_LINK_ID_NA);
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
-	ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1);
+	if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER))
+		goto fail;
+	ret = send_and_recv(drv->global, bss->nl_connect, msg, NULL, NULL, NULL,
+			    NULL, NULL);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
 			   ret, strerror(-ret));
@@ -5466,7 +5499,9 @@
 		link->beacon_set = 1;
 		nl80211_set_bss(bss, params->cts_protect, params->preamble,
 				params->short_slot_time, params->ht_opmode,
-				params->isolate, params->basic_rates);
+				params->isolate, params->basic_rates,
+				params->mld_ap ? params->mld_link_id :
+				NL80211_DRV_LINK_ID_NA);
 		nl80211_set_multicast_to_unicast(bss,
 						 params->multicast_to_unicast);
 		if (beacon_set && params->freq &&
@@ -5564,7 +5599,7 @@
 		}
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret == 0) {
 		nl80211_link_set_freq(bss, freq->link_id, freq->freq);
 		return 0;
@@ -5905,7 +5940,7 @@
 			goto fail;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	msg = NULL;
 	if (ret)
 		wpa_printf(MSG_DEBUG, "nl80211: %s result: %d (%s)",
@@ -5976,7 +6011,7 @@
 		return -ENOBUFS;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
 		   " --> %d (%s)",
 		   bss->ifname, MAC2STR(addr), ret, strerror(-ret));
@@ -6007,7 +6042,7 @@
 	}
 
 	msg = nl80211_ifindex_msg(drv, ifidx, 0, NL80211_CMD_DEL_INTERFACE);
-	if (send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL) == 0)
+	if (send_and_recv_cmd(drv, msg) == 0)
 		return;
 	wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
 }
@@ -6091,7 +6126,7 @@
 	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
 		goto fail;
 
-	ret = send_and_recv_msgs(drv, msg, handler, arg, NULL, NULL);
+	ret = send_and_recv_resp(drv, msg, handler, arg);
 	msg = NULL;
 	if (ret) {
 	fail:
@@ -6238,7 +6273,8 @@
 		nl80211_mgmt_unsubscribe(bss, "AP teardown");
 
 	nl80211_put_wiphy_data_ap(bss);
-	bss->flink->beacon_set = 0;
+	if (bss->flink)
+		bss->flink->beacon_set = 0;
 }
 
 
@@ -6272,8 +6308,8 @@
 
 	os_memset(&ext_arg, 0, sizeof(struct nl80211_ack_ext_arg));
 	ext_arg.ext_data = &cookie;
-	ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL,
-				 ack_handler_cookie, &ext_arg);
+	ret = send_and_recv(bss->drv->global, bss->drv->global->nl, msg,
+			    NULL, NULL, ack_handler_cookie, &ext_arg, NULL);
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: tx_control_port failed: ret=%d (%s)",
@@ -6440,7 +6476,7 @@
 	if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
 		goto fail;
 
-	return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
+	return send_and_recv_cmd(bss->drv, msg);
 fail:
 	nlmsg_free(msg);
 	return -ENOBUFS;
@@ -6463,7 +6499,7 @@
 	    nla_put_u16(msg, NL80211_ATTR_AIRTIME_WEIGHT, weight))
 		goto fail;
 
-	ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(bss->drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: SET_STATION[AIRTIME_WEIGHT] failed: ret=%d (%s)",
@@ -6513,7 +6549,8 @@
 	int ret;
 
 	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS);
-	ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss, 1);
+	ret = send_and_recv(drv->global, drv->first_bss->nl_connect, msg, NULL,
+			    NULL, NULL, NULL, NULL);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
 			   "(%s)", ret, strerror(-ret));
@@ -6643,7 +6680,7 @@
 	    params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
 	    params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA384) {
 		wpa_printf(MSG_DEBUG, "  * control port");
-		if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
+		if (nl80211_put_control_port(drv, msg))
 			goto fail;
 	}
 
@@ -6660,7 +6697,10 @@
 	if (ret < 0)
 		goto fail;
 
-	ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss, 1);
+	if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER))
+		goto fail;
+	ret = send_and_recv(drv->global, drv->first_bss->nl_connect, msg, NULL,
+			    NULL, NULL, NULL, NULL);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
@@ -6793,6 +6833,9 @@
 				    mld_params->mld_links[link_id].bssid) ||
 			    nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
 					mld_params->mld_links[link_id].freq) ||
+			    (mld_params->mld_links[i].disabled &&
+			     nla_put_flag(msg,
+					  NL80211_ATTR_MLO_LINK_DISABLED)) ||
 			    (mld_params->mld_links[link_id].ies &&
 			     mld_params->mld_links[i].ies_len &&
 			     nla_put(msg, NL80211_ATTR_IE,
@@ -6891,8 +6934,20 @@
 
 		if (params->wpa_proto & WPA_PROTO_WPA)
 			ver |= NL80211_WPA_VERSION_1;
-		if (params->wpa_proto & WPA_PROTO_RSN)
-			ver |= NL80211_WPA_VERSION_2;
+		if (params->wpa_proto & WPA_PROTO_RSN) {
+#if !defined(CONFIG_DRIVER_NL80211_BRCM) && !defined(CONFIG_DRIVER_NL80211_SYNA)
+			/*
+			 * NL80211_ATTR_SAE_PASSWORD is related and was added
+			 * at the same time as NL80211_WPA_VERSION_3.
+			 */
+			if (nl80211_attr_supported(drv,
+						   NL80211_ATTR_SAE_PASSWORD) &&
+			    wpa_key_mgmt_sae(params->key_mgmt_suite))
+				ver |= NL80211_WPA_VERSION_3;
+			else
+#endif
+				ver |= NL80211_WPA_VERSION_2;
+		}
 
 		wpa_printf(MSG_DEBUG, "  * WPA Versions 0x%x", ver);
 		if (nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
@@ -7086,15 +7141,14 @@
 			return -1;
 	}
 
-	if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
+	if (nl80211_put_control_port(drv, msg))
 		return -1;
 
 	if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
 	    (params->pairwise_suite == WPA_CIPHER_NONE ||
 	     params->pairwise_suite == WPA_CIPHER_WEP104 ||
 	     params->pairwise_suite == WPA_CIPHER_WEP40) &&
-	    (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
-	     nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
+	    nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
 		return -1;
 
 	if (params->rrm_used) {
@@ -7244,7 +7298,10 @@
 	if (ret)
 		goto fail;
 
-	ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1);
+	if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER))
+		goto fail;
+	ret = send_and_recv(drv->global, bss->nl_connect, msg, NULL, NULL, NULL,
+			    NULL, NULL);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
@@ -7302,6 +7359,7 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl80211_err_info err_info;
 	int ret = -1;
 	struct nl_msg *msg;
 
@@ -7319,11 +7377,6 @@
 
 		if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
 			return -1;
-		if (wpa_key_mgmt_sae(params->key_mgmt_suite) ||
-		    wpa_key_mgmt_sae(params->allowed_key_mgmts))
-			bss->use_nl_connect = 1;
-		else
-			bss->use_nl_connect = 0;
 
 		return wpa_driver_nl80211_connect(drv, params, bss);
 	}
@@ -7360,13 +7413,45 @@
 			goto fail;
 	}
 
-	ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss, 1);
-	msg = NULL;
+	if (!TEST_FAIL_TAG("assoc")) {
+		if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER))
+			goto fail;
+		ret = send_and_recv(drv->global, drv->first_bss->nl_connect,
+				    msg, NULL, NULL, NULL, NULL, &err_info);
+		msg = NULL;
+	} else {
+		int i;
+
+		/* Error and force TEST_FAIL checking for each link */
+		ret = -EINVAL;
+		for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+			if (!(params->mld_params.valid_links & BIT(i)))
+				continue;
+
+			if (TEST_FAIL_TAG("link"))
+				err_info.link_id = i;
+		}
+	}
+
 	if (ret) {
 		wpa_dbg(drv->ctx, MSG_DEBUG,
 			"nl80211: MLME command failed (assoc): ret=%d (%s)",
 			ret, strerror(-ret));
 		nl80211_dump_scan(drv);
+
+		/* Mark failed link within params */
+		if (err_info.link_id >= 0) {
+			if (err_info.link_id >= MAX_NUM_MLD_LINKS ||
+			    !(params->mld_params.valid_links &
+			      BIT(err_info.link_id))) {
+				wpa_printf(MSG_DEBUG,
+					   "nl80211: Invalid errorred link_id %d",
+					   err_info.link_id);
+				goto fail;
+			}
+			params->mld_params.mld_links[err_info.link_id].error =
+				ret;
+		}
 	} else {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Association request send successfully");
@@ -7391,7 +7476,7 @@
 	if (!msg || nla_put_u32(msg, NL80211_ATTR_IFTYPE, mode))
 		goto fail;
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	msg = NULL;
 	if (!ret)
 		return 0;
@@ -7658,7 +7743,7 @@
 		return -ENOBUFS;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (!ret)
 		return 0;
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)",
@@ -7725,7 +7810,7 @@
 	}
 
 	os_memset(seq, 0, 6);
-	res = send_and_recv_msgs(drv, msg, get_key_handler, seq, NULL, NULL);
+	res = send_and_recv_resp(drv, msg, get_key_handler, seq);
 	if (res) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Failed to get current TX sequence for a key (link_id=%d idx=%d): %d (%s)",
@@ -7755,7 +7840,7 @@
 		return -ENOBUFS;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (!ret)
 		return 0;
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
@@ -7783,7 +7868,7 @@
 		return -ENOBUFS;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (!ret)
 		return 0;
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
@@ -7805,7 +7890,7 @@
 	 * XXX: FIX! this needs to flush all VLANs too
 	 */
 	msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION);
-	res = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
+	res = send_and_recv_cmd(bss->drv, msg);
 	if (res) {
 		wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
 			   "(%s)", res, strerror(-res));
@@ -8136,7 +8221,7 @@
 		return -ENOBUFS;
 	}
 
-	return send_and_recv_msgs(drv, msg, get_sta_handler, data, NULL, NULL);
+	return send_and_recv_resp(drv, msg, get_sta_handler, data);
 }
 
 
@@ -8152,8 +8237,7 @@
 		return -ENOBUFS;
 	}
 
-	return send_and_recv_msgs(bss->drv, msg, get_sta_handler, data,
-				  NULL, NULL);
+	return send_and_recv_resp(bss->drv, msg, get_sta_handler, data);
 }
 
 
@@ -8215,10 +8299,10 @@
 	    nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id))
 		goto fail;
 
-	res = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	res = send_and_recv_cmd(drv, msg);
 	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);
+		   "nl80211: link=%d: TX queue param set: queue=%d aifs=%d cw_min=%d cw_max=%d burst_time=%d --> res=%d",
+		   link_id, queue, aifs, cw_min, cw_max, burst_time, res);
 	if (res == 0)
 		return 0;
 	msg = NULL;
@@ -8250,7 +8334,7 @@
 		return -ENOBUFS;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret < 0) {
 		wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
 			   MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
@@ -8769,7 +8853,7 @@
 	struct wpa_driver_nl80211_data *drv;
 	dl_list_for_each(drv, &global->interfaces,
 			 struct wpa_driver_nl80211_data, list) {
-		if (os_memcmp(addr, drv->first_bss->addr, ETH_ALEN) == 0)
+		if (ether_addr_equal(addr, drv->first_bss->addr))
 			return 1;
 	}
 	return 0;
@@ -9086,7 +9170,7 @@
 				  const u8 *buf, size_t buf_len,
 				  int save_cookie, int no_cck, int no_ack,
 				  int offchanok, const u16 *csa_offs,
-				  size_t csa_offs_len)
+				  size_t csa_offs_len, int link_id)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
@@ -9099,6 +9183,8 @@
 	wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len);
 
 	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME)) ||
+	    ((link_id != NL80211_DRV_LINK_ID_NA) &&
+	     nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) ||
 	    (freq && nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
 	    (wait && nla_put_u32(msg, NL80211_ATTR_DURATION, wait)) ||
 	    (offchanok && ((drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
@@ -9112,7 +9198,7 @@
 		goto fail;
 
 	cookie = 0;
-	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
+	ret = send_and_recv_resp(drv, msg, cookie_handler, &cookie);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
@@ -9170,9 +9256,14 @@
 	    bss->flink->beacon_set)
 		offchanok = 0;
 
-	wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
-		   "freq=%u MHz wait=%d ms no_cck=%d offchanok=%d)",
-		   drv->ifindex, freq, wait_time, no_cck, offchanok);
+	if (!freq && is_sta_interface(drv->nlmode))
+		offchanok = 0;
+
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: Send Action frame (ifindex=%d, freq=%u MHz wait=%d ms no_cck=%d offchanok=%d dst="
+		   MACSTR " src=" MACSTR " bssid=" MACSTR ")",
+		   drv->ifindex, freq, wait_time, no_cck, offchanok,
+		   MAC2STR(dst), MAC2STR(src), MAC2STR(bssid));
 
 	buf = os_zalloc(24 + data_len);
 	if (buf == NULL)
@@ -9185,7 +9276,7 @@
 	os_memcpy(hdr->addr2, src, ETH_ALEN);
 	os_memcpy(hdr->addr3, bssid, ETH_ALEN);
 
-	if (os_memcmp(bss->addr, src, ETH_ALEN) != 0) {
+	if (!ether_addr_equal(bss->addr, src)) {
 		wpa_printf(MSG_DEBUG, "nl80211: Use random TA " MACSTR,
 			   MAC2STR(src));
 		os_memcpy(bss->rand_addr, src, ETH_ALEN);
@@ -9224,8 +9315,9 @@
 						   wait_time, NULL, 0, 0, -1);
 	else
 		ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
-					     24 + data_len,
-					     1, no_cck, 0, offchanok, NULL, 0);
+					     24 + data_len, 1, no_cck, 0,
+					     offchanok, NULL, 0,
+					     NL80211_DRV_LINK_ID_NA);
 
 	os_free(buf);
 	return ret;
@@ -9246,7 +9338,7 @@
 		return;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret)
 		wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
 			   "(%s)", ret, strerror(-ret));
@@ -9278,6 +9370,46 @@
 }
 
 
+static int nl80211_put_any_link_id(struct nl_msg *msg,
+			       struct driver_sta_mlo_info *mlo,
+			       int freq)
+{
+	int i;
+	int link_id = -1;
+	int any_valid_link_id = -1;
+
+	if (!mlo->valid_links)
+		return 0;
+
+	/* First try to pick a link that uses the same band */
+	for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+		if (!(mlo->valid_links & BIT(i)))
+			continue;
+
+		if (any_valid_link_id == -1)
+			any_valid_link_id = i;
+
+		if (is_same_band(freq, mlo->links[i].freq)) {
+			link_id = i;
+			break;
+		}
+	}
+
+	/* Use any valid link ID if no band match was found */
+	if (link_id == -1)
+		link_id = any_valid_link_id;
+
+	if (link_id == -1) {
+		wpa_printf(MSG_INFO,
+			   "nl80211: No valid Link ID found for freq %u", freq);
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Add Link ID %d", link_id);
+	return nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id);
+}
+
+
 static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
 						unsigned int duration)
 {
@@ -9289,13 +9421,14 @@
 
 	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REMAIN_ON_CHANNEL)) ||
 	    nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
-	    nla_put_u32(msg, NL80211_ATTR_DURATION, duration)) {
+	    nla_put_u32(msg, NL80211_ATTR_DURATION, duration) ||
+	    nl80211_put_any_link_id(msg, &drv->sta_mlo_info, freq)) {
 		nlmsg_free(msg);
 		return -1;
 	}
 
 	cookie = 0;
-	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
+	ret = send_and_recv_resp(drv, msg, cookie_handler, &cookie);
 	if (ret == 0) {
 		wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
 			   "0x%llx for freq=%u MHz duration=%u",
@@ -9335,7 +9468,7 @@
 		return -1;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret == 0)
 		return 0;
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
@@ -9432,7 +9565,7 @@
 
 	nla_nest_end(msg, bands);
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
 			   "(%s)", ret, strerror(-ret));
@@ -9454,6 +9587,9 @@
 	int ret;
 	u8 link_id;
 
+	if (bss->n_links == 0)
+		return;
+
 	while (bss->links[0].link_id != NL80211_DRV_LINK_ID_NA) {
 		struct i802_link *link = &bss->links[0];
 
@@ -9489,7 +9625,7 @@
 			return;
 		}
 
-		ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+		ret = send_and_recv_cmd(drv, msg);
 		if (ret) {
 			wpa_printf(MSG_ERROR,
 				   "nl80211: remove link (%d) failed. ret=%d (%s)",
@@ -9588,7 +9724,7 @@
 	}
 	nla_nest_end(msg, cqm);
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	return send_and_recv_cmd(drv, msg);
 }
 
 
@@ -9626,7 +9762,7 @@
 	struct nl_msg *msg;
 
 	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
-	return send_and_recv_msgs(drv, msg, get_channel_width, sig, NULL, NULL);
+	return send_and_recv_resp(drv, msg, get_channel_width, sig);
 }
 
 
@@ -9710,8 +9846,7 @@
 	struct nl_msg *msg;
 
 	msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
-	return send_and_recv_msgs(drv, msg, get_links_noise, mlo_sig,
-				  NULL, NULL);
+	return send_and_recv_resp(drv, msg, get_links_noise, mlo_sig);
 }
 
 
@@ -9765,8 +9900,7 @@
 	struct nl_msg *msg;
 
 	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
-	return send_and_recv_msgs(drv, msg, get_links_channel_width, mlo_sig,
-				  NULL, NULL);
+	return send_and_recv_resp(drv, msg, get_links_channel_width, mlo_sig);
 }
 
 
@@ -9887,6 +10021,13 @@
 {
 	struct nl80211_global *global;
 	struct netlink_config *cfg;
+	struct utsname name;
+
+	if (uname(&name) == 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: Kernel version: %s %s (%s; %s)",
+			   name.sysname, name.release,
+			   name.version, name.machine);
+	}
 
 	global = os_zalloc(sizeof(*global));
 	if (global == NULL)
@@ -9997,7 +10138,7 @@
 		return -ENOBUFS;
 	}
 
-	return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
+	return send_and_recv_cmd(bss->drv, msg);
 }
 
 
@@ -10073,7 +10214,7 @@
 	msg = nl80211_bss_msg(bss, 0, NL80211_CMD_FLUSH_PMKSA);
 	if (!msg)
 		return -ENOBUFS;
-	return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
+	return send_and_recv_cmd(bss->drv, msg);
 }
 
 
@@ -10237,8 +10378,8 @@
 
 	do {
 		wpa_printf(MSG_DEBUG, "nl80211: Fetch survey data");
-		err = send_and_recv_msgs(drv, msg, survey_handler,
-					 survey_results, NULL, NULL);
+		err = send_and_recv_resp(drv, msg, survey_handler,
+					 survey_results);
 	} while (err > 0);
 
 	if (err)
@@ -10278,7 +10419,7 @@
 
 	nla_nest_end(msg, replay_nested);
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret == -EOPNOTSUPP) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Driver does not support rekey offload");
@@ -10345,7 +10486,7 @@
 		return;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
+	ret = send_and_recv_resp(drv, msg, cookie_handler, &cookie);
 	if (ret < 0) {
 		wpa_printf(MSG_DEBUG, "nl80211: Client probe request for "
 			   MACSTR " failed: ret=%d (%s)",
@@ -10371,7 +10512,7 @@
 		return -ENOBUFS;
 	}
 
-	ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(bss->drv, msg);
 	if (ret < 0) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Setting PS state %s failed: %d (%s)",
@@ -10431,7 +10572,7 @@
 		return -1;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret == 0)
 		return 0;
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
@@ -10490,7 +10631,7 @@
 	}
 	nla_nest_end(msg, params);
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	return send_and_recv_cmd(drv, msg);
 #else /* CONFIG_DRIVER_NL80211_QCA */
 	wpa_printf(MSG_ERROR,
 		   "nl80211: Setting TX link for TDLS Discovery Response not supported");
@@ -10528,7 +10669,7 @@
 	    nla_put(msg, NL80211_ATTR_IE, len, buf))
 		goto fail;
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	return send_and_recv_cmd(drv, msg);
 
 fail:
 	nlmsg_free(msg);
@@ -10578,7 +10719,7 @@
 		return -ENOBUFS;
 	}
 
-	res = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	res = send_and_recv_cmd(drv, msg);
 	wpa_printf(MSG_DEBUG, "nl80211: TDLS_OPER: oper=%d mac=" MACSTR
 		   " --> res=%d (%s)", nl80211_oper, MAC2STR(peer), res,
 		   strerror(-res));
@@ -10612,7 +10753,7 @@
 		return ret;
 	}
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	return send_and_recv_cmd(drv, msg);
 }
 
 
@@ -10638,7 +10779,7 @@
 		return -ENOBUFS;
 	}
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	return send_and_recv_cmd(drv, msg);
 }
 
 #endif /* CONFIG TDLS */
@@ -10783,7 +10924,7 @@
 		return -ENOBUFS;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed "
 			   "err=%d (%s)", ret, strerror(-ret));
@@ -10811,7 +10952,7 @@
 		return -ENOBUFS;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: update_dh_ie failed err=%d (%s)",
@@ -10953,9 +11094,9 @@
 			  drv->retry_auth ? "retry_auth=1\n" : "",
 			  drv->use_monitor ? "use_monitor=1\n" : "",
 			  drv->ignore_next_local_disconnect ?
-			  "ignore_next_local_disconnect=1\n" : "",
+			  "ignore_next_local_disconnect\n" : "",
 			  drv->ignore_next_local_deauth ?
-			  "ignore_next_local_deauth=1\n" : "");
+			  "ignore_next_local_deauth\n" : "");
 	if (os_snprintf_error(end - pos, res))
 		return pos - buf;
 	pos += res;
@@ -11063,8 +11204,8 @@
 	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, NULL, NULL) == 0 &&
+		if (send_and_recv_resp(drv, msg, nl80211_get_country,
+				       alpha2) == 0 &&
 		    alpha2[0]) {
 			res = os_snprintf(pos, end - pos, "country=%s\n",
 					  alpha2);
@@ -11117,7 +11258,7 @@
 	int i;
 
 	wpa_printf(MSG_DEBUG,
-		   "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d channel=%d sec_channel_offset=%d width=%d cf1=%d cf2=%d puncturing_bitmap=0x%04x%s%s%s)",
+		   "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d channel=%d sec_channel_offset=%d width=%d cf1=%d cf2=%d puncturing_bitmap=0x%04x link_id=%d%s%s%s)",
 		   settings->cs_count, settings->block_tx,
 		   settings->freq_params.freq,
 		   settings->freq_params.channel,
@@ -11126,6 +11267,7 @@
 		   settings->freq_params.center_freq1,
 		   settings->freq_params.center_freq2,
 		   settings->punct_bitmap,
+		   settings->link_id,
 		   settings->freq_params.ht_enabled ? " ht" : "",
 		   settings->freq_params.vht_enabled ? " vht" : "",
 		   settings->freq_params.he_enabled ? " he" : "");
@@ -11199,7 +11341,9 @@
 	     nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX)) ||
 	    (settings->punct_bitmap &&
 	     nla_put_u32(msg, NL80211_ATTR_PUNCT_BITMAP,
-			 settings->punct_bitmap)))
+			 settings->punct_bitmap)) ||
+	    (settings->link_id != NL80211_DRV_LINK_ID_NA &&
+	     nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, settings->link_id)))
 		goto error;
 
 	/* beacon_after params */
@@ -11226,7 +11370,7 @@
 		goto fail;
 
 	nla_nest_end(msg, beacon_csa);
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)",
 			   ret, strerror(-ret));
@@ -11307,7 +11451,7 @@
 	}
 
 	nla_nest_end(msg, beacon_cca);
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: switch_color failed err=%d (%s)",
@@ -11348,7 +11492,7 @@
 		return -ENOBUFS;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret)
 		wpa_printf(MSG_DEBUG, "nl80211: add_ts failed err=%d (%s)",
 			   ret, strerror(-ret));
@@ -11375,7 +11519,7 @@
 		return -ENOBUFS;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret)
 		wpa_printf(MSG_DEBUG, "nl80211: del_ts failed err=%d (%s)",
 			   ret, strerror(-ret));
@@ -11477,12 +11621,10 @@
 		    0)
 			goto fail;
 		/* This test vendor_cmd can be used with nl80211 commands that
-		 * need the connect nl_sock, so use the owner-setting variant
-		 * of send_and_recv_msgs(). */
-		ret = send_and_recv_msgs_owner(drv, msg,
-					       get_connect_handle(bss), 0,
-					       cmd_reply_handler, buf,
-					       NULL, NULL);
+		 * need the connect nl_sock, so use the variant that takes in
+		 * bss->nl_connect as the handle. */
+		ret = send_and_recv(drv->global, bss->nl_connect, msg,
+				    cmd_reply_handler, buf, NULL, NULL, NULL);
 		if (ret)
 			wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
 				   ret);
@@ -11506,8 +11648,7 @@
 		     data_len, data)))
 		goto fail;
 
-	ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf,
-				 NULL, NULL);
+	ret = send_and_recv_resp(drv, msg, vendor_reply_handler, buf);
 	if (ret)
 		wpa_printf(MSG_DEBUG, "nl80211: vendor command failed err=%d",
 			   ret);
@@ -11536,7 +11677,7 @@
 		return -ENOBUFS;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret)
 		wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
 
@@ -11571,8 +11712,7 @@
 
 	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_WOWLAN);
 
-	ret = send_and_recv_msgs(drv, msg, get_wowlan_handler, &wowlan_enabled,
-				 NULL, NULL);
+	ret = send_and_recv_resp(drv, msg, get_wowlan_handler, &wowlan_enabled);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status failed");
 		return 0;
@@ -11619,7 +11759,7 @@
 
 	nla_nest_end(msg, wowlan_triggers);
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret)
 		wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan failed");
 
@@ -11658,7 +11798,7 @@
 	}
 	nla_nest_end(msg, params);
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	return send_and_recv_cmd(drv, msg);
 }
 
 
@@ -11686,7 +11826,7 @@
 	}
 	nla_nest_end(msg, params);
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	return send_and_recv_cmd(drv, msg);
 }
 
 
@@ -11743,7 +11883,7 @@
 	nla_nest_end(msg, nlbssids);
 	nla_nest_end(msg, params);
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	return send_and_recv_cmd(drv, msg);
 
 fail:
 	nlmsg_free(msg);
@@ -11781,7 +11921,7 @@
 	}
 	nla_nest_end(msg, params);
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	return send_and_recv_cmd(drv, msg);
 }
 
 #endif /* CONFIG_DRIVER_NL80211_QCA */
@@ -11820,7 +11960,7 @@
 		}
 		nla_nest_end(msg, params);
 
-		ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
+		ret = send_and_recv_cmd(drv, msg);
 		if (ret) {
 			wpa_printf(MSG_ERROR, "nl80211: p2p set macaddr failed: ret=%d (%s)",
 				ret, strerror(-ret));
@@ -11991,7 +12131,10 @@
 	if (nl80211_put_mesh_config(msg, &params->conf) < 0)
 		goto fail;
 
-	ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1);
+	if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER))
+		return -1;
+	ret = send_and_recv(drv->global, bss->nl_connect, msg, NULL, NULL, NULL,
+			    NULL, NULL);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
@@ -12048,7 +12191,8 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
 	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH);
-	ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 0);
+	ret = send_and_recv(drv->global, bss->nl_connect, msg, NULL, NULL, NULL,
+			    NULL, NULL);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
 			   ret, strerror(-ret));
@@ -12084,7 +12228,7 @@
 		return -ENOBUFS;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: mesh link probe to " MACSTR
 			   " failed: ret=%d (%s)",
@@ -12489,19 +12633,22 @@
 	    add_acs_ch_list(msg, params->freq_list) ||
 	    add_acs_freq_list(msg, params->freq_list) ||
 	    (params->edmg_enabled &&
-	     nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED))) {
+	     nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED)) ||
+	    (params->link_id != NL80211_DRV_LINK_ID_NA &&
+	     nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_ACS_LINK_ID,
+			params->link_id))) {
 		nlmsg_free(msg);
 		return -ENOBUFS;
 	}
 	nla_nest_end(msg, data);
 
 	wpa_printf(MSG_DEBUG,
-		   "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d EHT: %d BW: %d EDMG: %d",
+		   "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d EHT: %d BW: %d EDMG: %d, link_id: %d",
 		   params->hw_mode, params->ht_enabled, params->ht40_enabled,
 		   params->vht_enabled, params->eht_enabled, params->ch_width,
-		   params->edmg_enabled);
+		   params->edmg_enabled, params->link_id);
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Failed to invoke driver ACS function: %s",
@@ -12559,7 +12706,7 @@
 	}
 	nla_nest_end(msg, data);
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Driver setband function failed: %s",
@@ -12761,11 +12908,10 @@
 
 	if (freq_list)
 		os_memset(freq_list, 0, *num * sizeof(struct weighted_pcl));
-	ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, &param,
-				 NULL, NULL);
+	ret = send_and_recv_resp(drv, msg, preferred_freq_info_handler, &param);
 	if (ret) {
 		wpa_printf(MSG_ERROR,
-			   "%s: err in send_and_recv_msgs", __func__);
+			   "%s: err in send_and_recv_resp", __func__);
 		return ret;
 	}
 
@@ -12816,10 +12962,10 @@
 	}
 	nla_nest_end(msg, params);
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	msg = NULL;
 	if (ret) {
-		wpa_printf(MSG_ERROR, "%s: err in send_and_recv_msgs",
+		wpa_printf(MSG_ERROR, "%s: err in send_and_recv_cmd",
 			   __func__);
 		return ret;
 	}
@@ -12872,7 +13018,7 @@
 		goto fail;
 
 	nla_nest_end(msg, container);
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
@@ -12907,7 +13053,7 @@
 		return -1;
 	}
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	return send_and_recv_cmd(drv, msg);
 }
 
 
@@ -12946,7 +13092,7 @@
 
 	nla_nest_end(msg, params);
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_ERROR,
@@ -13137,9 +13283,9 @@
 	nla_nest_end(msg, attr1);
 	nla_nest_end(msg, attr);
 
-	ret = send_and_recv_msgs(drv, msg,
+	ret = send_and_recv_resp(drv, msg,
 				 nl80211_get_bss_transition_status_handler,
-				 info, NULL, NULL);
+				 info);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_ERROR,
@@ -13192,7 +13338,7 @@
 
 	nla_nest_end(msg, attr);
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_ERROR,
@@ -13263,7 +13409,7 @@
 	nla_nest_end(msg, nlpeers);
 	nla_nest_end(msg, attr);
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	return send_and_recv_cmd(drv, msg);
 
 fail:
 	nlmsg_free(msg);
@@ -13359,7 +13505,7 @@
 	}
 	nla_nest_end(msg, attr);
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret)
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Set secure ranging context failed: ret=%d (%s)",
@@ -13374,6 +13520,60 @@
 
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
+
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
+static int wpa_driver_do_broadcom_acs(struct wpa_driver_nl80211_data *drv,
+				      struct drv_acs_params *params)
+{
+	struct nl_msg *msg;
+	struct nlattr *data;
+	int freq_list_len;
+	int ret = -1;
+
+	freq_list_len = int_array_len(params->freq_list);
+	wpa_printf(MSG_DEBUG, "%s: freq_list_len=%d",
+		   __func__, freq_list_len);
+
+	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+	if (!msg ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+			BRCM_VENDOR_SCMD_ACS) ||
+	    !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+	    nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HW_MODE, params->hw_mode) ||
+	    nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT_ENABLED,
+		       params->ht_enabled) ||
+	    nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT40_ENABLED,
+		       params->ht40_enabled) ||
+	    nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_VHT_ENABLED,
+		       params->vht_enabled) ||
+	    nla_put_u16(msg, BRCM_VENDOR_ATTR_ACS_CHWIDTH, params->ch_width) ||
+	    (freq_list_len > 0 &&
+	     nla_put(msg, BRCM_VENDOR_ATTR_ACS_FREQ_LIST,
+		     sizeof(int) * freq_list_len, params->freq_list)))
+		goto fail;
+	nla_nest_end(msg, data);
+
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d",
+		   params->hw_mode, params->ht_enabled, params->ht40_enabled,
+		   params->vht_enabled, params->ch_width);
+
+	ret = send_and_recv_cmd(drv, msg);
+	if (ret) {
+		wpa_printf(MSG_ERROR,
+			   "nl80211: BRCM Failed to invoke driver ACS function: %s",
+			   strerror(errno));
+	}
+
+	msg = NULL;
+fail:
+	nlmsg_free(msg);
+	return ret;
+}
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
+
+
 static int nl80211_do_acs(void *priv, struct drv_acs_params *params)
 {
 #if defined(CONFIG_DRIVER_NL80211_QCA) || defined(CONFIG_DRIVER_NL80211_BRCM) \
@@ -13629,7 +13829,7 @@
 	    nl80211_put_fils_connect_params(drv, params, msg))
 		goto fail;
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	msg = NULL;
 	if (ret)
 		wpa_dbg(drv->ctx, MSG_DEBUG,
@@ -13672,7 +13872,7 @@
 	    (params->bssid &&
 	     nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid)))
 		goto fail;
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
@@ -13712,7 +13912,7 @@
 		bss->added_if_into_bridge = 0;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	msg = NULL;
 	if (ret && val && nl80211_get_4addr(bss) == 1) {
 		wpa_printf(MSG_DEBUG,
@@ -13776,7 +13976,7 @@
 	nla_nest_end(msg, params);
 	wpa_printf(MSG_DEBUG, "nl80211: Transition Disable Policy %d\n", td_policy);
 
-	ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Transition Disable setting failed: ret=%d (%s)",
 		ret, strerror(-ret));
@@ -13840,7 +14040,7 @@
 		return -ENOBUFS;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: add link failed. ret=%d (%s)",
 			   ret, strerror(-ret));
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index d922912..048c9a3 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -32,6 +32,7 @@
 	struct nl_cb *nl_cb;
 	struct nl_sock *nl;
 	int nl80211_id;
+	unsigned int nl80211_maxattr;
 	int nlctrl_id;
 	int ioctl_sock; /* socket for ioctl() use */
 	struct nl_sock *nl_event;
@@ -81,7 +82,6 @@
 	unsigned int wdev_id_set:1;
 	unsigned int added_if:1;
 	unsigned int static_ap:1;
-	unsigned int use_nl_connect:1;
 
 	u8 addr[ETH_ALEN];
 	u8 prev_addr[ETH_ALEN];
@@ -165,8 +165,6 @@
 	unsigned int scan_for_auth:1;
 	unsigned int retry_auth:1;
 	unsigned int use_monitor:1;
-	unsigned int ignore_next_local_disconnect:1;
-	unsigned int ignore_next_local_deauth:1;
 	unsigned int hostapd:1;
 	unsigned int start_mode_sta:1;
 	unsigned int start_iface_up:1;
@@ -199,10 +197,14 @@
 	unsigned int qca_do_acs:1;
 	unsigned int brcm_do_acs:1;
 	unsigned int uses_6ghz:1;
+	unsigned int uses_s1g:1;
 	unsigned int secure_ranging_ctx_vendor_cmd_avail:1;
 	unsigned int puncturing:1;
 	unsigned int qca_ap_allowed_freqs:1;
 
+	u32 ignore_next_local_disconnect;
+	u32 ignore_next_local_deauth;
+
 	u64 vendor_scan_cookie;
 	u64 remain_on_chan_cookie;
 	u64 send_frame_cookie;
@@ -271,18 +273,43 @@
 
 struct nl_msg;
 
+struct nl80211_err_info {
+	int link_id;
+};
+
 void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
 		   struct nl_msg *msg, int flags, uint8_t cmd);
 struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd);
 struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
 				uint8_t cmd);
 struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd);
-int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg,
-		       int (*valid_handler)(struct nl_msg *, void *),
-		       void *valid_data,
-		       int (*ack_handler_custom)(struct nl_msg *, void *),
-		       void *ack_data);
-struct nl_sock * get_connect_handle(struct i802_bss *bss);
+
+int send_and_recv(struct nl80211_global *global,
+		  struct nl_sock *nl_handle, struct nl_msg *msg,
+		  int (*valid_handler)(struct nl_msg *, void *),
+		  void *valid_data,
+		  int (*ack_handler_custom)(struct nl_msg *, void *),
+		  void *ack_data,
+		  struct nl80211_err_info *err_info);
+
+static inline int
+send_and_recv_cmd(struct wpa_driver_nl80211_data *drv,
+		  struct nl_msg *msg)
+{
+	return send_and_recv(drv->global, drv->global->nl, msg,
+			     NULL, NULL, NULL, NULL, NULL);
+}
+
+static inline int
+send_and_recv_resp(struct wpa_driver_nl80211_data *drv,
+		   struct nl_msg *msg,
+		   int (*valid_handler)(struct nl_msg *, void *),
+		   void *valid_data)
+{
+	return send_and_recv(drv->global, drv->global->nl, msg,
+			     valid_handler, valid_data, NULL, NULL, NULL);
+}
+
 int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
 			 const char *ifname, enum nl80211_iftype iftype,
 			 const u8 *addr, int wds,
@@ -330,6 +357,12 @@
 void nl80211_restore_ap_mode(struct i802_bss *bss);
 struct i802_link * nl80211_get_link(struct i802_bss *bss, s8 link_id);
 
+static inline bool
+nl80211_attr_supported(struct wpa_driver_nl80211_data *drv, unsigned int attr)
+{
+	return attr <= drv->global->nl80211_maxattr;
+}
+
 #ifdef ANDROID
 int android_nl_socket_set_nonblocking(struct nl_sock *handle);
 int android_pno_start(struct i802_bss *bss,
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 11a32af..0b6f511 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -49,8 +49,7 @@
 		return 0;
 	}
 
-	if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat,
-			       NULL, NULL) == 0)
+	if (send_and_recv_resp(drv, msg, protocol_feature_handler, &feat) == 0)
 		return feat;
 
 	return 0;
@@ -1207,7 +1206,7 @@
 		return -1;
 	}
 
-	if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info, NULL, NULL))
+	if (send_and_recv_resp(drv, msg, wiphy_info_handler, info))
 		return -1;
 
 	if (info->auth_supported)
@@ -1320,8 +1319,7 @@
 		return;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, dfs_info_handler, &dfs_capability,
-				 NULL, NULL);
+	ret = send_and_recv_resp(drv, msg, dfs_info_handler, &dfs_capability);
 	if (!ret && dfs_capability)
 		drv->capa.flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD;
 }
@@ -1408,8 +1406,7 @@
 
 	os_memset(&info, 0, sizeof(info));
 	info.capa = &drv->capa;
-	ret = send_and_recv_msgs(drv, msg, features_info_handler, &info,
-				 NULL, NULL);
+	ret = send_and_recv_resp(drv, msg, features_info_handler, &info);
 	if (ret || !info.flags)
 		return;
 
@@ -2549,8 +2546,7 @@
 		}
 	}
 
-	return send_and_recv_msgs(drv, msg, nl80211_get_reg, results,
-				  NULL, NULL);
+	return send_and_recv_resp(drv, msg, nl80211_get_reg, results);
 }
 
 
@@ -2592,6 +2588,8 @@
 
 			if (is_6ghz_freq(chan->freq))
 				drv->uses_6ghz = true;
+			if (chan->freq >= 900 && chan->freq < 1000)
+				drv->uses_s1g = true;
 			res = os_snprintf(pos, end - pos, " %d%s%s%s",
 					  chan->freq,
 					  (chan->flag & HOSTAPD_CHAN_DISABLED) ?
@@ -2642,8 +2640,7 @@
 		return NULL;
 	}
 
-	if (send_and_recv_msgs(drv, msg, phy_info_handler, &result,
-			       NULL, NULL) == 0) {
+	if (send_and_recv_resp(drv, msg, phy_info_handler, &result) == 0) {
 		struct hostapd_hw_modes *modes;
 
 		nl80211_set_regulatory_flags(drv, &result);
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index fdaf07b..4163f79 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -385,9 +385,9 @@
 		return 0;
 	}
 
-	ret = send_and_recv_msgs(drv, msg,
+	ret = send_and_recv_resp(drv, msg,
 				 qca_drv_connect_fail_reason_code_handler,
-				 &reason_code, NULL, NULL);
+				 &reason_code);
 	if (ret)
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Get connect fail reason_code failed: ret=%d (%s)",
@@ -442,7 +442,7 @@
 	wpa_printf(MSG_DEBUG, "nl80211: AP MLD address " MACSTR
 		   " received in link reconfig event", MAC2STR(ap_mld));
 	if (!drv->sta_mlo_info.valid_links ||
-	    os_memcmp(drv->sta_mlo_info.ap_mld_addr, ap_mld, ETH_ALEN) != 0) {
+	    !ether_addr_equal(drv->sta_mlo_info.ap_mld_addr, ap_mld)) {
 		if (drv->pending_link_reconfig_data == data) {
 			wpa_printf(MSG_DEBUG,
 				   "nl80211: Drop pending link reconfig event since AP MLD not matched even after new connect/roam event");
@@ -659,7 +659,8 @@
 		return -1;
 	}
 
-	mle = ieee802_11_defrag_mle(&req_elems, MULTI_LINK_CONTROL_TYPE_BASIC);
+	mle = ieee802_11_defrag(req_elems.basic_mle, req_elems.basic_mle_len,
+				true);
 	if (!mle) {
 		wpa_printf(MSG_INFO,
 			   "nl80211: MLO: Basic Multi-Link element not found in Association Request");
@@ -670,7 +671,8 @@
 					 &req_info);
 	wpabuf_free(mle);
 
-	mle = ieee802_11_defrag_mle(&resp_elems, MULTI_LINK_CONTROL_TYPE_BASIC);
+	mle = ieee802_11_defrag(resp_elems.basic_mle, resp_elems.basic_mle_len,
+				true);
 	if (!mle) {
 		wpa_printf(MSG_ERROR,
 			   "nl80211: MLO: Basic Multi-Link element not found in Association Response");
@@ -809,7 +811,7 @@
 	wpa_printf(MSG_DEBUG, "nl80211: AP MLD address " MACSTR
 		   " received in TID to link mapping event", MAC2STR(ap_mld));
 	if (!drv->sta_mlo_info.valid_links ||
-	    os_memcmp(drv->sta_mlo_info.ap_mld_addr, ap_mld, ETH_ALEN) != 0) {
+	    !ether_addr_equal(drv->sta_mlo_info.ap_mld_addr, ap_mld)) {
 		if (drv->pending_t2lm_data == data) {
 			wpa_printf(MSG_DEBUG,
 				   "nl80211: Drop pending TID-to-link mapping event since AP MLD not matched even after new connect/roam event");
@@ -957,9 +959,8 @@
 		if (drv->ignore_next_local_disconnect) {
 			drv->ignore_next_local_disconnect = 0;
 			if (!event.assoc_reject.bssid ||
-			    (os_memcmp(event.assoc_reject.bssid,
-				       drv->auth_attempt_bssid,
-				       ETH_ALEN) != 0)) {
+			    !ether_addr_equal(event.assoc_reject.bssid,
+					      drv->auth_attempt_bssid)) {
 				/*
 				 * Ignore the event that came without a BSSID or
 				 * for the old connection since this is likely
@@ -1270,12 +1271,16 @@
 	if (finished)
 		bss->flink->freq = data.ch_switch.freq;
 
+	if (link)
+		data.ch_switch.link_id = nla_get_u8(link);
+	else
+		data.ch_switch.link_id = NL80211_DRV_LINK_ID_NA;
+
 	if (link && is_sta_interface(drv->nlmode)) {
-		u8 link_id = nla_get_u8(link);
+		u8 link_id = data.ch_switch.link_id;
 
 		if (link_id < MAX_NUM_MLD_LINKS &&
 		    drv->sta_mlo_info.valid_links & BIT(link_id)) {
-			data.ch_switch.link_id = link_id;
 			drv->sta_mlo_info.links[link_id].freq =
 				data.ch_switch.freq;
 			wpa_supplicant_event(
@@ -1451,9 +1456,9 @@
 
 		if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
 		    !drv->associated &&
-		    os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 &&
-		    os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 &&
-		    os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) {
+		    !ether_addr_equal(bssid, drv->auth_bssid) &&
+		    !ether_addr_equal(bssid, drv->auth_attempt_bssid) &&
+		    ether_addr_equal(bssid, drv->prev_bssid)) {
 			/*
 			 * Avoid issues with some roaming cases where
 			 * disconnection event for the old AP may show up after
@@ -1462,11 +1467,10 @@
 			 * ignore_next_local_deauth as well, to avoid next local
 			 * deauth event be wrongly ignored.
 			 */
-			if (os_memcmp(mgmt->sa, drv->first_bss->addr,
-				      ETH_ALEN) == 0 ||
+			if (ether_addr_equal(mgmt->sa, drv->first_bss->addr) ||
 			    (!is_zero_ether_addr(drv->first_bss->prev_addr) &&
-			     os_memcmp(mgmt->sa, drv->first_bss->prev_addr,
-				       ETH_ALEN) == 0)) {
+			     ether_addr_equal(mgmt->sa,
+					      drv->first_bss->prev_addr))) {
 				wpa_printf(MSG_DEBUG,
 					   "nl80211: Received a locally generated deauth event. Clear ignore_next_local_deauth flag");
 				drv->ignore_next_local_deauth = 0;
@@ -1481,8 +1485,8 @@
 
 		if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
 		    drv->connect_reassoc && drv->associated &&
-		    os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0 &&
-		    os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0) {
+		    ether_addr_equal(bssid, drv->prev_bssid) &&
+		    !ether_addr_equal(bssid, drv->auth_attempt_bssid)) {
 			/*
 			 * Avoid issues with some roaming cases where
 			 * disconnection event for the old AP may show up after
@@ -1498,8 +1502,8 @@
 		}
 
 		if (drv->associated != 0 &&
-		    os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
-		    os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
+		    !ether_addr_equal(bssid, drv->bssid) &&
+		    !ether_addr_equal(bssid, drv->auth_bssid)) {
 			/*
 			 * We have presumably received this deauth as a
 			 * response to a clear_state_mismatch() outgoing
@@ -1521,7 +1525,7 @@
 
 	if (type == EVENT_DISASSOC) {
 		event.disassoc_info.locally_generated =
-			!os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
+			ether_addr_equal(mgmt->sa, drv->first_bss->addr);
 		event.disassoc_info.addr = bssid;
 		event.disassoc_info.reason_code = reason_code;
 		if (frame + len > mgmt->u.disassoc.variable) {
@@ -1531,7 +1535,7 @@
 		}
 	} else {
 		event.deauth_info.locally_generated =
-			!os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
+			ether_addr_equal(mgmt->sa, drv->first_bss->addr);
 		if (drv->ignore_deauth_event) {
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event due to previous forced deauth-during-auth");
 			drv->ignore_deauth_event = 0;
@@ -1701,15 +1705,14 @@
 			   bss->ifname);
 	} else if (cmd != NL80211_CMD_FRAME_TX_STATUS  &&
 		   !(data[4] & 0x01) &&
-		   os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
+		   !ether_addr_equal(bss->addr, data + 4) &&
 		   (is_zero_ether_addr(bss->rand_addr) ||
-		    os_memcmp(bss->rand_addr, data + 4, ETH_ALEN) != 0) &&
-		   os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0 &&
+		    !ether_addr_equal(bss->rand_addr, data + 4)) &&
+		   !ether_addr_equal(bss->addr, data + 4 + ETH_ALEN) &&
 		   (is_zero_ether_addr(drv->first_bss->prev_addr) ||
-		    os_memcmp(bss->prev_addr, data + 4 + ETH_ALEN,
-			      ETH_ALEN) != 0) &&
+		    !ether_addr_equal(bss->prev_addr, data + 4 + ETH_ALEN)) &&
 		   (!mld_link ||
-		    os_memcmp(mld_link->addr, data + 4, ETH_ALEN) != 0)) {
+		    !ether_addr_equal(mld_link->addr, data + 4))) {
 		wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
 			   "for foreign address", bss->ifname);
 		return;
@@ -2449,14 +2452,23 @@
 {
 	union wpa_event_data data;
 	enum nl80211_radar_event event_type;
+	struct i802_link *mld_link = NULL;
 
 	if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT])
 		return;
 
 	os_memset(&data, 0, sizeof(data));
+	data.dfs_event.link_id = NL80211_DRV_LINK_ID_NA;
 	data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
 	event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
 
+	if (data.dfs_event.freq) {
+		mld_link = nl80211_get_mld_link_by_freq(drv->first_bss,
+							data.dfs_event.freq);
+		if (mld_link)
+			data.dfs_event.link_id = mld_link->link_id;
+	}
+
 	/* Check HT params */
 	if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
 		data.dfs_event.ht_enabled = 1;
@@ -2487,10 +2499,12 @@
 	if (tb[NL80211_ATTR_CENTER_FREQ2])
 		data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
 
-	wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz",
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz, link_id=%d",
 		   data.dfs_event.freq, data.dfs_event.ht_enabled,
 		   data.dfs_event.chan_offset, data.dfs_event.chan_width,
-		   data.dfs_event.cf1, data.dfs_event.cf2);
+		   data.dfs_event.cf1, data.dfs_event.cf2,
+		   data.dfs_event.link_id);
 
 	switch (event_type) {
 	case NL80211_RADAR_DETECTED:
@@ -2722,8 +2736,14 @@
 	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_PUNCTURE_BITMAP])
 		event.acs_selected_channels.puncture_bitmap =
 			nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_PUNCTURE_BITMAP]);
+	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_LINK_ID])
+		event.acs_selected_channels.link_id =
+			nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_LINK_ID]);
+	else
+		event.acs_selected_channels.link_id = -1;
+
 	wpa_printf(MSG_INFO,
-		   "nl80211: ACS Results: PFreq: %d SFreq: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d EDMGCH: %d PUNCBITMAP: 0x%x",
+		   "nl80211: ACS Results: PFreq: %d SFreq: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d EDMGCH: %d PUNCBITMAP: 0x%x, LinkId: %d",
 		   event.acs_selected_channels.pri_freq,
 		   event.acs_selected_channels.sec_freq,
 		   event.acs_selected_channels.ch_width,
@@ -2731,7 +2751,8 @@
 		   event.acs_selected_channels.vht_seg1_center_ch,
 		   event.acs_selected_channels.hw_mode,
 		   event.acs_selected_channels.edmg_channel,
-		   event.acs_selected_channels.puncture_bitmap);
+		   event.acs_selected_channels.puncture_bitmap,
+		   event.acs_selected_channels.link_id);
 
 	/* Ignore ACS channel list check for backwards compatibility */
 
@@ -2810,6 +2831,7 @@
 {
 	union wpa_event_data data;
 	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct i802_link *mld_link = NULL;
 
 	wpa_printf(MSG_DEBUG,
 		   "nl80211: DFS offload radar vendor event received");
@@ -2826,9 +2848,17 @@
 
 	os_memset(&data, 0, sizeof(data));
 	data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+	data.dfs_event.link_id = NL80211_DRV_LINK_ID_NA;
 
-	wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz",
-		   data.dfs_event.freq);
+	if (data.dfs_event.freq) {
+		mld_link = nl80211_get_mld_link_by_freq(drv->first_bss,
+							data.dfs_event.freq);
+		if (mld_link)
+			data.dfs_event.link_id = mld_link->link_id;
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, link=%d",
+		   data.dfs_event.freq, data.dfs_event.link_id);
 
 	/* Check HT params */
 	if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
@@ -3386,7 +3416,8 @@
 }
 
 
-static void nl80211_dump_freq(const char *title, struct nlattr *nl_freq)
+static void nl80211_parse_freq_attrs(const char *title, struct nlattr *nl_freq,
+				     struct frequency_attrs *attrs)
 {
 	static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
 		[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
@@ -3413,6 +3444,15 @@
 		   tb[NL80211_FREQUENCY_ATTR_DISABLED] ? " disabled" : "",
 		   tb[NL80211_FREQUENCY_ATTR_NO_IR] ? " no-IR" : "",
 		   tb[NL80211_FREQUENCY_ATTR_RADAR] ? " radar" : "");
+
+	attrs->freq = freq;
+	attrs->max_tx_power = max_tx_power;
+	if (tb[NL80211_FREQUENCY_ATTR_DISABLED])
+		attrs->disabled = true;
+	if (tb[NL80211_FREQUENCY_ATTR_NO_IR])
+		attrs->no_ir = true;
+	if (tb[NL80211_FREQUENCY_ATTR_RADAR])
+		attrs->radar = true;
 }
 
 
@@ -3426,9 +3466,13 @@
 	data.channel_list_changed.initiator = REGDOM_BEACON_HINT;
 
 	if (tb[NL80211_ATTR_FREQ_BEFORE])
-		nl80211_dump_freq("before", tb[NL80211_ATTR_FREQ_BEFORE]);
+		nl80211_parse_freq_attrs(
+			"before", tb[NL80211_ATTR_FREQ_BEFORE],
+			&data.channel_list_changed.beacon_hint_before);
 	if (tb[NL80211_ATTR_FREQ_AFTER])
-		nl80211_dump_freq("after", tb[NL80211_ATTR_FREQ_AFTER]);
+		nl80211_parse_freq_attrs(
+			"after", tb[NL80211_ATTR_FREQ_AFTER],
+			&data.channel_list_changed.beacon_hint_after);
 
 	wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data);
 }
@@ -3494,8 +3538,6 @@
 {
 	const u8 *addr;
 	union wpa_event_data event;
-	const u8 *connected_addr = drv->sta_mlo_info.valid_links ?
-				drv->sta_mlo_info.ap_mld_addr : drv->bssid;
 
 	os_memset(&event, 0, sizeof(event));
 
@@ -3512,13 +3554,19 @@
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Port authorized for STA addr "  MACSTR,
 			MAC2STR(addr));
-	} else if (is_sta_interface(drv->nlmode) &&
-		   os_memcmp(addr, connected_addr, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG,
-			   "nl80211: Ignore port authorized event for " MACSTR
-			   " (not the currently connected BSSID " MACSTR ")",
-			   MAC2STR(addr), MAC2STR(connected_addr));
-		return;
+	} else if (is_sta_interface(drv->nlmode)) {
+		const u8 *connected_addr;
+
+		connected_addr = drv->sta_mlo_info.valid_links ?
+			drv->sta_mlo_info.ap_mld_addr : drv->bssid;
+		if (!ether_addr_equal(addr, connected_addr)) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Ignore port authorized event for "
+				   MACSTR " (not the currently connected BSSID "
+				   MACSTR ")",
+				   MAC2STR(addr), MAC2STR(connected_addr));
+			return;
+		}
 	}
 
 	if (tb[NL80211_ATTR_TD_BITMAP]) {
@@ -3881,6 +3929,7 @@
 	case NL80211_CMD_ASSOCIATE:
 	case NL80211_CMD_DEAUTHENTICATE:
 	case NL80211_CMD_DISASSOCIATE:
+	case NL80211_CMD_FRAME:
 	case NL80211_CMD_FRAME_TX_STATUS:
 	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
 	case NL80211_CMD_UNPROT_DISASSOCIATE:
@@ -4041,6 +4090,9 @@
 		nl80211_color_change_announcement_completed(bss);
 		break;
 #endif /* CONFIG_IEEE80211AX */
+	case NL80211_CMD_LINKS_REMOVED:
+		wpa_supplicant_event(drv->ctx, EVENT_LINK_RECONFIG, NULL);
+		break;
 	default:
 		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
 			"(cmd=%d)", cmd);
@@ -4049,6 +4101,21 @@
 }
 
 
+static bool nl80211_drv_in_list(struct nl80211_global *global,
+				struct wpa_driver_nl80211_data *drv)
+{
+	struct wpa_driver_nl80211_data *tmp;
+
+	dl_list_for_each(tmp, &global->interfaces,
+			 struct wpa_driver_nl80211_data, list) {
+		if (drv == tmp)
+			return true;
+	}
+
+	return false;
+}
+
+
 int process_global_event(struct nl_msg *msg, void *arg)
 {
 	struct nl80211_global *global = arg;
@@ -4060,6 +4127,31 @@
 	u64 wdev_id = 0;
 	int wdev_id_set = 0;
 	int wiphy_idx_set = 0;
+	bool processed = false;
+
+	/* Event marker, all prior events have been processed */
+	if (gnlh->cmd == NL80211_CMD_GET_PROTOCOL_FEATURES) {
+		u32 seq = nlmsg_hdr(msg)->nlmsg_seq;
+
+		dl_list_for_each_safe(drv, tmp, &global->interfaces,
+				      struct wpa_driver_nl80211_data, list) {
+			if (drv->ignore_next_local_deauth > 0 &&
+			    drv->ignore_next_local_deauth <= seq) {
+				wpa_printf(MSG_DEBUG,
+					   "nl80211: No DEAUTHENTICATE event was ignored");
+				drv->ignore_next_local_deauth = 0;
+			}
+
+			if (drv->ignore_next_local_disconnect > 0 &&
+			    drv->ignore_next_local_disconnect <= seq) {
+				wpa_printf(MSG_DEBUG,
+					   "nl80211: No DISCONNECT event was ignored");
+				drv->ignore_next_local_disconnect = 0;
+			}
+		}
+
+		return NL_SKIP;
+	}
 
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 		  genlmsg_attrlen(gnlh, 0), NULL);
@@ -4084,16 +4176,28 @@
 			    (wiphy_idx_set && wiphy_idx == wiphy_idx_rx) ||
 			    (wdev_id_set && bss->wdev_id_set &&
 			     wdev_id == bss->wdev_id)) {
+				processed = true;
 				do_process_drv_event(bss, gnlh->cmd, tb);
-				return NL_SKIP;
+				if (!wiphy_idx_set)
+					return NL_SKIP;
+				/* The driver instance could have been removed,
+				 * e.g., due to NL80211_CMD_RADAR_DETECT event,
+				 * so need to stop the loop if that has
+				 * happened. */
+				if (!nl80211_drv_in_list(global, drv))
+					break;
 			}
 		}
-		wpa_printf(MSG_DEBUG,
-			   "nl80211: Ignored event %d (%s) for foreign interface (ifindex %d wdev 0x%llx)",
-			   gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
-			   ifidx, (long long unsigned int) wdev_id);
 	}
 
+	if (processed)
+		return NL_SKIP;
+
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: Ignored event %d (%s) for foreign interface (ifindex %d wdev 0x%llx wiphy %d)",
+		   gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
+		   ifidx, (long long unsigned int) wdev_id, wiphy_idx_rx);
+
 	return NL_SKIP;
 }
 
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index 4907e3c..68ae579 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -82,8 +82,7 @@
 
 	os_memset(info, 0, sizeof(*info));
 	msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
-	return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, info,
-				  NULL, NULL);
+	return send_and_recv_resp(drv, msg, get_noise_for_scan_results, info);
 }
 
 
@@ -95,7 +94,7 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: Abort scan");
 	msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ABORT_SCAN);
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Abort scan failed: ret=%d (%s)",
 			   ret, strerror(-ret));
@@ -126,7 +125,7 @@
 
 	nla_nest_end(msg, params);
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_INFO,
@@ -397,7 +396,7 @@
 			goto fail;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
@@ -428,7 +427,9 @@
 	drv->scan_state = SCAN_REQUESTED;
 	/* Not all drivers generate "scan completed" wireless event, so try to
 	 * read results after a timeout. */
-	timeout = drv->uses_6ghz ? 15 : 10;
+	timeout = drv->uses_6ghz ? 20 : 10;
+	if (drv->uses_s1g)
+		timeout += 5;
 	if (drv->scan_complete_events) {
 		/*
 		 * The driver seems to deliver events to notify when scan is
@@ -650,7 +651,7 @@
 			params->sched_scan_start_delay))
 		goto fail;
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 
 	/* TODO: if we get an error here, we should fall back to normal scan */
 
@@ -687,7 +688,7 @@
 #endif /* ANDROID */
 
 	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_STOP_SCHED_SCAN);
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Sched scan stop failed: ret=%d (%s)",
@@ -922,14 +923,14 @@
 			   "nl80211: Local state (not associated) does not match with BSS state");
 		clear_state_mismatch(drv, r->bssid);
 	} else if (is_sta_interface(drv->nlmode) &&
-		   os_memcmp(drv->bssid, r->bssid, ETH_ALEN) != 0) {
+		   !ether_addr_equal(drv->bssid, r->bssid)) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Local state (associated with " MACSTR
 			   ") does not match with BSS state",
 			   MAC2STR(drv->bssid));
 
-		if (os_memcmp(drv->sta_mlo_info.ap_mld_addr, drv->bssid,
-			      ETH_ALEN) != 0) {
+		if (!ether_addr_equal(drv->sta_mlo_info.ap_mld_addr,
+				      drv->bssid)) {
 			clear_state_mismatch(drv, r->bssid);
 
 			if (!is_zero_ether_addr(drv->sta_mlo_info.ap_mld_addr))
@@ -992,7 +993,7 @@
 
 	arg.drv = drv;
 	arg.res = res;
-	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg, NULL, NULL);
+	ret = send_and_recv_resp(drv, msg, bss_info_handler, &arg);
 	if (ret == -EAGAIN) {
 		count++;
 		if (count >= 10) {
@@ -1076,8 +1077,7 @@
 	ctx.idx = 0;
 	msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
 	if (msg)
-		send_and_recv_msgs(drv, msg, nl80211_dump_scan_handler, &ctx,
-				   NULL, NULL);
+		send_and_recv_resp(drv, msg, nl80211_dump_scan_handler, &ctx);
 }
 
 
@@ -1270,8 +1270,7 @@
 
 	nla_nest_end(msg, attr);
 
-	ret = send_and_recv_msgs(drv, msg, scan_cookie_handler, &cookie,
-				 NULL, NULL);
+	ret = send_and_recv_resp(drv, msg, scan_cookie_handler, &cookie);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
@@ -1334,7 +1333,7 @@
 
 	nla_nest_end(msg, attr);
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	ret = send_and_recv_cmd(drv, msg);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_ERROR,
diff --git a/src/drivers/driver_roboswitch.c b/src/drivers/driver_roboswitch.c
index 9beb6c4..23c7086 100644
--- a/src/drivers/driver_roboswitch.c
+++ b/src/drivers/driver_roboswitch.c
@@ -175,7 +175,7 @@
 	struct wpa_driver_roboswitch_data *drv = priv;
 
 	if (len > 14 && WPA_GET_BE16(buf + 12) == ETH_P_EAPOL &&
-	    os_memcmp(buf, drv->own_addr, ETH_ALEN) == 0)
+	    ether_addr_equal(buf, drv->own_addr))
 		drv_event_eapol_rx(drv->ctx, src_addr, buf + 14, len - 14);
 }
 
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index cf201fe..2c656fb 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -452,9 +452,10 @@
 				   MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
 			if (is_zero_ether_addr(
 				    (const u8 *) iwe->u.ap_addr.sa_data) ||
-			    os_memcmp(iwe->u.ap_addr.sa_data,
-				      "\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
-			    0) {
+			    ether_addr_equal((const u8 *)
+					     iwe->u.ap_addr.sa_data,
+					     (const u8 *)
+					     "\x44\x44\x44\x44\x44\x44")) {
 				os_free(drv->assoc_req_ies);
 				drv->assoc_req_ies = NULL;
 				os_free(drv->assoc_resp_ies);
diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c
index 7edb9df..29abc0c 100644
--- a/src/drivers/linux_ioctl.c
+++ b/src/drivers/linux_ioctl.c
@@ -161,11 +161,20 @@
 	ifr.ifr_ifindex = ifindex;
 	if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) {
 		int saved_errno = errno;
+		char in_br[IFNAMSIZ];
 
 		wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge "
 			   "%s: %s", ifname, brname, strerror(errno));
 		errno = saved_errno;
-		return -1;
+
+		/* If ioctl() returns EBUSY when adding an interface into the
+		 * bridge, the interface might have already been added by an
+		 * external operation, so check whether the interface is
+		 * currently on the right bridge and ignore the error if it is.
+		 */
+		if (errno != EBUSY || linux_br_get(in_br, ifname) != 0 ||
+		    os_strcmp(in_br, brname) != 0)
+			return -1;
 	}
 
 	return 0;