Revert "Revert "[wpa_supplicant] cumilative patch from commit 4b..."
Revert submission 28102966-revert-26533062-Supplicant_merge_June24-CUATTSRBBR
Fixed the regression issue (ag/28389573)
Bug: 329004037
Reverted changes: /q/submissionid:28102966-revert-26533062-Supplicant_merge_June24-CUATTSRBBR
Test: Turn ON/OFF SoftAp
Change-Id: Ie7ea1ee7f8b1311fce280907d37a2e321542f547
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index a55e8e3..069e741 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -43,6 +43,7 @@
#define HOSTAPD_CHAN_VHT_80MHZ_SUBCHANNEL 0x00000800
#define HOSTAPD_CHAN_VHT_160MHZ_SUBCHANNEL 0x00001000
+#define HOSTAPD_CHAN_EHT_320MHZ_SUBCHANNEL 0x00002000
#define HOSTAPD_CHAN_INDOOR_ONLY 0x00010000
#define HOSTAPD_CHAN_GO_CONCURRENT 0x00020000
@@ -247,6 +248,11 @@
enum hostapd_hw_mode mode;
/**
+ * is_6ghz - Whether the mode information is for the 6 GHz band
+ */
+ bool is_6ghz;
+
+ /**
* num_channels - Number of entries in the channels array
*/
int num_channels;
@@ -695,6 +701,14 @@
*/
unsigned int min_probe_req_content:1;
+ /**
+ * link_id - Specify the link that is requesting the scan on an MLD
+ *
+ * This is set when operating as an AP MLD and doing an OBSS scan.
+ * -1 indicates that no particular link ID is set.
+ */
+ s8 link_id;
+
/*
* NOTE: Whenever adding new parameters here, please make sure
* wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -3371,6 +3385,17 @@
size_t ies_len);
/**
+ * get_scan_results - Fetch the latest scan results
+ * @priv: Private driver interface data
+ * @bssid: Return results only for the specified BSSID, %NULL for all
+ *
+ * Returns: Allocated buffer of scan results (caller is responsible for
+ * freeing the data structure) on success, NULL on failure
+ */
+ struct wpa_scan_results * (*get_scan_results)(void *priv,
+ const u8 *bssid);
+
+ /**
* get_scan_results2 - Fetch the latest scan results
* @priv: private driver interface data
*
@@ -4554,13 +4579,14 @@
/**
* stop_ap - Removes beacon from AP
* @priv: Private driver interface data
+ * @link_id: Link ID of the specified link; -1 for non-MLD
* Returns: 0 on success, -1 on failure (or if not supported)
*
* This optional function can be used to disable AP mode related
* configuration. Unlike deinit_ap, it does not change to station
* mode.
*/
- int (*stop_ap)(void *priv);
+ int (*stop_ap)(void *priv, int link_id);
/**
* get_survey - Retrieve survey data
@@ -5140,9 +5166,44 @@
* @priv: Private driver interface data
* @link_id: The link ID
* @addr: The MAC address to use for the link
+ * @bss_ctx: BSS context for %WPA_IF_AP_BSS interfaces
* Returns: 0 on success, negative value on failure
*/
- int (*link_add)(void *priv, u8 link_id, const u8 *addr);
+ int (*link_add)(void *priv, u8 link_id, const u8 *addr, void *bss_ctx);
+
+ /**
+ * link_remove - Remove a link from the AP MLD interface
+ * @priv: Private driver interface data
+ * @type: Interface type
+ * @ifname: Interface name of the virtual interface from where the link
+ * is to be removed.
+ * @link_id: Valid link ID to remove
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*link_remove)(void *priv, enum wpa_driver_if_type type,
+ const char *ifname, u8 link_id);
+
+ /**
+ * is_drv_shared - Check whether the driver interface is shared
+ * @priv: Private driver interface data from init()
+ * @bss_ctx: BSS context for %WPA_IF_AP_BSS interfaces
+ *
+ * Checks whether the driver interface is being used by other partner
+ * BSS(s) or not. This is used to decide whether the driver interface
+ * needs to be deinitilized when one interface is getting deinitialized.
+ *
+ * Returns: true if it is being used or else false.
+ */
+ bool (*is_drv_shared)(void *priv, void *bss_ctx);
+
+ /**
+ * link_sta_remove - Remove a link STA from an MLD STA
+ * @priv: Private driver interface data
+ * @link_id: The link ID which the link STA is using
+ * @addr: The MLD MAC address of the MLD STA
+ * Returns: 0 on success, negative value on failure
+ */
+ int (*link_sta_remove)(void *priv, u8 link_id, const u8 *addr);
#ifdef CONFIG_TESTING_OPTIONS
int (*register_frame)(void *priv, u16 type,
@@ -6352,6 +6413,8 @@
* (if available).
* @scan_start_tsf_bssid: The BSSID according to which %scan_start_tsf
* is set.
+ * @scan_cookie: Unique identification representing the corresponding
+ * scan request. 0 if no unique identification is available.
*/
struct scan_info {
int aborted;
@@ -6363,6 +6426,7 @@
int nl_scan_event;
u64 scan_start_tsf;
u8 scan_start_tsf_bssid[ETH_ALEN];
+ u64 scan_cookie;
} scan_info;
/**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 9b50b6f..194a5cd 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -18,9 +18,6 @@
#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 */
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/errqueue.h>
@@ -2295,7 +2292,6 @@
{
struct wpa_driver_nl80211_data *drv;
struct i802_bss *bss;
- unsigned int i;
char path[128], buf[200], *pos;
ssize_t len;
int ret;
@@ -2395,16 +2391,12 @@
}
/*
- * Set the default link to be the first one, and set its address to that
- * of the interface.
+ * Use link ID 0 for the single "link" of a non-MLD.
*/
+ bss->valid_links = 0;
bss->flink = &bss->links[0];
- bss->n_links = 1;
os_memcpy(bss->flink->addr, bss->addr, ETH_ALEN);
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++)
- bss->links[i].link_id = NL80211_DRV_LINK_ID_NA;
-
return bss;
failed:
@@ -3079,31 +3071,31 @@
static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss,
- struct i802_link *link)
+ int link_id)
{
struct nl_msg *msg;
struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct i802_link *link = nl80211_get_link(bss, link_id);
if (!link->beacon_set)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
- drv->ifindex);
+ bss->ifindex);
link->beacon_set = 0;
link->freq = 0;
nl80211_put_wiphy_data_ap(bss);
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_BEACON);
if (!msg)
return -ENOBUFS;
- if (link->link_id != NL80211_DRV_LINK_ID_NA) {
+ if (link_id != NL80211_DRV_LINK_ID_NA) {
wpa_printf(MSG_DEBUG,
"nl80211: MLD: stop beaconing on link=%u",
- link->link_id);
+ link_id);
- if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID,
- link->link_id)) {
+ if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) {
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -3115,10 +3107,10 @@
static void wpa_driver_nl80211_del_beacon_all(struct i802_bss *bss)
{
- unsigned int i;
+ int link_id;
- for (i = 0; i < bss->n_links; i++)
- wpa_driver_nl80211_del_beacon(bss, &bss->links[i]);
+ for_each_link_default(bss->valid_links, link_id, NL80211_DRV_LINK_ID_NA)
+ wpa_driver_nl80211_del_beacon(bss, link_id);
}
@@ -4258,14 +4250,11 @@
struct i802_link * nl80211_get_link(struct i802_bss *bss, s8 link_id)
{
- unsigned int i;
+ if (link_id < 0 || link_id >= MAX_NUM_MLD_LINKS)
+ return bss->flink;
- for (i = 0; i < bss->n_links; i++) {
- if (bss->links[i].link_id != link_id)
- continue;
-
- return &bss->links[i];
- }
+ if (BIT(link_id) & bss->valid_links)
+ return &bss->links[link_id];
return bss->flink;
}
@@ -4282,9 +4271,9 @@
static int nl80211_get_link_freq(struct i802_bss *bss, const u8 *addr,
bool bss_freq_debug)
{
- size_t i;
+ u8 i;
- for (i = 0; i < bss->n_links; i++) {
+ for_each_link(bss->valid_links, i) {
if (ether_addr_equal(bss->links[i].addr, addr)) {
wpa_printf(MSG_DEBUG,
"nl80211: Use link freq=%d for address "
@@ -5125,20 +5114,18 @@
#endif /* CONFIG_MESH */
if (params->mld_ap) {
- size_t i;
-
- for (i = 0; i < bss->n_links; i++) {
- if (bss->links[i].link_id == params->mld_link_id) {
- link = &bss->links[i];
- break;
- }
- }
-
- if (i == bss->n_links) {
- wpa_printf(MSG_DEBUG, "nl80211: Link ID=%u not found",
- params->mld_link_id);
+ if (!nl80211_link_valid(bss->valid_links,
+ params->mld_link_id)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Link ID=%u invalid (valid: 0x%04x)",
+ params->mld_link_id, bss->valid_links);
return -EINVAL;
}
+
+ link = nl80211_get_link(bss, params->mld_link_id);
+ } else if (bss->valid_links) {
+ wpa_printf(MSG_DEBUG, "nl80211: MLD configuration expected");
+ return -EINVAL;
}
beacon_set = params->reenable ? 0 : link->beacon_set;
@@ -5179,13 +5166,12 @@
params->mld_link_id);
if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID,
- params->mld_link_id) ||
- (params->freq &&
- nl80211_put_freq_params(msg, params->freq) < 0))
+ params->mld_link_id))
goto fail;
- nl80211_link_set_freq(bss, params->mld_link_id,
- params->freq->freq);
+ if (params->freq)
+ nl80211_link_set_freq(bss, params->mld_link_id,
+ params->freq->freq);
}
if (params->proberesp && params->proberesp_len) {
@@ -5393,6 +5379,9 @@
nla_nest_end(msg, ftm);
}
+ if (params->freq && nl80211_put_freq_params(msg, params->freq) < 0)
+ goto fail;
+
#ifdef CONFIG_IEEE80211AX
if (params->he_spr_ctrl) {
struct nlattr *spr;
@@ -5427,9 +5416,6 @@
nla_nest_end(msg, spr);
}
- if (params->freq && nl80211_put_freq_params(msg, params->freq) < 0)
- goto fail;
-
if (params->freq && params->freq->he_enabled &&
nl80211_attr_supported(drv, NL80211_ATTR_HE_BSS_COLOR)) {
struct nlattr *bss_color;
@@ -5548,27 +5534,6 @@
}
-static bool nl80211_link_valid(struct i802_bss *bss, s8 link_id)
-{
- unsigned int i;
-
- if (link_id < 0)
- return false;
-
- for (i = 0; i < bss->n_links; i++) {
- wpa_printf(MSG_DEBUG, "nl80211: %s - i=%u, link_id=%u",
- __func__, i, bss->links[i].link_id);
- if (bss->links[i].link_id == NL80211_DRV_LINK_ID_NA)
- continue;
-
- if (bss->links[i].link_id == link_id)
- return true;
- }
-
- return false;
-}
-
-
static int nl80211_set_channel(struct i802_bss *bss,
struct hostapd_freq_params *freq, int set_chan)
{
@@ -5589,7 +5554,7 @@
return -1;
}
- if (nl80211_link_valid(bss, freq->link_id)) {
+ if (nl80211_link_valid(bss->valid_links, freq->link_id)) {
wpa_printf(MSG_DEBUG, "nl80211: Set link_id=%u for freq",
freq->link_id);
@@ -5955,26 +5920,25 @@
static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr)
{
-#ifdef CONFIG_LIBNL3_ROUTE
struct wpa_driver_nl80211_data *drv = bss->drv;
- struct rtnl_neigh *rn;
- struct nl_addr *nl_addr;
+ struct ndmsg nhdr = {
+ .ndm_state = NUD_PERMANENT,
+ .ndm_ifindex = bss->ifindex,
+ .ndm_family = AF_BRIDGE,
+ };
+ struct nl_msg *msg;
int err;
- rn = rtnl_neigh_alloc();
- if (!rn)
+ msg = nlmsg_alloc_simple(RTM_DELNEIGH, NLM_F_CREATE);
+ if (!msg)
return;
- rtnl_neigh_set_family(rn, AF_BRIDGE);
- rtnl_neigh_set_ifindex(rn, bss->ifindex);
- nl_addr = nl_addr_build(AF_BRIDGE, (void *) addr, ETH_ALEN);
- if (!nl_addr) {
- rtnl_neigh_put(rn);
- return;
- }
- rtnl_neigh_set_lladdr(rn, nl_addr);
+ if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0 ||
+ nla_put(msg, NDA_LLADDR, ETH_ALEN, (void *) addr) ||
+ nl_send_auto_complete(drv->rtnl_sk, msg) < 0)
+ goto errout;
- err = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
+ err = nl_wait_for_ack(drv->rtnl_sk);
if (err < 0) {
wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for "
MACSTR " ifindex=%d failed: %s", MAC2STR(addr),
@@ -5984,9 +5948,8 @@
MACSTR, MAC2STR(addr));
}
- nl_addr_put(nl_addr);
- rtnl_neigh_put(rn);
-#endif /* CONFIG_LIBNL3_ROUTE */
+errout:
+ nlmsg_free(msg);
}
@@ -6783,7 +6746,6 @@
if (params->mld_params.mld_addr && params->mld_params.valid_links > 0) {
struct wpa_driver_mld_params *mld_params = ¶ms->mld_params;
struct nlattr *links, *attr;
- int i;
u8 link_id;
wpa_printf(MSG_DEBUG, " * MLD: MLD addr=" MACSTR,
@@ -6799,31 +6761,8 @@
if (!links)
return -1;
- attr = nla_nest_start(msg, 0);
- if (!attr)
- return -1;
-
- /* First add the association link ID */
- link_id = mld_params->assoc_link_id;
- if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id) ||
- nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
- mld_params->mld_links[link_id].bssid) ||
- nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
- mld_params->mld_links[link_id].freq))
- return -1;
-
- os_memcpy(drv->sta_mlo_info.links[link_id].bssid,
- mld_params->mld_links[link_id].bssid, ETH_ALEN);
-
- nla_nest_end(msg, attr);
-
- for (i = 1, link_id = 0; link_id < MAX_NUM_MLD_LINKS;
- link_id++) {
- if (!(mld_params->valid_links & BIT(link_id)) ||
- link_id == mld_params->assoc_link_id)
- continue;
-
- attr = nla_nest_start(msg, i);
+ for_each_link(mld_params->valid_links, link_id) {
+ attr = nla_nest_start(msg, 0);
if (!attr)
return -1;
@@ -6833,11 +6772,11 @@
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 &&
+ (mld_params->mld_links[link_id].disabled &&
nla_put_flag(msg,
NL80211_ATTR_MLO_LINK_DISABLED)) ||
(mld_params->mld_links[link_id].ies &&
- mld_params->mld_links[i].ies_len &&
+ mld_params->mld_links[link_id].ies_len &&
nla_put(msg, NL80211_ATTR_IE,
mld_params->mld_links[link_id].ies_len,
mld_params->mld_links[link_id].ies)))
@@ -6847,7 +6786,6 @@
mld_params->mld_links[link_id].bssid,
ETH_ALEN);
nla_nest_end(msg, attr);
- i++;
}
nla_nest_end(msg, links);
@@ -7424,10 +7362,7 @@
/* 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;
-
+ for_each_link(params->mld_params.valid_links, i) {
if (TEST_FAIL_TAG("link"))
err_info.link_id = i;
}
@@ -8762,7 +8697,6 @@
(params->num_bridge == 0 || !params->bridge[0]))
add_ifidx(drv, br_ifindex, drv->ifindex);
-#ifdef CONFIG_LIBNL3_ROUTE
if (bss->added_if_into_bridge || bss->already_in_bridge) {
int err;
@@ -8779,7 +8713,6 @@
goto failed;
}
}
-#endif /* CONFIG_LIBNL3_ROUTE */
if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) {
wpa_printf(MSG_DEBUG,
@@ -9004,7 +8937,6 @@
if (type == WPA_IF_AP_BSS && setup_ap) {
struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
- unsigned int i;
if (new_bss == NULL) {
if (added)
@@ -9012,10 +8944,6 @@
return -1;
}
- /* Initialize here before any failure path */
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++)
- new_bss->links[i].link_id = NL80211_DRV_LINK_ID_NA;
-
if (bridge &&
i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
@@ -9040,7 +8968,7 @@
new_bss->drv = drv;
new_bss->next = drv->first_bss->next;
new_bss->flink = &new_bss->links[0];
- new_bss->n_links = 1;
+ new_bss->valid_links = 0;
os_memcpy(new_bss->flink->addr, new_bss->addr, ETH_ALEN);
new_bss->flink->freq = drv->first_bss->flink->freq;
@@ -9120,6 +9048,7 @@
tbss->next = bss->next;
/* Unsubscribe management frames */
nl80211_teardown_ap(bss);
+ nl80211_remove_links(bss);
nl80211_destroy_bss(bss);
if (!bss->added_if)
i802_set_iface_flags(bss, 0);
@@ -9134,6 +9063,7 @@
} else {
wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
nl80211_teardown_ap(bss);
+ nl80211_remove_links(bss);
if (!bss->added_if && !drv->first_bss->next)
wpa_driver_nl80211_del_beacon_all(bss);
nl80211_destroy_bss(bss);
@@ -9142,6 +9072,7 @@
if (drv->first_bss->next) {
drv->first_bss = drv->first_bss->next;
drv->ctx = drv->first_bss->ctx;
+ drv->ifindex = drv->first_bss->ifindex;
os_free(bss);
} else {
wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");
@@ -9382,10 +9313,7 @@
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;
-
+ for_each_link(mlo->valid_links, i) {
if (any_valid_link_id == -1)
any_valid_link_id = i;
@@ -9580,59 +9508,81 @@
}
-static void nl80211_remove_links(struct i802_bss *bss)
+static int nl80211_remove_link(struct i802_bss *bss, int link_id)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct i802_link *link;
struct nl_msg *msg;
+ size_t i;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Remove link (ifindex=%d link_id=%u)",
+ bss->ifindex, link_id);
+
+ if (!(bss->valid_links & BIT(link_id))) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: MLD: remove link: Link not found");
+ return -1;
+ }
+
+ link = &bss->links[link_id];
+
+ wpa_driver_nl80211_del_beacon(bss, link_id);
+
+ /* First remove the link locally */
+ bss->valid_links &= ~BIT(link_id);
+ os_memset(link->addr, 0, ETH_ALEN);
+
+ /* Choose new deflink if we are removing that link */
+ if (bss->flink == link) {
+ for_each_link_default(bss->valid_links, i, 0) {
+ bss->flink = &bss->links[i];
+ break;
+ }
+ }
+
+ /* If this was the last link, reset default link */
+ if (!bss->valid_links) {
+ /* TODO: Does keeping freq/bandwidth make sense? */
+ if (bss->flink != link)
+ os_memcpy(bss->flink, link, sizeof(*link));
+
+ os_memcpy(bss->flink->addr, bss->addr, ETH_ALEN);
+ }
+
+ /* Remove the link from the kernel */
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_REMOVE_LINK);
+ if (!msg ||
+ nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) {
+ nlmsg_free(msg);
+ wpa_printf(MSG_ERROR,
+ "nl80211: remove link (%d) failed", link_id);
+ return -1;
+ }
+
+ ret = send_and_recv_cmd(drv, msg);
+ if (ret)
+ wpa_printf(MSG_ERROR,
+ "nl80211: remove link (%d) failed. ret=%d (%s)",
+ link_id, ret, strerror(-ret));
+
+ return ret;
+}
+
+
+static void nl80211_remove_links(struct i802_bss *bss)
+{
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];
-
- wpa_printf(MSG_DEBUG, "nl80211: MLD: remove link_id=%u",
- link->link_id);
-
- wpa_driver_nl80211_del_beacon(bss, link);
-
- link_id = link->link_id;
-
- /* First remove the link locally */
- if (bss->n_links == 1) {
- bss->flink->link_id = NL80211_DRV_LINK_ID_NA;
- os_memcpy(bss->flink->addr, bss->addr, ETH_ALEN);
- } else {
- struct i802_link *other = &bss->links[bss->n_links - 1];
-
- os_memcpy(link, other, sizeof(*link));
- other->link_id = NL80211_DRV_LINK_ID_NA;
- os_memset(other->addr, 0, ETH_ALEN);
-
- bss->n_links--;
- }
-
- /* Remove the link from the kernel */
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_REMOVE_LINK);
- if (!msg ||
- nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) {
- nlmsg_free(msg);
- wpa_printf(MSG_ERROR,
- "nl80211: remove link (%d) failed",
- link_id);
- return;
- }
-
- ret = send_and_recv_cmd(drv, msg);
- if (ret) {
- wpa_printf(MSG_ERROR,
- "nl80211: remove link (%d) failed. ret=%d (%s)",
- link_id, ret, strerror(-ret));
- return;
- }
+ for_each_link(bss->valid_links, link_id) {
+ ret = nl80211_remove_link(bss, link_id);
+ if (ret)
+ break;
}
+
+ if (bss->flink)
+ os_memcpy(bss->flink->addr, bss->addr, ETH_ALEN);
}
@@ -9645,7 +9595,7 @@
return -1;
/* Stop beaconing */
- wpa_driver_nl80211_del_beacon(bss, bss->flink);
+ wpa_driver_nl80211_del_beacon(bss, NL80211_DRV_LINK_ID_NA);
nl80211_remove_links(bss);
@@ -9660,7 +9610,7 @@
}
-static int wpa_driver_nl80211_stop_ap(void *priv)
+static int wpa_driver_nl80211_stop_ap(void *priv, int link_id)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -9668,9 +9618,17 @@
if (!is_ap_interface(drv->nlmode))
return -1;
- wpa_driver_nl80211_del_beacon_all(bss);
+ if (link_id == -1) {
+ wpa_driver_nl80211_del_beacon_all(bss);
+ return 0;
+ }
- return 0;
+ if (nl80211_link_valid(bss->valid_links, link_id)) {
+ wpa_driver_nl80211_del_beacon(bss, link_id);
+ return 0;
+ }
+
+ return -1;
}
@@ -9823,10 +9781,7 @@
if (!sinfo[NL80211_SURVEY_INFO_NOISE])
return NL_SKIP;
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(mlo_sig->valid_links & BIT(i)))
- continue;
-
+ for_each_link(mlo_sig->valid_links, i) {
if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
mlo_sig->links[i].frequency)
continue;
@@ -9919,10 +9874,7 @@
os_memset(mlo_si, 0, sizeof(*mlo_si));
mlo_si->valid_links = drv->sta_mlo_info.valid_links;
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(mlo_si->valid_links & BIT(i)))
- continue;
-
+ for_each_link(mlo_si->valid_links, i) {
res = nl80211_get_link_signal(drv,
drv->sta_mlo_info.links[i].bssid,
&mlo_si->links[i].data);
@@ -10846,6 +10798,73 @@
}
+#ifdef CONFIG_IEEE80211BE
+
+static int driver_nl80211_link_remove(void *priv, enum wpa_driver_if_type type,
+ const char *ifname, u8 link_id)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ if (type != WPA_IF_AP_BSS ||
+ !nl80211_link_valid(bss->valid_links, link_id))
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Teardown AP(%s) link %d (type=%d ifname=%s links=0x%x)",
+ bss->ifname, link_id, type, ifname, bss->valid_links);
+
+ nl80211_remove_link(bss, link_id);
+
+ bss->ctx = bss->flink->ctx;
+
+ if (drv->first_bss == bss && !bss->valid_links)
+ drv->ctx = bss->ctx;
+
+ if (!bss->valid_links) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: No more links remaining, so remove interface");
+ return wpa_driver_nl80211_if_remove(bss, type, ifname);
+ }
+
+ return 0;
+}
+
+
+static bool nl80211_is_drv_shared(void *priv, void *bss_ctx)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ unsigned int num_bss = 0;
+
+ /* If any other BSS exist, someone else is using this since at this
+ * time, we would have removed all BSSs created by this driver and only
+ * this BSS should be remaining if the driver is not shared by anyone.
+ */
+ for (bss = drv->first_bss; bss; bss = bss->next) {
+ num_bss++;
+ if (num_bss > 1)
+ return true;
+ }
+
+ /* This is the only BSS present */
+ bss = priv;
+
+ /* If only one/no link is there no one is sharing */
+ if (bss->valid_links <= 1)
+ return false;
+
+ /* More than one link means someone is still using. To check if
+ * only 1 bit is set, power of 2 condition can be checked. */
+ if (!(bss->valid_links & (bss->valid_links - 1)))
+ return false;
+
+ return true;
+}
+
+#endif /* CONFIG_IEEE80211BE */
+
+
static int driver_nl80211_send_mlme(void *priv, const u8 *data,
size_t data_len, int noack,
unsigned int freq,
@@ -11114,10 +11133,7 @@
return pos - buf;
pos += res;
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(mlo->valid_links & BIT(i)))
- continue;
-
+ for_each_link(mlo->valid_links, i) {
res = os_snprintf(pos, end - pos,
"link_addr[%u]=" MACSTR "\n"
"link_bssid[%u]=" MACSTR "\n"
@@ -12248,13 +12264,14 @@
const u8 *ipaddr, int prefixlen,
const u8 *addr)
{
-#ifdef CONFIG_LIBNL3_ROUTE
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- struct rtnl_neigh *rn;
- struct nl_addr *nl_ipaddr = NULL;
- struct nl_addr *nl_lladdr = NULL;
- int family, addrsize;
+ struct ndmsg nhdr = {
+ .ndm_state = NUD_PERMANENT,
+ .ndm_ifindex = bss->br_ifindex,
+ };
+ struct nl_msg *msg;
+ int addrsize;
int res;
if (!ipaddr || prefixlen == 0 || !addr)
@@ -12273,85 +12290,62 @@
}
if (version == 4) {
- family = AF_INET;
+ nhdr.ndm_family = AF_INET;
addrsize = 4;
} else if (version == 6) {
- family = AF_INET6;
+ nhdr.ndm_family = AF_INET6;
addrsize = 16;
} else {
return -EINVAL;
}
- rn = rtnl_neigh_alloc();
- if (rn == NULL)
+ msg = nlmsg_alloc_simple(RTM_NEWNEIGH, NLM_F_CREATE);
+ if (!msg)
return -ENOMEM;
- /* set the destination ip address for neigh */
- nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
- if (nl_ipaddr == NULL) {
- wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
- res = -ENOMEM;
+ res = -ENOMEM;
+ if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0 ||
+ nla_put(msg, NDA_DST, addrsize, (void *) ipaddr) ||
+ nla_put(msg, NDA_LLADDR, ETH_ALEN, (void *) addr))
goto errout;
- }
- nl_addr_set_prefixlen(nl_ipaddr, prefixlen);
- res = rtnl_neigh_set_dst(rn, nl_ipaddr);
- if (res) {
- wpa_printf(MSG_DEBUG,
- "nl80211: neigh set destination addr failed");
+
+ res = nl_send_auto_complete(drv->rtnl_sk, msg);
+ if (res < 0)
goto errout;
- }
- /* set the corresponding lladdr for neigh */
- nl_lladdr = nl_addr_build(AF_BRIDGE, (u8 *) addr, ETH_ALEN);
- if (nl_lladdr == NULL) {
- wpa_printf(MSG_DEBUG, "nl80211: neigh set lladdr failed");
- res = -ENOMEM;
- goto errout;
- }
- rtnl_neigh_set_lladdr(rn, nl_lladdr);
-
- rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
- rtnl_neigh_set_state(rn, NUD_PERMANENT);
-
- res = rtnl_neigh_add(drv->rtnl_sk, rn, NLM_F_CREATE);
+ res = nl_wait_for_ack(drv->rtnl_sk);
if (res) {
wpa_printf(MSG_DEBUG,
"nl80211: Adding bridge ip neigh failed: %s",
nl_geterror(res));
}
errout:
- if (nl_lladdr)
- nl_addr_put(nl_lladdr);
- if (nl_ipaddr)
- nl_addr_put(nl_ipaddr);
- if (rn)
- rtnl_neigh_put(rn);
+ nlmsg_free(msg);
return res;
-#else /* CONFIG_LIBNL3_ROUTE */
- return -1;
-#endif /* CONFIG_LIBNL3_ROUTE */
}
static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version,
const u8 *ipaddr)
{
-#ifdef CONFIG_LIBNL3_ROUTE
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- struct rtnl_neigh *rn;
- struct nl_addr *nl_ipaddr;
- int family, addrsize;
+ struct ndmsg nhdr = {
+ .ndm_state = NUD_PERMANENT,
+ .ndm_ifindex = bss->br_ifindex,
+ };
+ struct nl_msg *msg;
+ int addrsize;
int res;
if (!ipaddr)
return -EINVAL;
if (version == 4) {
- family = AF_INET;
+ nhdr.ndm_family = AF_INET;
addrsize = 4;
} else if (version == 6) {
- family = AF_INET6;
+ nhdr.ndm_family = AF_INET6;
addrsize = 16;
} else {
return -EINVAL;
@@ -12369,41 +12363,28 @@
return -1;
}
- rn = rtnl_neigh_alloc();
- if (rn == NULL)
+ msg = nlmsg_alloc_simple(RTM_DELNEIGH, NLM_F_CREATE);
+ if (!msg)
return -ENOMEM;
- /* set the destination ip address for neigh */
- nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
- if (nl_ipaddr == NULL) {
- wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
- res = -ENOMEM;
+ res = -ENOMEM;
+ if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0 ||
+ nla_put(msg, NDA_DST, addrsize, (void *) ipaddr))
goto errout;
- }
- res = rtnl_neigh_set_dst(rn, nl_ipaddr);
- if (res) {
- wpa_printf(MSG_DEBUG,
- "nl80211: neigh set destination addr failed");
+
+ res = nl_send_auto_complete(drv->rtnl_sk, msg);
+ if (res < 0)
goto errout;
- }
- rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
-
- res = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
+ res = nl_wait_for_ack(drv->rtnl_sk);
if (res) {
wpa_printf(MSG_DEBUG,
"nl80211: Deleting bridge ip neigh failed: %s",
nl_geterror(res));
}
errout:
- if (nl_ipaddr)
- nl_addr_put(nl_ipaddr);
- if (rn)
- rtnl_neigh_put(rn);
+ nlmsg_free(msg);
return res;
-#else /* CONFIG_LIBNL3_ROUTE */
- return -1;
-#endif /* CONFIG_LIBNL3_ROUTE */
}
@@ -13986,12 +13967,12 @@
}
#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
-static int nl80211_link_add(void *priv, u8 link_id, const u8 *addr)
+static int nl80211_link_add(void *priv, u8 link_id, const u8 *addr,
+ void *bss_ctx)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- unsigned int idx, i;
int ret;
wpa_printf(MSG_DEBUG, "nl80211: MLD: add link_id=%u, addr=" MACSTR,
@@ -14004,32 +13985,24 @@
return -EINVAL;
}
- if (bss->n_links >= MAX_NUM_MLD_LINKS) {
- wpa_printf(MSG_DEBUG, "nl80211: MLD: already have n_links=%zu",
- bss->n_links);
+ if (link_id >= MAX_NUM_MLD_LINKS) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: invalid link_id=%u", link_id);
return -EINVAL;
}
- for (i = 0; i < bss->n_links; i++) {
- if (bss->links[i].link_id == link_id &&
- bss->links[i].beacon_set) {
- wpa_printf(MSG_DEBUG,
- "nl80211: MLD: link already set");
- return -EINVAL;
- }
+ if (bss->valid_links & BIT(link_id)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: MLD: Link %u already set", link_id);
+ return -EINVAL;
}
- /* try using the first link entry, assuming it is not beaconing yet */
- if (bss->n_links == 1 &&
- bss->flink->link_id == NL80211_DRV_LINK_ID_NA) {
+ if (!bss->valid_links) {
+ /* Becoming MLD, verify we were not beaconing */
if (bss->flink->beacon_set) {
wpa_printf(MSG_DEBUG, "nl80211: BSS already beaconing");
return -EINVAL;
}
-
- idx = 0;
- } else {
- idx = bss->n_links;
}
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_ADD_LINK);
@@ -14047,16 +14020,51 @@
return ret;
}
- bss->links[idx].link_id = link_id;
- os_memcpy(bss->links[idx].addr, addr, ETH_ALEN);
+ os_memcpy(bss->links[link_id].addr, addr, ETH_ALEN);
- bss->n_links = idx + 1;
+ /* The new link is the first one, make it the default */
+ if (!bss->valid_links)
+ bss->flink = &bss->links[link_id];
- wpa_printf(MSG_DEBUG, "nl80211: MLD: n_links=%zu", bss->n_links);
+ bss->valid_links |= BIT(link_id);
+ bss->links[link_id].ctx = bss_ctx;
+
+ wpa_printf(MSG_DEBUG, "nl80211: MLD: valid_links=0x%04x",
+ bss->valid_links);
return 0;
}
+#ifdef CONFIG_IEEE80211BE
+static int wpa_driver_nl80211_link_sta_remove(void *priv, u8 link_id,
+ const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ if (!(bss->valid_links & BIT(link_id)))
+ return -ENOLINK;
+
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_REMOVE_LINK_STA)) ||
+ nla_put(msg, NL80211_ATTR_MLD_ADDR, ETH_ALEN, addr) ||
+ nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_cmd(drv, msg);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: link_sta_remove -> REMOVE_LINK_STA on link_id %u from MLD STA "
+ MACSTR ", from %s --> %d (%s)",
+ link_id, MAC2STR(addr), bss->ifname, ret, strerror(-ret));
+
+ return ret;
+}
+#endif /* CONFIG_IEEE80211BE */
+
+
#ifdef CONFIG_TESTING_OPTIONS
static int testing_nl80211_register_frame(void *priv, u16 type,
@@ -14111,7 +14119,7 @@
.scan2 = driver_nl80211_scan2,
.sched_scan = wpa_driver_nl80211_sched_scan,
.stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
- .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
+ .get_scan_results = wpa_driver_nl80211_get_scan_results,
.abort_scan = wpa_driver_nl80211_abort_scan,
.deauthenticate = driver_nl80211_deauthenticate,
.authenticate = driver_nl80211_authenticate,
@@ -14251,6 +14259,11 @@
#endif /* CONFIG_DPP */
.get_sta_mlo_info = nl80211_get_sta_mlo_info,
.link_add = nl80211_link_add,
+#ifdef CONFIG_IEEE80211BE
+ .link_remove = driver_nl80211_link_remove,
+ .is_drv_shared = nl80211_is_drv_shared,
+ .link_sta_remove = wpa_driver_nl80211_link_sta_remove,
+#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_TESTING_OPTIONS
.register_frame = testing_nl80211_register_frame,
.radio_disable = testing_nl80211_radio_disable,
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 048c9a3..d2c1ffa 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -55,7 +55,6 @@
struct i802_link {
unsigned int beacon_set:1;
- s8 link_id;
int freq;
int bandwidth;
u8 addr[ETH_ALEN];
@@ -66,7 +65,7 @@
struct wpa_driver_nl80211_data *drv;
struct i802_bss *next;
- size_t n_links;
+ u16 valid_links;
struct i802_link links[MAX_NUM_MLD_LINKS];
struct i802_link *flink;
@@ -292,6 +291,21 @@
void *ack_data,
struct nl80211_err_info *err_info);
+// This function is not used in supplicant anymore. But keeping this wrapper
+// functions for libraries outside wpa_supplicant to build (For eg: lib_driver_cmd_XX)
+static inline 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)
+{
+ return send_and_recv(drv->global, drv->global->nl, msg,
+ valid_handler, valid_data,
+ ack_handler_custom, ack_data, NULL);
+}
+
static inline int
send_and_recv_cmd(struct wpa_driver_nl80211_data *drv,
struct nl_msg *msg)
@@ -357,6 +371,18 @@
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_link_valid(u16 links, s8 link_id)
+{
+ if (link_id < 0 || link_id >= MAX_NUM_MLD_LINKS)
+ return false;
+
+ if (links & BIT(link_id))
+ return true;
+
+ return false;
+}
+
+
static inline bool
nl80211_attr_supported(struct wpa_driver_nl80211_data *drv, unsigned int attr)
{
@@ -394,7 +420,8 @@
int wpa_driver_nl80211_sched_scan(void *priv,
struct wpa_driver_scan_params *params);
int wpa_driver_nl80211_stop_sched_scan(void *priv);
-struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv);
+struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv,
+ const u8 *bssid);
void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv);
int wpa_driver_nl80211_abort_scan(void *priv, u64 scan_cookie);
int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss,
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 0b6f511..d8375cc 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -888,6 +888,10 @@
nla_get_u16(tb1[NL80211_ATTR_MLD_CAPA_AND_OPS]);
}
+ wpa_printf(MSG_DEBUG,
+ "nl80211: EML Capability: 0x%x MLD Capability: 0x%x",
+ capa->eml_capa, capa->mld_capa_and_ops);
+
drv->num_iface_capa++;
if (drv->num_iface_capa == NL80211_IFTYPE_MAX)
break;
@@ -2165,6 +2169,9 @@
for (m = 0; m < *num_modes; m++) {
if (!modes[m].num_channels)
continue;
+
+ modes[m].is_6ghz = false;
+
if (modes[m].channels[0].freq < 2000) {
modes[m].num_channels = 0;
continue;
@@ -2176,10 +2183,14 @@
break;
}
}
- } else if (modes[m].channels[0].freq > 50000)
+ } else if (modes[m].channels[0].freq > 50000) {
modes[m].mode = HOSTAPD_MODE_IEEE80211AD;
- else
+ } else if (is_6ghz_freq(modes[m].channels[0].freq)) {
modes[m].mode = HOSTAPD_MODE_IEEE80211A;
+ modes[m].is_6ghz = true;
+ } else {
+ modes[m].mode = HOSTAPD_MODE_IEEE80211A;
+ }
}
/* Remove unsupported bands */
@@ -2407,6 +2418,57 @@
}
+static void nl80211_set_6ghz_mode(struct hostapd_hw_modes *mode, int start,
+ int end, int max_bw)
+{
+ int c;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if (chan->freq - 10 < start || chan->freq + 10 > end)
+ continue;
+
+ if (max_bw >= 80)
+ chan->flag |= HOSTAPD_CHAN_VHT_80MHZ_SUBCHANNEL;
+
+ if (max_bw >= 160)
+ chan->flag |= HOSTAPD_CHAN_VHT_160MHZ_SUBCHANNEL;
+
+ if (max_bw >= 320)
+ chan->flag |= HOSTAPD_CHAN_EHT_320MHZ_SUBCHANNEL;
+ }
+}
+
+
+static void nl80211_reg_rule_6ghz(struct nlattr *tb[],
+ struct phy_info_arg *results)
+{
+ u32 start, end, max_bw;
+ u16 m;
+
+ if (!tb[NL80211_ATTR_FREQ_RANGE_START] ||
+ !tb[NL80211_ATTR_FREQ_RANGE_END] ||
+ !tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
+ return;
+
+ start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+ end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+ max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+ if (max_bw < 80)
+ return;
+
+ for (m = 0; m < *results->num_modes; m++) {
+ if (results->modes[m].num_channels == 0 ||
+ !is_6ghz_freq(results->modes[m].channels[0].freq))
+ continue;
+
+ nl80211_set_6ghz_mode(&results->modes[m], start, end, max_bw);
+ }
+}
+
+
static void nl80211_set_dfs_domain(enum nl80211_dfs_regions region,
u8 *dfs_domain)
{
@@ -2525,6 +2587,13 @@
nl80211_reg_rule_vht(tb_rule, results);
}
+ nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+ {
+ nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+ nl80211_reg_rule_6ghz(tb_rule, results);
+ }
+
return NL_SKIP;
}
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 4163f79..9ce73c6 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -476,10 +476,7 @@
* links when the link used for (re)association is removed.
*/
if (removed_links & BIT(drv->sta_mlo_info.assoc_link_id)) {
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(drv->sta_mlo_info.valid_links & BIT(i)))
- continue;
-
+ for_each_link(drv->sta_mlo_info.valid_links, i) {
os_memcpy(drv->bssid, drv->sta_mlo_info.links[i].bssid,
ETH_ALEN);
drv->sta_mlo_info.assoc_link_id = i;
@@ -701,10 +698,7 @@
}
/* Get MLO links info for rejected links */
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!((mlo->req_links & ~mlo->valid_links) & BIT(i)))
- continue;
-
+ for_each_link((mlo->req_links & ~mlo->valid_links), i) {
os_memcpy(mlo->links[i].bssid, resp_info.addr[i], ETH_ALEN);
os_memcpy(mlo->links[i].addr, req_info.addr[i], ETH_ALEN);
}
@@ -874,9 +868,7 @@
wpa_printf(MSG_DEBUG,
"nl80211: TID-to-link: Received uplink %x downlink %x",
uplink, downlink);
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(drv->sta_mlo_info.valid_links & BIT(i)))
- continue;
+ for_each_link(drv->sta_mlo_info.valid_links, i) {
if (uplink & BIT(i))
event.t2l_map_info.t2lmap[i].uplink |=
BIT(tidnum);
@@ -1268,14 +1260,23 @@
if (cf2)
data.ch_switch.cf2 = nla_get_u32(cf2);
- 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 (finished) {
+ if (data.ch_switch.link_id != NL80211_DRV_LINK_ID_NA) {
+ struct i802_link *mld_link;
+
+ mld_link = nl80211_get_link(bss,
+ data.ch_switch.link_id);
+ mld_link->freq = data.ch_switch.freq;
+ } else {
+ bss->flink->freq = data.ch_switch.freq;
+ }
+ }
+
if (link && is_sta_interface(drv->nlmode)) {
u8 link_id = data.ch_switch.link_id;
@@ -1618,18 +1619,17 @@
}
-static struct i802_link *
-nl80211_get_mld_link_by_freq(struct i802_bss *bss, unsigned int freq)
+static s8
+nl80211_get_link_id_by_freq(struct i802_bss *bss, unsigned int freq)
{
unsigned int i;
- for (i = 0; i < bss->n_links; i++) {
- if ((unsigned int) bss->links[i].freq == freq &&
- bss->links[i].link_id != -1)
- return &bss->links[i];
+ for_each_link(bss->valid_links, i) {
+ if ((unsigned int) bss->links[i].freq == freq)
+ return i;
}
- return NULL;
+ return NL80211_DRV_LINK_ID_NA;
}
@@ -1663,12 +1663,12 @@
/* Determine the MLD link either by an explicitly provided link id or
* finding a match based on the frequency. */
if (link)
- mld_link = nl80211_get_link(bss, nla_get_u8(link));
+ link_id = nla_get_u8(link);
else if (freq)
- mld_link = nl80211_get_mld_link_by_freq(bss, nla_get_u32(freq));
+ link_id = nl80211_get_link_id_by_freq(bss, nla_get_u32(freq));
- if (mld_link)
- link_id = mld_link->link_id;
+ if (nl80211_link_valid(bss->valid_links, link_id))
+ mld_link = nl80211_get_link(bss, link_id);
data = nla_data(frame);
len = nla_len(frame);
@@ -1920,7 +1920,7 @@
os_memset(&data, 0, sizeof(data));
addr = nla_data(tb[NL80211_ATTR_MAC]);
- if (bss->links[0].link_id == NL80211_DRV_LINK_ID_NA &&
+ if (!bss->valid_links &&
(tb[NL80211_ATTR_MLO_LINK_ID] ||
tb[NL80211_ATTR_MLD_ADDR])) {
wpa_printf(MSG_ERROR,
@@ -2184,7 +2184,7 @@
u8 *req_ies = NULL, *resp_ies = NULL;
size_t req_ies_len = 0, resp_ies_len = 0;
- if (bss->links[0].link_id == NL80211_DRV_LINK_ID_NA &&
+ if (!bss->valid_links &&
(tb[NL80211_ATTR_MLO_LINK_ID] ||
tb[NL80211_ATTR_MLD_ADDR])) {
wpa_printf(MSG_ERROR,
@@ -2452,7 +2452,6 @@
{
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;
@@ -2462,11 +2461,13 @@
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;
+ if (tb[NL80211_ATTR_MLO_LINK_ID]) {
+ data.dfs_event.link_id =
+ nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]);
+ } else if (data.dfs_event.freq) {
+ data.dfs_event.link_id =
+ nl80211_get_link_id_by_freq(drv->first_bss,
+ data.dfs_event.freq);
}
/* Check HT params */
@@ -2831,7 +2832,6 @@
{
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");
@@ -2850,11 +2850,13 @@
data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
data.dfs_event.link_id = NL80211_DRV_LINK_ID_NA;
- 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;
+ if (tb[NL80211_ATTR_MLO_LINK_ID]) {
+ data.dfs_event.link_id =
+ nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]);
+ } else if (data.dfs_event.freq) {
+ data.dfs_event.link_id =
+ nl80211_get_link_id_by_freq(drv->first_bss,
+ data.dfs_event.freq);
}
wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, link=%d",
@@ -2966,6 +2968,7 @@
info = &event.scan_info;
info->aborted = aborted;
info->external_scan = external_scan;
+ info->scan_cookie = nla_get_u64(tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]);
if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS]) {
nla_for_each_nested(nl,
@@ -3748,8 +3751,11 @@
(long long unsigned int) cookie,
match ? " (match)" : "",
drv->send_frame_cookie == cookie ? " (match-saved)" : "");
- if (drv->send_frame_cookie == cookie)
+ if (drv->send_frame_cookie == cookie) {
drv->send_frame_cookie = (u64) -1;
+ if (!match)
+ goto send_event;
+ }
if (!match)
return;
@@ -3759,6 +3765,7 @@
(drv->num_send_frame_cookies - i - 1) * sizeof(u64));
drv->num_send_frame_cookies--;
+send_event:
wpa_supplicant_event(drv->ctx, EVENT_TX_WAIT_EXPIRE, NULL);
}
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index 68ae579..1eb4374 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -728,7 +728,7 @@
static struct wpa_scan_res *
nl80211_parse_bss_info(struct wpa_driver_nl80211_data *drv,
- struct nl_msg *msg)
+ struct nl_msg *msg, const u8 *bssid)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
@@ -762,6 +762,9 @@
if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
bss_policy))
return NULL;
+ if (bssid && bss[NL80211_BSS_BSSID] &&
+ !ether_addr_equal(bssid, nla_data(bss[NL80211_BSS_BSSID])))
+ return NULL;
if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
@@ -866,6 +869,7 @@
struct nl80211_bss_info_arg {
struct wpa_driver_nl80211_data *drv;
struct wpa_scan_results *res;
+ const u8 *bssid;
};
static int bss_info_handler(struct nl_msg *msg, void *arg)
@@ -875,7 +879,7 @@
struct wpa_scan_res **tmp;
struct wpa_scan_res *r;
- r = nl80211_parse_bss_info(_arg->drv, msg);
+ r = nl80211_parse_bss_info(_arg->drv, msg, _arg->bssid);
if (!r)
return NL_SKIP;
@@ -973,7 +977,7 @@
static struct wpa_scan_results *
-nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
+nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv, const u8 *bssid)
{
struct nl_msg *msg;
struct wpa_scan_results *res;
@@ -993,6 +997,7 @@
arg.drv = drv;
arg.res = res;
+ arg.bssid = bssid;
ret = send_and_recv_resp(drv, msg, bss_info_handler, &arg);
if (ret == -EAGAIN) {
count++;
@@ -1029,16 +1034,18 @@
/**
* wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
- * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init()
+ * @bssid: Return results only for the specified BSSID, %NULL for all
* Returns: Scan results on success, -1 on failure
*/
-struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv)
+struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv,
+ const u8 *bssid)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct wpa_scan_results *res;
- res = nl80211_get_scan_results(drv);
+ res = nl80211_get_scan_results(drv, bssid);
if (res)
wpa_driver_nl80211_check_bss_status(drv, res);
return res;
@@ -1055,7 +1062,7 @@
struct nl80211_dump_scan_ctx *ctx = arg;
struct wpa_scan_res *r;
- r = nl80211_parse_bss_info(ctx->drv, msg);
+ r = nl80211_parse_bss_info(ctx->drv, msg, NULL);
if (!r)
return NL_SKIP;
wpa_printf(MSG_DEBUG, "nl80211: %d " MACSTR " %d%s",
@@ -1268,6 +1275,11 @@
goto fail;
}
+ if (is_ap_interface(drv->nlmode) &&
+ params->link_id != NL80211_DRV_LINK_ID_NA &&
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_SCAN_LINK_ID, params->link_id))
+ goto fail;
+
nla_nest_end(msg, attr);
ret = send_and_recv_resp(drv, msg, scan_cookie_handler, &cookie);
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index 0186099..3b3098d 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -160,7 +160,6 @@
NEED_LINUX_IOCTL=y
ifdef CONFIG_VLAN_NETLINK
NEED_LIBNL=y
-CONFIG_LIBNL3_ROUTE=y
endif
endif
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 8c58456..1cbe652 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -154,7 +154,6 @@
NEED_LINUX_IOCTL=y
ifdef CONFIG_VLAN_NETLINK
NEED_LIBNL=y
-CONFIG_LIBNL3_ROUTE=y
endif
endif