diff --git a/core/dp/htt/htt_rx.c b/core/dp/htt/htt_rx.c index 8a9e9fa509..62a293dc0e 100644 --- a/core/dp/htt/htt_rx.c +++ b/core/dp/htt/htt_rx.c @@ -60,6 +60,7 @@ #include #include #endif +#include #ifdef HTT_DEBUG_DATA #define HTT_PKT_DUMP(x) x @@ -1998,6 +1999,7 @@ htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev, uint8_t offload_ind, frag_ind; struct htt_host_rx_desc_base *rx_desc; uint8_t peer_id; + enum rx_pkt_fate status = RX_PKT_FATE_SUCCESS; HTT_ASSERT1(htt_rx_in_order_ring_elems(pdev) != 0); @@ -2083,6 +2085,15 @@ htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev, msdu_count--; + /* calling callback function for packet logging */ + if (pdev->rx_pkt_dump_cb) { + if (qdf_unlikely((*((u_int8_t *) + &rx_desc->fw_desc.u.val)) & + FW_RX_DESC_ANY_ERR_M)) + status = RX_PKT_FATE_FW_DROP_INVALID; + pdev->rx_pkt_dump_cb(msdu, peer_id, status); + } + if (qdf_unlikely((*((u_int8_t *) &rx_desc->fw_desc.u.val)) & FW_RX_DESC_ANY_ERR_M)) { uint8_t tid = @@ -3536,3 +3547,51 @@ int htt_rx_ipa_uc_detach(struct htt_pdev_t *pdev) return 0; } #endif /* IPA_OFFLOAD */ + +/** + * htt_register_rx_pkt_dump_callback() - registers callback to + * get rx pkt status and call callback to do rx packet dump + * + * @pdev: htt pdev handle + * @callback: callback to get rx pkt status and + * call callback to do rx packet dump + * + * This function is used to register the callback to get + * rx pkt status and call callback to do rx packet dump + * + * Return: None + * + */ +void htt_register_rx_pkt_dump_callback(struct htt_pdev_t *pdev, + tp_rx_pkt_dump_cb callback) +{ + if (!pdev) { + qdf_print("%s: htt pdev is NULL, rx packet status callback register unsuccessful\n", + __func__); + return; + } + pdev->rx_pkt_dump_cb = callback; +} + +/** + * htt_deregister_rx_pkt_dump_callback() - deregisters callback to + * get rx pkt status and call callback to do rx packet dump + * + * @pdev: htt pdev handle + * + * This function is used to deregister the callback to get + * rx pkt status and call callback to do rx packet dump + * + * Return: None + * + */ +void htt_deregister_rx_pkt_dump_callback(struct htt_pdev_t *pdev) +{ + if (!pdev) { + qdf_print("%s: htt pdev is NULL, rx packet status callback deregister unsuccessful\n", + __func__); + return; + } + pdev->rx_pkt_dump_cb = NULL; +} + diff --git a/core/dp/htt/htt_types.h b/core/dp/htt/htt_types.h index 9c67355e74..82b3d97bd3 100644 --- a/core/dp/htt/htt_types.h +++ b/core/dp/htt/htt_types.h @@ -35,6 +35,7 @@ #include /* qdf_atomic_inc */ #include /* qdf_nbuf_t */ #include /* HTC_PACKET */ +#include #define DEBUG_DMA_DONE @@ -412,6 +413,10 @@ struct htt_pdev_t { struct rx_buf_debug *rx_buff_list; int rx_buff_index; #endif + + /* callback function for packetdump */ + tp_rx_pkt_dump_cb rx_pkt_dump_cb; + struct mon_channel mon_ch_info; }; diff --git a/core/dp/ol/inc/ol_htt_api.h b/core/dp/ol/inc/ol_htt_api.h index 21da264912..311de88967 100644 --- a/core/dp/ol/inc/ol_htt_api.h +++ b/core/dp/ol/inc/ol_htt_api.h @@ -384,5 +384,11 @@ static inline void htt_clear_bundle_stats(struct htt_pdev_t *pdev) #endif void htt_mark_first_wakeup_packet(htt_pdev_handle pdev, uint8_t value); +typedef void (*tp_rx_pkt_dump_cb)(qdf_nbuf_t msdu, uint8_t peer_id, + uint8_t status); +void htt_register_rx_pkt_dump_callback(struct htt_pdev_t *pdev, + tp_rx_pkt_dump_cb ol_rx_pkt_dump_call); +void htt_deregister_rx_pkt_dump_callback(struct htt_pdev_t *pdev); +void ol_rx_pkt_dump_call(qdf_nbuf_t msdu, uint8_t peer_id, uint8_t status); #endif /* _OL_HTT_API__H_ */ diff --git a/core/dp/ol/inc/ol_txrx_api.h b/core/dp/ol/inc/ol_txrx_api.h index f350ecfa7d..b0d56ee1df 100644 --- a/core/dp/ol/inc/ol_txrx_api.h +++ b/core/dp/ol/inc/ol_txrx_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -60,4 +60,10 @@ enum ol_sec_type { ol_sec_type_types }; +typedef void (*tp_ol_packetdump_cb)(qdf_nbuf_t netbuf, + uint8_t status, uint8_t vdev_id, uint8_t type); +void ol_register_packetdump_callback(tp_ol_packetdump_cb ol_tx_packetdump_cb, + tp_ol_packetdump_cb ol_rx_packetdump_cb); +void ol_deregister_packetdump_callback(void); + #endif /* _OL_TXRX_API__H_ */ diff --git a/core/dp/txrx/ol_rx.c b/core/dp/txrx/ol_rx.c index 9268bbe9bb..3591c617ad 100644 --- a/core/dp/txrx/ol_rx.c +++ b/core/dp/txrx/ol_rx.c @@ -58,6 +58,7 @@ #include #include #include +#include "pktlog_ac_fmt.h" #include @@ -1400,6 +1401,51 @@ ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev, peer->rx_opt_proc(vdev, peer, tid, head_msdu); } +/** + * ol_rx_pkt_dump_call() - updates status and + * calls packetdump callback to log rx packet + * + * @msdu: rx packet + * @peer_id: peer id + * @status: status of rx packet + * + * This function is used to update the status of rx packet + * and then calls packetdump callback to log that packet. + * + * Return: None + * + */ +void ol_rx_pkt_dump_call( + qdf_nbuf_t msdu, + uint8_t peer_id, + uint8_t status) +{ + v_CONTEXT_t vos_context; + ol_txrx_pdev_handle pdev; + struct ol_txrx_peer_t *peer = NULL; + + vos_context = cds_get_global_context(); + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL", __func__); + return; + } + + if (pdev->ol_rx_packetdump_cb) { + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (!peer) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: peer with peer id %d is NULL", __func__, + peer_id); + return; + } + pdev->ol_rx_packetdump_cb(msdu, status, peer->vdev->vdev_id, + RX_DATA_PKT); + } +} + /* the msdu_list passed here must be NULL terminated */ void ol_rx_in_order_deliver(struct ol_txrx_vdev_t *vdev, diff --git a/core/dp/txrx/ol_tx_desc.c b/core/dp/txrx/ol_tx_desc.c index 5294c8a242..dbaef89c7c 100644 --- a/core/dp/txrx/ol_tx_desc.c +++ b/core/dp/txrx/ol_tx_desc.c @@ -105,8 +105,6 @@ static inline void ol_tx_desc_reset_timestamp(struct ol_tx_desc_t *tx_desc) } #endif -#ifdef CONFIG_HL_SUPPORT - /** * ol_tx_desc_vdev_update() - vedv assign. * @tx_desc: tx descriptor pointer @@ -120,15 +118,6 @@ ol_tx_desc_vdev_update(struct ol_tx_desc_t *tx_desc, { tx_desc->vdev = vdev; } -#else - -static inline void -ol_tx_desc_vdev_update(struct ol_tx_desc_t *tx_desc, - struct ol_txrx_vdev_t *vdev) -{ - return; -} -#endif #ifdef CONFIG_PER_VDEV_TX_DESC_POOL @@ -235,6 +224,7 @@ struct ol_tx_desc_t *ol_tx_desc_alloc(struct ol_txrx_pdev_t *pdev, } ol_tx_desc_sanity_checks(pdev, tx_desc); ol_tx_desc_compute_delay(tx_desc); + ol_tx_desc_vdev_update(tx_desc, vdev); } else { pool->pkt_drop_no_desc++; qdf_spin_unlock_bh(&pool->flow_pool_lock); diff --git a/core/dp/txrx/ol_tx_send.c b/core/dp/txrx/ol_tx_send.c index 4d30adf308..a90bf86d4f 100644 --- a/core/dp/txrx/ol_tx_send.c +++ b/core/dp/txrx/ol_tx_send.c @@ -60,7 +60,7 @@ #endif #include #include - +#include #ifdef TX_CREDIT_RECLAIM_SUPPORT @@ -552,6 +552,11 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev, tx_desc->status = status; netbuf = tx_desc->netbuf; QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_FREE); + + if (pdev->ol_tx_packetdump_cb) + pdev->ol_tx_packetdump_cb(netbuf, status, + tx_desc->vdev->vdev_id, TX_DATA_PKT); + DPTRACE(qdf_dp_trace_ptr(netbuf, QDF_DP_TRACE_FREE_PACKET_PTR_RECORD, qdf_nbuf_data_addr(netbuf), @@ -766,6 +771,10 @@ ol_tx_single_completion_handler(ol_txrx_pdev_handle pdev, /* Do one shot statistics */ TXRX_STATS_UPDATE_TX_STATS(pdev, status, 1, qdf_nbuf_len(netbuf)); + if (pdev->ol_tx_packetdump_cb) + pdev->ol_tx_packetdump_cb(netbuf, status, + tx_desc->vdev->vdev_id, TX_MGMT_PKT); + if (OL_TX_DESC_NO_REFS(tx_desc)) { ol_tx_desc_frame_free_nonstd(pdev, tx_desc, status != htt_tx_status_ok); @@ -1168,3 +1177,57 @@ ol_tx_delay_compute(struct ol_txrx_pdev_t *pdev, } #endif /* QCA_COMPUTE_TX_DELAY */ + +/** + * ol_register_packetdump_callback() - registers + * tx data packet, tx mgmt. packet and rx data packet + * dump callback handler. + * + * @ol_tx_packetdump_cb: tx packetdump cb + * @ol_rx_packetdump_cb: rx packetdump cb + * + * This function is used to register tx data pkt, tx mgmt. + * pkt and rx data pkt dump callback + * + * Return: None + * + */ +void ol_register_packetdump_callback(tp_ol_packetdump_cb ol_tx_packetdump_cb, + tp_ol_packetdump_cb ol_rx_packetdump_cb) +{ + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL", __func__); + return; + } + + pdev->ol_tx_packetdump_cb = ol_tx_packetdump_cb; + pdev->ol_rx_packetdump_cb = ol_rx_packetdump_cb; +} + +/** + * ol_deregister_packetdump_callback() - deregidters + * tx data packet, tx mgmt. packet and rx data packet + * dump callback handler + * + * This function is used to deregidter tx data pkt., + * tx mgmt. pkt and rx data pkt. dump callback + * + * Return: None + * + */ +void ol_deregister_packetdump_callback(void) +{ + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL", __func__); + return; + } + + pdev->ol_tx_packetdump_cb = NULL; + pdev->ol_rx_packetdump_cb = NULL; +} diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c index f08e60c0e8..0ed97844c0 100644 --- a/core/dp/txrx/ol_txrx.c +++ b/core/dp/txrx/ol_txrx.c @@ -1013,6 +1013,8 @@ ol_txrx_pdev_attach(ol_pdev_handle ctrl_pdev, if (!pdev->htt_pdev) goto fail3; + htt_register_rx_pkt_dump_callback(pdev->htt_pdev, + ol_rx_pkt_dump_call); return pdev; fail3: @@ -1631,6 +1633,7 @@ void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force) ol_txrx_peer_find_hash_erase(pdev); } + htt_deregister_rx_pkt_dump_callback(pdev->htt_pdev); ol_tx_deregister_flow_control(pdev); /* Stop the communication between HTT and target at first */ htt_detach_target(pdev->htt_pdev); diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h index ee1bfb309a..db2ccfd72e 100644 --- a/core/dp/txrx/ol_txrx_types.h +++ b/core/dp/txrx/ol_txrx_types.h @@ -187,9 +187,9 @@ struct ol_tx_desc_t { * This field is filled in with the ol_tx_frm_type enum. */ uint8_t pkt_type; -#if defined(CONFIG_HL_SUPPORT) + struct ol_txrx_vdev_t *vdev; -#endif + void *txq; #ifdef QCA_SUPPORT_SW_TXRX_ENCAP @@ -663,6 +663,10 @@ struct ol_txrx_pdev_t { } callbacks[OL_TXRX_MGMT_NUM_TYPES]; } tx_mgmt; + /* packetdump callback functions */ + tp_ol_packetdump_cb ol_tx_packetdump_cb; + tp_ol_packetdump_cb ol_rx_packetdump_cb; + struct { uint16_t pool_size; uint16_t num_free; diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index 341ef18ea1..84b87a32d1 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -63,6 +63,7 @@ #include "cdp_txrx_flow_ctrl_legacy.h" #include "cdp_txrx_peer_ops.h" #include "wlan_hdd_napi.h" +#include /* These are needed to recognize WPA and RSN suite types */ #define HDD_WPA_OUI_SIZE 4 @@ -1537,6 +1538,8 @@ static QDF_STATUS hdd_dis_connect_handler(hdd_adapter_t *pAdapter, hdd_clear_roam_profile_ie(pAdapter); hdd_wmm_init(pAdapter); + hdd_info("Invoking packetdump deregistration API"); + wlan_deregister_txrx_packetdump(); /* indicate 'disconnect' status to wpa_supplicant... */ hdd_send_association_event(dev, pRoamInfo); @@ -2800,6 +2803,9 @@ static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter, MAC_ADDR_ARRAY(pWextState->req_bssId.bytes), roamResult, roamStatus); + hdd_err("Invoking packetdump deregistration API"); + wlan_deregister_txrx_packetdump(); + /* inform association failure event to nl80211 */ if (eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL == roamResult) { diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index 3800838143..fb4e58880e 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/core/hdd/src/wlan_hdd_power.c @@ -76,6 +76,7 @@ #include "cdp_txrx_flow_ctrl_v2.h" #include "pld_common.h" #include "wlan_hdd_driver_ops.h" +#include /* Preprocessor definitions and constants */ #define HDD_SSR_BRING_UP_TIME 30000 @@ -1455,6 +1456,10 @@ QDF_STATUS hdd_wlan_shutdown(void) } cds_clear_concurrent_session_count(); + + hdd_info("Invoking packetdump deregistration API"); + wlan_deregister_txrx_packetdump(); + hdd_cleanup_scan_queue(pHddCtx); hdd_reset_all_adapters(pHddCtx); diff --git a/core/sme/inc/csr_api.h b/core/sme/inc/csr_api.h index 1d619eb782..4cf951f675 100644 --- a/core/sme/inc/csr_api.h +++ b/core/sme/inc/csr_api.h @@ -1756,5 +1756,6 @@ static inline void csr_roam_fill_tdls_info(tpAniSirGlobal mac_ctx, tCsrRoamInfo tpSirSmeJoinRsp join_rsp) {} #endif +void csr_packetdump_timer_stop(void); #endif diff --git a/core/sme/inc/csr_internal.h b/core/sme/inc/csr_internal.h index 89bf7b20a3..a9e1896c16 100644 --- a/core/sme/inc/csr_internal.h +++ b/core/sme/inc/csr_internal.h @@ -1046,6 +1046,7 @@ typedef struct tagCsrRoamStruct { uint32_t deauthRspStatus; uint8_t *pReassocResp; /* reassociation response from new AP */ uint16_t reassocRespLen; /* length of reassociation response */ + qdf_mc_timer_t packetdump_timer; } tCsrRoamStruct; #define GET_NEXT_ROAM_ID(pRoamStruct) (((pRoamStruct)->nextRoamId + 1 == 0) ? \ diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index 91103f3e8e..1edcd0b533 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -57,6 +57,7 @@ #include "cds_concurrency.h" #include "sme_nan_datapath.h" #include "pld_common.h" +#include #define MAX_PWR_FCC_CHAN_12 8 #define MAX_PWR_FCC_CHAN_13 2 @@ -85,6 +86,10 @@ #define MAX_CB_VALUE_IN_INI (2) #define MAX_SOCIAL_CHANNELS 3 + +/* packet dump timer duration of 60 secs */ +#define PKT_DUMP_TIMER_DURATION 60 + /* Choose the largest possible value that can be accomodates in 8 bit signed */ /* variable. */ #define SNR_HACK_BMPS (127) @@ -960,6 +965,58 @@ void csr_set_global_cfgs(tpAniSirGlobal pMac) csr_set_default_dot11_mode(pMac); } +/** + * csr_packetdump_timer_handler() - packet dump timer + * handler + * @pv: user data + * + * This function is used to handle packet dump timer + * + * Return: None + * + */ +static void csr_packetdump_timer_handler(void *pv) +{ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s Invoking packetdump deregistration API", __func__); + wlan_deregister_txrx_packetdump(); +} + +/** + * csr_packetdump_timer_stop() - stops packet dump timer + * + * This function is used to stop packet dump timer + * + * Return: None + * + */ +void csr_packetdump_timer_stop(void) +{ + QDF_STATUS status; + tHalHandle hal; + tpAniSirGlobal mac; + v_CONTEXT_t vos_ctx_ptr; + + /* get the global voss context */ + vos_ctx_ptr = cds_get_global_context(); + if (vos_ctx_ptr == NULL) { + QDF_ASSERT(0); + return; + } + + hal = cds_get_context(QDF_MODULE_ID_SME); + if (hal == NULL) { + QDF_ASSERT(0); + return; + } + + mac = PMAC_STRUCT(hal); + status = qdf_mc_timer_stop(&mac->roam.packetdump_timer); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, FL("cannot stop packetdump timer")); + } +} + QDF_STATUS csr_roam_open(tpAniSirGlobal pMac) { QDF_STATUS status = QDF_STATUS_SUCCESS; @@ -986,6 +1043,14 @@ QDF_STATUS csr_roam_open(tpAniSirGlobal pMac) ("cannot allocate memory for WaitForKey time out timer")); break; } + status = qdf_mc_timer_init(&pMac->roam.packetdump_timer, + QDF_TIMER_TYPE_SW, csr_packetdump_timer_handler, + pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("cannot allocate memory for packetdump timer")); + break; + } status = qdf_mc_timer_init(&pMac->roam.tlStatsReqInfo.hTlStatsTimer, QDF_TIMER_TYPE_SW, @@ -1010,6 +1075,8 @@ QDF_STATUS csr_roam_close(tpAniSirGlobal pMac) qdf_mc_timer_destroy(&pMac->roam.hTimerWaitForKey); qdf_mc_timer_stop(&pMac->roam.tlStatsReqInfo.hTlStatsTimer); qdf_mc_timer_destroy(&pMac->roam.tlStatsReqInfo.hTlStatsTimer); + qdf_mc_timer_stop(&pMac->roam.packetdump_timer); + qdf_mc_timer_destroy(&pMac->roam.packetdump_timer); return QDF_STATUS_SUCCESS; } @@ -13762,6 +13829,7 @@ QDF_STATUS csr_send_join_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, uint8_t ese_config = 0; tpCsrNeighborRoamControlInfo neigh_roam_info; uint32_t value = 0, value1 = 0; + QDF_STATUS packetdump_timer_status; if (!pSession) { sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); @@ -14413,6 +14481,25 @@ QDF_STATUS csr_send_join_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, csr_join_req = NULL; break; } else { + if (pProfile->csrPersona == QDF_STA_MODE) { + sms_log(pMac, LOG1, + FL(" Invoking packetdump register API")); + wlan_register_txrx_packetdump(); + packetdump_timer_status = + qdf_mc_timer_start( + &pMac->roam.packetdump_timer, + (PKT_DUMP_TIMER_DURATION * + QDF_MC_TIMER_TO_SEC_UNIT)/ + QDF_MC_TIMER_TO_MS_UNIT); + if (!QDF_IS_STATUS_SUCCESS( + packetdump_timer_status)) { + sms_log(pMac, LOGE, + FL("cannot start packetdump timer")); + sms_log(pMac, LOGE, + FL("packetdump_timer_status: %d"), + packetdump_timer_status); + } + } #ifndef WLAN_MDM_CODE_REDUCTION_OPT if (eWNI_SME_JOIN_REQ == messageType) { /* Notify QoS module that join happening */ diff --git a/core/utils/logging/inc/wlan_logging_sock_svc.h b/core/utils/logging/inc/wlan_logging_sock_svc.h index 1edb42cea6..af85ab6943 100644 --- a/core/utils/logging/inc/wlan_logging_sock_svc.h +++ b/core/utils/logging/inc/wlan_logging_sock_svc.h @@ -80,4 +80,7 @@ static inline void wlan_report_log_completion(uint32_t is_fatal, void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data); +void wlan_deregister_txrx_packetdump(void); +void wlan_register_txrx_packetdump(void); + #endif /* WLAN_LOGGING_SOCK_SVC_H */ diff --git a/core/utils/logging/src/wlan_logging_sock_svc.c b/core/utils/logging/src/wlan_logging_sock_svc.c index 1385b8008f..cbd8c8f362 100644 --- a/core/utils/logging/src/wlan_logging_sock_svc.c +++ b/core/utils/logging/src/wlan_logging_sock_svc.c @@ -37,10 +37,39 @@ #include #include #include -#include "pktlog_ac.h" #include #include "cds_utils.h" #include "host_diag_core_log.h" +#include "wma.h" +#include "ol_txrx_api.h" +#include "csr_api.h" +#include "wlan_hdd_main.h" +#include "pktlog_ac.h" + +#define MAX_NUM_PKT_LOG 32 + +/** + * struct tx_status - tx status + * @tx_status_ok: successfully sent + acked + * @tx_status_discard: discard - not sent (congestion control) + * @tx_status_no_ack: no_ack - sent, but no ack + * @tx_status_download_fail: download_fail - + * the host could not deliver the tx frame to the target + * @tx_status_peer_del: peer_del - tx completion for + * alreay deleted peer used for HL case + * + * This enum has tx status types + */ +enum tx_status { + tx_status_ok, + tx_status_discard, + tx_status_no_ack, + tx_status_download_fail, + tx_status_peer_del, +}; + +static uint8_t gtx_count; +static uint8_t grx_count; #define LOGGING_TRACE(level, args ...) \ QDF_TRACE(QDF_MODULE_ID_HDD, level, ## args) @@ -1187,12 +1216,7 @@ void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data) } pkt_stats_dump = (struct packet_dump *)pkt_dump; - if (pkt_stats_dump) - total_stats_len = sizeof(struct ath_pktlog_hdr) + - pktlog_hdr->size + - sizeof(struct packet_dump); - else - total_stats_len = sizeof(struct ath_pktlog_hdr) + + total_stats_len = sizeof(struct ath_pktlog_hdr) + pktlog_hdr->size; spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags); @@ -1217,16 +1241,24 @@ void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data) pktlog_hdr, sizeof(struct ath_pktlog_hdr)); - if (pkt_stats_dump) + if (pkt_stats_dump) { qdf_mem_copy(skb_put(ptr, sizeof(struct packet_dump)), pkt_stats_dump, sizeof(struct packet_dump)); + pktlog_hdr->size -= sizeof(struct packet_dump); + } - qdf_mem_copy(skb_put(ptr, + if (data) + qdf_mem_copy(skb_put(ptr, pktlog_hdr->size), data, pktlog_hdr->size); + if (pkt_stats_dump->type == STOP_MONITOR) { + wake_up_thread = true; + wlan_get_pkt_stats_free_node(); + } + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags); /* Wakeup logger thread */ @@ -1236,5 +1268,238 @@ void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data) } } +/** + * driver_hal_status_map() - maps driver to hal + * status + * @status: status to be mapped + * + * This function is used to map driver to hal status + * + * Return: None + * + */ +static void driver_hal_status_map(uint8_t *status) +{ + switch (*status) { + case tx_status_ok: + *status = TX_PKT_FATE_ACKED; + break; + case tx_status_discard: + *status = TX_PKT_FATE_DRV_DROP_OTHER; + break; + case tx_status_no_ack: + *status = TX_PKT_FATE_SENT; + break; + case tx_status_download_fail: + *status = TX_PKT_FATE_FW_QUEUED; + break; + default: + *status = TX_PKT_FATE_DRV_DROP_OTHER; + break; + } +} + + +/* + * send_packetdump() - send packet dump + * @netbuf: netbuf + * @status: status of tx packet + * @vdev_id: virtual device id + * @type: type of packet + * + * This function is used to send packet dump to HAL layer + * using wlan_pkt_stats_to_logger_thread + * + * Return: None + * + */ +static void send_packetdump(qdf_nbuf_t netbuf, uint8_t status, + uint8_t vdev_id, uint8_t type) +{ + struct ath_pktlog_hdr pktlog_hdr = {0}; + struct packet_dump pd_hdr = {0}; + hdd_context_t *hdd_ctx; + hdd_adapter_t *adapter; + v_CONTEXT_t vos_ctx; + + vos_ctx = cds_get_global_context(); + if (!vos_ctx) + return; + + hdd_ctx = (hdd_context_t *)cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + + /* Send packet dump only for STA interface */ + if (adapter->device_mode != QDF_STA_MODE) + return; + + pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP; + pktlog_hdr.size = sizeof(pd_hdr) + netbuf->len; + + pd_hdr.status = status; + pd_hdr.type = type; + pd_hdr.driver_ts = qdf_get_monotonic_boottime(); + + if ((type == TX_MGMT_PKT) || (type == TX_DATA_PKT)) + gtx_count++; + else if ((type == RX_MGMT_PKT) || (type == RX_DATA_PKT)) + grx_count++; + + wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, netbuf->data); +} + + +/* + * send_packetdump_monitor() - sends start/stop packet dump indication + * @type: type of packet + * + * This function is used to indicate HAL layer to start/stop monitoring + * of packets + * + * Return: None + * + */ +static void send_packetdump_monitor(uint8_t type) +{ + struct ath_pktlog_hdr pktlog_hdr = {0}; + struct packet_dump pd_hdr = {0}; + + pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP; + pktlog_hdr.size = sizeof(pd_hdr); + + pd_hdr.type = type; + + LOGGING_TRACE(QDF_TRACE_LEVEL_INFO, + "fate Tx-Rx %s: type: %d", __func__, type); + + wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, NULL); +} + +/** + * wlan_deregister_txrx_packetdump() - tx/rx packet dump + * deregistration + * + * This function is used to deregister tx/rx packet dump callbacks + * with ol, pe and htt layers + * + * Return: None + * + */ +void wlan_deregister_txrx_packetdump(void) +{ + if (gtx_count || grx_count) { + ol_deregister_packetdump_callback(); + wma_deregister_packetdump_callback(); + send_packetdump_monitor(STOP_MONITOR); + csr_packetdump_timer_stop(); + + gtx_count = 0; + grx_count = 0; + } else + LOGGING_TRACE(QDF_TRACE_LEVEL_INFO, + "%s: deregistered packetdump already", __func__); +} + +/* + * check_txrx_packetdump_count() - function to check + * tx/rx packet dump global counts + * + * This function is used to check global counts of tx/rx + * packet dump functionality. + * + * Return: 1 if either gtx_count or grx_count reached 32 + * 0 otherwise + * + */ +static bool check_txrx_packetdump_count(void) +{ + if (gtx_count == MAX_NUM_PKT_LOG || + grx_count == MAX_NUM_PKT_LOG) { + LOGGING_TRACE(QDF_TRACE_LEVEL_INFO, + "%s gtx_count: %d grx_count: %d deregister packetdump", + __func__, gtx_count, grx_count); + wlan_deregister_txrx_packetdump(); + return 1; + } + return 0; +} + +/* + * tx_packetdump_cb() - tx packet dump callback + * @netbuf: netbuf + * @status: status of tx packet + * @vdev_id: virtual device id + * @type: packet type + * + * This function is used to send tx packet dump to HAL layer + * and deregister packet dump callbacks + * + * Return: None + * + */ +static void tx_packetdump_cb(qdf_nbuf_t netbuf, uint8_t status, + uint8_t vdev_id, uint8_t type) +{ + bool temp; + + temp = check_txrx_packetdump_count(); + if (temp) + return; + + driver_hal_status_map(&status); + send_packetdump(netbuf, status, vdev_id, type); +} + + +/* + * rx_packetdump_cb() - rx packet dump callback + * @netbuf: netbuf + * @status: status of rx packet + * @vdev_id: virtual device id + * @type: packet type + * + * This function is used to send rx packet dump to HAL layer + * and deregister packet dump callbacks + * + * Return: None + * + */ +static void rx_packetdump_cb(qdf_nbuf_t netbuf, uint8_t status, + uint8_t vdev_id, uint8_t type) +{ + bool temp; + + temp = check_txrx_packetdump_count(); + if (temp) + return; + + send_packetdump(netbuf, status, vdev_id, type); +} + + +/** + * wlan_register_txrx_packetdump() - tx/rx packet dump + * registration + * + * This function is used to register tx/rx packet dump callbacks + * with ol, pe and htt layers + * + * Return: None + * + */ +void wlan_register_txrx_packetdump(void) +{ + ol_register_packetdump_callback(tx_packetdump_cb, + rx_packetdump_cb); + wma_register_packetdump_callback(tx_packetdump_cb, + rx_packetdump_cb); + send_packetdump_monitor(START_MONITOR); + + gtx_count = 0; + grx_count = 0; +} #endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index b8468bb672..bda463e010 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -511,6 +511,9 @@ typedef void (*encrypt_decrypt_cb)(struct sir_encrypt_decrypt_rsp_params *encrypt_decrypt_rsp_params); +typedef void (*tp_wma_packetdump_cb)(qdf_nbuf_t netbuf, + uint8_t status, uint8_t vdev_id, uint8_t type); + /** * enum t_wma_drv_type - wma driver type * @WMA_DRIVER_TYPE_PRODUCTION: production driver type @@ -1191,6 +1194,7 @@ struct wmi_desc_t { pWMAAckFnTxComp ota_post_proc_cb; qdf_nbuf_t nbuf; uint32_t desc_id; + uint8_t vdev_id; }; /** @@ -1602,6 +1606,9 @@ typedef struct { QDF_STATUS (*pe_ndp_event_handler)(tpAniSirGlobal mac_ctx, cds_msg_t *msg); bool sub_20_support; + + tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb; + tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb; } t_wma_handle, *tp_wma_handle; /** @@ -2324,3 +2331,7 @@ QDF_STATUS wma_start_oem_data_req(tp_wma_handle wma_handle, QDF_STATUS wma_enable_disable_caevent_ind(tp_wma_handle wma_handle, uint8_t val); +void wma_register_packetdump_callback( + tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb, + tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb); +void wma_deregister_packetdump_callback(void); diff --git a/core/wma/src/wma_data.c b/core/wma/src/wma_data.c index 8972e1791c..84674c38f2 100644 --- a/core/wma/src/wma_data.c +++ b/core/wma/src/wma_data.c @@ -2831,6 +2831,7 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen, status = QDF_STATUS_E_FAILURE; } else { mgmt_param.desc_id = wmi_desc->desc_id; + wmi_desc->vdev_id = vdev_id; status = wmi_mgmt_unified_cmd_send( wma_handle->wmi_handle, &mgmt_param); diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c index a3223b2f68..a0f798fc71 100644 --- a/core/wma/src/wma_mgmt.c +++ b/core/wma/src/wma_mgmt.c @@ -2496,6 +2496,11 @@ int wma_process_mgmt_tx_completion(tp_wma_handle wma_handle, if (wmi_desc->nbuf) qdf_nbuf_unmap_single(pdev->osdev, wmi_desc->nbuf, QDF_DMA_TO_DEVICE); + + if (wma_handle->wma_mgmt_tx_packetdump_cb) + wma_handle->wma_mgmt_tx_packetdump_cb(wmi_desc->nbuf, + QDF_STATUS_SUCCESS, wmi_desc->vdev_id, TX_MGMT_PKT); + if (wmi_desc->tx_cmpl_cb) wmi_desc->tx_cmpl_cb(wma_handle->mac_context, wmi_desc->nbuf, 1); @@ -3298,6 +3303,13 @@ static int wma_mgmt_rx_process(void *handle, uint8_t *data, return -EINVAL; } + if ((mgt_type == IEEE80211_FC0_TYPE_MGT && + mgt_subtype != IEEE80211_FC0_SUBTYPE_BEACON) && + wma_handle->wma_mgmt_rx_packetdump_cb) + wma_handle->wma_mgmt_rx_packetdump_cb(rx_pkt->pkt_buf, + QDF_STATUS_SUCCESS, rx_pkt->pkt_meta.sessionId, + RX_MGMT_PKT); + wma_handle->mgmt_rx(wma_handle, rx_pkt); return 0; } @@ -3395,3 +3407,51 @@ QDF_STATUS wma_register_mgmt_frm_client( return QDF_STATUS_SUCCESS; } + +/** + * wma_register_packetdump_callback() - stores tx and rx mgmt packet dump + * callback handler + * @wma_mgmt_tx_packetdump_cb: tx mgmt packetdump cb + * @wma_mgmt_rx_packetdump_cb: rx mgmt packetdump cb + * + * This function is used to store tx and rx mgmt. packet dump callback + * + * Return: None + * + */ +void wma_register_packetdump_callback( + tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb, + tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + WMA_LOGE("wma handle is NULL"); + return; + } + + wma_handle->wma_mgmt_tx_packetdump_cb = wma_mgmt_tx_packetdump_cb; + wma_handle->wma_mgmt_rx_packetdump_cb = wma_mgmt_rx_packetdump_cb; +} + +/** + * wma_deregister_packetdump_callback() - removes tx and rx mgmt packet dump + * callback handler + * + * This function is used to remove tx and rx mgmt. packet dump callback + * + * Return: None + * + */ +void wma_deregister_packetdump_callback(void) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + WMA_LOGE("wma handle is NULL"); + return; + } + + wma_handle->wma_mgmt_tx_packetdump_cb = NULL; + wma_handle->wma_mgmt_tx_packetdump_cb = NULL; +} diff --git a/uapi/linux/pktlog_ac_fmt.h b/uapi/linux/pktlog_ac_fmt.h index c8782fd03f..46dc10a8a5 100644 --- a/uapi/linux/pktlog_ac_fmt.h +++ b/uapi/linux/pktlog_ac_fmt.h @@ -70,6 +70,26 @@ struct ath_pktlog_hdr { #endif } __ATTRIB_PACK; +/** + * enum pkt_type - packet type + * @START_MONITOR: indicates parser to start packetdump parsing + * @STOP_MONITOR: indicates parser to stop packetdump parsing + * @TX_MGMT_PKT: TX management Packet + * @TX_DATA_PKT: TX data Packet + * @RX_MGMT_PKT: RX management Packet + * @RX_DATA_PKT: RX data Packet + * + * This enum has packet types + */ +enum pkt_type { + START_MONITOR = 1, + STOP_MONITOR, + TX_MGMT_PKT, + TX_DATA_PKT, + RX_MGMT_PKT, + RX_DATA_PKT, +}; + #define ATH_PKTLOG_HDR_FLAGS_MASK 0xffff #define ATH_PKTLOG_HDR_FLAGS_SHIFT 0 #define ATH_PKTLOG_HDR_FLAGS_OFFSET 0 @@ -127,17 +147,18 @@ enum { /* Types of packet log events */ -#define PKTLOG_TYPE_TX_CTRL 1 -#define PKTLOG_TYPE_TX_STAT 2 -#define PKTLOG_TYPE_TX_MSDU_ID 3 -#define PKTLOG_TYPE_TX_FRM_HDR 4 -#define PKTLOG_TYPE_RX_STAT 5 -#define PKTLOG_TYPE_RC_FIND 6 -#define PKTLOG_TYPE_RC_UPDATE 7 +#define PKTLOG_TYPE_TX_CTRL 1 +#define PKTLOG_TYPE_TX_STAT 2 +#define PKTLOG_TYPE_TX_MSDU_ID 3 +#define PKTLOG_TYPE_TX_FRM_HDR 4 +#define PKTLOG_TYPE_RX_STAT 5 +#define PKTLOG_TYPE_RC_FIND 6 +#define PKTLOG_TYPE_RC_UPDATE 7 #define PKTLOG_TYPE_TX_VIRT_ADDR 8 #define PKTLOG_TYPE_SMART_ANTENNA 9 #define PKTLOG_TYPE_SW_EVENT 10 -#define PKTLOG_TYPE_MAX 11 +#define PKTLOG_TYPE_PKT_DUMP 11 +#define PKTLOG_TYPE_MAX 12 #define PKTLOG_MAX_TXCTL_WORDS 57 /* +2 words for bitmap */ #define PKTLOG_MAX_TXSTATUS_WORDS 32 @@ -287,5 +308,82 @@ struct ath_pktlog_buf { sizeof(struct ath_pktlog_hdr)) ? _rd_offset : 0; \ } while(0) +/** + * enum tx_pkt_fate - tx packet fate + * @TX_PKT_FATE_ACKED: Sent over air and ACKed + * @TX_PKT_FATE_SENT: Sent over air but not ACKed. + * @TX_PKT_FATE_FW_QUEUED: Queued within firmware, + * but not yet sent over air + * @TX_PKT_FATE_FW_DROP_INVALID: Dropped by firmware as invalid. + * E.g. bad source address, bad checksum, or invalid for current state. + * @TX_PKT_FATE_FW_DROP_NOBUFS: Dropped by firmware due + * to lack of buffer space + * @TX_PKT_FATE_FW_DROP_OTHER: Dropped by firmware for any other + * reason. Includes frames that were sent by driver to firmware, but + * unaccounted for by firmware. + * @TX_PKT_FATE_DRV_QUEUED: Queued within driver, not yet sent to firmware. + * @TX_PKT_FATE_DRV_DROP_INVALID: Dropped by driver as invalid. + * E.g. bad source address, or invalid for current state. + * @TX_PKT_FATE_DRV_DROP_NOBUFS: Dropped by driver due to lack of buffer space + * @TX_PKT_FATE_DRV_DROP_OTHER: Dropped by driver for any other reason. + * E.g. out of buffers. + * + * This enum has packet fate types + */ + +enum tx_pkt_fate { + TX_PKT_FATE_ACKED, + TX_PKT_FATE_SENT, + TX_PKT_FATE_FW_QUEUED, + TX_PKT_FATE_FW_DROP_INVALID, + TX_PKT_FATE_FW_DROP_NOBUFS, + TX_PKT_FATE_FW_DROP_OTHER, + TX_PKT_FATE_DRV_QUEUED, + TX_PKT_FATE_DRV_DROP_INVALID, + TX_PKT_FATE_DRV_DROP_NOBUFS, + TX_PKT_FATE_DRV_DROP_OTHER, +}; + +/** + * enum rx_pkt_fate - rx packet fate + * @RX_PKT_FATE_SUCCESS: Valid and delivered to + * network stack (e.g., netif_rx()). + * @RX_PKT_FATE_FW_QUEUED: Queued within firmware, + * but not yet sent to driver. + * @RX_PKT_FATE_FW_DROP_FILTER: Dropped by firmware + * due to host-programmable filters. + * @RX_PKT_FATE_FW_DROP_INVALID: Dropped by firmware + * as invalid. E.g. bad checksum, decrypt failed, or invalid for current state. + * @RX_PKT_FATE_FW_DROP_NOBUFS: Dropped by firmware + * due to lack of buffer space. + * @RX_PKT_FATE_FW_DROP_OTHER: Dropped by firmware + * for any other reason. + * @RX_PKT_FATE_DRV_QUEUED: Queued within driver, + * not yet delivered to network stack. + * @RX_PKT_FATE_DRV_DROP_FILTER: Dropped by driver + * due to filter rules. + * @RX_PKT_FATE_DRV_DROP_INVALID: Dropped by driver as invalid. + * E.g. not permitted in current state. + * @RX_PKT_FATE_DRV_DROP_NOBUFS: Dropped by driver + * due to lack of buffer space. + * @RX_PKT_FATE_DRV_DROP_OTHER: Dropped by driver for any other reason. + * + * This enum has packet fate types + */ + +enum rx_pkt_fate { + RX_PKT_FATE_SUCCESS, + RX_PKT_FATE_FW_QUEUED, + RX_PKT_FATE_FW_DROP_FILTER, + RX_PKT_FATE_FW_DROP_INVALID, + RX_PKT_FATE_FW_DROP_NOBUFS, + RX_PKT_FATE_FW_DROP_OTHER, + RX_PKT_FATE_DRV_QUEUED, + RX_PKT_FATE_DRV_DROP_FILTER, + RX_PKT_FATE_DRV_DROP_INVALID, + RX_PKT_FATE_DRV_DROP_NOBUFS, + RX_PKT_FATE_DRV_DROP_OTHER, +}; + #endif /* _PKTLOG_FMT_H_ */ #endif /* REMOVE_PKT_LOG */