From e631785117e34d830071dce7d6a02025ef161df4 Mon Sep 17 00:00:00 2001 From: Stanislav Kuchar Date: Wed, 19 Nov 2025 05:40:41 +0100 Subject: [PATCH 1/3] BCOMB-3166: Runtime mld_addr update (#703) Reason for change: Runtime MLO reconfiguration requires regeneration of MLD_Addr according to the new configuration received in runtime. Test Procedure: - Perform runtime change of MLO configuration (change of main link) via TR-181 Data Model and check if MLO address is correctly generated for MLO VAPs - Check wifi connectivity with focus on MLO. Risks: Low Priority: P1 Signed-off-by: Stanislav Kuchar Co-authored-by: Narendra Varma Dandu --- include/wifi_base.h | 14 ++++ source/core/wifi_ctrl_webconfig.c | 131 ++++++++++++++++++++++++++++++ source/db/wifi_db_apis.c | 11 +-- source/utils/wifi_util.c | 3 + 4 files changed, 152 insertions(+), 7 deletions(-) diff --git a/include/wifi_base.h b/include/wifi_base.h index cf61e79d2..8c5668074 100644 --- a/include/wifi_base.h +++ b/include/wifi_base.h @@ -79,6 +79,20 @@ extern "C" { #define WIFI_CSA_BEACON_FRAME_RECEIVED "Device.WiFi.CSABeaconFrameRecieved" #define WIFI_STUCK_DETECT_FILE_NAME "/nvram/wifi_stuck_detect" +#ifdef CONFIG_IEEE80211BE + +#ifndef MAX_NUM_MLD_LINKS +#define MAX_NUM_MLD_LINKS 15 +#endif /*MAX_NUM_MLD_LINKS*/ + +#ifdef CONFIG_NO_MLD_ONLY_PRIVATE +#define MLD_UNIT_COUNT 8 +#else +#define MLD_UNIT_COUNT 1 +#endif /* CONFIG_NO_MLD_ONLY_PRIVATE */ + +#endif /* CONFIG_IEEE80211BE */ + #define PLAN_ID_LENGTH 38 #define MAX_STEP_COUNT 32 /*Active Measurement Step Count */ #define MAC_ADDRESS_LENGTH 13 diff --git a/source/core/wifi_ctrl_webconfig.c b/source/core/wifi_ctrl_webconfig.c index 5d31d3978..53261cca9 100644 --- a/source/core/wifi_ctrl_webconfig.c +++ b/source/core/wifi_ctrl_webconfig.c @@ -760,6 +760,134 @@ bool is_force_apply_true(rdk_wifi_vap_info_t *rdk_vap_info) { return false; } + +#ifdef CONFIG_IEEE80211BE +wifi_vap_info_t *get_vap_info_from_webconfig(webconfig_subdoc_decoded_data_t *data, char *vap_name) +{ + unsigned int j, k; + + for (j = 0; j < getNumberRadios(); j++) { + for (k = 0; k < getNumberVAPsPerRadio(j); k++) { + if (strcmp(data->radios[j].vaps.vap_map.vap_array[k].vap_name, vap_name) == 0) { + return &data->radios[j].vaps.vap_map.vap_array[k]; + } + } + } + return NULL; +} + +wifi_vap_info_t *get_vap_info_from_radio(char *vap_name) +{ + unsigned int j; + int tgt_radio_idx, tgt_vap_index; + rdk_wifi_radio_t *radio; + wifi_vap_info_t *mgr_vap_info = NULL; + wifi_vap_info_map_t *mgr_vap_map = NULL; + wifi_mgr_t *mgr = get_wifimgr_obj(); + + if ((tgt_radio_idx = convert_vap_name_to_radio_array_index(&mgr->hal_cap.wifi_prop, vap_name)) == -1) { + wifi_util_error_print(WIFI_MGR, "%s:%d: Could not find radio index for vap name:%s\n", + __func__, __LINE__, vap_name); + return NULL; + } + + tgt_vap_index = convert_vap_name_to_index(&mgr->hal_cap.wifi_prop, vap_name); + if (tgt_vap_index == -1) { + wifi_util_error_print(WIFI_MGR, "%s:%d: Could not find vap index for vap name:%s\n", + __func__, __LINE__, vap_name); + return NULL; + } + + for (j = 0; j < getNumberRadios(); j++) { + radio = &mgr->radio_config[j]; + if (radio->vaps.radio_index == (unsigned int)tgt_radio_idx) { + mgr_vap_map = &radio->vaps.vap_map; + break; + } + } + + if (mgr_vap_map == NULL) { + wifi_util_error_print(WIFI_MGR, + "%s:%d: Could not find tgt_radio_idx:%d for vap name:%s\n", __func__, __LINE__, + tgt_radio_idx, vap_name); + return NULL; + } + + for (j = 0; j < mgr_vap_map->num_vaps; j++) { + if (mgr_vap_map->vap_array[j].vap_index == (unsigned int)tgt_vap_index) { + mgr_vap_info = &mgr_vap_map->vap_array[j]; + break; + } + } + + return mgr_vap_info; +} + +static void update_mld_mac(webconfig_subdoc_decoded_data_t *data, char **vap_names, unsigned int size) +{ + unsigned int i; + wifi_vap_info_t *mgr_vap_info, *vap_info; + wifi_mld_common_info_t *mld_conf; + mac_address_t zero_mac = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + mac_address_t mlo_mac = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + mac_addr_str_t mac_str = { 0 }; + unsigned char *mld_addr_map[MAX_NUM_RADIOS] = {0}; + unsigned char mld_id = 255; + + for (i = 0; i < size; i++) { + + vap_info = get_vap_info_from_webconfig(data, vap_names[i]); + if (vap_info == NULL) { + wifi_util_error_print(WIFI_MGR, "%s:%d: Could not find vap_info vap name:%s\n", + __func__, __LINE__, vap_names[i]); + return; + } + + if (isVapSTAMesh(vap_info->vap_index)) + continue; + + mgr_vap_info = get_vap_info_from_radio(vap_names[i]); + if (mgr_vap_info == NULL) { + wifi_util_error_print(WIFI_MGR, "%s:%d: Could not find mgr_vap_info vap name:%s\n", + __func__, __LINE__, vap_names[i]); + return; + } + + mld_conf = &vap_info->u.bss_info.mld_info.common_info; + + /* Initialize mld_mac with VAP's BSSID */ + memcpy(mld_conf->mld_addr, mgr_vap_info->u.bss_info.bssid, sizeof(mac_address_t)); + + if (mld_conf->mld_enable && mld_conf->mld_id < MLD_UNIT_COUNT && mld_conf->mld_link_id < MAX_NUM_MLD_LINKS) { + if (mld_id == 255) + mld_id = mld_conf->mld_id; + if (mld_id != mld_conf->mld_id) { + wifi_util_error_print(WIFI_MGR, "%s:%d: vap name:%s is not part of mld unit %d. VAP's mld_id %d\n", + __func__, __LINE__, vap_names[i], mld_id, mld_conf->mld_id); + continue; + } + mld_addr_map[i] = mld_conf->mld_addr; + if (mld_conf->mld_link_id == 0) { + memcpy(mlo_mac, mgr_vap_info->u.bss_info.bssid, sizeof(mac_address_t)); + } + } + } + + if (memcmp(mlo_mac, zero_mac, sizeof(mac_address_t)) == 0) { + return; /* VAPs group does not contain MLO enabled VAPs */ + } + + to_mac_str(mlo_mac, mac_str); + for (i = 0; i < size; i++) { + if (mld_addr_map[i] != NULL) { + memcpy(mld_addr_map[i], mlo_mac, sizeof(mac_address_t)); + wifi_util_info_print(WIFI_MGR, "%s:%d: Updating mld_addr %s for vap name:%s\n", + __func__, __LINE__, mac_str, vap_names[i]); + } + } +} +#endif // CONFIG_IEEE80211BE + int webconfig_hal_vap_apply_by_name(wifi_ctrl_t *ctrl, webconfig_subdoc_decoded_data_t *data, char **vap_names, unsigned int size) { unsigned int i, j, k; @@ -776,6 +904,9 @@ int webconfig_hal_vap_apply_by_name(wifi_ctrl_t *ctrl, webconfig_subdoc_decoded_ rdk_wifi_vap_info_t tgt_rdk_vap_info; int ret = 0; +#ifdef CONFIG_IEEE80211BE + update_mld_mac(data, vap_names, size); +#endif for (i = 0; i < size; i++) { if ((svc = get_svc_by_name(ctrl, vap_names[i])) == NULL) { diff --git a/source/db/wifi_db_apis.c b/source/db/wifi_db_apis.c index 3fdcad939..cc6e07e90 100644 --- a/source/db/wifi_db_apis.c +++ b/source/db/wifi_db_apis.c @@ -92,12 +92,6 @@ #define ONEWIFI_DB_VERSION_WPA3_T_DISABLE_FLAG 100042 #define ONEWIFI_DB_VERSION_UPDATE_MLD_FLAG 100043 -#ifdef CONFIG_NO_MLD_ONLY_PRIVATE -#define MLD_UNIT_COUNT 8 -#else -#define MLD_UNIT_COUNT 1 -#endif /* CONFIG_NO_MLD_ONLY_PRIVATE */ - ovsdb_table_t table_Wifi_Radio_Config; ovsdb_table_t table_Wifi_VAP_Config; ovsdb_table_t table_Wifi_Security_Config; @@ -7632,7 +7626,7 @@ void wifidb_init_default_value() wifi_util_info_print(WIFI_DB,"%s:%d Wifi db update completed\n",__func__, __LINE__); } - +#ifdef CONFIG_IEEE80211BE static int get_ap_mac_by_vap_index(wifi_vap_info_map_t *hal_vap_info_map, int vap_index, mac_address_t mac) { unsigned int j = 0; @@ -7726,6 +7720,7 @@ static int wifidb_vap_config_update_mld_mac() hal_vap_info_map = NULL; return RETURN_OK; } +#endif /* CONFIG_IEEE80211BE */ /************************************************************************************ ************************************************************************************ @@ -7925,7 +7920,9 @@ void init_wifidb_data() pthread_mutex_unlock(&g_wifidb->data_cache_lock); return; } + #ifdef CONFIG_IEEE80211BE wifidb_vap_config_update_mld_mac(); + #endif pthread_mutex_unlock(&g_wifidb->data_cache_lock); } diff --git a/source/utils/wifi_util.c b/source/utils/wifi_util.c index 609bc80df..f6863ff53 100644 --- a/source/utils/wifi_util.c +++ b/source/utils/wifi_util.c @@ -3913,6 +3913,9 @@ bool is_vap_param_config_changed(wifi_vap_info_t *vap_info_old, wifi_vap_info_t vap_info_new->u.bss_info.mld_info.common_info.mld_link_id) || IS_CHANGED(vap_info_old->u.bss_info.mld_info.common_info.mld_apply, vap_info_new->u.bss_info.mld_info.common_info.mld_apply) || + IS_BIN_CHANGED(&vap_info_old->u.bss_info.mld_info.common_info.mld_addr, + &vap_info_new->u.bss_info.mld_info.common_info.mld_addr, + sizeof(vap_info_old->u.bss_info.mld_info.common_info.mld_addr)) || IS_CHANGED(vap_info_old->u.bss_info.hostap_mgt_frame_ctrl, vap_info_new->u.bss_info.hostap_mgt_frame_ctrl) || IS_CHANGED(vap_info_old->u.bss_info.mbo_enabled, From f3af5eb8797d7bc66fc1778ae6d1f6a9b1bf6096 Mon Sep 17 00:00:00 2001 From: Stanislav Kuchar Date: Mon, 8 Dec 2025 18:19:08 +0100 Subject: [PATCH 2/3] RDKB-62658: Do not check mld address on non mld enabled VAPs (#762) The problem: mld address change was detected also on non mld enabled VAPs Test Procedure: - Mesh_backhaul connectivity is not loosing when we change the ssid - Perform runtime change of MLO configuration (change of main link) via TR-181 Data Model and check if MLO address is correctly generated for MLO VAPs - Check wifi connectivity with focus on MLO. Risks: Low Priority: P1 Signed-off-by: Stanislav Kuchar Co-authored-by: Narendra Varma Dandu --- source/utils/wifi_util.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/source/utils/wifi_util.c b/source/utils/wifi_util.c index f6863ff53..b49b3318d 100644 --- a/source/utils/wifi_util.c +++ b/source/utils/wifi_util.c @@ -3808,6 +3808,34 @@ static bool is_vap_preassoc_cac_config_changed(char *vap_name, } } +#ifdef CONFIG_IEEE80211BE +static bool is_mld_addr_changed(wifi_vap_info_t *vap_info_old, wifi_vap_info_t *vap_info_new) +{ + if ((vap_info_old == NULL) || (vap_info_new == NULL)) { + wifi_util_error_print(WIFI_WEBCONFIG, + "%s:%d: input args are NULL vap_info_old : %p vap_info_new : %p\n", __func__, __LINE__, + vap_info_old, vap_info_new); + return false; + } + if (vap_info_old->u.bss_info.mld_info.common_info.mld_enable || + vap_info_new->u.bss_info.mld_info.common_info.mld_enable) { + if (IS_BIN_CHANGED(&vap_info_old->u.bss_info.mld_info.common_info.mld_addr, + &vap_info_new->u.bss_info.mld_info.common_info.mld_addr, + sizeof(vap_info_old->u.bss_info.mld_info.common_info.mld_addr))) { + mac_addr_str_t old_mld_mac_str = { 0 }; + mac_addr_str_t new_mld_mac_str = { 0 }; + + to_mac_str(vap_info_old->u.bss_info.mld_info.common_info.mld_addr, old_mld_mac_str); + to_mac_str(vap_info_new->u.bss_info.mld_info.common_info.mld_addr, new_mld_mac_str); + wifi_util_info_print(WIFI_WEBCONFIG, "%s:%d: MLD address changed old: %s ,new: %s\n", + __func__, __LINE__, old_mld_mac_str, new_mld_mac_str); + return true; + } + } + return false; +} +#endif /* CONFIG_IEEE80211BE */ + bool is_vap_param_config_changed(wifi_vap_info_t *vap_info_old, wifi_vap_info_t *vap_info_new, rdk_wifi_vap_info_t *rdk_old, rdk_wifi_vap_info_t *rdk_new, bool isSta) { @@ -3913,9 +3941,9 @@ bool is_vap_param_config_changed(wifi_vap_info_t *vap_info_old, wifi_vap_info_t vap_info_new->u.bss_info.mld_info.common_info.mld_link_id) || IS_CHANGED(vap_info_old->u.bss_info.mld_info.common_info.mld_apply, vap_info_new->u.bss_info.mld_info.common_info.mld_apply) || - IS_BIN_CHANGED(&vap_info_old->u.bss_info.mld_info.common_info.mld_addr, - &vap_info_new->u.bss_info.mld_info.common_info.mld_addr, - sizeof(vap_info_old->u.bss_info.mld_info.common_info.mld_addr)) || +#ifdef CONFIG_IEEE80211BE + is_mld_addr_changed(vap_info_old, vap_info_new) || +#endif /* CONFIG_IEEE80211BE */ IS_CHANGED(vap_info_old->u.bss_info.hostap_mgt_frame_ctrl, vap_info_new->u.bss_info.hostap_mgt_frame_ctrl) || IS_CHANGED(vap_info_old->u.bss_info.mbo_enabled, From 56cba2010ef47d89c625df60921061c7377022ce Mon Sep 17 00:00:00 2001 From: Stanislav Kuchar Date: Wed, 14 Jan 2026 06:49:24 +0100 Subject: [PATCH 3/3] BCOMB-3166: Disable mld if the main link is removed or if mld has only one link. (#794) Reason for change: MLD needs to be disabled when main link (link_ID = 0) is being disabled MLD needs to be disabled when it contains only one link (MLD needs at least two links) Test Procedure: Disable the main link with TR-181 DataModel and check MLO configuration in the driver and check MLO connection details of the connected station. Disable two links with TR-181 DataModel and check MLO configuration in the driver and check MLO connection details of the connected station. Risks: Low Priority: P1 Signed-off-by: Stanislav Kuchar Co-authored-by: Narendra Varma Dandu --- include/wifi_base.h | 2 ++ source/core/wifi_ctrl_webconfig.c | 51 +++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/include/wifi_base.h b/include/wifi_base.h index 8c5668074..f8431bc47 100644 --- a/include/wifi_base.h +++ b/include/wifi_base.h @@ -85,6 +85,8 @@ extern "C" { #define MAX_NUM_MLD_LINKS 15 #endif /*MAX_NUM_MLD_LINKS*/ +#define UNDEFINED_MLD_ID 255 + #ifdef CONFIG_NO_MLD_ONLY_PRIVATE #define MLD_UNIT_COUNT 8 #else diff --git a/source/core/wifi_ctrl_webconfig.c b/source/core/wifi_ctrl_webconfig.c index 53261cca9..2ce8a375d 100644 --- a/source/core/wifi_ctrl_webconfig.c +++ b/source/core/wifi_ctrl_webconfig.c @@ -823,7 +823,7 @@ wifi_vap_info_t *get_vap_info_from_radio(char *vap_name) return mgr_vap_info; } -static void update_mld_mac(webconfig_subdoc_decoded_data_t *data, char **vap_names, unsigned int size) +static void update_mld_group(webconfig_subdoc_decoded_data_t *data, char **vap_names, unsigned int size) { unsigned int i; wifi_vap_info_t *mgr_vap_info, *vap_info; @@ -831,9 +831,17 @@ static void update_mld_mac(webconfig_subdoc_decoded_data_t *data, char **vap_nam mac_address_t zero_mac = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; mac_address_t mlo_mac = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; mac_addr_str_t mac_str = { 0 }; - unsigned char *mld_addr_map[MAX_NUM_RADIOS] = {0}; - unsigned char mld_id = 255; - + unsigned char *mld_addr_map[MAX_NUM_RADIOS] = { 0 }; + unsigned char mld_id = UNDEFINED_MLD_ID; + wifi_mld_common_info_t *mld_map[MAX_NUM_RADIOS] = { 0 }; + unsigned int mld_vap_count = 0; + bool disable_mld = false; + + if (size > MAX_NUM_RADIOS) { + wifi_util_error_print(WIFI_MGR, "%s:%d: size %d exceeds MAX_NUM_RADIOS %d\n", + __func__, __LINE__, size, MAX_NUM_RADIOS); + return; + } for (i = 0; i < size; i++) { vap_info = get_vap_info_from_webconfig(data, vap_names[i]); @@ -858,20 +866,43 @@ static void update_mld_mac(webconfig_subdoc_decoded_data_t *data, char **vap_nam /* Initialize mld_mac with VAP's BSSID */ memcpy(mld_conf->mld_addr, mgr_vap_info->u.bss_info.bssid, sizeof(mac_address_t)); - if (mld_conf->mld_enable && mld_conf->mld_id < MLD_UNIT_COUNT && mld_conf->mld_link_id < MAX_NUM_MLD_LINKS) { - if (mld_id == 255) + if (mld_conf->mld_id < MLD_UNIT_COUNT && mld_conf->mld_link_id < MAX_NUM_MLD_LINKS) { + if (mld_id == UNDEFINED_MLD_ID) mld_id = mld_conf->mld_id; if (mld_id != mld_conf->mld_id) { wifi_util_error_print(WIFI_MGR, "%s:%d: vap name:%s is not part of mld unit %d. VAP's mld_id %d\n", __func__, __LINE__, vap_names[i], mld_id, mld_conf->mld_id); continue; } - mld_addr_map[i] = mld_conf->mld_addr; - if (mld_conf->mld_link_id == 0) { - memcpy(mlo_mac, mgr_vap_info->u.bss_info.bssid, sizeof(mac_address_t)); + if (mld_conf->mld_enable) { + mld_vap_count++; + mld_addr_map[i] = mld_conf->mld_addr; + mld_map[i] = mld_conf; + if (mld_conf->mld_link_id == 0) { + memcpy(mlo_mac, mgr_vap_info->u.bss_info.bssid, sizeof(mac_address_t)); + } + } else { + if (mld_conf->mld_link_id == 0) { + wifi_util_info_print(WIFI_MGR, "%s:%d: Main link is disabled -> Disable whole MLO group\n",__func__, __LINE__); + disable_mld = true; + } } } } + if (mld_vap_count > 0) { + if (disable_mld || mld_vap_count < 2) { + /* Disable MLD when main link is disabled or less than 2 VAPs are mld enabled */ + for (i = 0; i < size; i++) { + if (mld_map[i] != NULL) { + mld_map[i]->mld_enable = false; + wifi_util_info_print(WIFI_MGR, + "%s:%d: Disabling mld for vap name:%s - disable_mld %d mld_vap_count %d\n", + __func__, __LINE__, vap_names[i], disable_mld, mld_vap_count); + } + } + return; + } + } if (memcmp(mlo_mac, zero_mac, sizeof(mac_address_t)) == 0) { return; /* VAPs group does not contain MLO enabled VAPs */ @@ -905,7 +936,7 @@ int webconfig_hal_vap_apply_by_name(wifi_ctrl_t *ctrl, webconfig_subdoc_decoded_ int ret = 0; #ifdef CONFIG_IEEE80211BE - update_mld_mac(data, vap_names, size); + update_mld_group(data, vap_names, size); #endif for (i = 0; i < size; i++) {