diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index 3e6eba22aa..2bf0b5ea10 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -3865,6 +3865,7 @@ struct sir_nss_update_request { * @REASON_COLOR_CHANGE: Color change * @REASON_CHANNEL_SWITCH: channel switch * @REASON_MLO_IE_UPDATE: mlo ie update + * @REASON_RNR_UPDATE: SAP is changed, notify co-located SAP */ enum sir_bcn_update_reason { REASON_DEFAULT = 0, @@ -3874,6 +3875,7 @@ enum sir_bcn_update_reason { REASON_COLOR_CHANGE = 4, REASON_CHANNEL_SWITCH = 5, REASON_MLO_IE_UPDATE = 6, + REASON_RNR_UPDATE = 7, }; /** diff --git a/core/mac/src/include/parser_api.h b/core/mac/src/include/parser_api.h index 0ce54051aa..bca5fa8c56 100644 --- a/core/mac/src/include/parser_api.h +++ b/core/mac/src/include/parser_api.h @@ -1609,4 +1609,31 @@ dot11f_parse_assoc_rsp_mlo_partner_info(struct pe_session *pe_session, { } #endif + +/** + * populate_dot11f_6g_rnr() - populate rnr with 6g bss information + * @mac_ctx: MAC context + * @session: reporting session + * @dot11f: pointer to tDot11fIEreduced_neighbor_report to fill + * + * Return: none + */ +void populate_dot11f_6g_rnr(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEreduced_neighbor_report *dot11f); + +/** + * populate_dot11f_rnr_tbtt_info_7() - populate rnr with tbtt_info length 7 + * @mac_ctx: pointer to mac_context + * @pe_session: pe session + * @rnr_session: session to populate in rnr ie + * @dot11f: tDot11fIEreduced_neighbor_report to be filled + * + * Return: none + */ +void populate_dot11f_rnr_tbtt_info_7(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct pe_session *rnr_session, + tDot11fIEreduced_neighbor_report *dot11f); + #endif /* __PARSE_H__ */ diff --git a/core/mac/src/pe/lim/lim_utils.c b/core/mac/src/pe/lim/lim_utils.c index fef0a22b76..2cfade310c 100644 --- a/core/mac/src/pe/lim/lim_utils.c +++ b/core/mac/src/pe/lim/lim_utils.c @@ -9318,6 +9318,63 @@ QDF_STATUS lim_ap_mlme_vdev_up_send(struct vdev_mlme_obj *vdev_mlme, return status; } +QDF_STATUS lim_ap_mlme_vdev_rnr_notify(struct pe_session *session) +{ + struct mac_context *mac_ctx; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + qdf_freq_t freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t vdev_num; + uint8_t i; + struct pe_session *co_session; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + pe_err("mac ctx is null"); + return QDF_STATUS_E_INVAL; + } + if (!session) { + pe_err("session is NULL"); + return QDF_STATUS_E_INVAL; + } + if (!mlme_is_notify_co_located_ap_update_rnr(session->vdev)) + return status; + mlme_set_notify_co_located_ap_update_rnr(session->vdev, false); + // Only 6G SAP need to notify co-located SAP to add RNR + if (!wlan_reg_is_6ghz_chan_freq(session->curr_op_freq)) + return status; + pe_debug("vdev id %d non mlo 6G AP notify co-located AP to update RNR", + wlan_vdev_get_id(session->vdev)); + vdev_num = policy_mgr_get_mode_specific_conn_info( + mac_ctx->psoc, freq_list, vdev_id_list, + PM_SAP_MODE); + for (i = 0; i < vdev_num; i++) { + if (vdev_id_list[i] == session->vdev_id) + continue; + if (wlan_reg_is_6ghz_chan_freq(freq_list[i])) + continue; + co_session = pe_find_session_by_vdev_id(mac_ctx, + vdev_id_list[i]); + if (!co_session) + continue; + + status = sch_set_fixed_beacon_fields(mac_ctx, co_session); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Unable to update 6g co located RNR in beacon"); + return status; + } + + status = lim_send_beacon_ind(mac_ctx, co_session, + REASON_RNR_UPDATE); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Unable to send beacon indication"); + return status; + } + } + + return status; +} + QDF_STATUS lim_ap_mlme_vdev_disconnect_peers(struct vdev_mlme_obj *vdev_mlme, uint16_t data_len, void *data) { @@ -9356,6 +9413,10 @@ QDF_STATUS lim_ap_mlme_vdev_stop_send(struct vdev_mlme_obj *vdev_mlme, return QDF_STATUS_E_INVAL; } + if (!wlan_vdev_mlme_is_mlo_ap(vdev_mlme->vdev)) { + mlme_set_notify_co_located_ap_update_rnr(vdev_mlme->vdev, true); + lim_ap_mlme_vdev_rnr_notify(session); + } status = lim_send_vdev_stop(session); return status; diff --git a/core/mac/src/pe/lim/lim_utils.h b/core/mac/src/pe/lim/lim_utils.h index 2540b2757f..994e9960b2 100644 --- a/core/mac/src/pe/lim/lim_utils.h +++ b/core/mac/src/pe/lim/lim_utils.h @@ -2448,6 +2448,15 @@ QDF_STATUS lim_sap_move_to_cac_wait_state(struct pe_session *session); */ void lim_disconnect_complete(struct pe_session *session, bool del_bss); +/** + * lim_ap_mlme_vdev_rnr_notify() - SAP is changed, notify co-located sap to + * update RNR IE + * @session: PE session pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_ap_mlme_vdev_rnr_notify(struct pe_session *session); + /** * lim_sta_mlme_vdev_stop_send() - send VDEV stop * @vdev_mlme_obj: VDEV MLME comp object diff --git a/core/mac/src/pe/sch/sch_api.c b/core/mac/src/pe/sch/sch_api.c index ea38ca55af..7b645884ff 100644 --- a/core/mac/src/pe/sch/sch_api.c +++ b/core/mac/src/pe/sch/sch_api.c @@ -202,6 +202,8 @@ QDF_STATUS sch_send_beacon_req(struct mac_context *mac, uint8_t *beaconPayload, if (QDF_IS_STATUS_SUCCESS(retCode)) { if (wlan_vdev_mlme_is_mlo_ap(pe_session->vdev)) lim_notify_link_info(pe_session); + else + lim_ap_mlme_vdev_rnr_notify(pe_session); } return retCode; diff --git a/core/mac/src/pe/sch/sch_beacon_gen.c b/core/mac/src/pe/sch/sch_beacon_gen.c index 5e2c3d7c7e..5e51c15f3e 100644 --- a/core/mac/src/pe/sch/sch_beacon_gen.c +++ b/core/mac/src/pe/sch/sch_beacon_gen.c @@ -810,6 +810,14 @@ sch_set_fixed_beacon_fields(struct mac_context *mac_ctx, struct pe_session *sess populate_dot11f_mlo_rnr( mac_ctx, session, &bcn_2->reduced_neighbor_report); + } else if (!wlan_reg_is_6ghz_chan_freq(session->curr_op_freq)) { + /* + * TD: If current AP is MLO, RNR IE is already populated + * More effor to populate RNR IE for + * MLO SAP + 6G legacy SAP + */ + populate_dot11f_6g_rnr(mac_ctx, session, + &bcn_2->reduced_neighbor_report); } /* * Can be efficiently updated whenever new IE added in Probe diff --git a/core/mac/src/sys/legacy/src/utils/src/parser_api.c b/core/mac/src/sys/legacy/src/utils/src/parser_api.c index 37aea6a485..b2412dd6be 100644 --- a/core/mac/src/sys/legacy/src/utils/src/parser_api.c +++ b/core/mac/src/sys/legacy/src/utils/src/parser_api.c @@ -8865,4 +8865,122 @@ QDF_STATUS populate_dot11f_assoc_req_mlo_ie(struct mac_context *mac_ctx, return QDF_STATUS_SUCCESS; } #endif + +void populate_dot11f_rnr_tbtt_info_7(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct pe_session *rnr_session, + tDot11fIEreduced_neighbor_report *dot11f) +{ + uint8_t reg_class; + uint8_t ch_offset; + + dot11f->present = 1; + dot11f->tbtt_type = 0; + if (rnr_session->ch_width == CH_WIDTH_80MHZ) { + ch_offset = BW80; + } else { + switch (rnr_session->htSecondaryChannelOffset) { + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + ch_offset = BW40_HIGH_PRIMARY; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + ch_offset = BW40_LOW_PRIMARY; + break; + default: + ch_offset = BW20; + break; + } + } + + reg_class = lim_op_class_from_bandwidth(mac_ctx, + rnr_session->curr_op_freq, + rnr_session->ch_width, + ch_offset); + + dot11f->op_class = reg_class; + dot11f->channel_num = wlan_reg_freq_to_chan(mac_ctx->pdev, + rnr_session->curr_op_freq); + dot11f->tbtt_info_count = 0; + dot11f->tbtt_info_len = 7; + dot11f->tbtt_info.tbtt_info_7.tbtt_offset = + WLAN_RNR_TBTT_OFFSET_INVALID; + qdf_mem_copy(dot11f->tbtt_info.tbtt_info_7.bssid, + rnr_session->self_mac_addr, sizeof(tSirMacAddr)); +} + +/** + * lim_is_6g_vdev() - loop every vdev to populate 6g vdev id + * @psoc: pointer to psoc + * @obj: vdev + * @args: vdev list to record 6G vdev id + * + * Return: void + */ +static void lim_is_6g_vdev(struct wlan_objmgr_psoc *psoc, void *obj, void *args) +{ + struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)obj; + uint8_t *vdev_id_list = (uint8_t *)args; + int i; + + if (!vdev || (wlan_vdev_mlme_get_opmode(vdev) != QDF_SAP_MODE)) + return; + if (QDF_IS_STATUS_ERROR(wlan_vdev_chan_config_valid(vdev))) + return; + if (!wlan_reg_is_6ghz_chan_freq(wlan_get_operation_chan_freq(vdev))) + return; + + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (vdev_id_list[i] == INVALID_VDEV_ID) { + vdev_id_list[i] = wlan_vdev_get_id(vdev); + break; + } + } +} + +void populate_dot11f_6g_rnr(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEreduced_neighbor_report *dot11f) +{ + struct pe_session *co_session; + struct wlan_objmgr_psoc *psoc; + int vdev_id; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + + if (!session || !mac_ctx || !dot11f || !session->vdev) { + pe_err("Invalid params"); + return; + } + + psoc = wlan_vdev_get_psoc(session->vdev); + if (!psoc) { + pe_err("Invalid psoc"); + return; + } + + for (vdev_id = 0; vdev_id < MAX_NUMBER_OF_CONC_CONNECTIONS; vdev_id++) + vdev_id_list[vdev_id] = INVALID_VDEV_ID; + + wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, + lim_is_6g_vdev, + vdev_id_list, 1, + WLAN_LEGACY_MAC_ID); + + if (vdev_id_list[0] == INVALID_VDEV_ID) { + pe_debug("vdev id %d no 6G vdev, no need to populate RNR IE", + wlan_vdev_get_id(session->vdev)); + return; + } + + co_session = pe_find_session_by_vdev_id(mac_ctx, + vdev_id_list[0]); + if (!co_session) { + pe_err("Invalid co located session"); + return; + } + populate_dot11f_rnr_tbtt_info_7(mac_ctx, session, co_session, dot11f); + pe_debug("vdev id %d populate RNR IE with 6G vdev id %d op class %d chan num %d", + wlan_vdev_get_id(session->vdev), + wlan_vdev_get_id(co_session->vdev), + dot11f->op_class, dot11f->channel_num); +} /* parser_api.c ends here. */