diff --git a/include/wifi_events.h b/include/wifi_events.h index f27fd8334..ab8d180ed 100644 --- a/include/wifi_events.h +++ b/include/wifi_events.h @@ -178,6 +178,7 @@ typedef enum { wifi_event_type_xfi_tel_enable_rfc, wifi_event_type_sm_app_enable, wifi_event_type_link_quality_rfc, + wifi_event_type_backhaul_steer, wifi_event_command_max, wifi_event_monitor_diagnostics = wifi_event_type_base diff --git a/source/apps/em/wifi_em.c b/source/apps/em/wifi_em.c index 4e4a17c25..b1660d48d 100644 --- a/source/apps/em/wifi_em.c +++ b/source/apps/em/wifi_em.c @@ -85,6 +85,13 @@ typedef struct { em_ap_radio_report_t radio_report[MAX_NUM_RADIOS]; } em_ap_metrics_report_cache_t; +typedef struct { + mac_addr_t bh_sta_mac_addr; + mac_addr_t target_bssid; + unsigned char op_class; + unsigned char channel_num; +} bh_steering_req_t; + //em_ap_metrics_report_cache_t em_ap_metrics_report_cache[MAX_NUM_RADIOS] = { 0 }; em_ap_metrics_report_cache_t em_ap_metrics_report_cache = { 0 }; client_assoc_stats_t client_assoc_stats[MAX_NUM_RADIOS] = { 0 }; @@ -2273,6 +2280,136 @@ static void em_toggle_disconn_steady_state(void *data, unsigned int len) return bus_error_success; } +static wifi_vap_info_t *get_mesh_sta_vap_by_mac(wifi_mgr_t *mgr, unsigned char *mac) +{ + unsigned int r, i, num_vaps; + + if (mgr == NULL || mac == NULL) { + wifi_util_error_print(WIFI_EM, "%s:%d NULL input (mgr=%p mac=%p)\n", + __func__, __LINE__, mgr, mac); + return NULL; + } + + for (r = 0; r < MAX_NUM_RADIOS; r++) { + num_vaps = mgr->radio_config[r].vaps.vap_map.num_vaps; + for (i = 0; i < num_vaps; i++) { + wifi_vap_info_t *v = &mgr->radio_config[r].vaps.vap_map.vap_array[i]; + if (vap_svc_is_mesh_ext(v->vap_index) && + memcmp(v->u.sta_info.mac, mac, sizeof(mac_addr_t)) == 0) { + return v; + } + } + } + return NULL; +} + +static void em_handle_backhaul_steer(void *data, unsigned int len) +{ + bh_steering_req_t *req; + wifi_mgr_t *mgr; + wifi_ctrl_t *ctrl; + vap_svc_t *ext_svc; + wifi_vap_info_t *sta_vap; + wifi_vap_info_t steer_vap; + mac_addr_str_t sta_str, bssid_str; + + if (data == NULL) { + wifi_util_error_print(WIFI_EM, "%s:%d NULL data pointer\n", __func__, __LINE__); + return; + } + + if (len != sizeof(bh_steering_req_t)) { + wifi_util_error_print(WIFI_EM, "%s:%d Invalid length %u, expected %zu\n", + __func__, __LINE__, len, sizeof(bh_steering_req_t)); + return; + } + + req = (bh_steering_req_t *)data; + to_mac_str(req->bh_sta_mac_addr, sta_str); + to_mac_str(req->target_bssid, bssid_str); + wifi_util_info_print(WIFI_EM, + "%s:%d BH Steer Request received: sta=%s target_bssid=%s op_class=%d channel=%d\n", + __func__, __LINE__, sta_str, bssid_str, req->op_class, req->channel_num); + + mgr = (wifi_mgr_t *)get_wifimgr_obj(); + if (mgr == NULL) { + wifi_util_error_print(WIFI_EM, "%s:%d wifi mgr object is NULL\n", + __func__, __LINE__); + return; + } + + sta_vap = get_mesh_sta_vap_by_mac(mgr, req->bh_sta_mac_addr); + if (sta_vap == NULL) { + wifi_util_error_print(WIFI_EM, + "%s:%d No mesh STA vap found for sta=%s\n", + __func__, __LINE__, sta_str); + return; + } + + wifi_util_info_print(WIFI_EM, + "%s:%d Mesh STA vap_index=%d ssid='%s' -> target_bssid=%s\n", + __func__, __LINE__, sta_vap->vap_index, + sta_vap->u.sta_info.ssid, bssid_str); + + // Trigger the mesh STA connection state machine with the target BSSID. + steer_vap = *sta_vap; + memcpy(steer_vap.u.sta_info.bssid, req->target_bssid, sizeof(bssid_t)); + + ctrl = (wifi_ctrl_t *)get_wifictrl_obj(); + if (ctrl == NULL) { + wifi_util_error_print(WIFI_EM, "%s:%d wifi ctrl object is NULL\n", + __func__, __LINE__); + return; + } + + ext_svc = get_svc_by_type(ctrl, vap_svc_type_mesh_ext); + if (ext_svc == NULL) { + wifi_util_error_print(WIFI_EM, + "%s:%d mesh ext service not available\n", __func__, __LINE__); + return; + } + + ext_svc->event_fn(ext_svc, wifi_event_type_webconfig, + wifi_event_webconfig_set_data_sta_bssid, vap_svc_event_none, &steer_vap); +} + +bus_error_t em_backhaul_steer(char *name, raw_data_t *p_data) +{ + char *pTmp = NULL; + + if (!name) { + wifi_util_error_print(WIFI_EM, "%s:%d Property name is not found\n", + __func__, __LINE__); + return bus_error_element_name_missing; + } + + if (p_data == NULL) { + wifi_util_error_print(WIFI_EM, "%s:%d NULL p_data\n", __func__, __LINE__); + return bus_error_invalid_input; + } + + pTmp = (char *)p_data->raw_data.bytes; + if ((p_data->data_type != bus_data_type_bytes) || (pTmp == NULL)) { + wifi_util_error_print(WIFI_EM, "%s:%d Wrong bus data_type:%x or null data\n", + __func__, __LINE__, p_data->data_type); + return bus_error_invalid_input; + } + + if (p_data->raw_data_len != sizeof(bh_steering_req_t)) { + wifi_util_error_print(WIFI_EM, + "%s:%d Invalid raw_data_len %u, expected %zu\n", + __func__, __LINE__, p_data->raw_data_len, sizeof(bh_steering_req_t)); + return bus_error_invalid_input; + } + + wifi_util_info_print(WIFI_EM, "%s:%d Pushing event to ctrl queue (len=%u)\n", + __func__, __LINE__, p_data->raw_data_len); + push_event_to_ctrl_queue(pTmp, p_data->raw_data_len, wifi_event_type_command, + wifi_event_type_backhaul_steer, NULL); + + return bus_error_success; +} + void handle_em_command_event(wifi_app_t *app, wifi_event_t *event) { switch (event->sub_type) { @@ -2293,6 +2430,11 @@ void handle_em_command_event(wifi_app_t *app, wifi_event_t *event) case wifi_event_type_toggle_disconn_steady_state: em_toggle_disconn_steady_state(event->u.core_data.msg, event->u.core_data.len); break; + + case wifi_event_type_backhaul_steer: + em_handle_backhaul_steer(event->u.core_data.msg, event->u.core_data.len); + break; + default: break; } @@ -2706,6 +2848,9 @@ int em_init(wifi_app_t *app, unsigned int create_flag) { bus_data_type_string, false, 0, 0, 0, NULL } }, { WIFI_EM_CLIENT_ASSOC_CTRL_REQ, bus_element_type_method, { NULL, controller_set_client_acl_rules, NULL, NULL, NULL, NULL }, slow_speed, ZERO_TABLE, + { bus_data_type_bytes, true, 0, 0, 0, NULL } }, + { WIFI_EM_BACKHAUL_STEER, bus_element_type_method, + { NULL, em_backhaul_steer, NULL, NULL, NULL, NULL}, slow_speed, ZERO_TABLE, { bus_data_type_bytes, true, 0, 0, 0, NULL } } }; diff --git a/source/apps/em/wifi_em.h b/source/apps/em/wifi_em.h index 1598b8510..7e7cd299d 100644 --- a/source/apps/em/wifi_em.h +++ b/source/apps/em/wifi_em.h @@ -33,6 +33,7 @@ extern "C" { #define WIFI_SET_DISCONN_STEADY_STATE "Device.WiFi.EM.SetDisconnSteadyState" #define WIFI_SET_DISCONN_SCAN_NONE_STATE "Device.WiFi.EM.SetDisconnScanNoneState" #define WIFI_EM_CLIENT_ASSOC_CTRL_REQ "Device.WiFi.EM.ClientAssocCtrlRequest" +#define WIFI_EM_BACKHAUL_STEER "Device.WiFi.EM.BackhaulSteer" typedef struct wifi_app wifi_app_t; diff --git a/source/core/wifi_ctrl_queue_handlers.c b/source/core/wifi_ctrl_queue_handlers.c index a820d5441..c7487ba07 100644 --- a/source/core/wifi_ctrl_queue_handlers.c +++ b/source/core/wifi_ctrl_queue_handlers.c @@ -4239,7 +4239,8 @@ void handle_command_event(wifi_ctrl_t *ctrl, void *data, unsigned int len, case wifi_event_type_stop_inst_msmt: case wifi_event_type_xfinity_rrm: case wifi_event_type_sm_app_enable: - // not handle here + case wifi_event_type_backhaul_steer: + // not handled here, forwarded to apps break; default: wifi_util_error_print(WIFI_CTRL, "[%s]:WIFI hal handler not supported this event %s\r\n", diff --git a/source/core/wifi_events.c b/source/core/wifi_events.c index d111b4fc8..07391fc4d 100644 --- a/source/core/wifi_events.c +++ b/source/core/wifi_events.c @@ -153,6 +153,7 @@ const char *wifi_event_subtype_to_string(wifi_event_subtype_t type) DOC2S(wifi_event_type_rsn_override_rfc) DOC2S(wifi_event_type_sta_client_info) DOC2S(wifi_event_type_sm_app_enable) + DOC2S(wifi_event_type_backhaul_steer) DOC2S(wifi_event_command_max) DOC2S(wifi_event_monitor_diagnostics) DOC2S(wifi_event_monitor_connect)