diff --git a/core/mac/inc/ani_global.h b/core/mac/inc/ani_global.h index 7cd8b1cbc2..f81f28fe91 100644 --- a/core/mac/inc/ani_global.h +++ b/core/mac/inc/ani_global.h @@ -828,7 +828,7 @@ typedef struct sAniSirLim { uint8_t scan_disabled; uint8_t beacon_probe_rsp_cnt_per_scan; wlan_scan_requester req_id; - uint8_t obss_detection_offloaded; + bool global_obss_offload_enabled; } tAniSirLim, *tpAniSirLim; struct mgmt_frm_reg_info { diff --git a/core/mac/src/pe/include/lim_session.h b/core/mac/src/pe/include/lim_session.h index ca3b506bf4..a13007c499 100644 --- a/core/mac/src/pe/include/lim_session.h +++ b/core/mac/src/pe/include/lim_session.h @@ -115,6 +115,7 @@ struct bss_color_info { * @obss_ht_legacy_detect_mode: detection mode for ht ap with legacy mode. * @obss_ht_mixed_detect_mode: detection mode for ht ap with mixed mode. * @obss_ht_20mhz_detect_mode: detection mode for ht ap with 20mhz mode. + * @obss_current_detection_masks: current detection masks. */ struct obss_detection_cfg { uint8_t obss_11b_ap_detect_mode; @@ -124,6 +125,7 @@ struct obss_detection_cfg { uint8_t obss_ht_legacy_detect_mode; uint8_t obss_ht_mixed_detect_mode; uint8_t obss_ht_20mhz_detect_mode; + uint32_t obss_current_detection_masks; }; typedef struct sPESession /* Added to Support BT-AMP */ @@ -547,7 +549,8 @@ typedef struct sPESession /* Added to Support BT-AMP */ /* previous auth frame's sequence number */ uint16_t prev_auth_seq_num; struct obss_detection_cfg obss_offload_cfg; - bool enable_obss_detection_offload; + bool is_session_obss_offload_enabled; + bool is_obss_reset_timer_initialized; } tPESession, *tpPESession; /*------------------------------------------------------------------------- diff --git a/core/mac/src/pe/lim/lim_api.c b/core/mac/src/pe/lim/lim_api.c index d3430d5715..112802ebe6 100644 --- a/core/mac/src/pe/lim/lim_api.c +++ b/core/mac/src/pe/lim/lim_api.c @@ -470,7 +470,7 @@ static tSirRetStatus __lim_init_config(tpAniSirGlobal pMac) if (eSIR_SUCCESS != wlan_cfg_get_int(pMac, WNI_CFG_OBSS_DETECTION_OFFLOAD, (uint32_t *)&pMac->lim. - obss_detection_offloaded)) { + global_obss_offload_enabled)) { pe_err("cfg get obss_detection_offloaded failed"); return eSIR_FAILURE; } diff --git a/core/mac/src/pe/lim/lim_assoc_utils.c b/core/mac/src/pe/lim/lim_assoc_utils.c index cadb931744..afb22a2cc0 100644 --- a/core/mac/src/pe/lim/lim_assoc_utils.c +++ b/core/mac/src/pe/lim/lim_assoc_utils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -3087,6 +3087,9 @@ lim_delete_dph_hash_entry(tpAniSirGlobal mac_ctx, tSirMacAddr sta_addr, lim_send_beacon_params(mac_ctx, &beacon_params, session_entry); } + + lim_obss_send_detection_cfg(mac_ctx, session_entry, false); + #ifdef WLAN_FEATURE_11W if (sta_ds->rmfEnabled) { pe_debug("delete pmf timer sta-idx:%d assoc-id:%d", diff --git a/core/mac/src/pe/lim/lim_process_message_queue.c b/core/mac/src/pe/lim/lim_process_message_queue.c index cf7b7316e1..33029619cc 100644 --- a/core/mac/src/pe/lim/lim_process_message_queue.c +++ b/core/mac/src/pe/lim/lim_process_message_queue.c @@ -1901,6 +1901,7 @@ static void lim_process_messages(tpAniSirGlobal mac_ctx, msg->bodyptr = NULL; break; case WMA_OBSS_DETECTION_INFO: + lim_process_obss_detection_ind(mac_ctx, msg->bodyptr); qdf_mem_free(msg->bodyptr); msg->bodyptr = NULL; break; diff --git a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c index 6697ebc456..7977e1bc14 100644 --- a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c +++ b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c @@ -255,6 +255,7 @@ void lim_process_mlm_start_cnf(tpAniSirGlobal pMac, uint32_t *pMsgBuf) psessionEntry->ssId.ssId, psessionEntry->currentOperChannel); lim_send_beacon_ind(pMac, psessionEntry); + lim_enable_obss_detection_config (pMac, psessionEntry); } } } diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c index bd18c76fab..e28321e326 100644 --- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -5072,6 +5072,7 @@ static void lim_process_sme_start_beacon_req(tpAniSirGlobal pMac, uint32_t *pMsg psessionEntry->ssId.ssId, psessionEntry->currentOperChannel); lim_send_beacon_ind(pMac, psessionEntry); + lim_enable_obss_detection_config(pMac, psessionEntry); } else { pe_err("Invalid Beacon Start Indication"); return; diff --git a/core/mac/src/pe/lim/lim_send_management_frames.c b/core/mac/src/pe/lim/lim_send_management_frames.c index 0c6b5ec841..1736feeb83 100644 --- a/core/mac/src/pe/lim/lim_send_management_frames.c +++ b/core/mac/src/pe/lim/lim_send_management_frames.c @@ -1323,6 +1323,8 @@ lim_send_assoc_rsp_mgmt_frame(tpAniSirGlobal mac_ctx, lim_send_beacon_params(mac_ctx, &beacon_params, pe_session); } + lim_obss_send_detection_cfg(mac_ctx, pe_session, false); + if (assoc_req != NULL) { addn_ie_len = pe_session->addIeParams.assocRespDataLen; diff --git a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c index 10c6755dd2..13f72e613f 100644 --- a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c +++ b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c @@ -2492,6 +2492,8 @@ lim_send_sme_ap_channel_switch_resp(tpAniSirGlobal pMac, pe_debug("Failed to Transmit Beacons on channel: %d after AP channel change response", psessionEntry->bcnLen); } + + lim_obss_send_detection_cfg(pMac, psessionEntry, true); } return; } diff --git a/core/mac/src/pe/lim/lim_session.c b/core/mac/src/pe/lim/lim_session.c index 9eccb56d89..9f7460b632 100644 --- a/core/mac/src/pe/lim/lim_session.c +++ b/core/mac/src/pe/lim/lim_session.c @@ -515,18 +515,20 @@ pe_create_session(tpAniSirGlobal pMac, uint8_t *bssid, uint8_t *sessionId, if (eSIR_INFRA_AP_MODE == bssType) { session_ptr->old_protection_state = 0; + session_ptr->is_session_obss_offload_enabled = false; + session_ptr->is_obss_reset_timer_initialized = false; session_ptr->mac_ctx = (void *)pMac; - status = qdf_mc_timer_init( - &session_ptr->protection_fields_reset_timer, - QDF_TIMER_TYPE_SW, pe_reset_protection_callback, - (void *)&pMac->lim.gpSession[i]); - if (status == QDF_STATUS_SUCCESS) { - status = qdf_mc_timer_start( - &session_ptr->protection_fields_reset_timer, - SCH_PROTECTION_RESET_TIME); - } - if (status != QDF_STATUS_SUCCESS) - pe_err("cannot create or start protectionFieldsResetTimer"); + + status = qdf_mc_timer_init(&session_ptr-> + protection_fields_reset_timer, + QDF_TIMER_TYPE_SW, + pe_reset_protection_callback, + (void *)&pMac->lim.gpSession[i]); + + if (QDF_IS_STATUS_ERROR(status)) + pe_err("cannot create protection fields reset timer"); + else + session_ptr->is_obss_reset_timer_initialized = true; } pe_init_fils_info(session_ptr); pe_init_pmf_comeback_timer(pMac, session_ptr, *sessionId); diff --git a/core/mac/src/pe/lim/lim_utils.c b/core/mac/src/pe/lim/lim_utils.c index 899ba12e28..7710d9d951 100644 --- a/core/mac/src/pe/lim/lim_utils.c +++ b/core/mac/src/pe/lim/lim_utils.c @@ -1041,6 +1041,10 @@ void lim_handle_update_olbc_cache(tpAniSirGlobal mac_ctx) return; } + if (psessionEntry->is_session_obss_offload_enabled) { + pe_debug("protection offloaded"); + return; + } qdf_mem_set((uint8_t *) &beaconParams, sizeof(tUpdateBeaconParams), 0); beaconParams.bssIdx = psessionEntry->bssIdx; diff --git a/core/mac/src/pe/lim/lim_utils.h b/core/mac/src/pe/lim/lim_utils.h index 12d28ed747..2b02a39037 100644 --- a/core/mac/src/pe/lim/lim_utils.h +++ b/core/mac/src/pe/lim/lim_utils.h @@ -71,6 +71,43 @@ typedef enum { #define MGMT_RX_PACKETS_THRESHOLD 200 +/* 11B AP detection bit position */ +#define OBSS_DETECTION_11B_AP_BIT_MASK 0x0001 +/* 11B STA detection bit position */ +#define OBSS_DETECTION_11B_STA_BIT_MASK 0x0002 +/* 11G AP detection bit position */ +#define OBSS_DETECTION_11G_AP_BIT_MASK 0x0004 +/* 11A AP detection bit position */ +#define OBSS_DETECTION_11A_BIT_MASK 0x0008 +/* HT legacy detection bit position */ +#define OBSS_DETECTION_HT_LEGACY_BIT_MASK 0x0010 +/* HT mixed detection bit position */ +#define OBSS_DETECTION_HT_MIXED_BIT_MASK 0x0020 +/* HT 20mhz detection bit position */ +#define OBSS_DETECTION_HT_20MHZ_BIT_MASK 0x0040 + +/** + * OBSS detection period in ms, used by firmware to decide + * absent detection and also gap between same detection ind. + */ +#define OBSS_DETECTION_PERIOD_MS 4000 + +/* To check if 11B AP detection bit set */ +#define OBSS_DETECTION_IS_11B_AP(_m) ((_m) & OBSS_DETECTION_11B_AP_BIT_MASK) +/* To check if 11B STA detection bit set */ +#define OBSS_DETECTION_IS_11B_STA(_m) ((_m) & OBSS_DETECTION_11B_STA_BIT_MASK) +/* To check if 11G AP detection bit set */ +#define OBSS_DETECTION_IS_11G_AP(_m) ((_m) & OBSS_DETECTION_11G_AP_BIT_MASK) +/* To check if 11A AP detection bit set */ +#define OBSS_DETECTION_IS_11A(_m) ((_m) & OBSS_DETECTION_11A_BIT_MASK) +/* To check if HT legacy detection bit set */ +#define OBSS_DETECTION_IS_HT_LEGACY(_m) \ + ((_m) & OBSS_DETECTION_HT_LEGACY_BIT_MASK) +/* To check if HT mixed detection bit set */ +#define OBSS_DETECTION_IS_HT_MIXED(_m) ((_m) & OBSS_DETECTION_HT_MIXED_BIT_MASK) +/* To check if HT 20mhz detection bit set */ +#define OBSS_DETECTION_IS_HT_20MHZ(_m) ((_m) & OBSS_DETECTION_HT_20MHZ_BIT_MASK) + #ifdef WLAN_FEATURE_11W typedef union uPmfSaQueryTimerId { struct { @@ -1235,4 +1272,60 @@ void lim_send_chan_switch_action_frame(tpAniSirGlobal mac_ctx, uint8_t ch_bandwidth, tpPESession session_entry); +/** + * lim_process_obss_detection_ind() - Process obss detection indication + * @mac_ctx: Pointer to Global MAC structure. + * @obss_detection: obss detection info. + * + * Process obss detection indication and apply necessary protection for + * the given AP session. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_process_obss_detection_ind(tpAniSirGlobal mac_ctx, + struct wmi_obss_detect_info + *obss_detection); + +/** + * lim_obss_send_detection_cfg() - Send obss detection configuration to firmware + * @mac_ctx: Pointer to Global MAC structure + * @session: Pointer to session + * @force: Force to send new configuration even if new cfg same as old + * + * Generate new cfg based on current protection status and send new cfg to + * firmware. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_obss_send_detection_cfg(tpAniSirGlobal mac_ctx, + tpPESession session, + bool force); + +/** + * lim_obss_generate_detection_config() - get new obss offload detection cfg + * @mac_ctx: Pointer to Global MAC structure + * @session: Pointer to session + * @cfg: Obss detection cfg buffer pointer + * + * Generate new cfg based on current protection status. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_obss_generate_detection_config(tpAniSirGlobal mac_ctx, + tpPESession session, + struct obss_detection_cfg *cfg); + +/** + * lim_enable_obss_detection_config() - Enable obss detection + * @mac_ctx: Pointer to Global MAC structure + * @session: Pointer to session + * + * This function will enable legacy obss detection (by starting timer) + * or also offload based detection based on support. + * + * Return: None + */ +void lim_enable_obss_detection_config(tpAniSirGlobal mac_ctx, + tpPESession session); + #endif /* __LIM_UTILS_H */ diff --git a/core/mac/src/pe/sch/sch_beacon_process.c b/core/mac/src/pe/sch/sch_beacon_process.c index df819d40ea..e988305261 100644 --- a/core/mac/src/pe/sch/sch_beacon_process.c +++ b/core/mac/src/pe/sch/sch_beacon_process.c @@ -1057,8 +1057,9 @@ sch_beacon_process(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, sch_check_bss_color_ie(mac_ctx, ap_session, &bcn, &bcn_prm); - if (ap_session->gLimProtectionControl != - WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + if ((ap_session->gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) && + !ap_session->is_session_obss_offload_enabled) ap_beacon_process(mac_ctx, rx_pkt_info, &bcn, &bcn_prm, ap_session); @@ -1187,3 +1188,428 @@ sch_beacon_edca_process(tpAniSirGlobal pMac, tSirMacEdcaParamSetIE *edca, } return eSIR_SUCCESS; } + +void lim_enable_obss_detection_config(tpAniSirGlobal mac_ctx, + tpPESession session) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!session) { + pe_err("Invalid session, protection not enabled"); + return; + } + + if (session->gLimProtectionControl == + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) { + pe_err("protectiond disabled, force policy, session %d", + session->smeSessionId); + return; + } + + if (mac_ctx->lim.global_obss_offload_enabled) { + status = lim_obss_send_detection_cfg(mac_ctx, session, true); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("vdev %d: offload enable failed, trying legacy", + session->smeSessionId); + session->is_session_obss_offload_enabled = false; + } else { + pe_debug("vdev %d: offload detection enabled", + session->smeSessionId); + session->is_session_obss_offload_enabled = true; + lim_obss_send_detection_cfg(mac_ctx, session, true); + } + } + + if (!mac_ctx->lim.global_obss_offload_enabled || + QDF_IS_STATUS_ERROR(status)) { + status = qdf_mc_timer_start(&session-> + protection_fields_reset_timer, + SCH_PROTECTION_RESET_TIME); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("vdev %d: start timer failed", + session->smeSessionId); + else + pe_debug("vdev %d: legacy detection enabled", + session->smeSessionId); + } +} + +QDF_STATUS lim_obss_generate_detection_config(tpAniSirGlobal mac_ctx, + tpPESession session, + struct obss_detection_cfg *cfg) +{ + uint32_t phy_mode; + enum band_info rf_band = BAND_UNKNOWN; + uint32_t detect_masks; + + if (!mac_ctx || !session || !cfg) { + pe_err("Invalid params mac_ctx %pK, session %pK, cfg %pK", + mac_ctx, session, cfg); + return QDF_STATUS_E_INVAL; + } + + lim_get_phy_mode(mac_ctx, &phy_mode, session); + rf_band = session->limRFBand; + qdf_mem_zero(cfg, sizeof(*cfg)); + detect_masks = session->obss_offload_cfg.obss_current_detection_masks; + + pe_debug("band:%d, phy_mode:%d, ht_cap:%d, ht_oper_mode:%d", + rf_band, phy_mode, session->htCapability, + mac_ctx->lim.gHTOperMode); + pe_debug("assoc_sta: 11b:%d, 11g:%d, 11a:%d, ht20:%d", + session->gLim11bParams.protectionEnabled, + session->gLim11gParams.protectionEnabled, + session->gLim11aParams.protectionEnabled, + session->gLimHt20Params.protectionEnabled); + pe_debug("obss: 11b:%d, 11g:%d, 11a:%d, ht20:%d, masks:0x%0x", + session->gLimOlbcParams.protectionEnabled, + session->gLimOverlap11gParams.protectionEnabled, + session->gLimOverlap11aParams.protectionEnabled, + session->gLimOverlapHt20Params.protectionEnabled, + detect_masks); + + if ((rf_band == BAND_2G)) { + if ((phy_mode == WNI_CFG_PHY_MODE_11G || + session->htCapability) && + !session->gLim11bParams.protectionEnabled) { + if (!session->gLimOlbcParams.protectionEnabled && + !session->gLimOverlap11gParams.protectionEnabled) { + cfg->obss_11b_ap_detect_mode = + OBSS_OFFLOAD_DETECTION_PRESENT; + cfg->obss_11b_sta_detect_mode = + OBSS_OFFLOAD_DETECTION_PRESENT; + } else { + if (OBSS_DETECTION_IS_11B_AP(detect_masks)) + cfg->obss_11b_ap_detect_mode = + OBSS_OFFLOAD_DETECTION_ABSENT; + if (OBSS_DETECTION_IS_11B_STA(detect_masks)) + cfg->obss_11b_sta_detect_mode = + OBSS_OFFLOAD_DETECTION_ABSENT; + } + } else if (session->gLim11bParams.protectionEnabled) { + session->gLimOlbcParams.protectionEnabled = false; + } + + if (session->htCapability && + session->cfgProtection.overlapFromllg && + !session->gLim11gParams.protectionEnabled) { + if (!session->gLimOverlap11gParams.protectionEnabled) { + cfg->obss_11g_ap_detect_mode = + OBSS_OFFLOAD_DETECTION_PRESENT; + cfg->obss_ht_legacy_detect_mode = + OBSS_OFFLOAD_DETECTION_PRESENT; + cfg->obss_ht_mixed_detect_mode = + OBSS_OFFLOAD_DETECTION_PRESENT; + } else { + if (OBSS_DETECTION_IS_11G_AP(detect_masks)) + cfg->obss_11g_ap_detect_mode = + OBSS_OFFLOAD_DETECTION_ABSENT; + if (OBSS_DETECTION_IS_HT_LEGACY(detect_masks)) + cfg->obss_ht_legacy_detect_mode = + OBSS_OFFLOAD_DETECTION_ABSENT; + if (OBSS_DETECTION_IS_HT_MIXED(detect_masks)) + cfg->obss_ht_mixed_detect_mode = + OBSS_OFFLOAD_DETECTION_ABSENT; + } + } else if (session->gLim11gParams.protectionEnabled) { + session->gLimOverlap11gParams.protectionEnabled = false; + } + + /* INI related settings */ + if (mac_ctx->roam.configParam.ignore_peer_erp_info) + cfg->obss_11b_sta_detect_mode = + OBSS_OFFLOAD_DETECTION_DISABLED; + + if (mac_ctx->roam.configParam.ignore_peer_ht_opmode) + cfg->obss_ht_legacy_detect_mode = + OBSS_OFFLOAD_DETECTION_DISABLED; + } + + if ((rf_band == BAND_5G) && session->htCapability) { + if (!session->gLim11aParams.protectionEnabled) { + if (!session->gLimOverlap11aParams.protectionEnabled) + cfg->obss_11a_detect_mode = + OBSS_OFFLOAD_DETECTION_PRESENT; + else if (OBSS_DETECTION_IS_11A(detect_masks)) + cfg->obss_11a_detect_mode = + OBSS_OFFLOAD_DETECTION_ABSENT; + } else { + session->gLimOverlap11aParams.protectionEnabled = false; + } + } + + if (((rf_band == BAND_2G) || (rf_band == BAND_5G)) && + session->htCapability) { + + if (!session->gLimHt20Params.protectionEnabled) { + if (!session->gLimOverlapHt20Params.protectionEnabled) { + cfg->obss_ht_20mhz_detect_mode = + OBSS_OFFLOAD_DETECTION_PRESENT; + } else if (OBSS_DETECTION_IS_HT_20MHZ(detect_masks)) { + cfg->obss_ht_20mhz_detect_mode = + OBSS_OFFLOAD_DETECTION_ABSENT; + } + } else { + session->gLimOverlapHt20Params.protectionEnabled = + false; + } + } + + pe_debug("b_ap:%d, b_s:%d, g:%d, a:%d, ht_le:%d, ht_m:%d, ht_20:%d", + cfg->obss_11b_ap_detect_mode, + cfg->obss_11b_sta_detect_mode, + cfg->obss_11g_ap_detect_mode, + cfg->obss_11a_detect_mode, + cfg->obss_ht_legacy_detect_mode, + cfg->obss_ht_mixed_detect_mode, + cfg->obss_ht_20mhz_detect_mode); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_obss_send_detection_cfg(tpAniSirGlobal mac_ctx, + tpPESession session, bool force) +{ + QDF_STATUS status; + struct obss_detection_cfg obss_cfg; + struct wmi_obss_detection_cfg_param *req_param; + + if (!session) { + pe_err("Invalid session"); + return QDF_STATUS_E_INVAL; + } + + if (!session->is_session_obss_offload_enabled) { + pe_debug("obss offload protectiond disabled, session %d", + session->smeSessionId); + /* Send success */ + return QDF_STATUS_SUCCESS; + } + + if (session->gLimProtectionControl == + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) { + pe_debug("protectiond disabled, force from policy, session %d", + session->smeSessionId); + /* Send success */ + return QDF_STATUS_SUCCESS; + } + + status = lim_obss_generate_detection_config(mac_ctx, + session, + &obss_cfg); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to generate obss detection cfg, session %d", + session->smeSessionId); + return status; + } + + if (qdf_mem_cmp(&session->obss_offload_cfg, &obss_cfg, sizeof(obss_cfg)) + || force) { + struct scheduler_msg msg = {0}; + req_param = qdf_mem_malloc(sizeof(*req_param)); + if (!req_param) { + pe_err("Failed to allocate memory"); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(&session->obss_offload_cfg, &obss_cfg, + sizeof(obss_cfg)); + req_param->vdev_id = session->smeSessionId; + req_param->obss_detect_period_ms = OBSS_DETECTION_PERIOD_MS; + req_param->obss_11b_ap_detect_mode = + obss_cfg.obss_11b_ap_detect_mode; + req_param->obss_11b_sta_detect_mode = + obss_cfg.obss_11b_sta_detect_mode; + req_param->obss_11g_ap_detect_mode = + obss_cfg.obss_11g_ap_detect_mode; + req_param->obss_11a_detect_mode = + obss_cfg.obss_11a_detect_mode; + req_param->obss_ht_legacy_detect_mode = + obss_cfg.obss_ht_legacy_detect_mode; + req_param->obss_ht_20mhz_detect_mode = + obss_cfg.obss_ht_20mhz_detect_mode; + req_param->obss_ht_mixed_detect_mode = + obss_cfg.obss_ht_mixed_detect_mode; + + msg.type = WMA_OBSS_DETECTION_REQ; + msg.bodyptr = req_param; + msg.reserved = 0; + status = scheduler_post_msg(QDF_MODULE_ID_WMA, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to post WMA_OBSS_DETECTION_REQ to WMA"); + qdf_mem_free(req_param); + return status; + } + } else { + pe_debug("Skiping WMA_OBSS_DETECTION_REQ, force = %d", force); + } + + return status; +} + +QDF_STATUS lim_process_obss_detection_ind(tpAniSirGlobal mac_ctx, + struct wmi_obss_detect_info + *obss_detection) +{ + QDF_STATUS status; + uint32_t detect_masks; + uint32_t reason; + struct obss_detection_cfg *obss_cfg; + bool enable; + tpPESession session; + tUpdateBeaconParams bcn_prm; + enum band_info rf_band = BAND_UNKNOWN; + + pe_debug("obss detect ind id %d, reason %d, msk 0x%x, " MAC_ADDRESS_STR, + obss_detection->vdev_id, obss_detection->reason, + obss_detection->matched_detection_masks, + MAC_ADDR_ARRAY(obss_detection->matched_bssid_addr)); + + session = pe_find_session_by_sme_session_id(mac_ctx, + obss_detection->vdev_id); + if (!session) { + pe_err("Failed to get session for id %d", + obss_detection->vdev_id); + return QDF_STATUS_E_INVAL; + } + + if (!LIM_IS_AP_ROLE(session)) { + pe_err("session %d is not AP", obss_detection->vdev_id); + return QDF_STATUS_E_INVAL; + } + + if (!session->is_session_obss_offload_enabled) { + pe_err("Offload already disabled for session %d", + obss_detection->vdev_id); + return QDF_STATUS_SUCCESS; + } + + reason = obss_detection->reason; + detect_masks = obss_detection->matched_detection_masks; + + if (reason == OBSS_OFFLOAD_DETECTION_PRESENT) { + enable = true; + } else if (reason == OBSS_OFFLOAD_DETECTION_ABSENT) { + enable = false; + } else if (reason == OBSS_OFFLOAD_DETECTION_DISABLED) { + /* + * Most common reason for this event-type from firmware + * is insufficient memory. + * Disable offload OBSS detection and enable legacy-way + * of detecting OBSS by parsing beacons. + **/ + session->is_session_obss_offload_enabled = false; + pe_err("FW indicated obss offload disabled"); + pe_err("Enabling host based detection, session %d", + obss_detection->vdev_id); + + status = qdf_mc_timer_start(&session-> + protection_fields_reset_timer, + SCH_PROTECTION_RESET_TIME); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("cannot start protection reset timer"); + + return QDF_STATUS_SUCCESS; + } else { + pe_err("Invalid reason %d, session %d", + obss_detection->reason, + obss_detection->vdev_id); + return QDF_STATUS_E_INVAL; + } + + rf_band = session->limRFBand; + qdf_mem_zero(&bcn_prm, sizeof(bcn_prm)); + obss_cfg = &session->obss_offload_cfg; + + if (OBSS_DETECTION_IS_11B_AP(detect_masks)) { + if (reason != obss_cfg->obss_11b_ap_detect_mode || + rf_band != BAND_2G) + goto wrong_detection; + + lim_enable11g_protection(mac_ctx, enable, true, + &bcn_prm, session); + } + if (OBSS_DETECTION_IS_11B_STA(detect_masks)) { + if (reason != obss_cfg->obss_11b_sta_detect_mode || + rf_band != BAND_2G) + goto wrong_detection; + + lim_enable11g_protection(mac_ctx, enable, true, + &bcn_prm, session); + } + if (OBSS_DETECTION_IS_11G_AP(detect_masks)) { + if (reason != obss_cfg->obss_11g_ap_detect_mode || + rf_band != BAND_2G) + goto wrong_detection; + + lim_enable_ht_protection_from11g(mac_ctx, enable, true, + &bcn_prm, session); + } + if (OBSS_DETECTION_IS_11A(detect_masks)) { + if (reason != obss_cfg->obss_11a_detect_mode || + rf_band != BAND_5G) + goto wrong_detection; + + lim_update_11a_protection(mac_ctx, enable, true, + &bcn_prm, session); + } + if (OBSS_DETECTION_IS_HT_LEGACY(detect_masks)) { + /* for 5GHz, we have only 11a detection, which covers legacy */ + if (reason != obss_cfg->obss_ht_legacy_detect_mode || + rf_band != BAND_2G) + goto wrong_detection; + + lim_enable_ht_protection_from11g(mac_ctx, enable, true, + &bcn_prm, session); + } + if (OBSS_DETECTION_IS_HT_MIXED(detect_masks)) { + /* for 5GHz, we have only 11a detection, which covers ht mix */ + if (reason != obss_cfg->obss_ht_mixed_detect_mode || + rf_band != BAND_2G) + goto wrong_detection; + + lim_enable_ht_protection_from11g(mac_ctx, enable, true, + &bcn_prm, session); + } + if (OBSS_DETECTION_IS_HT_20MHZ(detect_masks)) { + if (reason != obss_cfg->obss_ht_20mhz_detect_mode) + goto wrong_detection; + + lim_enable_ht20_protection(mac_ctx, enable, true, + &bcn_prm, session); + } + + /* save current detection */ + session->obss_offload_cfg.obss_current_detection_masks = detect_masks; + + if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) && + bcn_prm.paramChangeBitmap) { + /* Update the bcn and apply the new settings to HAL */ + sch_set_fixed_beacon_fields(mac_ctx, session); + pe_debug("Beacon for PE session: %d got changed: 0x%x", + session->smeSessionId, bcn_prm.paramChangeBitmap); + if (!IS_SIR_STATUS_SUCCESS(lim_send_beacon_params( + mac_ctx, &bcn_prm, session))) { + pe_err("Failed to send beacon param, session %d", + obss_detection->vdev_id); + return QDF_STATUS_E_FAULT; + } + } + + status = lim_obss_send_detection_cfg(mac_ctx, session, true); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to send obss detection cfg, session %d", + obss_detection->vdev_id); + return status; + } + + return QDF_STATUS_SUCCESS; + +wrong_detection: + /* + * We may get this wrong detection before FW can update latest cfg, + * So keeping log level debug + **/ + pe_debug("Wrong detection, session %d", obss_detection->vdev_id); + + return QDF_STATUS_E_INVAL; +}