Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions include/webconfig_external_proto_easymesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ typedef void (*ext_proto_update_ap_mld_info_t)(void *data_model, em_ap_mld_info_
typedef void (*ext_proto_update_bsta_mld_info_t)(void *data_model, em_bsta_mld_info_t *bsta_mld_info);
typedef void (*ext_proto_update_assoc_sta_mld_info_t)(void *data_model, em_assoc_sta_mld_info_t *assoc_sta_mld_info);
typedef em_ap_mld_info_t * (*ext_proto_get_ap_mld_frm_bssid_t)(void *data_model, mac_address_t bss_id);
typedef em_radio_cap_info_t * (*ext_proto_get_radio_cap_t)(void *data_model, int index);

typedef struct {
void *data_model; /* agent data model dm_easy_mesh_t */
Expand Down Expand Up @@ -75,7 +76,8 @@ typedef struct {
ext_proto_update_ap_mld_info_t update_ap_mld_info;
ext_proto_update_bsta_mld_info_t update_bsta_mld_info;
ext_proto_update_assoc_sta_mld_info_t update_assoc_sta_mld_info;
ext_proto_get_ap_mld_frm_bssid_t get_ap_mld_frm_bssid;
ext_proto_get_ap_mld_frm_bssid_t get_ap_mld_frm_bssid;
ext_proto_get_radio_cap_t get_radio_cap;
} webconfig_external_easymesh_t;

void webconfig_proto_easymesh_init(webconfig_external_easymesh_t *proto, void *data_model, void *m2ctrl_vapconfig, void *policy_config,
Expand All @@ -89,7 +91,7 @@ void webconfig_proto_easymesh_init(webconfig_external_easymesh_t *proto, void *d
ext_proto_get_sta_info_t get_sta, ext_proto_put_sta_info_t put_sta, ext_proto_em_get_bss_info_with_mac_t get_bss_info_with_mac,
ext_proto_put_scan_results_t put_scan_results, ext_proto_update_ap_mld_info_t update_ap_mld_info,
ext_proto_update_bsta_mld_info_t update_bsta_mld_info, ext_proto_update_assoc_sta_mld_info_t update_assoc_sta_mld_info,
ext_proto_get_ap_mld_frm_bssid_t get_ap_mld_frm_bssid);
ext_proto_get_ap_mld_frm_bssid_t get_ap_mld_frm_bssid, ext_proto_get_radio_cap_t get_radio_cap);

#ifdef __cplusplus
}
Expand Down
13 changes: 13 additions & 0 deletions include/wifi_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,19 @@ extern "C" {
#define CFG_ID_LEN 64
typedef char stats_cfg_id_t[CFG_ID_LEN];

/* HE PHY/MAC capability bit positions (IEEE 802.11ax-2021) */
#define HE_PHY_CHAN_WIDTH_160_BIT 3
#define HE_PHY_CHAN_WIDTH_80P80_BIT 4
#define HE_PHY_SU_BEAMFORMER_BIT 7 /* byte 3 */
#define HE_PHY_SU_BEAMFORMEE_BIT 0 /* byte 4 */
#define HE_PHY_MU_BEAMFORMER_BIT 1 /* byte 4 */
#define HE_MAC_TWT_REQ_BIT 0 /* byte 0 */
#define HE_MAC_TWT_RESP_BIT 1 /* byte 0 */
#define HE_MAC_DL_MU_MIMO_BIT 0 /* byte 4 */
#define HE_MAC_UL_MU_MIMO_BIT 1 /* byte 4 */
#define HE_MAC_UL_OFDMA_BIT 2 /* byte 2 */
#define HE_MAC_DL_OFDMA_BIT 3 /* byte 2 */

typedef enum {
wifi_app_inst_blaster = wifi_app_inst_base,
wifi_app_inst_harvester = wifi_app_inst_base << 1,
Expand Down
138 changes: 137 additions & 1 deletion source/webconfig/wifi_decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -4850,13 +4850,26 @@ webconfig_error_t decode_wifiradiocap(wifi_platform_property_t *wifi_prop, cJSON
for (i = 0; i < size; i++) {
object = cJSON_GetArrayItem(obj_wificap, i);
radio_cap = &wifi_prop->radiocap[i];
value_object = cJSON_GetObjectItem(object, "PhyIndex");
if ((value_object == NULL) || (cJSON_IsNumber(value_object) == false)) {
/* Fallback to legacy RadioIndex for older producers */
cJSON *legacy_radio_index = cJSON_GetObjectItem(object, "RadioIndex");
if ((legacy_radio_index == NULL) || (cJSON_IsNumber(legacy_radio_index) == false)) {
wifi_util_error_print(WIFI_WEBCONFIG, "%s:%d: Validation Failed\n", __func__, __LINE__);
return webconfig_error_decode;
}
radio_cap->index = legacy_radio_index->valuedouble;
} else {
radio_cap->index = value_object->valuedouble;
}

value_object = cJSON_GetObjectItem(object, "RadioIndex");
if ((value_object == NULL) || (cJSON_IsNumber(value_object) == false)) {
wifi_util_error_print(WIFI_WEBCONFIG, "%s:%d: Validation Failed\n", __func__, __LINE__);
return webconfig_error_decode;
}

radio_cap->index = value_object->valuedouble;
radio_cap->rdk_radio_index = value_object->valuedouble;

/*allowed_channels*/
allowed_channels = cJSON_GetObjectItem(object, "PossibleChannels");
Expand Down Expand Up @@ -4896,6 +4909,129 @@ webconfig_error_t decode_wifiradiocap(wifi_platform_property_t *wifi_prop, cJSON
return webconfig_error_decode;
}
wifi_prop->radio_presence[i] = value_object->valuedouble;

#ifdef CONFIG_IEEE80211AX
/* WiFi6 (HE) capabilities */
decode_param_bool(object, "WiFi6Supported", value_object);
if (value_object != NULL) {
radio_cap->wifi6_supported = (value_object->type & cJSON_True) ? true : false;
}

value_object = cJSON_GetObjectItem(object, "HEPHYCap");
if (value_object != NULL && cJSON_IsArray(value_object)) {
int array_size = cJSON_GetArraySize(value_object);
if (array_size > sizeof(radio_cap->he_phy_cap)) {
array_size = sizeof(radio_cap->he_phy_cap);
}
for (int j = 0; j < array_size; j++) {
cJSON *array_item = cJSON_GetArrayItem(value_object, j);
if (cJSON_IsNumber(array_item)) {
radio_cap->he_phy_cap[j] = (uint8_t)array_item->valuedouble;
}
}
}

value_object = cJSON_GetObjectItem(object, "HEMACCap");
if (value_object != NULL && cJSON_IsArray(value_object)) {
int array_size = cJSON_GetArraySize(value_object);
if (array_size > sizeof(radio_cap->he_mac_cap)) {
array_size = sizeof(radio_cap->he_mac_cap);
}
for (int j = 0; j < array_size; j++) {
cJSON *array_item = cJSON_GetArrayItem(value_object, j);
if (cJSON_IsNumber(array_item)) {
radio_cap->he_mac_cap[j] = (uint8_t)array_item->valuedouble;
}
}
}

value_object = cJSON_GetObjectItem(object, "HEMCSNSSSet");
if (value_object != NULL && cJSON_IsArray(value_object)) {
int array_size = cJSON_GetArraySize(value_object);
if (array_size > sizeof(radio_cap->he_mcs_nss_set)) {
array_size = sizeof(radio_cap->he_mcs_nss_set);
}
for (int j = 0; j < array_size; j++) {
cJSON *array_item = cJSON_GetArrayItem(value_object, j);
if (cJSON_IsNumber(array_item)) {
radio_cap->he_mcs_nss_set[j] = (uint8_t)array_item->valuedouble;
}
}
}

value_object = cJSON_GetObjectItem(object, "HEPPET");
if (value_object != NULL && cJSON_IsArray(value_object)) {
int array_size = cJSON_GetArraySize(value_object);
if (array_size > sizeof(radio_cap->he_ppet)) {
array_size = sizeof(radio_cap->he_ppet);
}
for (int j = 0; j < array_size; j++) {
cJSON *array_item = cJSON_GetArrayItem(value_object, j);
if (cJSON_IsNumber(array_item)) {
radio_cap->he_ppet[j] = (uint8_t)array_item->valuedouble;
}
}
}

//decode_param_integer(cap_obj, "HE6GHzCapa", param);
//if (param != NULL && cJSON_IsNumber(param)) {
// radio_cap->he_cap.6ghz_capa = (USHORT)param->valuedouble;
//}
#endif /* CONFIG_IEEE80211AX */

#ifdef CONFIG_IEEE80211BE
decode_param_bool(object, "WiFi7Supported", value_object);
if (value_object != NULL) {
radio_cap->wifi7_supported = (value_object->type & cJSON_True) ? true : false;
}

value_object = cJSON_GetObjectItem(object, "EHTMACCap");
if (value_object != NULL && cJSON_IsNumber(value_object)) {
radio_cap->eht_mac_cap = (UCHAR)value_object->valuedouble;
}

value_object = cJSON_GetObjectItem(object, "EHTPHYCap");
if (value_object != NULL && cJSON_IsArray(value_object)) {
int array_size = cJSON_GetArraySize(value_object);
if ((size_t)array_size > sizeof(radio_cap->eht_phy_cap)) {
array_size = sizeof(radio_cap->eht_phy_cap);
}
for (int j = 0; j < array_size; j++) {
cJSON *array_item = cJSON_GetArrayItem(value_object, j);
if (cJSON_IsNumber(array_item)) {
radio_cap->eht_phy_cap[j] = (UCHAR)array_item->valuedouble;
}
}
}

value_object = cJSON_GetObjectItem(object, "EHTMCS");
if (value_object != NULL && cJSON_IsArray(value_object)) {
int array_size = cJSON_GetArraySize(value_object);
if ((size_t)array_size > sizeof(radio_cap->eht_mcs)) {
array_size = sizeof(radio_cap->eht_mcs);
}
for (int j = 0; j < array_size; j++) {
cJSON *array_item = cJSON_GetArrayItem(value_object, j);
if (cJSON_IsNumber(array_item)) {
radio_cap->eht_mcs[j] = (UCHAR)array_item->valuedouble;
}
}
}

value_object = cJSON_GetObjectItem(object, "EHTPPET");
if (value_object != NULL && cJSON_IsArray(value_object)) {
int array_size = cJSON_GetArraySize(value_object);
if ((size_t)array_size > sizeof(radio_cap->eht_ppet)) {
array_size = sizeof(radio_cap->eht_ppet);
}
for (int j = 0; j < array_size; j++) {
cJSON *array_item = cJSON_GetArrayItem(value_object, j);
if (cJSON_IsNumber(array_item)) {
radio_cap->eht_ppet[j] = (UCHAR)array_item->valuedouble;
}
}
}
#endif /* CONFIG_IEEE80211BE */
}
return webconfig_error_none;
}
Expand Down
133 changes: 132 additions & 1 deletion source/webconfig/wifi_easymesh_translator.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ webconfig_error_t translate_device_object_to_easymesh_for_dml(webconfig_subdoc

return webconfig_error_none;
}

// This routine converts Radio webconfig subdoc values to em_radio_list_t,em_radio_info_t easymesh structures
webconfig_error_t translate_radio_object_to_easymesh_for_radio(webconfig_subdoc_data_t *data)
{
Expand Down Expand Up @@ -388,6 +389,121 @@ webconfig_error_t translate_radio_object_to_easymesh_for_radio(webconfig_subdoc_
return webconfig_error_none;
}

/* Helper function to translate radio capabilities from OneWifi to EasyMesh */
static webconfig_error_t translate_radio_capability_to_easymesh(wifi_platform_property_t *wifi_prop,
int radio_index,
em_radio_cap_info_t *cap_info)
{
wifi_radio_capabilities_t *radio_cap;
em_radio_wifi6_cap_data_t *wifi6_cap;
em_wifi7_agent_cap_t *wifi7_cap;
em_wifi7_mlo_cap_support_tlv_t *wifi7_radio;
unsigned int i;
const unsigned char *phy;
const unsigned char *mac;

if (cap_info == NULL) {
wifi_util_error_print(WIFI_WEBCONFIG, "%s:%d: NULL pointer or get_radio_cap not set\n", __func__, __LINE__);
return webconfig_error_translate_to_easymesh;
}
Comment on lines +405 to +408

radio_cap = &wifi_prop->radiocap[radio_index];
wifi6_cap = &cap_info->wifi6_cap;
wifi7_cap = &cap_info->wifi7_cap;

memset(wifi6_cap, 0, sizeof(*wifi6_cap));

if (radio_cap->wifi6_supported) {
mac_addr_str_t mac_str;
uint8_mac_to_string_mac(cap_info->ruid.mac, mac_str);
wifi_util_error_print(WIFI_WEBCONFIG, "%s:%d: radio_cap index: %d and mac:%s and radio_index:%d\n", __func__,
__LINE__, radio_index, mac_str, radio_index);

phy = radio_cap->he_phy_cap;
mac = radio_cap->he_mac_cap;

//AP role
wifi6_cap->num_role = 1;
for (int role = 0; role < wifi6_cap->num_role; role++) {
wifi6_cap->roles[role].role_head.agent_role = 0; /* AP */

/* HE PHY: Channel width (byte 0) */
wifi6_cap->roles[role].role_head.he_160 = (phy[0] & (1u << HE_PHY_CHAN_WIDTH_160_BIT)) ? 1 : 0;
wifi6_cap->roles[role].role_head.he_8080 = (phy[0] & (1u << HE_PHY_CHAN_WIDTH_80P80_BIT)) ? 1 : 0;

/* HE PHY: Beamforming (bytes 3, 4, 5, 6) */
wifi6_cap->roles[role].role_tail.su_beam_former = (phy[3] & (1u << HE_PHY_SU_BEAMFORMER_BIT)) ? 1 : 0;
wifi6_cap->roles[role].role_tail.su_beam_formee = (phy[4] & (1u << HE_PHY_SU_BEAMFORMEE_BIT)) ? 1 : 0;
wifi6_cap->roles[role].role_tail.mu_beam_former = (phy[4] & (1u << HE_PHY_MU_BEAMFORMER_BIT)) ? 1 : 0;
wifi6_cap->roles[role].role_tail.beam_formee_sts_l80 = (phy[5] & 0x38u) ? 1 : 0; /* Nr bits 3-5 */
wifi6_cap->roles[role].role_tail.beam_formee_sts_g80 = (phy[6] & 0x38u) ? 1 : 0; /* Nr bits 3-5 for >80MHz */

/* HE PHY byte 8: Number of RX/TX HE-MIMO-LTF (4 bits each) */
wifi6_cap->roles[role].role_tail.max_ul_mumimo_rx = phy[8] & 0x0Fu;
wifi6_cap->roles[role].role_tail.max_dl_mumimo_tx = (phy[8] >> 4) & 0x0Fu;

/* HE MAC: OFDMA (byte 2 in 4-byte mac_cap); UL MU-MIMO inferred from PHY */
wifi6_cap->roles[role].role_tail.dl_ofdma = (mac[2] & (1u << HE_MAC_DL_OFDMA_BIT)) ? 1 : 0;
wifi6_cap->roles[role].role_tail.ul_ofdma = (mac[2] & (1u << HE_MAC_UL_OFDMA_BIT)) ? 1 : 0;
wifi6_cap->roles[role].role_tail.ul_mumimo = (wifi6_cap->roles[role].role_tail.max_ul_mumimo_rx != 0) ? 1 : 0;

/* HE MAC byte 5 (not in rdk 4-byte mac_cap): max OFDMA RU; use 0 or skip */
wifi6_cap->roles[role].role_tail.max_dl_ofdma_tx = 0;
wifi6_cap->roles[role].role_tail.max_ul_ofdma_rx = 0;

/* HE MAC: TWT (byte 0) */
wifi6_cap->roles[role].role_tail.twt_req = (mac[0] & (1u << HE_MAC_TWT_REQ_BIT)) ? 1 : 0;
wifi6_cap->roles[role].role_tail.twt_resp = (mac[0] & (1u << HE_MAC_TWT_RESP_BIT)) ? 1 : 0;

wifi6_cap->roles[role].role_tail.anticipated_channel_usage = 0;
wifi6_cap->roles[role].role_tail.spatial_reuse = 0;
wifi6_cap->roles[role].role_tail.mu_edca = 0;
wifi6_cap->roles[role].role_tail.multi_bssid = 0;
wifi6_cap->roles[role].role_tail.mu_rts = 0;
wifi6_cap->roles[role].role_tail.rts = 0;

/* MCS NSS: rdk has mcs_nss_set[6] -> 3 x uint16 (LE) */
wifi6_cap->roles[role].role_head.mcs_nss_num = 3;
for (i = 0; i < 3 && i < MAX_MCS_NSS; i++) {
wifi6_cap->roles[role].mcs_nss[i] = (unsigned short)radio_cap->he_mcs_nss_set[i * 2]
| ((unsigned short)radio_cap->he_mcs_nss_set[i * 2 + 1] << 8);
}
}
}

memset(wifi7_cap, 0, sizeof(*wifi7_cap));
if (radio_cap->wifi7_supported) {
wifi7_radio = &wifi7_cap->mlo_cap_support;
memset(wifi7_radio, 0, sizeof(*wifi7_radio));
memcpy(wifi7_radio->ruid, cap_info->ruid.mac, sizeof(mac_address_t));

unsigned short eht_mac = (unsigned short)radio_cap->eht_mac_cap;
(void)eht_mac;

/* Extract WiFi 7 Multi-Link modes from mldOperationalCap */
wifi_multi_link_modes_t mld_modes = radio_cap->mldOperationalCap;

/* AP mode support */
wifi7_radio->ap_str_support = (mld_modes & STR) ? 1 : 0;
wifi7_radio->ap_nstr_support = (mld_modes & NSTR) ? 1 : 0;
wifi7_radio->ap_emlsr_support = (mld_modes & eMLSR) ? 1 : 0;
wifi7_radio->ap_emlmr_support = (mld_modes & eMLMR) ? 1 : 0;

/* BSTA (Backhaul STA) mode support */
wifi7_radio->bsta_str_support = (mld_modes & STR) ? 1 : 0;
wifi7_radio->bsta_nstr_support = (mld_modes & NSTR) ? 1 : 0;
wifi7_radio->bsta_emlsr_support = (mld_modes & eMLSR) ? 1 : 0;
wifi7_radio->bsta_emlmr_support = (mld_modes & eMLMR) ? 1 : 0;

wifi_util_error_print(WIFI_WEBCONFIG, "%s:%d: ap_str_support: %d, ap_nstr_support: %d, ap_emlsr_support: %d, \
ap_emlmr_support: %d, bsta_str_support: %d, bsta_nstr_support: %d, bsta_emlsr_support: %d, bsta_emlmr_support: %d\n", __func__, \
__LINE__, wifi7_radio->ap_str_support, wifi7_radio->ap_nstr_support, wifi7_radio->ap_emlsr_support, wifi7_radio->ap_emlmr_support, \
wifi7_radio->bsta_str_support, wifi7_radio->bsta_nstr_support, wifi7_radio->bsta_emlsr_support, wifi7_radio->bsta_emlmr_support);
}

return webconfig_error_none;
}

// This routine converts DML webconfig subdoc values to em_radio_list_t,em_radio_info_t easymesh structures
webconfig_error_t translate_radio_object_to_easymesh_for_dml(webconfig_subdoc_data_t *data)
{
Expand All @@ -401,6 +517,7 @@ webconfig_error_t translate_radio_object_to_easymesh_for_dml(webconfig_subdoc_da
webconfig_external_easymesh_t *proto;
wifi_radio_operationParam_t *oper_param;
webconfig_subdoc_decoded_data_t *decoded_params;
mac_addr_str_t mac_str;

decoded_params = &data->u.decoded;
if (decoded_params == NULL) {
Expand Down Expand Up @@ -506,6 +623,19 @@ webconfig_error_t translate_radio_object_to_easymesh_for_dml(webconfig_subdoc_da
em_radio_info->associated_sta_link_mterics_inclusion_policy = 0;
strncpy (em_radio_info->chip_vendor, wifi_prop->manufacturer, strlen(em_radio_info->chip_vendor));

em_radio_cap_info_t *radio_cap = proto->get_radio_cap(proto->data_model, wifi_prop->radiocap[index].rdk_radio_index);
if (radio_cap == NULL) {
wifi_util_error_print(WIFI_WEBCONFIG, "%s:%d: radio_cap not found\n", __func__, __LINE__);
return webconfig_error_translate_to_easymesh;
}
if (radio_iface_map->radio_index == wifi_prop->radiocap[index].rdk_radio_index) {
memcpy(radio_cap->ruid.mac, em_radio_info->intf.mac, sizeof(mac_address_t));
uint8_mac_to_string_mac(radio_cap->ruid.mac, mac_str);
wifi_util_error_print(WIFI_WEBCONFIG, "%s:%d: radio_cap index: %d and mac:%s and radio_index:%d\n", __func__,
__LINE__, index, mac_str, radio_index);

translate_radio_capability_to_easymesh(wifi_prop, radio_index, radio_cap);
}
Comment on lines +626 to +638
}

return webconfig_error_none;
Expand Down Expand Up @@ -2991,7 +3121,7 @@ void webconfig_proto_easymesh_init(webconfig_external_easymesh_t *proto, void *d
ext_proto_get_sta_info_t get_sta, ext_proto_put_sta_info_t put_sta, ext_proto_em_get_bss_info_with_mac_t get_bss_with_mac,
ext_proto_put_scan_results_t put_scan_res, ext_proto_update_ap_mld_info_t update_ap_mld,
ext_proto_update_bsta_mld_info_t update_bsta_mld, ext_proto_update_assoc_sta_mld_info_t update_assoc_sta_mld,
ext_proto_get_ap_mld_frm_bssid_t get_ap_mld_frm_bssid)
ext_proto_get_ap_mld_frm_bssid_t get_ap_mld_frm_bssid, ext_proto_get_radio_cap_t get_radio_cap)
{
proto->data_model = data_model;
proto->m2ctrl_radioconfig = m2ctrl_radioconfig;
Expand All @@ -3018,4 +3148,5 @@ void webconfig_proto_easymesh_init(webconfig_external_easymesh_t *proto, void *d
proto->update_bsta_mld_info = update_bsta_mld;
proto->update_assoc_sta_mld_info = update_assoc_sta_mld;
proto->get_ap_mld_frm_bssid = get_ap_mld_frm_bssid;
proto->get_radio_cap = get_radio_cap;
}
Loading
Loading