blob: 27f986a43da1c232bc54ff48f7383b6312be5af1 [file] [log] [blame]
From 0cc6f925c0a97da331f41462a07c4ae4b6698409 Mon Sep 17 00:00:00 2001
From: Michael-CY Lee <michael-cy.lee@mediatek.com>
Date: Tue, 2 Apr 2024 15:36:29 +0800
Subject: [PATCH 101/104] mtk: hostapd: MLD: hostapd: add support for basic MLD
Extender
Add basic MLD Extender support, including
1. Extender STA stops all Extender AP's links before scaning.
2. After finishing the connection with root AP, Extender STA
synchronizes control channel with each link on the Extender
AP.
Advanced support includes BW cynchronization and channel switch.
CR-Id: WCNCR00289305
Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
---
src/ap/ucode.c | 52 ++++++++++++++++++++++++++++++++++++++----
src/utils/ucode.c | 4 +++-
wpa_supplicant/ucode.c | 45 +++++++++++++++++++++++++++++-------
3 files changed, 88 insertions(+), 13 deletions(-)
diff --git a/src/ap/ucode.c b/src/ap/ucode.c
index 98b2a3bf2..2642e87c7 100644
--- a/src/ap/ucode.c
+++ b/src/ap/ucode.c
@@ -487,14 +487,16 @@ static uc_value_t *
uc_hostapd_iface_stop(uc_vm_t *vm, size_t nargs)
{
struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
+ struct hostapd_data *first_hapd;
+ struct hostapd_bss_config *conf;
int i;
- wpa_printf(MSG_INFO, "ucode: mtk: stop iface for %s in state %s\n",
- iface->phy, hostapd_state_text(iface->state));
-
if (!iface)
return NULL;
+ wpa_printf(MSG_INFO, "ucode: mtk: stop iface for %s in state %s\n",
+ iface->phy, hostapd_state_text(iface->state));
+
if (iface->state != HAPD_IFACE_ENABLED)
uc_hostapd_disable_iface(iface);
@@ -505,6 +507,32 @@ uc_hostapd_iface_stop(uc_vm_t *vm, size_t nargs)
hapd->beacon_set_done = 0;
}
+#ifdef CONFIG_IEEE80211BE
+ first_hapd = iface->bss[0];
+ conf = first_hapd->conf;
+ for (i = 0; conf->mld_ap && i < iface->interfaces->count; i++) {
+ struct hostapd_iface *h = iface->interfaces->iface[i];
+ struct hostapd_data *h_hapd = h->bss[0];
+ struct hostapd_bss_config *hconf = h_hapd->conf;
+
+ if (h == iface) {
+ wpa_printf(MSG_DEBUG, "MLD: Skip own interface");
+ continue;
+ }
+
+ if (!hconf->mld_ap) {
+ wpa_printf(MSG_DEBUG,
+ "MLD: Skip non MLD");
+ continue;
+ }
+
+ if (hostapd_is_ml_partner(first_hapd, h_hapd)) {
+ hostapd_drv_stop_ap(h_hapd);
+ h_hapd->beacon_set_done = 0;
+ }
+ }
+#endif /* CONFIG_IEEE80211BE */
+
return NULL;
}
@@ -512,11 +540,12 @@ static uc_value_t *
uc_hostapd_iface_start(uc_vm_t *vm, size_t nargs)
{
struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
+ struct hostapd_data *tmp_hapd;
uc_value_t *info = uc_fn_arg(0);
struct hostapd_config *conf;
bool changed = false;
uint64_t intval;
- int i;
+ int i, band_idx;
wpa_printf(MSG_INFO, "ucode: mtk: start iface for %s in state %s\n",
iface->phy, hostapd_state_text(iface->state));
@@ -532,6 +561,21 @@ uc_hostapd_iface_start(uc_vm_t *vm, size_t nargs)
if (ucv_type(info) != UC_OBJECT)
return NULL;
+ intval = ucv_int64_get(ucv_object_get(info, "band_idx", NULL));
+ if (!errno)
+ band_idx = intval;
+
+#ifdef CONFIG_IEEE80211BE
+ if (hostapd_is_mld_ap(iface->bss[0])) {
+ for_each_mld_link(tmp_hapd, iface->bss[0]) {
+ if (band_idx == tmp_hapd->iconf->band_idx) {
+ iface = tmp_hapd->iface;
+ break;
+ }
+ }
+ }
+#endif /* CONFIG_IEEE80211BE */
+
#define UPDATE_VAL(field, name) \
if ((intval = ucv_int64_get(ucv_object_get(info, name, NULL))) && \
!errno && intval != conf->field) do { \
diff --git a/src/utils/ucode.c b/src/utils/ucode.c
index 6f82382f3..81d472f6b 100644
--- a/src/utils/ucode.c
+++ b/src/utils/ucode.c
@@ -110,7 +110,7 @@ uc_value_t *uc_wpa_freq_info(uc_vm_t *vm, size_t nargs)
uc_value_t *freq = uc_fn_arg(0);
uc_value_t *sec = uc_fn_arg(1);
int width = ucv_uint64_get(uc_fn_arg(2));
- int bw320_offset = 1;
+ int bw320_offset = 1, band_idx;
int freq_val, center_idx, center_ofs;
enum oper_chan_width chanwidth;
enum hostapd_hw_mode hw_mode;
@@ -123,6 +123,7 @@ uc_value_t *uc_wpa_freq_info(uc_vm_t *vm, size_t nargs)
return NULL;
freq_val = ucv_int64_get(freq);
+ band_idx = ucv_int64_get(uc_fn_arg(4));
if (ucv_type(sec) == UC_INTEGER)
sec_channel = ucv_int64_get(sec);
else if (sec)
@@ -183,6 +184,7 @@ uc_value_t *uc_wpa_freq_info(uc_vm_t *vm, size_t nargs)
ucv_object_add(ret, "sec_channel", ucv_int64_new(sec_channel));
ucv_object_add(ret, "frequency", ucv_int64_new(freq_val));
ucv_object_add(ret, "oper_chwidth", ucv_int64_new(chanwidth));
+ ucv_object_add(ret, "band_idx", ucv_int64_new(band_idx));
if (chanwidth == CONF_OPER_CHWIDTH_USE_HT && !sec_channel) {
ucv_object_add(ret, "center_seg0_idx", ucv_int64_new(channel));
diff --git a/wpa_supplicant/ucode.c b/wpa_supplicant/ucode.c
index 542ca25c9..ac0639a90 100644
--- a/wpa_supplicant/ucode.c
+++ b/wpa_supplicant/ucode.c
@@ -246,12 +246,13 @@ uc_wpas_iface_status(uc_vm_t *vm, size_t nargs)
{
struct wpa_supplicant *wpa_s = uc_fn_thisval("wpas.iface");
struct wpa_bss *bss;
- uc_value_t *ret, *val;
+ uc_value_t *ret, *val, *link_obj = uc_fn_arg(0);
struct wpa_channel_info ci;
u8 op_class, channel;
- enum oper_chan_width ch_width;
- int center_freq1, bw320_offset = 1, is_24ghz;
+ enum oper_chan_width ch_width = CONF_OPER_CHWIDTH_USE_HT;
+ int center_freq1, bw320_offset = 1, is_24ghz, band_idx;
enum hostapd_hw_mode hw_mode;
+ int link_id = ucv_int64_get(link_obj);
if (!wpa_s)
return NULL;
@@ -261,13 +262,25 @@ uc_wpas_iface_status(uc_vm_t *vm, size_t nargs)
val = ucv_string_new(wpa_supplicant_state_txt(wpa_s->wpa_state));
ucv_object_add(ret, "state", ucv_get(val));
- bss = wpa_s->current_bss;
+ bss = link_id == -1 ? wpa_s->current_bss : wpa_s->links[link_id].bss;
if (bss) {
int sec_chan = 0;
hw_mode = ieee80211_freq_to_chan(bss->freq, &channel);
is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
hw_mode == HOSTAPD_MODE_IEEE80211B;
+ /*
+ * Assume that the mapping between band and band_idx is
+ * 2 GHz band: band_idx 0
+ * 5 GHz band: band_idx 1
+ * 6 GHz band: band_idx 2
+ * */
+ if (is_24ghz)
+ band_idx = 0;
+ else if (IS_5GHZ(bss->freq))
+ band_idx = 1;
+ else if (is_6ghz_freq(bss->freq))
+ band_idx = 2;
wpa_drv_channel_info(wpa_s, &ci);
center_freq1 = ci.center_frq1;
@@ -279,11 +292,10 @@ uc_wpas_iface_status(uc_vm_t *vm, size_t nargs)
sec_chan = (bss->freq / 20) & 1 ? 1 : -1;
}
- if (ieee80211_chaninfo_to_channel(ci.frequency, ci.chanwidth,
- sec_chan, &op_class, &channel))
- return NULL;
+ if (!ieee80211_chaninfo_to_channel(ci.frequency, ci.chanwidth,
+ sec_chan, &op_class, &channel))
+ ch_width = op_class_to_ch_width(op_class);
- ch_width = op_class_to_ch_width(op_class);
if (ch_width == CONF_OPER_CHWIDTH_320MHZ &&
(center_freq1 == 6265) || center_freq1 == 6585 ||
center_freq1 == 6905) {
@@ -295,6 +307,7 @@ uc_wpas_iface_status(uc_vm_t *vm, size_t nargs)
ucv_object_add(ret, "frequency", ucv_int64_new(bss->freq));
ucv_object_add(ret, "ch_width", ucv_int64_new(ch_width));
ucv_object_add(ret, "bw320_offset", ucv_int64_new(bw320_offset));
+ ucv_object_add(ret, "band_idx", ucv_int64_new(band_idx));
}
#ifdef CONFIG_MESH
@@ -309,6 +322,21 @@ uc_wpas_iface_status(uc_vm_t *vm, size_t nargs)
return ret;
}
+static uc_value_t *
+uc_wpas_iface_get_valid_links(uc_vm_t *vm, size_t nargs)
+{
+ struct wpa_supplicant *wpa_s = uc_fn_thisval("wpas.iface");
+ uc_value_t *ret;
+
+ if (!wpa_s)
+ return NULL;
+
+ ret = ucv_object_new(vm);
+ ucv_object_add(ret, "valid_links", ucv_uint64_new(wpa_s->valid_links));
+
+ return ret;
+}
+
int wpas_ucode_init(struct wpa_global *gl)
{
static const uc_function_list_t global_fns[] = {
@@ -320,6 +348,7 @@ int wpas_ucode_init(struct wpa_global *gl)
};
static const uc_function_list_t iface_fns[] = {
{ "status", uc_wpas_iface_status },
+ { "get_valid_links", uc_wpas_iface_get_valid_links },
};
uc_value_t *data, *proto;
--
2.39.2