From: Kavita Kavita Date: Tue, 16 Jul 2024 06:28:35 +0000 (+0530) Subject: SCS: Renegotiate configured SCS policies with new AP after roaming X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1adffc2003ff4fd7a3f829d14b0fda6c07a27f1d;p=thirdparty%2Fhostap.git SCS: Renegotiate configured SCS policies with new AP after roaming After STA roams to a new AP, previously configured SCS policies were not automatically reapplied, as neither IEEE 802.11 nor WFA mandates policy persistence across roaming events. However, it can be better for real use cases to maintain the same configuration whenever possible. Furthermore, the previously negotiated SCS session might still appear to be active in wpa_supplicant status after roaming even when it was not really in use anymore. Ensures that active SCS rules are retriggered post-roaming to maintain the agreed QoS levels, preserving consistent performance. Co-developed-by: Purushottam Kushwaha Signed-off-by: Purushottam Kushwaha Signed-off-by: Kavita Kavita --- diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index b9b6371c2..d388f31ff 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -433,6 +433,7 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) wpa_s->wps_scan_done = false; wpas_reset_mlo_info(wpa_s); + wpas_scs_deinit(wpa_s); #ifdef CONFIG_SME wpa_s->sme.bss_max_idle_period = 0; @@ -6320,6 +6321,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, "Ignore unexpected EVENT_ASSOC in disconnected state"); break; } + if (dl_list_len(&wpa_s->active_scs_ids) > 0) { + wpa_printf(MSG_DEBUG, + "SCS rules renegotiation required after roaming"); + wpa_s->scs_reconfigure = true; + } wpa_supplicant_event_assoc(wpa_s, data); wpa_s->assoc_status_code = WLAN_STATUS_SUCCESS; if (data && diff --git a/wpa_supplicant/robust_av.c b/wpa_supplicant/robust_av.c index b4d46e3f6..318fdf4ba 100644 --- a/wpa_supplicant/robust_av.c +++ b/wpa_supplicant/robust_av.c @@ -263,6 +263,51 @@ end: } +static int populate_type10_classifier_data(const struct tclas_element *src, + struct tclas_element *dst, + unsigned int num_tclas_elem) +{ + struct type10_params *t10_param; + unsigned int i; + size_t filter_len; + + if (!src) + return 0; + + if (!dst) + return -1; + + for (i = 0; i < num_tclas_elem; i++, src++, dst++) { + if (src->classifier_type != 10) + continue; + + filter_len = src->frame_classifier.type10_param.filter_len; + if (!filter_len) + continue; + + t10_param = &dst->frame_classifier.type10_param; + t10_param->filter_value = os_memdup( + src->frame_classifier.type10_param.filter_value, + filter_len); + if (!t10_param->filter_value) + return -1; + + t10_param->filter_mask = os_memdup( + src->frame_classifier.type10_param.filter_mask, + filter_len); + if (!t10_param->filter_mask) { + os_free(t10_param->filter_value); + t10_param->filter_value = NULL; + return -1; + } + + t10_param->filter_len = filter_len; + } + + return 0; +} + + int wpas_send_mscs_req(struct wpa_supplicant *wpa_s) { struct wpabuf *buf; @@ -471,6 +516,16 @@ static struct wpabuf * allocate_scs_buf(struct scs_desc_elem *desc_elem, } +static void scs_cleanup_descriptors(struct active_scs_elem *scs_elem) +{ + if (!scs_elem) + return; + dl_list_del(&scs_elem->list); + free_up_tclas_elem(&scs_elem->desc_elem); + os_free(scs_elem); +} + + static void scs_request_timer(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; @@ -497,10 +552,9 @@ static void scs_request_timer(void *eloop_ctx, void *timeout_ctx) " SCSID=%u status_code=timedout", MAC2STR(src), scs_desc->scs_id); - dl_list_del(&scs_desc->list); wpa_printf(MSG_INFO, "%s: SCSID %d removed after timeout", __func__, scs_desc->scs_id); - os_free(scs_desc); + scs_cleanup_descriptors(scs_desc); } eloop_cancel_timeout(scs_request_timer, wpa_s, NULL); @@ -508,17 +562,19 @@ static void scs_request_timer(void *eloop_ctx, void *timeout_ctx) } -int wpas_send_scs_req(struct wpa_supplicant *wpa_s) +static int _wpa_send_scs_req(struct wpa_supplicant *wpa_s, + struct scs_desc_elem *desc_elem, + unsigned int num_scs_desc) { struct wpabuf *buf = NULL; - struct scs_desc_elem *desc_elem = NULL; const struct ieee80211_eht_capabilities *eht; const u8 *eht_ie; int ret = -1; unsigned int i; bool allow_scs_traffic_desc = false; - if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) + if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid || + !desc_elem) return -1; if (!wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_SCS)) { @@ -527,10 +583,6 @@ int wpas_send_scs_req(struct wpa_supplicant *wpa_s) return -1; } - desc_elem = wpa_s->scs_robust_av_req.scs_desc_elems; - if (!desc_elem) - return -1; - if (wpa_is_non_eht_scs_traffic_desc_supported(wpa_s->current_bss)) allow_scs_traffic_desc = true; @@ -550,9 +602,7 @@ int wpas_send_scs_req(struct wpa_supplicant *wpa_s) return -1; } - buf = allocate_scs_buf(desc_elem, - wpa_s->scs_robust_av_req.num_scs_desc, - allow_scs_traffic_desc); + buf = allocate_scs_buf(desc_elem, num_scs_desc, allow_scs_traffic_desc); if (!buf) return -1; @@ -563,8 +613,7 @@ int wpas_send_scs_req(struct wpa_supplicant *wpa_s) wpa_s->scs_dialog_token++; wpabuf_put_u8(buf, wpa_s->scs_dialog_token); - for (i = 0; i < wpa_s->scs_robust_av_req.num_scs_desc; - i++, desc_elem++) { + for (i = 0; i < num_scs_desc; i++, desc_elem++) { /* SCS Descriptor element */ if (wpas_populate_scs_descriptor_ie(desc_elem, buf, allow_scs_traffic_desc) < 0) @@ -581,34 +630,151 @@ int wpas_send_scs_req(struct wpa_supplicant *wpa_s) goto end; } + /* + * Register a timeout after which this request will be removed from + * the cache. + */ + eloop_register_timeout(SCS_RESP_TIMEOUT, 0, scs_request_timer, wpa_s, + NULL); + wpa_s->ongoing_scs_req = true; + +end: + wpabuf_free(buf); + return ret; +} + + +int wpas_scs_reconfigure(struct wpa_supplicant *wpa_s) +{ + struct scs_desc_elem *desc_elems, *desc_data, desc_elem; + struct active_scs_elem *scs_desc; + unsigned int num_scs_desc; + unsigned int i; + unsigned int num_tclas_elem; + int ret = -1; + + if (!wpa_s->scs_reconfigure) + return 0; + + num_scs_desc = dl_list_len(&wpa_s->active_scs_ids); + if (!num_scs_desc) + return 0; + + desc_elems = os_calloc(num_scs_desc, sizeof(struct scs_desc_elem)); + if (!desc_elems) { + wpa_printf(MSG_ERROR, "SCS: Failed to allocate memory"); + return ret; + } + + num_scs_desc = 0; + dl_list_for_each(scs_desc, &wpa_s->active_scs_ids, + struct active_scs_elem, list) { + os_memcpy(&desc_elem, &scs_desc->desc_elem, sizeof(desc_elem)); + + num_tclas_elem = scs_desc->desc_elem.num_tclas_elem; + if (num_tclas_elem) { + desc_elem.tclas_elems = + os_memdup(scs_desc->desc_elem.tclas_elems, + num_tclas_elem * + sizeof(struct tclas_element)); + if (!desc_elem.tclas_elems) + goto end; + + if (populate_type10_classifier_data( + scs_desc->desc_elem.tclas_elems, + desc_elem.tclas_elems, + num_tclas_elem) < 0) { + free_up_tclas_elem(&desc_elem); + goto end; + } + } + + os_memcpy(&desc_elems[num_scs_desc], &desc_elem, + sizeof(desc_elem)); + num_scs_desc++; + } + + if (_wpa_send_scs_req(wpa_s, desc_elems, num_scs_desc) < 0) { + wpa_printf(MSG_DEBUG, + "SCS: Failed to reconfigure SCS requests - retain for next roaming"); + } else { + dl_list_for_each(scs_desc, &wpa_s->active_scs_ids, + struct active_scs_elem, list) + scs_desc->status = SCS_DESC_SENT; + } + ret = 0; +end: + wpa_s->scs_reconfigure = false; + + if (desc_elems) { + desc_data = desc_elems; + for (i = 0; i < num_scs_desc; i++, desc_data++) { + if (desc_data->tclas_elems) + free_up_tclas_elem(desc_data); + } + os_free(desc_elems); + } + + return ret; +} + + +int wpas_send_scs_req(struct wpa_supplicant *wpa_s) +{ + struct scs_desc_elem *desc_elem = NULL; + int ret = -1; + unsigned int i; + + if (_wpa_send_scs_req(wpa_s, wpa_s->scs_robust_av_req.scs_desc_elems, + wpa_s->scs_robust_av_req.num_scs_desc) < 0) + goto end; + desc_elem = wpa_s->scs_robust_av_req.scs_desc_elems; + for (i = 0; i < wpa_s->scs_robust_av_req.num_scs_desc; i++, desc_elem++) { struct active_scs_elem *active_scs_elem; + struct tclas_element *tclas_elem; + unsigned int num_tclas_elem = desc_elem->num_tclas_elem; if (desc_elem->request_type != SCS_REQ_ADD) continue; - active_scs_elem = os_malloc(sizeof(struct active_scs_elem)); + active_scs_elem = os_zalloc(sizeof(struct active_scs_elem)); if (!active_scs_elem) break; + + os_memcpy(&active_scs_elem->desc_elem, desc_elem, + sizeof(struct scs_desc_elem)); + + if (num_tclas_elem) { + tclas_elem = os_memdup(desc_elem->tclas_elems, + num_tclas_elem * + sizeof(struct tclas_element)); + if (!tclas_elem) { + os_free(active_scs_elem); + goto end; + } + + active_scs_elem->desc_elem.tclas_elems = tclas_elem; + + if (populate_type10_classifier_data( + desc_elem->tclas_elems, tclas_elem, + num_tclas_elem) < 0) { + free_up_tclas_elem(&active_scs_elem->desc_elem); + os_free(active_scs_elem); + goto end; + } + } + active_scs_elem->scs_id = desc_elem->scs_id; active_scs_elem->status = SCS_DESC_SENT; dl_list_add(&wpa_s->active_scs_ids, &active_scs_elem->list); } - - /* - * Register a timeout after which this request will be removed from - * the cache. - */ - eloop_register_timeout(SCS_RESP_TIMEOUT, 0, scs_request_timer, wpa_s, - NULL); - wpa_s->ongoing_scs_req = true; + ret = 0; /* Success */ end: - wpabuf_free(buf); free_up_scs_desc(&wpa_s->scs_robust_av_req); - return ret; } @@ -895,12 +1061,10 @@ void wpas_handle_robust_av_scs_recv_action(struct wpa_supplicant *wpa_s, continue; } - if (status != WLAN_STATUS_SUCCESS) { - dl_list_del(&scs_desc->list); - os_free(scs_desc); - } else if (status == WLAN_STATUS_SUCCESS) { + if (status == WLAN_STATUS_SUCCESS) scs_desc->status = SCS_DESC_SUCCESS; - } + else + scs_cleanup_descriptors(scs_desc); wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCS_RESULT "bssid=" MACSTR " SCSID=%u status_code=%u", MAC2STR(src), id, status); @@ -916,8 +1080,7 @@ void wpas_handle_robust_av_scs_recv_action(struct wpa_supplicant *wpa_s, WPA_EVENT_SCS_RESULT "bssid=" MACSTR " SCSID=%u status_code=response_not_received", MAC2STR(src), scs_desc->scs_id); - dl_list_del(&scs_desc->list); - os_free(scs_desc); + scs_cleanup_descriptors(scs_desc); } } } @@ -929,8 +1092,7 @@ static void wpas_clear_active_scs_ids(struct wpa_supplicant *wpa_s) while ((scs_elem = dl_list_first(&wpa_s->active_scs_ids, struct active_scs_elem, list))) { - dl_list_del(&scs_elem->list); - os_free(scs_elem); + scs_cleanup_descriptors(scs_elem); } } @@ -942,6 +1104,7 @@ void wpas_scs_deinit(struct wpa_supplicant *wpa_s) wpas_clear_active_scs_ids(wpa_s); eloop_cancel_timeout(scs_request_timer, wpa_s, NULL); wpa_s->ongoing_scs_req = false; + wpa_s->scs_reconfigure = false; } diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 65e9e90bc..1114b3b25 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1277,6 +1277,12 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, } wpa_s->wpa_state = state; +#ifndef CONFIG_NO_ROBUST_AV + if (state == WPA_COMPLETED && dl_list_len(&wpa_s->active_scs_ids) && + wpa_s->scs_reconfigure) + wpas_scs_reconfigure(wpa_s); +#endif /* CONFIG_NO_ROBUST_AV */ + #ifdef CONFIG_BGSCAN if (state == WPA_COMPLETED && wpa_s->current_ssid != wpa_s->bgscan_ssid) wpa_supplicant_reset_bgscan(wpa_s); diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 3f86182fa..2f77413d5 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -650,6 +650,7 @@ struct active_scs_elem { struct dl_list list; u8 scs_id; enum scs_response_status status; + struct scs_desc_elem desc_elem; }; @@ -1628,6 +1629,8 @@ struct wpa_supplicant { u64 first_beacon_tsf; unsigned int beacons_checked; unsigned int next_beacon_check; + + bool scs_reconfigure; }; @@ -2000,6 +2003,7 @@ void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s, void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid, const u8 *ies, size_t ies_len); int wpas_send_scs_req(struct wpa_supplicant *wpa_s); +int wpas_scs_reconfigure(struct wpa_supplicant *wpa_s); void free_up_tclas_elem(struct scs_desc_elem *elem); void free_up_scs_desc(struct scs_robust_av_data *data); void wpas_handle_robust_av_scs_recv_action(struct wpa_supplicant *wpa_s,