diff --git a/source/apps/em/wifi_em.c b/source/apps/em/wifi_em.c index ee64f6cca..1ab6f41a9 100644 --- a/source/apps/em/wifi_em.c +++ b/source/apps/em/wifi_em.c @@ -466,6 +466,7 @@ static int em_sta_stats_publish(wifi_app_t *app, client_assoc_data_t *stats, int if (rc != bus_error_success) { wifi_util_error_print(WIFI_EM, "%s:%d: bus: bus_event_publish_fn Event failed %d\n", __func__, __LINE__, rc); + free(data->u.encoded.raw); free(data->u.decoded.em_sta_link_metrics_rsp.per_sta_metrics); free(data); return RETURN_ERR; @@ -477,8 +478,11 @@ static int em_sta_stats_publish(wifi_app_t *app, client_assoc_data_t *stats, int } } + free(data->u.encoded.raw); free(data->u.decoded.em_sta_link_metrics_rsp.per_sta_metrics); free(data); + + return RETURN_OK; } static int handle_ready_client_stats(wifi_app_t *app, client_assoc_data_t *stats, size_t stats_num, @@ -896,10 +900,12 @@ static int em_publish_stats_data(channel_scan_response_t *scan_response) if (status != bus_error_success) { wifi_util_error_print(WIFI_EM, "%s:%d: bus: bus_event_publish_fn Event failed %d\n", __func__, __LINE__, status); + free(data->u.encoded.raw); free(data->u.decoded.collect_stats.stats); free(data); return RETURN_ERR; } + free(data->u.encoded.raw); free(data->u.decoded.collect_stats.stats); free(data); @@ -2027,7 +2033,8 @@ static int ap_report_push_cb(em_ap_report_callback_arg_t *args) // Cleanup allocated memory if (data != NULL) { for (int j = 0; j < req_radio_count; j++) { - for (int i = 0; i < radio->vaps.num_vaps && i < MAX_NUM_VAP_PER_RADIO; i++) { + // num_vaps differs per radio; unused entries are NULL + for (int i = 0; i < MAX_NUM_VAP_PER_RADIO; i++) { vap_report = &data->u.decoded.em_ap_metrics_report.radio_reports[j].vap_reports[i]; if (vap_report->sta_link_metrics != NULL) { free(vap_report->sta_link_metrics); @@ -2037,6 +2044,8 @@ static int ap_report_push_cb(em_ap_report_callback_arg_t *args) } } } + // u.encoded.raw is NULL if encode was not reached (data is memset) + free(data->u.encoded.raw); free(data); } @@ -2948,6 +2957,7 @@ static int em_beacon_report_publish(bus_handle_t *handle, void *msg_data) if (rc != bus_error_success) { wifi_util_error_print(WIFI_EM, "%s:%d: bus_event_publish_fn Event failed %d\n", __func__, __LINE__, rc); + free(wb_data->u.encoded.raw); free(wb_data); return RETURN_ERR; } else { @@ -2955,6 +2965,8 @@ static int em_beacon_report_publish(bus_handle_t *handle, void *msg_data) __LINE__, WIFI_EM_BEACON_REPORT); } + free(wb_data->u.encoded.raw); + free(wb_data); return RETURN_OK; } diff --git a/source/webconfig/wifi_easymesh_translator.c b/source/webconfig/wifi_easymesh_translator.c index 74e4774ad..ad8ed6d13 100644 --- a/source/webconfig/wifi_easymesh_translator.c +++ b/source/webconfig/wifi_easymesh_translator.c @@ -94,6 +94,36 @@ unsigned int translate_auth_type_from_easymesh(unsigned int authtype) } } +#ifdef EM_APP +// the ap metrics report decoder mallocs per-vap sta arrays into the decoded +// params (see decode_em_ap_metrics_report_object); webconfig_data_free only +// frees u.encoded.raw, so they must be freed here after translation +static void webconfig_easymesh_free_ap_metrics_report(webconfig_subdoc_data_t *data) +{ + webconfig_subdoc_decoded_data_t *decoded = &data->u.decoded; + int i, j; + + if (data->type != webconfig_subdoc_type_em_ap_metrics_report) { + return; + } + + for (i = 0; i < MAX_NUM_RADIOS; i++) { + for (j = 0; j < MAX_NUM_VAP_PER_RADIO; j++) { + em_vap_metrics_t *vap_report = &decoded->em_ap_metrics_report.radio_reports[i].vap_reports[j]; + + if (vap_report->sta_traffic_stats != NULL) { + free(vap_report->sta_traffic_stats); + vap_report->sta_traffic_stats = NULL; + } + if (vap_report->sta_link_metrics != NULL) { + free(vap_report->sta_link_metrics); + vap_report->sta_link_metrics = NULL; + } + } + } +} +#endif + // webconfig_easymesh_decode() will convert the onewifi structures to easymesh structures webconfig_error_t webconfig_easymesh_decode(webconfig_t *config, const char *str, webconfig_external_easymesh_t *data, @@ -111,6 +141,9 @@ webconfig_error_t webconfig_easymesh_decode(webconfig_t *config, const char *str wifi_util_info_print(WIFI_WEBCONFIG,"%s:%d: Easymesh decode subdoc type %d sucessfully\n", __func__, __LINE__, webconfig_easymesh_data.type); *type = webconfig_easymesh_data.type; //debug_external_protos(&webconfig_easymesh_data, __func__, __LINE__); +#ifdef EM_APP + webconfig_easymesh_free_ap_metrics_report(&webconfig_easymesh_data); +#endif webconfig_data_free(&webconfig_easymesh_data); return webconfig_error_none; } diff --git a/source/webconfig/wifi_webconfig_em_ap_metrics_report.c b/source/webconfig/wifi_webconfig_em_ap_metrics_report.c index 54873198d..5a508ceab 100644 --- a/source/webconfig/wifi_webconfig_em_ap_metrics_report.c +++ b/source/webconfig/wifi_webconfig_em_ap_metrics_report.c @@ -133,6 +133,25 @@ webconfig_error_t encode_em_ap_metrics_report_subdoc(webconfig_t *config, webcon return webconfig_error_none; } +// frees the per-vap arrays allocated by decode_em_ap_metrics_report_object +static void free_em_ap_metrics_report_params(webconfig_subdoc_decoded_data_t *params) +{ + for (int r = 0; r < MAX_NUM_RADIOS; r++) { + for (int v = 0; v < MAX_NUM_VAP_PER_RADIO; v++) { + em_vap_metrics_t *vap_report = ¶ms->em_ap_metrics_report.radio_reports[r].vap_reports[v]; + + if (vap_report->sta_traffic_stats != NULL) { + free(vap_report->sta_traffic_stats); + vap_report->sta_traffic_stats = NULL; + } + if (vap_report->sta_link_metrics != NULL) { + free(vap_report->sta_link_metrics); + vap_report->sta_link_metrics = NULL; + } + } + } +} + webconfig_error_t decode_em_ap_metrics_report_subdoc(webconfig_t *config, webconfig_subdoc_data_t *data) { webconfig_subdoc_decoded_data_t *params; @@ -174,6 +193,14 @@ webconfig_error_t decode_em_ap_metrics_report_subdoc(webconfig_t *config, webcon if (em_ap_report_arr == NULL || !cJSON_IsArray(em_ap_report_arr)) { wifi_util_error_print(WIFI_WEBCONFIG, "%s:%d: Invalid or missing EMAPMetricsReport\n", __func__, __LINE__); + cJSON_Delete(json); + return webconfig_error_decode; + } + + if (cJSON_GetArraySize(em_ap_report_arr) > MAX_NUM_RADIOS) { + wifi_util_error_print(WIFI_WEBCONFIG, "%s:%d: EMAPMetricsReport has %d entries, max is %d\n", + __func__, __LINE__, cJSON_GetArraySize(em_ap_report_arr), MAX_NUM_RADIOS); + cJSON_Delete(json); return webconfig_error_decode; } @@ -182,17 +209,22 @@ webconfig_error_t decode_em_ap_metrics_report_subdoc(webconfig_t *config, webcon if (em_ap_report_obj == NULL) { wifi_util_error_print(WIFI_WEBCONFIG, "%s:%d: Invalid EMAPMetricsReport object at index %d\n", __func__, __LINE__, i); + free_em_ap_metrics_report_params(params); + cJSON_Delete(json); return webconfig_error_decode; } if(decode_em_ap_metrics_report_object(em_ap_report_obj, ¶ms->em_ap_metrics_report.radio_reports[i]) != webconfig_error_none) { wifi_util_error_print(WIFI_WEBCONFIG, "%s:%d: decode_em_ap_metrics_report_object failed\n", __func__, __LINE__); + free_em_ap_metrics_report_params(params); cJSON_Delete(json); return webconfig_error_decode; } } params->em_ap_metrics_report.radio_count = i; + // the subdoc decoder owns u.encoded.json (see decode_radio_subdoc) + cJSON_Delete(json); return webconfig_error_none; } #endif \ No newline at end of file