diff --git a/core/cds/src/cds_api.c b/core/cds/src/cds_api.c index 5a49095bd8fd..a95a27c78cd7 100644 --- a/core/cds/src/cds_api.c +++ b/core/cds/src/cds_api.c @@ -89,6 +89,14 @@ static struct __qdf_device g_qdf_ctx; static uint8_t cds_multicast_logging; #ifdef QCA_WIFI_QCA8074 +static inline int +cds_send_delba(struct cdp_ctrl_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t *peer_macaddr, + uint8_t tid, uint8_t reason_code) +{ + return wma_dp_send_delba_ind(vdev_id, peer_macaddr, tid, reason_code); +} + static struct ol_if_ops dp_ol_if_ops = { .peer_set_default_routing = target_if_peer_set_default_routing, .peer_rx_reorder_queue_setup = target_if_peer_rx_reorder_queue_setup, @@ -97,7 +105,8 @@ static struct ol_if_ops dp_ol_if_ops = { .lro_hash_config = target_if_lro_hash_config, .rx_invalid_peer = wma_rx_invalid_peer_ind, .is_roam_inprogress = wma_is_roam_in_progress, - .get_con_mode = cds_get_conparam + .get_con_mode = cds_get_conparam, + .send_delba = cds_send_delba, /* TODO: Add any other control path calls required to OL_IF/WMA layer */ }; #else diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h index 37bbf3e02bb8..72b594a7140d 100644 --- a/core/mac/src/include/sir_params.h +++ b/core/mac/src/include/sir_params.h @@ -654,6 +654,8 @@ struct sir_cfg_action_frm_tb_ppdu { #define SIR_HAL_ROAM_SCAN_CH_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 414) +#define SIR_HAL_REQ_SEND_DELBA_REQ_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 415) + #define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) /* LIM message types */ diff --git a/core/mac/src/pe/include/lim_global.h b/core/mac/src/pe/include/lim_global.h index 11a971eb7fe2..6a71333aaae5 100644 --- a/core/mac/src/pe/include/lim_global.h +++ b/core/mac/src/pe/include/lim_global.h @@ -491,4 +491,17 @@ typedef struct sLimSpecMgmtInfo { tLimDot11hChanSwStates dot11hChanSwState; } tLimSpecMgmtInfo, *tpLimSpecMgmtInfo; +/** + * struct lim_delba_req_info - Delba request struct + * @vdev_id: vdev id + * @peer_macaddr: peer mac address + * @tid: tid + * @reason_code: reason code + */ +struct lim_delba_req_info { + uint8_t vdev_id; + tSirMacAddr peer_macaddr; + uint8_t tid; + uint8_t reason_code; +}; #endif diff --git a/core/mac/src/pe/lim/lim_link_monitoring_algo.c b/core/mac/src/pe/lim/lim_link_monitoring_algo.c index 11565c337910..1e4dedd9a2dc 100644 --- a/core/mac/src/pe/lim/lim_link_monitoring_algo.c +++ b/core/mac/src/pe/lim/lim_link_monitoring_algo.c @@ -584,3 +584,27 @@ void lim_rx_invalid_peer_process(struct mac_context *mac_ctx, qdf_mem_free(msg); lim_msg->bodyptr = NULL; } + +void lim_req_send_delba_ind_process(struct mac_context *mac_ctx, + struct scheduler_msg *lim_msg) +{ + struct lim_delba_req_info *req = + (struct lim_delba_req_info *)lim_msg->bodyptr; + QDF_STATUS status; + void *dp_soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!req) { + pe_err("Invalid body pointer in message"); + return; + } + + status = lim_send_delba_action_frame(mac_ctx, req->vdev_id, + req->peer_macaddr, + req->tid, req->reason_code); + if (status != QDF_STATUS_SUCCESS) + cdp_delba_tx_completion(dp_soc, req->peer_macaddr, + req->vdev_id, req->tid, + WMI_MGMT_TX_COMP_TYPE_DISCARD); + qdf_mem_free(req); + lim_msg->bodyptr = NULL; +} 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 663b69820cb1..25c8e4fc4e0b 100644 --- a/core/mac/src/pe/lim/lim_process_message_queue.c +++ b/core/mac/src/pe/lim/lim_process_message_queue.c @@ -1841,6 +1841,9 @@ static void lim_process_messages(struct mac_context *mac_ctx, case SIR_LIM_RX_INVALID_PEER: lim_rx_invalid_peer_process(mac_ctx, msg); break; + case SIR_HAL_REQ_SEND_DELBA_REQ_IND: + lim_req_send_delba_ind_process(mac_ctx, msg); + break; case SIR_LIM_JOIN_FAIL_TIMEOUT: case SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT: case SIR_LIM_AUTH_FAIL_TIMEOUT: 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 80d51ed81bcc..37d5a72f75ed 100644 --- a/core/mac/src/pe/lim/lim_send_management_frames.c +++ b/core/mac/src/pe/lim/lim_send_management_frames.c @@ -5116,6 +5116,165 @@ error_addba_rsp: return qdf_status; } +/** + * lim_delba_tx_complete_cnf() - Confirmation for Delba OTA + * @context: pointer to global mac + * @buf: netbuf of Del BA frame + * @tx_complete : Sent status + * @params; tx completion params + * + * Return: This returns QDF_STATUS + */ +static QDF_STATUS lim_delba_tx_complete_cnf(void *context, + qdf_nbuf_t buf, + uint32_t tx_complete, + void *params) +{ + struct mac_context *mac_ctx = (struct mac_context *)context; + tSirMacMgmtHdr *mac_hdr; + struct sDot11fdelba_req frm; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint32_t frame_len; + QDF_STATUS status; + uint8_t *data; + struct wmi_mgmt_params *mgmt_params = (struct wmi_mgmt_params *)params; + + if (!mgmt_params || !mac_ctx || !buf || !soc) { + pe_err("delba tx cnf invalid parameters"); + goto error; + } + data = qdf_nbuf_data(buf); + if (!data) { + pe_err("Delba frame is NULL"); + goto error; + } + + mac_hdr = (tSirMacMgmtHdr *)data; + qdf_mem_zero((void *)&frm, sizeof(struct sDot11fdelba_req)); + frame_len = sizeof(frm); + status = dot11f_unpack_delba_req(mac_ctx, (uint8_t *)data + + sizeof(*mac_hdr), frame_len, + &frm, false); + if (DOT11F_FAILED(status)) { + pe_err("Failed to unpack and parse delba (0x%08x, %d bytes)", + status, frame_len); + goto error; + } + pe_debug("delba ota done vdev %d %pM tid %d desc_id %d status %d", + mgmt_params->vdev_id, mac_hdr->da, frm.delba_param_set.tid, + mgmt_params->desc_id, tx_complete); + cdp_delba_tx_completion(soc, mac_hdr->da, mgmt_params->vdev_id, + frm.delba_param_set.tid, tx_complete); + +error: + if (buf) + qdf_nbuf_free(buf); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_send_delba_action_frame(struct mac_context *mac_ctx, + uint8_t vdev_id, uint8_t *peer_macaddr, + uint8_t tid, uint8_t reason_code) +{ + struct pe_session *session; + struct sDot11fdelba_req frm; + QDF_STATUS qdf_status; + tpSirMacMgmtHdr mgmt_hdr; + uint32_t num_bytes, payload_size = 0; + uint32_t status; + void *pkt_ptr = NULL; + uint8_t *frame_ptr; + uint8_t tx_flag = 0; + + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session) { + pe_debug("delba invalid vdev id %d ", vdev_id); + return QDF_STATUS_E_INVAL; + } + pe_debug("send delba vdev %d %pM tid %d reason %d", vdev_id, + peer_macaddr, tid, reason_code); + qdf_mem_zero((uint8_t *)&frm, sizeof(frm)); + frm.Category.category = ACTION_CATEGORY_BACK; + frm.Action.action = DELBA; + frm.delba_param_set.initiator = 0; + frm.delba_param_set.tid = tid; + frm.Reason.code = reason_code; + + status = dot11f_get_packed_delba_req_size(mac_ctx, &frm, &payload_size); + if (DOT11F_FAILED(status)) { + pe_err("Failed to calculate the packed size for a DELBA(0x%08x).", + status); + /* We'll fall back on the worst case scenario: */ + payload_size = sizeof(struct sDot11fdelba_req); + } else if (DOT11F_WARNED(status)) { + pe_warn("Warnings in calculating the packed size for a DELBA (0x%08x).", + status); + } + num_bytes = payload_size + sizeof(*mgmt_hdr); + qdf_status = cds_packet_alloc(num_bytes, (void **)&frame_ptr, + (void **)&pkt_ptr); + if (!QDF_IS_STATUS_SUCCESS(qdf_status) || !pkt_ptr) { + pe_err("Failed to allocate %d bytes for a DELBA", + num_bytes); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(frame_ptr, num_bytes); + + lim_populate_mac_header(mac_ctx, frame_ptr, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer_macaddr, + session->self_mac_addr); + + /* Update A3 with the BSSID */ + mgmt_hdr = (tpSirMacMgmtHdr)frame_ptr; + sir_copy_mac_addr(mgmt_hdr->bssId, session->bssId); + + /* DEL is a robust mgmt action frame, + * set the "protect" (aka WEP) bit in the FC + */ + lim_set_protected_bit(mac_ctx, session, peer_macaddr, mgmt_hdr); + + status = dot11f_pack_delba_req(mac_ctx, &frm, + frame_ptr + sizeof(tSirMacMgmtHdr), + payload_size, &payload_size); + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a DELBA (0x%08x)", + status); + qdf_status = QDF_STATUS_E_FAILURE; + goto error_delba; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing DELBA (0x%08x)", + status); + } + if (wlan_reg_is_5ghz_ch_freq(session->curr_op_freq) || + wlan_reg_is_6ghz_chan_freq(session->curr_op_freq) || + session->opmode == QDF_P2P_CLIENT_MODE || + session->opmode == QDF_P2P_GO_MODE) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + session->peSessionId, mgmt_hdr->fc.subType)); + qdf_status = wma_tx_frameWithTxComplete(mac_ctx, pkt_ptr, + (uint16_t)num_bytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, 7, + NULL, frame_ptr, + lim_delba_tx_complete_cnf, + tx_flag, vdev_id, + false, 0, RATEID_DEFAULT); + if (qdf_status != QDF_STATUS_SUCCESS) { + pe_err("delba wma_tx_frame FAILED! Status [%d]", qdf_status); + return qdf_status; + } else { + return QDF_STATUS_SUCCESS; + } + +error_delba: + if (pkt_ptr) + cds_packet_free((void *)pkt_ptr); + + return qdf_status; +} + /** * lim_tx_mgmt_frame() - Transmits Auth mgmt frame * @mac_ctx Pointer to Global MAC structure diff --git a/core/mac/src/pe/lim/lim_types.h b/core/mac/src/pe/lim/lim_types.h index 4774520b02fe..738bc0e7ab20 100644 --- a/core/mac/src/pe/lim/lim_types.h +++ b/core/mac/src/pe/lim/lim_types.h @@ -1163,6 +1163,22 @@ QDF_STATUS lim_send_addba_response_frame(struct mac_context *mac_ctx, struct pe_session *session, uint8_t addba_extn_present, uint8_t amsdu_support, uint8_t is_wep); + +/** + * lim_send_delba_action_frame() - Send delba to peer + * @mac_ctx: mac context + * @vdev_id: vdev id + * @peer_macaddr: Peer mac addr + * @tid: Tid number + * @reason_code: reason code + * + * Return: 0 for success, non-zero for failure + */ +QDF_STATUS lim_send_delba_action_frame(struct mac_context *mac_ctx, + uint8_t vdev_id, + uint8_t *peer_macaddr, uint8_t tid, + uint8_t reason_code); + /** * lim_process_join_failure_timeout() - This function is called to process * JoinFailureTimeout diff --git a/core/mac/src/pe/lim/lim_utils.h b/core/mac/src/pe/lim/lim_utils.h index db7deec59ee3..6db9a01265d6 100644 --- a/core/mac/src/pe/lim/lim_utils.h +++ b/core/mac/src/pe/lim/lim_utils.h @@ -1806,6 +1806,18 @@ static inline void lim_set_peer_twt_cap(struct pe_session *session, void lim_rx_invalid_peer_process(struct mac_context *mac_ctx, struct scheduler_msg *lim_msg); +/** + * lim_req_send_delba_ind_process() - process send delba indication + * @mac_ctx: mac context + * @lim_msg: lim message + * + * This function will process the send delba indication from DP. + * + * Return: None + */ +void lim_req_send_delba_ind_process(struct mac_context *mac_ctx, + struct scheduler_msg *lim_msg); + /** * lim_send_beacon() - send beacon indication to firmware * @mac_ctx: Pointer to Global MAC structure diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index bec4a6e139c4..44dcf4f89034 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -2395,6 +2395,21 @@ void wma_delete_invalid_peer_entries(uint8_t vdev_id, uint8_t *peer_mac_addr); */ uint8_t wma_rx_invalid_peer_ind(uint8_t vdev_id, void *wh); +/** + * wma_dp_send_delba_ind() - the callback for DP to notify WMA layer + * to del ba of rx + * @vdev_id: vdev id + * @peer_macaddr: peer mac address + * @tid: tid of rx + * @reason_code: reason code + * + * Return: 0 for success or non-zero on failure + */ +int wma_dp_send_delba_ind(uint8_t vdev_id, + uint8_t *peer_macaddr, + uint8_t tid, + uint8_t reason_code); + /** * is_roam_inprogress() - Is vdev in progress * @vdev_id: vdev of interest diff --git a/core/wma/src/wma_data.c b/core/wma/src/wma_data.c index 0682238ea7f4..92892a2cb104 100644 --- a/core/wma/src/wma_data.c +++ b/core/wma/src/wma_data.c @@ -3196,6 +3196,31 @@ uint8_t wma_rx_invalid_peer_ind(uint8_t vdev_id, void *wh) return 0; } +int wma_dp_send_delba_ind(uint8_t vdev_id, uint8_t *peer_macaddr, + uint8_t tid, uint8_t reason_code) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct lim_delba_req_info *req; + + if (!wma || !peer_macaddr) { + wma_err("wma handle or mac addr is NULL"); + return -EINVAL; + } + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return -ENOMEM; + req->vdev_id = vdev_id; + qdf_mem_copy(req->peer_macaddr, peer_macaddr, QDF_MAC_ADDR_SIZE); + req->tid = tid; + req->reason_code = reason_code; + WMA_LOGD("req delba_ind vdev %d %pM tid %d reason %d", + vdev_id, peer_macaddr, tid, reason_code); + wma_send_msg_high_priority(wma, SIR_HAL_REQ_SEND_DELBA_REQ_IND, + (void *)req, 0); + + return 0; +} + bool wma_is_roam_in_progress(uint32_t vdev_id) { tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);