RDKB-64679 Add support for MLO associated clients subdoc#1136
Conversation
df38ec1 to
98e4c9e
Compare
There was a problem hiding this comment.
Pull request overview
Adds support for representing MLO (multi-link) associated clients in the associated clients subdoc. Per-radio encoding now diverts MLD entries into an aggregated per-MLO-VAP structure that emits a single client object containing a Links[] array, with matching decoder logic that fans the links back out into per-radio associated-device maps. The per-client field encoding/decoding has been factored into shared helpers (encode_assoc_dev_stats, decode_assoc_dev_stats, etc.), and several MLO-related utilities and types are introduced.
Changes:
- Refactor per-VAP associated-client encode/decode into reusable helpers and a new
encode_vap_assoc_clientsthat can route MLD entries to a collector. - Add MLO-aware encode (
encode_mlo_assoc_clients) and decode (decode_mlo_associated_clients_objectand friends) paths, plus new MLO VAP-name helpers and types (wifi_mld_unit_t,mlo_client_t). - Add a sample subdoc schema for the MLO associated-clients layout.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| source/webconfig/wifi_webconfig_associated_client.c | Routes per-VAP encoding through MLO collection and emits an MLO section in the subdoc. |
| source/webconfig/wifi_encoder.c | Splits client encoding into helpers and adds MLO grouping/emit logic with per-link encoding. |
| source/webconfig/wifi_decoder.c | Splits client decoding into helpers and adds MLO client/link decoding into per-radio maps. |
| source/utils/wifi_util.c | Adds convert_freq_band_to_band_str_g and MLO VAP-name conversion helpers. |
| source/utils/wifi_util.h | Declares the new MLO helpers and band string conversion. |
| include/wifi_base.h | Introduces mlo_client_t and wifi_mld_unit_t types under CONFIG_IEEE80211BE. |
| config/subdoc_schemas_1_4/wifi7_mlo_associated_clients_subdoc_schema | New schema sample showing the MLO subdoc layout. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| #if defined(CONFIG_IEEE80211BE) | ||
| encode_per_vap_assoc_clients(params, assoc_array, assoclist_type_add, mld_units, &mld_unit_count); | ||
| encode_mlo_assoc_clients(params, mld_units, mld_unit_count, assoc_array, assoclist_type_add); | ||
| #else | ||
| encode_per_vap_assoc_clients(params, assoc_array, assoclist_type_add); | ||
| #endif | ||
|
|
||
| assoc_array = cJSON_CreateArray(); | ||
| cJSON_AddItemToObject(json, "RemoveWiFiAssociatedClients", assoc_array); | ||
| for (i = 0; i < params->num_radios; i++) { | ||
| //vap_info_map data | ||
| vap_map = ¶ms->radios[i].vaps.vap_map; | ||
| #if defined(CONFIG_IEEE80211BE) | ||
| encode_per_vap_assoc_clients(params, assoc_array, assoclist_type_remove, mld_units, &mld_unit_count); | ||
| encode_mlo_assoc_clients(params, mld_units, mld_unit_count, assoc_array, assoclist_type_remove); | ||
| #else | ||
| encode_per_vap_assoc_clients(params, assoc_array, assoclist_type_remove); | ||
| #endif |
| if (mld_units != NULL && | ||
| get_mlo_vap_name_from_per_radio(rdk_vap_info->vap_name, derived_mlo, sizeof(derived_mlo))) { | ||
| unit = find_or_create_mld_unit(mld_units, mld_unit_count, derived_mlo); | ||
| if (unit == NULL) { | ||
| encode_associated_client_object(rdk_vap_info, assoc_array, assoclist_type); | ||
| continue; | ||
| } | ||
| encode_vap_assoc_clients(rdk_vap_info, assoc_array, assoclist_type, collect_mlo_entry, unit); | ||
| continue; | ||
| } |
There was a problem hiding this comment.
Updated. Added error log.
| for (li = 0; li < cl->num_links; li++) { | ||
| if (should_print_assoc_client(assoclist_type, cl->links[li].client_state)) { | ||
| emit = true; | ||
| break; | ||
| } | ||
| } | ||
| if (!emit) { | ||
| cl = hash_map_get_next(unit->mlo_sta_map, cl); | ||
| continue; | ||
| } | ||
|
|
||
| obj_client = cJSON_CreateObject(); | ||
| cJSON_AddItemToArray(obj_array, obj_client); | ||
|
|
||
| to_mac_str(cl->links[0].dev_stats.cli_MACAddress, mac_str); | ||
| str_tolower(mac_str); | ||
| cJSON_AddStringToObject(obj_client, "MACAddress", mac_str); | ||
| cJSON_AddNumberToObject(obj_client, "NumLinks", cl->num_links); | ||
|
|
||
| links_arr = cJSON_CreateArray(); | ||
| cJSON_AddItemToObject(obj_client, "Links", links_arr); | ||
|
|
||
| for (li = 0; li < cl->num_links; li++) { | ||
| assoc_dev_data_t *link = &cl->links[li]; | ||
| cJSON *link_obj = cJSON_CreateObject(); | ||
| int radio_idx = 0; | ||
| int freq_band = 0; | ||
| const char *band = ""; | ||
| const char *band_str = NULL; | ||
|
|
||
| cJSON_AddItemToArray(links_arr, link_obj); | ||
|
|
||
| radio_idx = get_radio_index_for_vap_index(¶ms->hal_cap.wifi_prop, link->ap_index); | ||
| if (radio_idx >= 0 && | ||
| convert_radio_index_to_freq_band(¶ms->hal_cap.wifi_prop, | ||
| (unsigned int)radio_idx, &freq_band) == RETURN_OK) { | ||
| band_str = convert_freq_band_to_band_str_g(freq_band); | ||
| if (band_str != NULL) { | ||
| band = band_str; | ||
| } | ||
| } | ||
| cJSON_AddStringToObject(link_obj, "Band", band); | ||
|
|
||
| memset(mac_str, 0, sizeof(mac_str)); | ||
| to_mac_str(link->link_address, mac_str); | ||
| str_tolower(mac_str); | ||
| cJSON_AddStringToObject(link_obj, "LinkAddress", mac_str); | ||
|
|
||
| cJSON_AddBoolToObject(link_obj, "AssociationLink", link->association_link); | ||
| cJSON_AddNumberToObject(link_obj, "MLCapabilities", link->dev_stats.cli_MLModeCapa); | ||
| cJSON_AddNumberToObject(link_obj, "TIDLinkMapNegotiation", | ||
| link->dev_stats.cli_TIDLinkMapNegotiation); | ||
| encode_assoc_dev_stats(link_obj, link); | ||
| if (should_include_frame_data(assoclist_type, link->client_state)) { | ||
| encode_frame_data(link_obj, &link->sta_data.msg_data); | ||
| } | ||
| } |
| to_mac_str(link->dev_stats.cli_MACAddress, mac_key); | ||
| str_tolower(mac_key); | ||
|
|
||
| store_assoc_dev_data(per_radio_map, mac_key, link, link->ap_index, link->ap_index); |
| for (k = 0; k < num_links; k++) { | ||
| link_obj = cJSON_GetArrayItem(links_array, k); | ||
| if (link_obj == NULL) { | ||
| ret = webconfig_error_decode; | ||
| goto done; | ||
| } | ||
| memset(link, 0, sizeof(*link)); | ||
| if (decode_mlo_assoc_client_link(link_obj, vap_name, link, | ||
| assoclist_type, params, mac) != webconfig_error_none) { | ||
| ret = webconfig_error_decode; | ||
| goto done; | ||
| } | ||
| } |
There was a problem hiding this comment.
If the decode failed, it is an error, and we should not use the data.
Reason for change: Modify associated clients schema to indicate associations of MLO clients. Test Procedure: 1. Connect MLO capable client to the Wi-Fi network. 2. Verify that the associated clients subdoc in the Wi-Fi schema reflects the MLO associations correctly. 3. Verify no regressions with WFA and AssociatedClients DMLs and Ovsdb. Risks: Medium Priority: P1
98e4c9e to
5f3ecb6
Compare
Reason for change: Modify associated clients schema to indicate associations of MLO clients.
Test Procedure: 1. Connect MLO and non-clients.
2. Verify that the associated clients' subdoc in the Wi-Fi schema reflects the MLO associations correctly.
3. Verify no regressions with WFA and AssociatedClients DMLs and Ovsdb.
Risks: Medium
Priority: P1