qcacld-2.0: Add peer flush pend feature
Add peer flush pending data feature. With this feature,
user layer APP can discard any data(per access class)
currently pending transmission.
Change-Id: I4021ab73eaa793d44f945c9bc081235575337e9b
CRs-Fixed: 2143652
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index e530f70..79de31f 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -304,6 +304,8 @@
/* subcommand to get chain rssi value */
QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI = 138,
QCA_NL80211_VENDOR_SUBCMD_CHIP_PWRSAVE_FAILURE = 148,
+ /* subcommand to flush peer tids */
+ QCA_NL80211_VENDOR_SUBCMD_PEER_FLUSH_PENDING = 162,
};
/**
@@ -1578,6 +1580,27 @@
NUM_QCA_WLAN_VENDOR_FEATURES
};
+/**
+ * enum qca_wlan_vendor_attr_flush_pending - Attributes for
+ * flush pending traffic in firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_ADDR: Configure peer mac address.
+ * @QCA_WLAN_VENDOR_ATTR_AC: Configure access category the pending
+ * packets using. It is u8 value with bit0~3 represent AC_BE, AC_BK,
+ * AC_VI, AC_VO respectively. Set the corresponding bit to 1 to flush
+ * packets with access category.
+ */
+enum qca_wlan_vendor_attr_flush_pending{
+ QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_PEER_ADDR = 1,
+ QCA_WLAN_VENDOR_ATTR_AC = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_MAX =
+ QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_AFTER_LAST - 1,
+};
+
/* Feature defines */
#define WIFI_FEATURE_INFRA 0x0001 /* Basic infrastructure mode */
#define WIFI_FEATURE_INFRA_5G 0x0002 /* Support for 5 GHz Band */
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 0ac7edd..eeb7b93 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -14636,6 +14636,109 @@
return ret;
}
+static const struct
+nla_policy
+qca_wlan_vendor_peer_flush_pending_policy
+ [QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_MAX + 1] = {
+ [QCA_WLAN_VENDOR_ATTR_PEER_ADDR] = {.type = NLA_BINARY,
+ .len = VOS_MAC_ADDR_SIZE},
+ [QCA_WLAN_VENDOR_ATTR_AC] = { .type = NLA_U8 },
+};
+
+/**
+ * __wlan_hdd_cfg80211_peer_flush_tids() - flush peer pending packets
+ * @wiphy: Pointer to wireless phy
+ * @wdev: Pointer to wireless device
+ * @data: Pointer to data
+ * @data_len: Length of @data
+ *
+ * This function is used to flush peer pending packets using vendor commands
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+static int
+__wlan_hdd_cfg80211_peer_flush_pending(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
+ struct net_device *dev = wdev->netdev;
+ hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_MAX + 1];
+ struct sme_flush_pending flush_pending;
+ eHalStatus status;
+ int ret;
+
+ ENTER();
+
+ ret = wlan_hdd_validate_context(hdd_ctx);
+ if (0 != ret)
+ return ret;
+
+ if (VOS_FTM_MODE == hdd_get_conparam()) {
+ hddLog(LOGE, FL("Command not allowed in FTM mode"));
+ return -EINVAL;
+ }
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_MAX, data,
+ data_len, qca_wlan_vendor_peer_flush_pending_policy)) {
+ hddLog(LOGE, FL("Invalid attribute"));
+ return -EINVAL;
+ }
+
+ if (!tb[QCA_WLAN_VENDOR_ATTR_PEER_ADDR]) {
+ hddLog(LOGE,
+ FL("Attribute peerMac not provided"));
+ return -EINVAL;
+ }
+ memcpy(flush_pending.peer_addr.bytes,
+ nla_data(tb[QCA_WLAN_VENDOR_ATTR_PEER_ADDR]),
+ VOS_MAC_ADDR_SIZE);
+
+ if (!tb[QCA_WLAN_VENDOR_ATTR_AC]) {
+ hddLog(LOGE, FL("Attribute AC not provided"));
+ return -EINVAL;
+ }
+ flush_pending.flush_ac = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_AC]);
+ hddLog(LOG1, FL("flush ac = %02x"), flush_pending.flush_ac & 0x0f);
+
+ flush_pending.session_id = adapter->sessionId;
+ hddLog(LOG1, FL("session_id = %d"), flush_pending.session_id);
+
+ status = sme_peer_flush_pending(hdd_ctx->hHal, &flush_pending);
+ if (!HAL_STATUS_SUCCESS(status)) {
+ hddLog(LOGE, FL("sme_config_peer_flush_pending (err=%d)"),
+ status);
+ return -EINVAL;
+ }
+ EXIT();
+ return 0;
+}
+
+/**
+ * wlan_hdd_cfg80211_peer_flush_tids() - flush peer pending packets
+ * @wiphy: Pointer to wireless phy
+ * @wdev: Pointer to wireless device
+ * @data: Pointer to data
+ * @data_len: Length of @data
+ *
+ * Wrapper function of __wlan_hdd_cfg80211_peer_flush_ac()
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+static int wlan_hdd_cfg80211_peer_flush_pending(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ int ret;
+
+ vos_ssr_protect(__func__);
+ ret = __wlan_hdd_cfg80211_peer_flush_pending(wiphy, wdev,
+ data, data_len);
+ vos_ssr_unprotect(__func__);
+
+ return ret;
+}
+
const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] =
{
{
@@ -15171,6 +15274,14 @@
WIPHY_VENDOR_CMD_NEED_RUNNING,
.doit = wlan_hdd_cfg80211_ll_stats_ext_set_param
},
+ {
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_PEER_FLUSH_PENDING,
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wlan_hdd_cfg80211_peer_flush_pending
+ },
};
/*
diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h
index 8062d78..ed30ba1 100644
--- a/CORE/MAC/inc/sirApi.h
+++ b/CORE/MAC/inc/sirApi.h
@@ -8467,6 +8467,18 @@
};
/**
+ * struct sme_flush_pending - flush pending packets with specified tids
+ * @vdev_id: vdev Id.
+ * @peer_addr: peer mac address.
+ * @flush_ac: access category pending packets using
+ */
+struct sme_flush_pending {
+ uint8_t session_id;
+ v_MACADDR_t peer_addr;
+ uint8_t flush_ac;
+};
+
+/**
* struct scan_chan_info - channel info
* @freq: radio frequence
* @cmd flag: cmd flag
diff --git a/CORE/MAC/src/include/sirParams.h b/CORE/MAC/src/include/sirParams.h
index 497f329..7e0b89a 100644
--- a/CORE/MAC/src/include/sirParams.h
+++ b/CORE/MAC/src/include/sirParams.h
@@ -795,6 +795,8 @@
#define SIR_HAL_GET_PEER_INFO_EXT_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 373)
#define SIR_HAL_ACTION_FRAME_RANDOM_MAC (SIR_HAL_ITC_MSG_TYPES_BEGIN + 374)
+#define SIR_HAL_PEER_FLUSH_PENDING (SIR_HAL_ITC_MSG_TYPES_BEGIN + 375)
+
#define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF)
// CFG message types
diff --git a/CORE/SERVICES/WMA/wma.c b/CORE/SERVICES/WMA/wma.c
index 7cccc85..88d793f 100644
--- a/CORE/SERVICES/WMA/wma.c
+++ b/CORE/SERVICES/WMA/wma.c
@@ -33439,6 +33439,67 @@
}
/*
+ * wma_peer_flush_pending() - Flush peer data in fw
+ * @wma_handle: WMA handle
+ * @sta_inactivity_timer: sme_sta_inactivity_timeout
+ *
+ * This function is used to discard pending packets of tids in fw.
+ *
+ * Return: None
+ */
+static void wma_peer_flush_pending(tp_wma_handle wma,
+ struct sme_flush_pending *flush_pend)
+{
+ u_int8_t ac_to_tid[4][2] = { {0, 3}, {1, 2}, {4, 5}, {6, 7} };
+ u_int8_t vdev_id, peer_id;
+ u_int32_t peer_tid_bitmap = 0;
+ struct wma_txrx_node *iface;
+ u_int8_t i;
+ struct ol_txrx_peer_t *peer;
+ ol_txrx_pdev_handle pdev;
+
+ pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
+ if (!pdev) {
+ WMA_LOGE("%s: pdev is NULL", __func__);
+ return;
+ }
+
+ peer = ol_txrx_find_peer_by_addr(pdev, flush_pend->peer_addr.bytes,
+ &peer_id);
+ if (!peer) {
+ WMA_LOGE("PEER [%pM] not found", flush_pend->peer_addr.bytes);
+ return;
+ }
+ WMA_LOGI("PEER [%pM] found", flush_pend->peer_addr.bytes);
+
+ vdev_id = flush_pend->session_id;
+ iface = &wma->interfaces[vdev_id];
+ if (!iface->handle) {
+ WMA_LOGE("%s: Failed to get iface handle: %p",
+ __func__, iface->handle);
+ return;
+ }
+
+ if (flush_pend->flush_ac) {
+ for (i = 0; i < 4; ++i) {
+ if (((flush_pend->flush_ac & 0x0f) >> i) & 0x01) {
+ peer_tid_bitmap |= (1 << ac_to_tid[i][0]) |
+ (1 << ac_to_tid[i][1]);
+ }
+ }
+ } else {
+ return;
+ }
+
+ WMA_LOGI("%s: vdevid %d peer_tid_bitmap %08x", __func__,
+ vdev_id, peer_tid_bitmap);
+
+ wmi_unified_peer_flush_tids_send(wma->wmi_handle,
+ flush_pend->peer_addr.bytes,
+ peer_tid_bitmap, vdev_id);
+}
+
+/*
* function : wma_mc_process_msg
* Description :
* Args :
@@ -34371,6 +34432,10 @@
case WDA_GET_ISOLATION:
wma_get_isolation(wma_handle);
break;
+ case WDA_PEER_FLUSH_PENDING:
+ wma_peer_flush_pending(wma_handle, msg->bodyptr);
+ vos_mem_free(msg->bodyptr);
+ break;
default:
WMA_LOGD("unknow msg type %x", msg->type);
/* Do Nothing? MSG Body should be freed at here */
diff --git a/CORE/SME/inc/sme_Api.h b/CORE/SME/inc/sme_Api.h
index 3f553c1..0ffdfa0 100644
--- a/CORE/SME/inc/sme_Api.h
+++ b/CORE/SME/inc/sme_Api.h
@@ -4706,6 +4706,9 @@
eHalStatus sme_update_txrate(tHalHandle hal, struct sir_txrate_update *req);
+eHalStatus sme_peer_flush_pending(tHalHandle hal,
+ struct sme_flush_pending *req);
+
void sme_send_disassoc_req_frame(tHalHandle hal, uint8_t session_id,
uint8_t *peer_mac, tANI_U16 reason, uint8_t wait_for_ack);
diff --git a/CORE/SME/src/sme_common/sme_Api.c b/CORE/SME/src/sme_common/sme_Api.c
index 094c0fa..2eec9c6 100644
--- a/CORE/SME/src/sme_common/sme_Api.c
+++ b/CORE/SME/src/sme_common/sme_Api.c
@@ -18925,6 +18925,60 @@
}
/**
+ * sme_peer_flush_pending() - sme function to flush peer pending packets
+ * val
+ * @hal: Handle for Hal layer
+ * @req: specified flush pending
+ *
+ * Return: Hal status
+ */
+eHalStatus sme_peer_flush_pending(tHalHandle hal,
+ struct sme_flush_pending *req)
+{
+ eHalStatus status;
+ VOS_STATUS vos_status;
+ tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
+ vos_msg_t vos_msg;
+ struct sme_flush_pending *flush_pend;
+
+ smsLog(mac_ctx, LOG1, FL("enter"));
+
+ flush_pend = vos_mem_malloc(sizeof(*flush_pend));
+ if (NULL == flush_pend) {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("Failed to alloc flush_pend"));
+ return eHAL_STATUS_FAILED_ALLOC;
+ }
+
+ flush_pend->session_id = req->session_id;
+ flush_pend->flush_ac = req->flush_ac;
+ vos_mem_copy(flush_pend->peer_addr.bytes, req->peer_addr.bytes,
+ VOS_MAC_ADDR_SIZE);
+
+ status = sme_AcquireGlobalLock(&mac_ctx->sme);
+ if (eHAL_STATUS_SUCCESS == status) {
+ /* Serialize the req through MC thread */
+ vos_msg.bodyptr = flush_pend;
+ vos_msg.type = WDA_PEER_FLUSH_PENDING;
+ vos_status = vos_mq_post_message(VOS_MQ_ID_WDA, &vos_msg);
+
+ if (!VOS_IS_STATUS_SUCCESS(vos_status)) {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("Post peer flush pending msg fail"));
+ status = eHAL_STATUS_FAILURE;
+ vos_mem_free(flush_pend);
+ }
+ sme_ReleaseGlobalLock(&mac_ctx->sme);
+ } else {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("sme_AcquireGlobalLock failed"));
+ vos_mem_free(flush_pend);
+ }
+ smsLog(mac_ctx, LOG1, FL("exit"));
+ return status;
+}
+
+/**
* sme_delete_all_tdls_peers: send request to delete tdls peers
* @hal: handler for HAL
* @sessionId: session id
diff --git a/CORE/WDA/inc/wlan_qct_wda.h b/CORE/WDA/inc/wlan_qct_wda.h
index 0c378c8..71828b9 100644
--- a/CORE/WDA/inc/wlan_qct_wda.h
+++ b/CORE/WDA/inc/wlan_qct_wda.h
@@ -1099,6 +1099,7 @@
#define WDA_UPDATE_SHORT_RETRY_LIMIT_CNT SIR_HAL_SHORT_RETRY_LIMIT_CNT
#define WDA_UPDATE_LONG_RETRY_LIMIT_CNT SIR_HAL_LONG_RETRY_LIMIT_CNT
+#define WDA_PEER_FLUSH_PENDING SIR_HAL_PEER_FLUSH_PENDING
#define WDA_UPDATE_STA_INACTIVITY_TIMEOUT SIR_HAL_STA_INACTIVITY_TIMEOUT
#define WDA_ACTION_FRAME_RANDOM_MAC SIR_HAL_ACTION_FRAME_RANDOM_MAC