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
3 changes: 3 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,6 @@ Licensed under the BSD-3 License.
The Data_Elements_JSON_Schema_v3.0.json file is:
Copyright (C) 2021 Wi-Fi Alliance. All Rights Reserved.
The file is licensed according to the conditions in the header, and your use of the file must be in accordance with the permissions given in that header.

Copyright 2026 MaxLinear, Inc
Licensed under the Apache License, Version 2.0
1 change: 1 addition & 0 deletions build/linux/bpi/makefile
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ WEBCONFIG_SOURCES = $(ONE_WIFI_HOME)/source/webconfig/wifi_decoder.c \
$(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_assocdevice_stats.c \
$(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_memwraptool.c \
$(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_ignite.c \
$(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_nasta.c \
$(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_radio_temperature.c \
$(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_radiodiag_stats.c \
$(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_multivap.c \
Expand Down
1 change: 1 addition & 0 deletions build/openwrt/makefile
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ WEBCONFIG_SOURCES = $(ONE_WIFI_HOME)/source/webconfig/wifi_decoder.c \
$(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_radiodiag_stats.c \
$(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_multivap.c \
$(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_ignite.c \
$(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_nasta.c \
$(ONE_WIFI_HOME)/source/utils/wifi_util.c \


Expand Down
31 changes: 31 additions & 0 deletions include/wifi_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ extern "C" {
#define WIFI_CSA_BEACON_FRAME_RECEIVED "Device.WiFi.CSABeaconFrameRecieved"
#define HOTSPOT_CLIENT_DHCP_FAILURE_DISCONNECTED "Device.X_COMCAST-COM_GRE.Hotspot.RejectAssociatedClient"
#define WIFI_STUCK_DETECT_FILE_NAME "/nvram/wifi_stuck_detect"
#define WIFI_ACCESSPOINT_GET_NASTA "Device.WiFi.AccessPoint.{i}.X_RDKCENTRAL-COM_GetNaSta"
#define WIFI_NASTA_RESPONSE_EVENT "Device.WiFi.EM.NaStaResponse"
#define WIFI_QUALITY_LINKREPORT "Device.WiFi.LinkReport"
#define WIFI_LINK_QUALITY_DATA "Device.WiFi.LinkQualityData"
#define WIFI_LINK_QUALITY_FLAGS "Device.WiFi.LinkQualityFlags"
Expand Down Expand Up @@ -535,6 +537,35 @@ typedef struct {
link_report_t *links;
} report_batch_t;

/* Unassociated STA (NaSta) query/response structures */
#define MAX_NASTA_OPCLASS_ENTRIES 8
#define MAX_NASTA_CHANNELS 8
#define MAX_NASTA_STA_PER_CHANNEL 8
#define MAX_NASTA_RESPONSE_STAS (MAX_NASTA_OPCLASS_ENTRIES * MAX_NASTA_CHANNELS * MAX_NASTA_STA_PER_CHANNEL)

typedef struct {
unsigned int num_sta;
wifi_na_sta_info sta_list[MAX_NASTA_RESPONSE_STAS];
} nasta_response_t;

typedef struct {
mac_address_t sta_macs[MAX_NASTA_STA_PER_CHANNEL];
unsigned int sta_list_length;
unsigned int channel;
} nasta_channel_entry_t;

typedef struct {
unsigned int opclass;
unsigned int channels_length;
nasta_channel_entry_t channels[MAX_NASTA_CHANNELS];
} nasta_opclass_entry_t;

typedef struct {
unsigned int vap_index;
unsigned int num_opclass;
nasta_opclass_entry_t opclass_list[MAX_NASTA_OPCLASS_ENTRIES];
} nasta_query_t;

typedef struct {
unsigned int rss_check_interval; //minutes
unsigned int rss_threshold; //kbytes
Expand Down
1 change: 1 addition & 0 deletions include/wifi_events.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ typedef enum {
wifi_event_webconfig_em_config,
wifi_event_webconfig_br_report,
wifi_event_webconfig_set_ignite_data,
wifi_event_webconfig_set_data_nasta,
wifi_event_webconfig_max,

// HAL events
Expand Down
12 changes: 12 additions & 0 deletions include/wifi_webconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ typedef enum {
webconfig_subdoc_type_memwraptool,
webconfig_subdoc_type_link_report,
webconfig_subdoc_type_ignite,
webconfig_subdoc_type_nasta_query,
webconfig_subdoc_type_max
} webconfig_subdoc_type_t;

Expand Down Expand Up @@ -174,6 +175,7 @@ typedef enum {
webconfig_subdoc_object_type_em_sta_link_metrics,
webconfig_subdoc_object_type_em_ap_metrics_report,
webconfig_subdoc_object_type_link_report,
webconfig_subdoc_object_type_nasta_query,

webconfig_subdoc_object_max
} webconfig_subdoc_object_type_t;
Expand Down Expand Up @@ -233,6 +235,8 @@ typedef struct {
em_ap_metrics_report_t em_ap_metrics_report;
#endif
report_batch_t *qmgr_report;
nasta_query_t nasta_query;
nasta_response_t *nasta_response;
} webconfig_subdoc_decoded_data_t;

typedef char * webconfig_subdoc_encoded_raw_t;
Expand Down Expand Up @@ -602,6 +606,14 @@ webconfig_error_t encode_cac_config_subdoc(webconfig_t *config, webconfig_
webconfig_error_t translate_to_cac_config_subdoc(webconfig_t *config, webconfig_subdoc_data_t *data);
webconfig_error_t translate_from_cac_config_subdoc(webconfig_t *config, webconfig_subdoc_data_t *data);

// nasta query
webconfig_error_t init_nasta_query_subdoc(webconfig_subdoc_t *doc);
webconfig_error_t access_check_nasta_query_subdoc(webconfig_t *config, webconfig_subdoc_data_t *data);
webconfig_error_t decode_nasta_query_subdoc(webconfig_t *config, webconfig_subdoc_data_t *data);
webconfig_error_t encode_nasta_query_subdoc(webconfig_t *config, webconfig_subdoc_data_t *data);
webconfig_error_t translate_to_nasta_query_subdoc(webconfig_t *config, webconfig_subdoc_data_t *data);
webconfig_error_t translate_from_nasta_query_subdoc(webconfig_t *config, webconfig_subdoc_data_t *data);

// radio channel stats
webconfig_error_t init_radio_channel_stats_subdoc(webconfig_subdoc_t *doc);
webconfig_error_t access_check_radio_channel_stats_subdoc(webconfig_t *config, webconfig_subdoc_data_t *data);
Expand Down
14 changes: 14 additions & 0 deletions source/core/wifi_ctrl_queue_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -4712,6 +4712,20 @@ void handle_webconfig_event(wifi_ctrl_t *ctrl, const char *raw, unsigned int len
webconfig_data_free(data);
break;

case wifi_event_webconfig_set_data_nasta:
memcpy((unsigned char *)&data->u.decoded.hal_cap, (unsigned char *)&mgr->hal_cap,
sizeof(wifi_hal_capability_t));
if (raw == NULL) {
wifi_util_error_print(WIFI_CTRL, "%s:%d Empty raw data for NaSta\n",
__func__, __LINE__);
free(data);
data = NULL;
return;
}
webconfig_decode(config, data, raw);
webconfig_data_free(data);
break;

case wifi_event_webconfig_set_data_tunnel:
memcpy((unsigned char *)&data->u.decoded.hal_cap, (unsigned char *)&mgr->hal_cap,
sizeof(wifi_hal_capability_t));
Expand Down
71 changes: 71 additions & 0 deletions source/core/wifi_ctrl_rbus_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -4266,6 +4266,71 @@ void register_endpoint_components(wifi_ctrl_t *ctrl)
return;
}

bus_error_t get_NaSta(char const* methodName, bus_data_prop_t *inParams,
bus_data_prop_t *outParams, void *asyncHandle)
{
unsigned vap_idx;
char *json_str = NULL;
char *enriched_str = NULL;
cJSON *json = NULL;
int ret;

if (methodName == NULL || inParams == NULL) {
wifi_util_error_print(WIFI_CTRL, "%s:%d Invalid input parameters\r\n", __func__, __LINE__);
return bus_error_invalid_input;
}

if (inParams->value.data_type != bus_data_type_string || inParams->value.raw_data.bytes == NULL) {
wifi_util_error_print(WIFI_CTRL, "%s:%d Invalid input data type:0x%x\r\n",
__func__, __LINE__, inParams->value.data_type);
return bus_error_invalid_input;
}

ret = sscanf(methodName, "Device.WiFi.AccessPoint.%u.X_RDKCENTRAL-COM_GetNaSta", &vap_idx);
if (ret != 1 || vap_idx < 1 || vap_idx > MAX_VAP) {
wifi_util_error_print(WIFI_CTRL, "%s:%d Invalid vap index %u\r\n", __func__, __LINE__, vap_idx);
return bus_error_destination_not_found;
}

json_str = (char *)inParams->value.raw_data.bytes;

/* Parse the incoming JSON and inject vap_index (0-based) */
json = cJSON_Parse(json_str);
if (json == NULL) {
wifi_util_error_print(WIFI_CTRL, "%s:%d Failed to parse JSON input\r\n", __func__, __LINE__);
return bus_error_invalid_input;
}
cJSON_AddNumberToObject(json, "VapIndex", vap_idx - 1);
enriched_str = cJSON_PrintUnformatted(json);
cJSON_Delete(json);

if (enriched_str == NULL) {
wifi_util_error_print(WIFI_CTRL, "%s:%d Failed to serialize JSON\r\n", __func__, __LINE__);
return bus_error_out_of_resources;
}

wifi_util_info_print(WIFI_CTRL, "%s:%d NaSta query for vap %u, pushing to ctrl queue\r\n",
__func__, __LINE__, vap_idx);

push_event_to_ctrl_queue(enriched_str, (strlen(enriched_str) + 1),
wifi_event_type_webconfig, wifi_event_webconfig_set_data_nasta, NULL);

cJSON_free(enriched_str);

/* Return an ack so the synchronous RBUS invoke succeeds;
the actual NaSta response is published asynchronously via
Device.WiFi.EM.NaStaResponse event. */
if (outParams != NULL) {
char *ack = strdup("{\"Status\":\"Accepted\"}");
if (ack != NULL) {
outParams->value.data_type = bus_data_type_string;
outParams->value.raw_data.bytes = ack;
outParams->value.raw_data_len = strlen(ack);
}
}

return bus_error_success;
}

void bus_register_handlers(wifi_ctrl_t *ctrl)
{
Expand Down Expand Up @@ -4440,6 +4505,12 @@ void bus_register_handlers(wifi_ctrl_t *ctrl)
{ WIFI_IGNITE_STATUS, bus_element_type_event,
{ NULL, NULL, NULL, NULL, NULL, NULL }, slow_speed, ZERO_TABLE,
{ bus_data_type_string, false, 0, 0, 0, NULL } },
{ WIFI_ACCESSPOINT_GET_NASTA, bus_element_type_method,
{ NULL, NULL, NULL, NULL, NULL, get_NaSta }, slow_speed, ZERO_TABLE,
{ bus_data_type_string, true, 0, 0, 0, NULL } },
{ WIFI_NASTA_RESPONSE_EVENT, bus_element_type_event,
{ NULL, NULL, NULL, NULL, eventSubHandler, NULL }, slow_speed, ZERO_TABLE,
{ bus_data_type_string, false, 0, 0, 0, NULL } },
};

rc = get_bus_descriptor()->bus_open_fn(&ctrl->handle, component_name);
Expand Down
113 changes: 113 additions & 0 deletions source/core/wifi_ctrl_webconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -1764,6 +1764,113 @@ int webconfig_global_config_apply(wifi_ctrl_t *ctrl, webconfig_subdoc_decoded_da
return RETURN_OK;
}

int webconfig_nasta_apply(wifi_ctrl_t *ctrl, webconfig_subdoc_decoded_data_t *data)
{
nasta_query_t *query;
nasta_response_t response;
unsigned int oc_idx, ch_idx, sta_idx;
int rc;
raw_data_t rdata;
webconfig_subdoc_data_t resp_data;
webconfig_t *config;

if (ctrl == NULL || data == NULL) {
wifi_util_error_print(WIFI_CTRL, "%s:%d: NULL pointer\n", __func__, __LINE__);
return RETURN_ERR;
}

query = &data->nasta_query;
config = &ctrl->webconfig;
memset(&response, 0, sizeof(nasta_response_t));

wifi_util_info_print(WIFI_CTRL, "%s:%d: Processing NaSta query: vap=%u, %u opclass entries\n",
__func__, __LINE__, query->vap_index, query->num_opclass);

for (oc_idx = 0; oc_idx < query->num_opclass && oc_idx < MAX_NASTA_OPCLASS_ENTRIES; oc_idx++) {
nasta_opclass_entry_t *oc = &query->opclass_list[oc_idx];

for (ch_idx = 0; ch_idx < oc->channels_length && ch_idx < MAX_NASTA_CHANNELS; ch_idx++) {
nasta_channel_entry_t *ch = &oc->channels[ch_idx];

for (sta_idx = 0; sta_idx < ch->sta_list_length && sta_idx < MAX_NASTA_STA_PER_CHANNEL; sta_idx++) {
wifi_na_sta_req_params req_params;
wifi_na_sta_info sta_info;

if (response.num_sta >= MAX_NASTA_RESPONSE_STAS) {
wifi_util_error_print(WIFI_CTRL,
"%s:%d: Response STA list full (%d)\n",
__func__, __LINE__, MAX_NASTA_RESPONSE_STAS);
goto publish_response;
}

memset(&req_params, 0, sizeof(req_params));
memset(&sta_info, 0, sizeof(sta_info));

memcpy(req_params.sta_addr, ch->sta_macs[sta_idx], sizeof(mac_address_t));
req_params.op_class = oc->opclass;
req_params.channel = ch->channel;

rc = wifi_getNASta(query->vap_index, &req_params, &sta_info);
if (rc != WIFI_HAL_SUCCESS) {
wifi_util_error_print(WIFI_CTRL,
"%s:%d: wifi_getNASta failed for STA "
"%02X:%02X:%02X:%02X:%02X:%02X on ch %u (rc=%d)\n",
__func__, __LINE__,
ch->sta_macs[sta_idx][0], ch->sta_macs[sta_idx][1],
ch->sta_macs[sta_idx][2], ch->sta_macs[sta_idx][3],
ch->sta_macs[sta_idx][4], ch->sta_macs[sta_idx][5],
ch->channel, rc);
continue;
}

memcpy(&response.sta_list[response.num_sta], &sta_info, sizeof(wifi_na_sta_info));
response.num_sta++;
}
}
}

publish_response:
wifi_util_info_print(WIFI_CTRL, "%s:%d: NaSta query complete, %u STAs in response\n",
__func__, __LINE__, response.num_sta);

/* Encode the response as JSON and publish via RBUS event */
memset(&resp_data, 0, sizeof(webconfig_subdoc_data_t));
resp_data.type = webconfig_subdoc_type_nasta_query;
resp_data.descriptor = webconfig_data_descriptor_decoded;
resp_data.u.decoded.nasta_response = &response;
memcpy(&resp_data.u.decoded.hal_cap, &data->hal_cap, sizeof(wifi_hal_capability_t));

webconfig_subdoc_t *nasta_doc = &config->subdocs[webconfig_subdoc_type_nasta_query];
if (nasta_doc->encode_subdoc(config, &resp_data) != webconfig_error_none) {
wifi_util_error_print(WIFI_CTRL, "%s:%d: Failed to encode NaSta response\n",
__func__, __LINE__);
return RETURN_ERR;
}

if (resp_data.u.encoded.raw != NULL) {
memset(&rdata, 0, sizeof(raw_data_t));
rdata.data_type = bus_data_type_string;
rdata.raw_data.bytes = (void *)resp_data.u.encoded.raw;
rdata.raw_data_len = (strlen(resp_data.u.encoded.raw) + 1);

rc = get_bus_descriptor()->bus_event_publish_fn(&ctrl->handle,
WIFI_NASTA_RESPONSE_EVENT, &rdata);
if (rc != bus_error_success) {
wifi_util_error_print(WIFI_CTRL,
"%s:%d: Failed to publish NaSta response event (rc=%d)\n",
__func__, __LINE__, rc);
} else {
wifi_util_info_print(WIFI_CTRL,
"%s:%d: Published NaSta response: %u STAs\n",
__func__, __LINE__, response.num_sta);
}

free(resp_data.u.encoded.raw);
}

return RETURN_OK;
}

int webconfig_cac_apply(wifi_ctrl_t *ctrl, webconfig_subdoc_decoded_data_t *data)
{
wifi_util_dbg_print(WIFI_CTRL,"Inside webconfig_cac_apply\n");
Expand Down Expand Up @@ -3169,6 +3276,12 @@ webconfig_error_t webconfig_ctrl_apply(webconfig_subdoc_t *doc, webconfig_subdoc
}
break;

case webconfig_subdoc_type_nasta_query:
if (!(data->descriptor & webconfig_data_descriptor_encoded)) {
ret = webconfig_nasta_apply(ctrl, &data->u.decoded);
}
break;

default:
break;
}
Expand Down
2 changes: 1 addition & 1 deletion source/webconfig/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ libwifi_webconfig_la_CPPFLAGS += -I$(top_srcdir)/source/dml/wifi_ssp -I$(top_src

libwifi_webconfig_la_CFLAGS = $(SYSTEMD_CFLAGS)

libwifi_webconfig_la_SOURCES = wifi_webconfig.c wifi_encoder.c wifi_decoder.c wifi_ovsdb_translator.c wifi_webconfig_home.c wifi_webconfig_mesh.c wifi_webconfig_private.c wifi_webconfig_radio.c wifi_webconfig_xfinity.c wifi_webconfig_associated_client.c wifi_webconfig_wifiapi_radio.c wifi_webconfig_wifiapi_vap.c wifi_webconfig_macfilter.c wifi_webconfig_blaster.c wifi_webconfig_harvester.c wifi_webconfig_wifi_config.c wifi_webconfig_csi.c wifi_webconfig_mesh_sta.c wifi_webconfig_mesh_backhaul.c wifi_webconfig_null.c wifi_webconfig_stats_config.c wifi_webconfig_steering_config.c wifi_webconfig_steering_clients.c wifi_webconfig_lnf.c wifi_webconfig_vif_neighbors.c wifi_webconfig_mesh_backhaul_sta.c wifi_webconfig_dml.c wifi_webconfig_levl.c wifi_webconfig_cac.c wifi_webconfig_radio_stats.c wifi_webconfig_neighbor_stats.c wifi_webconfig_assocdevice_stats.c wifi_webconfig_radiodiag_stats.c wifi_webconfig_radio_temperature.c wifi_webconfig_multivap.c wifi_webconfig_easymesh_config.c wifi_webconfig_beacon_report.c wifi_webconfig_memwraptool.c wifi_webconfig_link_report.c wifi_webconfig_ignite.c
libwifi_webconfig_la_SOURCES = wifi_webconfig.c wifi_encoder.c wifi_decoder.c wifi_ovsdb_translator.c wifi_webconfig_home.c wifi_webconfig_mesh.c wifi_webconfig_private.c wifi_webconfig_radio.c wifi_webconfig_xfinity.c wifi_webconfig_associated_client.c wifi_webconfig_wifiapi_radio.c wifi_webconfig_wifiapi_vap.c wifi_webconfig_macfilter.c wifi_webconfig_blaster.c wifi_webconfig_harvester.c wifi_webconfig_wifi_config.c wifi_webconfig_csi.c wifi_webconfig_mesh_sta.c wifi_webconfig_mesh_backhaul.c wifi_webconfig_null.c wifi_webconfig_stats_config.c wifi_webconfig_steering_config.c wifi_webconfig_steering_clients.c wifi_webconfig_lnf.c wifi_webconfig_vif_neighbors.c wifi_webconfig_mesh_backhaul_sta.c wifi_webconfig_dml.c wifi_webconfig_levl.c wifi_webconfig_cac.c wifi_webconfig_radio_stats.c wifi_webconfig_neighbor_stats.c wifi_webconfig_assocdevice_stats.c wifi_webconfig_radiodiag_stats.c wifi_webconfig_radio_temperature.c wifi_webconfig_multivap.c wifi_webconfig_easymesh_config.c wifi_webconfig_beacon_report.c wifi_webconfig_memwraptool.c wifi_webconfig_link_report.c wifi_webconfig_ignite.c wifi_webconfig_nasta.c
Comment thread
vlad-safonov marked this conversation as resolved.
if EM_APP_SUPPORT
libwifi_webconfig_la_SOURCES += wifi_webconfig_em_channel_stats.c wifi_webconfig_em_sta_link_metrics.c wifi_webconfig_em_ap_metrics_report.c
libwifi_webconfig_la_CFLAGS += $(EM_APP_FLAG)
Expand Down
13 changes: 13 additions & 0 deletions source/webconfig/wifi_webconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,19 @@ webconfig_error_t webconfig_init(webconfig_t *config)
config->subdocs[webconfig_subdoc_type_ignite].translate_to_subdoc = translate_to_ignite_subdoc;
config->subdocs[webconfig_subdoc_type_ignite].translate_from_subdoc = translate_from_ignite_subdoc;

//webconfig_subdoc_type_nasta_query
config->subdocs[webconfig_subdoc_type_nasta_query].type = webconfig_subdoc_type_nasta_query;
strcpy(config->subdocs[webconfig_subdoc_type_nasta_query].name, "UnassocStaQuery");
config->subdocs[webconfig_subdoc_type_nasta_query].major = 1;
config->subdocs[webconfig_subdoc_type_nasta_query].minor = 0;
config->subdocs[webconfig_subdoc_type_nasta_query].init_subdoc = init_nasta_query_subdoc;
config->subdocs[webconfig_subdoc_type_nasta_query].init_subdoc(&config->subdocs[webconfig_subdoc_type_nasta_query]);
config->subdocs[webconfig_subdoc_type_nasta_query].access_check_subdoc = access_check_nasta_query_subdoc;
config->subdocs[webconfig_subdoc_type_nasta_query].encode_subdoc = encode_nasta_query_subdoc;
config->subdocs[webconfig_subdoc_type_nasta_query].decode_subdoc = decode_nasta_query_subdoc;
config->subdocs[webconfig_subdoc_type_nasta_query].translate_to_subdoc = translate_to_nasta_query_subdoc;
config->subdocs[webconfig_subdoc_type_nasta_query].translate_from_subdoc = translate_from_nasta_query_subdoc;

#ifdef ONEWIFI_HARVESTER_APP_SUPPORT
config->subdocs[webconfig_subdoc_type_harvester].type = webconfig_subdoc_type_harvester;
strcpy(config->subdocs[webconfig_subdoc_type_harvester].name, "instant measurement config");
Expand Down
Loading
Loading