qcacld-3.0: Initial snapshot of ihelium wlan driver
qcacld-3.0: Initial snapshot of ihelium wlan driver
to match code-scanned SU Release 5.0.0.139. This is
open-source version of wlan for next Android release.
Change-Id: Icf598ca97da74f84bea607e4e902d1889806f507
diff --git a/core/hdd/src/wlan_hdd_softap_tx_rx.c b/core/hdd/src/wlan_hdd_softap_tx_rx.c
new file mode 100644
index 0000000..6626ca2
--- /dev/null
+++ b/core/hdd/src/wlan_hdd_softap_tx_rx.c
@@ -0,0 +1,943 @@
+/*
+ * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+/* Include files */
+#include <linux/semaphore.h>
+#include <wlan_hdd_tx_rx.h>
+#include <wlan_hdd_softap_tx_rx.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <cdf_types.h>
+#include <ani_global.h>
+#include <cdf_types.h>
+#include <net/ieee80211_radiotap.h>
+#include <cds_sched.h>
+#include <wlan_hdd_napi.h>
+
+#ifdef IPA_OFFLOAD
+#include <wlan_hdd_ipa.h>
+#endif
+
+/* Preprocessor definitions and constants */
+#undef QCA_HDD_SAP_DUMP_SK_BUFF
+
+/* Type declarations */
+
+/* Function definitions and documenation */
+#ifdef QCA_HDD_SAP_DUMP_SK_BUFF
+/**
+ * hdd_softap_dump_sk_buff() - Dump an skb
+ * @skb: skb to dump
+ *
+ * Return: None
+ */
+static void hdd_softap_dump_sk_buff(struct sk_buff *skb)
+{
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: head = %p ", __func__, skb->head);
+ /* CDF_TRACE( CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,"%s: data = %p ", __func__, skb->data); */
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: tail = %p ", __func__, skb->tail);
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: end = %p ", __func__, skb->end);
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: len = %d ", __func__, skb->len);
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: data_len = %d ", __func__, skb->data_len);
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: mac_len = %d", __func__, skb->mac_len);
+
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ", skb->data[0],
+ skb->data[1], skb->data[2], skb->data[3], skb->data[4],
+ skb->data[5], skb->data[6], skb->data[7]);
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", skb->data[8],
+ skb->data[9], skb->data[10], skb->data[11], skb->data[12],
+ skb->data[13], skb->data[14], skb->data[15]);
+}
+#else
+static void hdd_softap_dump_sk_buff(struct sk_buff *skb)
+{
+}
+#endif
+
+#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
+/**
+ * hdd_softap_tx_resume_timer_expired_handler() - TX Q resume timer handler
+ * @adapter_context: pointer to vdev adapter
+ *
+ * TX Q resume timer handler for SAP and P2P GO interface. If Blocked
+ * OS Q is not resumed during timeout period, to prevent permanent
+ * stall, resume OS Q forcefully for SAP and P2P GO interface.
+ *
+ * Return: None
+ */
+void hdd_softap_tx_resume_timer_expired_handler(void *adapter_context)
+{
+ hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context;
+
+ if (!pAdapter) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: INV ARG", __func__);
+ /* INVALID ARG */
+ return;
+ }
+
+ hddLog(LOG1, FL("Enabling queues"));
+ wlan_hdd_netif_queue_control(pAdapter, WLAN_WAKE_ALL_NETIF_QUEUE,
+ WLAN_CONTROL_PATH);
+ return;
+}
+
+/**
+ * hdd_softap_tx_resume_cb() - Resume OS TX Q.
+ * @adapter_context: pointer to vdev apdapter
+ * @tx_resume: TX Q resume trigger
+ *
+ * Q was stopped due to WLAN TX path low resource condition
+ *
+ * Return: None
+ */
+void hdd_softap_tx_resume_cb(void *adapter_context, bool tx_resume)
+{
+ hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context;
+
+ if (!pAdapter) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: INV ARG", __func__);
+ /* INVALID ARG */
+ return;
+ }
+
+ /* Resume TX */
+ if (true == tx_resume) {
+ if (CDF_TIMER_STATE_STOPPED !=
+ cdf_mc_timer_get_current_state(&pAdapter->
+ tx_flow_control_timer)) {
+ cdf_mc_timer_stop(&pAdapter->tx_flow_control_timer);
+ }
+
+ hddLog(LOG1, FL("Enabling queues"));
+ wlan_hdd_netif_queue_control(pAdapter,
+ WLAN_WAKE_ALL_NETIF_QUEUE,
+ WLAN_DATA_FLOW_CONTROL);
+ }
+#if defined(CONFIG_PER_VDEV_TX_DESC_POOL)
+ else if (false == tx_resume) { /* Pause TX */
+ hddLog(LOG1, FL("Disabling queues"));
+ wlan_hdd_netif_queue_control(pAdapter,
+ WLAN_STOP_ALL_NETIF_QUEUE,
+ WLAN_DATA_FLOW_CONTROL);
+ if (CDF_TIMER_STATE_STOPPED ==
+ cdf_mc_timer_get_current_state(&pAdapter->
+ tx_flow_control_timer)) {
+ CDF_STATUS status;
+ status =
+ cdf_mc_timer_start(&pAdapter->tx_flow_control_timer,
+ WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ CDF_TRACE(CDF_MODULE_ID_HDD,
+ CDF_TRACE_LEVEL_ERROR,
+ "%s: Failed to start tx_flow_control_timer",
+ __func__);
+ else
+ pAdapter->hdd_stats.hddTxRxStats.txflow_timer_cnt++;
+ }
+ }
+#endif
+
+ return;
+}
+#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
+
+/**
+ * hdd_softap_hard_start_xmit() - Transmit a frame
+ * @skb: pointer to OS packet (sk_buff)
+ * @dev: pointer to network device
+ *
+ * Function registered with the Linux OS for transmitting
+ * packets. This version of the function directly passes
+ * the packet to Transport Layer.
+ *
+ * Return: Always returns NETDEV_TX_OK
+ */
+int hdd_softap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ sme_ac_enum_type ac = SME_AC_BE;
+ hdd_adapter_t *pAdapter = (hdd_adapter_t *) netdev_priv(dev);
+ hdd_ap_ctx_t *pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pAdapter);
+ hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+ struct cdf_mac_addr *pDestMacAddress;
+ uint8_t STAId;
+ uint8_t proto_type = 0;
+#ifdef QCA_PKT_PROTO_TRACE
+ hdd_context_t *hddCtxt = (hdd_context_t *) pAdapter->pHddCtx;
+#endif /* QCA_PKT_PROTO_TRACE */
+
+ ++pAdapter->hdd_stats.hddTxRxStats.txXmitCalled;
+ /* Prevent this function from being called during SSR since TL
+ * context may not be reinitialized at this time which may
+ * lead to a crash.
+ */
+ if (pHddCtx->isLogpInProgress) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: LOGP in Progress. Ignore!!!", __func__);
+ goto drop_pkt;
+ }
+
+ /*
+ * If the device is operating on a DFS Channel
+ * then check if SAP is in CAC WAIT state and
+ * drop the packets. In CAC WAIT state device
+ * is expected not to transmit any frames.
+ * SAP starts Tx only after the BSS START is
+ * done.
+ */
+ if (pHddApCtx->dfs_cac_block_tx) {
+ goto drop_pkt;
+ }
+
+ pDestMacAddress = (struct cdf_mac_addr *) skb->data;
+
+ if (cdf_is_macaddr_broadcast(pDestMacAddress) ||
+ cdf_is_macaddr_group(pDestMacAddress)) {
+ /* The BC/MC station ID is assigned during BSS
+ * starting phase. SAP will return the station ID
+ * used for BC/MC traffic.
+ */
+ STAId = pHddApCtx->uBCStaId;
+ } else {
+ if (CDF_STATUS_SUCCESS !=
+ hdd_softap_get_sta_id(pAdapter,
+ pDestMacAddress, &STAId)) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA,
+ CDF_TRACE_LEVEL_WARN,
+ "%s: Failed to find right station", __func__);
+ goto drop_pkt;
+ }
+
+ if (STAId == HDD_WLAN_INVALID_STA_ID) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA,
+ CDF_TRACE_LEVEL_WARN,
+ "%s: Failed to find right station", __func__);
+ goto drop_pkt;
+ } else if (false == pAdapter->aStaInfo[STAId].isUsed) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA,
+ CDF_TRACE_LEVEL_WARN,
+ "%s: STA %d is unregistered", __func__,
+ STAId);
+ goto drop_pkt;
+ }
+
+ if ((ol_txrx_peer_state_conn !=
+ pAdapter->aStaInfo[STAId].tlSTAState)
+ && (ol_txrx_peer_state_auth !=
+ pAdapter->aStaInfo[STAId].tlSTAState)) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA,
+ CDF_TRACE_LEVEL_WARN,
+ "%s: Station not connected yet", __func__);
+ goto drop_pkt;
+ } else if (ol_txrx_peer_state_conn ==
+ pAdapter->aStaInfo[STAId].tlSTAState) {
+ if (ntohs(skb->protocol) != HDD_ETHERTYPE_802_1_X) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA,
+ CDF_TRACE_LEVEL_WARN,
+ "%s: NON-EAPOL packet in non-Authenticated state",
+ __func__);
+ goto drop_pkt;
+ }
+ }
+ }
+
+ hdd_get_tx_resource(pAdapter, STAId,
+ WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME);
+
+ /* Get TL AC corresponding to Qdisc queue index/AC. */
+ ac = hdd_qdisc_ac_to_tl_ac[skb->queue_mapping];
+ ++pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[ac];
+
+#if defined (IPA_OFFLOAD)
+ if (!(NBUF_OWNER_ID(skb) == IPA_NBUF_OWNER_ID)) {
+#endif
+ /* Check if the buffer has enough header room */
+ skb = skb_unshare(skb, GFP_ATOMIC);
+ if (!skb)
+ goto drop_pkt;
+
+ if (skb_headroom(skb) < dev->hard_header_len) {
+ struct sk_buff *tmp;
+ tmp = skb;
+ skb = skb_realloc_headroom(tmp, dev->hard_header_len);
+ dev_kfree_skb(tmp);
+ if (!skb)
+ goto drop_pkt;
+ }
+#if defined (IPA_OFFLOAD)
+ }
+#endif
+
+ wlan_hdd_log_eapol(skb,
+ WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED);
+
+#ifdef QCA_PKT_PROTO_TRACE
+ if ((hddCtxt->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_EAPOL) ||
+ (hddCtxt->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_DHCP)) {
+ /* Proto Trace enabled */
+ proto_type = cds_pkt_get_proto_type(skb,
+ hddCtxt->config->
+ gEnableDebugLog, 0);
+ if (CDS_PKT_TRAC_TYPE_EAPOL & proto_type) {
+ cds_pkt_trace_buf_update("HA:T:EPL");
+ } else if (CDS_PKT_TRAC_TYPE_DHCP & proto_type) {
+ cds_pkt_trace_buf_update("HA:T:DHC");
+ }
+ }
+#endif /* QCA_PKT_PROTO_TRACE */
+ pAdapter->stats.tx_bytes += skb->len;
+ ++pAdapter->stats.tx_packets;
+
+ /* Zero out skb's context buffer for the driver to use */
+ cdf_mem_set(skb->cb, sizeof(skb->cb), 0);
+ NBUF_SET_PACKET_TRACK(skb, NBUF_TX_PKT_DATA_TRACK);
+ NBUF_UPDATE_TX_PKT_COUNT(skb, NBUF_TX_PKT_HDD);
+
+ cdf_dp_trace_set_track(skb);
+ DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_HDD_PACKET_PTR_RECORD,
+ (uint8_t *)skb->data, sizeof(skb->data)));
+ DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_HDD_PACKET_RECORD,
+ (uint8_t *)skb->data, cdf_nbuf_len(skb)));
+ if (cdf_nbuf_len(skb) > CDF_DP_TRACE_RECORD_SIZE)
+ DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_HDD_PACKET_RECORD,
+ (uint8_t *)&skb->data[CDF_DP_TRACE_RECORD_SIZE],
+ (cdf_nbuf_len(skb)-CDF_DP_TRACE_RECORD_SIZE)));
+
+ if (ol_tx_send_data_frame(STAId, skb,
+ proto_type) != NULL) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_WARN,
+ "%s: Failed to send packet to txrx for staid:%d",
+ __func__, STAId);
+ ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
+ goto drop_pkt;
+ }
+ dev->trans_start = jiffies;
+
+ return NETDEV_TX_OK;
+
+drop_pkt:
+
+ DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_DROP_PACKET_RECORD,
+ (uint8_t *)skb->data, cdf_nbuf_len(skb)));
+ if (cdf_nbuf_len(skb) > CDF_DP_TRACE_RECORD_SIZE)
+ DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_DROP_PACKET_RECORD,
+ (uint8_t *)&skb->data[CDF_DP_TRACE_RECORD_SIZE],
+ (cdf_nbuf_len(skb)-CDF_DP_TRACE_RECORD_SIZE)));
+
+ ++pAdapter->stats.tx_dropped;
+ ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
+ kfree_skb(skb);
+
+ return NETDEV_TX_OK;
+}
+
+/**
+ * __hdd_softap_tx_timeout() - TX timeout handler
+ * @dev: pointer to network device
+ *
+ * This function is registered as a netdev ndo_tx_timeout method, and
+ * is invoked by the kernel if the driver takes too long to transmit a
+ * frame.
+ *
+ * Return: None
+ */
+static void __hdd_softap_tx_timeout(struct net_device *dev)
+{
+ hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+ hdd_context_t *hdd_ctx;
+
+ DPTRACE(cdf_dp_trace(NULL, CDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT,
+ NULL, 0));
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: Transmission timeout occurred", __func__);
+ /* Getting here implies we disabled the TX queues for too
+ * long. Queues are disabled either because of disassociation
+ * or low resource scenarios. In case of disassociation it is
+ * ok to ignore this. But if associated, we have do possible
+ * recovery here
+ */
+ hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+ if (hdd_ctx->isLogpInProgress) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: LOGP in Progress. Ignore!!!", __func__);
+ return;
+ }
+}
+
+/**
+ * hdd_softap_tx_timeout() - SSR wrapper for __hdd_softap_tx_timeout
+ * @dev: pointer to net_device
+ *
+ * Return: none
+ */
+void hdd_softap_tx_timeout(struct net_device *dev)
+{
+ cds_ssr_protect(__func__);
+ __hdd_softap_tx_timeout(dev);
+ cds_ssr_unprotect(__func__);
+}
+
+/**
+ * @hdd_softap_init_tx_rx() - Initialize Tx/RX module
+ * @pAdapter: pointer to adapter context
+ *
+ * Return: CDF_STATUS_E_FAILURE if any errors encountered,
+ * CDF_STATUS_SUCCESS otherwise
+ */
+CDF_STATUS hdd_softap_init_tx_rx(hdd_adapter_t *pAdapter)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ uint8_t STAId = 0;
+
+ cdf_mem_zero(&pAdapter->stats, sizeof(struct net_device_stats));
+
+ spin_lock_init(&pAdapter->staInfo_lock);
+
+ for (STAId = 0; STAId < WLAN_MAX_STA_COUNT; STAId++) {
+ cdf_mem_zero(&pAdapter->aStaInfo[STAId],
+ sizeof(hdd_station_info_t));
+ }
+
+ return status;
+}
+
+/**
+ * @hdd_softap_deinit_tx_rx() - Deinitialize Tx/RX module
+ * @pAdapter: pointer to adapter context
+ *
+ * Return: CDF_STATUS_E_FAILURE if any errors encountered,
+ * CDF_STATUS_SUCCESS otherwise
+ */
+CDF_STATUS hdd_softap_deinit_tx_rx(hdd_adapter_t *pAdapter)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ return status;
+}
+
+/**
+ * hdd_softap_init_tx_rx_sta() - Initialize tx/rx for a softap station
+ * @pAdapter: pointer to adapter context
+ * @STAId: Station ID to initialize
+ * @pmacAddrSTA: pointer to the MAC address of the station
+ *
+ * Return: CDF_STATUS_E_FAILURE if any errors encountered,
+ * CDF_STATUS_SUCCESS otherwise
+ */
+CDF_STATUS hdd_softap_init_tx_rx_sta(hdd_adapter_t *pAdapter, uint8_t STAId,
+ struct cdf_mac_addr *pmacAddrSTA)
+{
+ spin_lock_bh(&pAdapter->staInfo_lock);
+ if (pAdapter->aStaInfo[STAId].isUsed) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: Reinit station %d", __func__, STAId);
+ spin_unlock_bh(&pAdapter->staInfo_lock);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ cdf_mem_zero(&pAdapter->aStaInfo[STAId], sizeof(hdd_station_info_t));
+
+ pAdapter->aStaInfo[STAId].isUsed = true;
+ pAdapter->aStaInfo[STAId].isDeauthInProgress = false;
+ cdf_copy_macaddr(&pAdapter->aStaInfo[STAId].macAddrSTA, pmacAddrSTA);
+
+ spin_unlock_bh(&pAdapter->staInfo_lock);
+ return CDF_STATUS_SUCCESS;
+}
+
+/**
+ * hdd_softap_deinit_tx_rx_sta() - Deinitialize tx/rx for a softap station
+ * @pAdapter: pointer to adapter context
+ * @STAId: Station ID to deinitialize
+ *
+ * Return: CDF_STATUS_E_FAILURE if any errors encountered,
+ * CDF_STATUS_SUCCESS otherwise
+ */
+CDF_STATUS hdd_softap_deinit_tx_rx_sta(hdd_adapter_t *pAdapter, uint8_t STAId)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ hdd_hostapd_state_t *pHostapdState;
+
+ pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter);
+
+ spin_lock_bh(&pAdapter->staInfo_lock);
+
+ if (false == pAdapter->aStaInfo[STAId].isUsed) {
+ spin_unlock_bh(&pAdapter->staInfo_lock);
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: Deinit station not inited %d", __func__, STAId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ pAdapter->aStaInfo[STAId].isUsed = false;
+ pAdapter->aStaInfo[STAId].isDeauthInProgress = false;
+
+ spin_unlock_bh(&pAdapter->staInfo_lock);
+ return status;
+}
+
+/**
+ * hdd_softap_rx_packet_cbk() - Receive packet handler
+ * @cds_context: pointer to CDS context
+ * @rxBuf: pointer to rx cdf_nbuf
+ * @staId: Station Id
+ *
+ * Receive callback registered with TL. TL will call this to notify
+ * the HDD when one or more packets were received for a registered
+ * STA.
+ *
+ * Return: CDF_STATUS_E_FAILURE if any errors encountered,
+ * CDF_STATUS_SUCCESS otherwise
+ */
+CDF_STATUS hdd_softap_rx_packet_cbk(void *cds_context,
+ cdf_nbuf_t rxBuf, uint8_t staId)
+{
+ hdd_adapter_t *pAdapter = NULL;
+ int rxstat;
+ unsigned int cpu_index;
+ struct sk_buff *skb = NULL;
+ hdd_context_t *pHddCtx = NULL;
+#ifdef QCA_PKT_PROTO_TRACE
+ uint8_t proto_type;
+#endif /* QCA_PKT_PROTO_TRACE */
+
+ /* Sanity check on inputs */
+ if ((NULL == cds_context) || (NULL == rxBuf)) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: Null params being passed", __func__);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ pHddCtx = cds_get_context(CDF_MODULE_ID_HDD);
+ if (NULL == pHddCtx) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: HDD context is Null", __func__);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ pAdapter = pHddCtx->sta_to_adapter[staId];
+ if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
+ hddLog(LOGE,
+ FL("invalid adapter %p or adapter has invalid magic"),
+ pAdapter);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ /* walk the chain until all are processed */
+ skb = (struct sk_buff *)rxBuf;
+
+ hdd_softap_dump_sk_buff(skb);
+
+ skb->dev = pAdapter->dev;
+
+ if (skb->dev == NULL) {
+
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: ERROR!!Invalid netdevice", __func__);
+ return CDF_STATUS_E_FAILURE;
+ }
+ cpu_index = wlan_hdd_get_cpu();
+ ++pAdapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
+ ++pAdapter->stats.rx_packets;
+ pAdapter->stats.rx_bytes += skb->len;
+
+ wlan_hdd_log_eapol(skb, WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED);
+
+#ifdef QCA_PKT_PROTO_TRACE
+ if ((pHddCtx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_EAPOL) ||
+ (pHddCtx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_DHCP)) {
+ proto_type = cds_pkt_get_proto_type(skb,
+ pHddCtx->config->
+ gEnableDebugLog, 0);
+ if (CDS_PKT_TRAC_TYPE_EAPOL & proto_type) {
+ cds_pkt_trace_buf_update("HA:R:EPL");
+ } else if (CDS_PKT_TRAC_TYPE_DHCP & proto_type) {
+ cds_pkt_trace_buf_update("HA:R:DHC");
+ }
+ }
+#endif /* QCA_PKT_PROTO_TRACE */
+
+ skb->protocol = eth_type_trans(skb, skb->dev);
+#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
+ cdf_wake_lock_timeout_acquire(&pHddCtx->rx_wake_lock,
+ HDD_WAKE_LOCK_DURATION,
+ WIFI_POWER_EVENT_WAKELOCK_HOLD_RX);
+#endif
+
+ /* Remove SKB from internal tracking table before submitting
+ * it to stack
+ */
+ cdf_net_buf_debug_release_skb(rxBuf);
+
+ if (hdd_napi_enabled(HDD_NAPI_ANY))
+ rxstat = netif_receive_skb(skb);
+ else
+ rxstat = netif_rx_ni(skb);
+ if (NET_RX_SUCCESS == rxstat) {
+ ++pAdapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
+ } else {
+ ++pAdapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
+ }
+
+ pAdapter->dev->last_rx = jiffies;
+
+ return CDF_STATUS_SUCCESS;
+}
+
+/**
+ * hdd_softap_deregister_sta(hdd_adapter_t *pAdapter, uint8_t staId)
+ * @pAdapter: pointer to adapter context
+ * @staId: Station ID to deregister
+ *
+ * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error
+ */
+CDF_STATUS hdd_softap_deregister_sta(hdd_adapter_t *pAdapter, uint8_t staId)
+{
+ CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
+ hdd_context_t *pHddCtx;
+
+ if (NULL == pAdapter) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: pAdapter is NULL", __func__);
+ return CDF_STATUS_E_INVAL;
+ }
+
+ if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: Invalid pAdapter magic", __func__);
+ return CDF_STATUS_E_INVAL;
+ }
+
+ pHddCtx = (hdd_context_t *) (pAdapter->pHddCtx);
+ /* Clear station in TL and then update HDD data
+ * structures. This helps to block RX frames from other
+ * station to this station.
+ */
+ cdf_status = ol_txrx_clear_peer(staId);
+ if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "ol_txrx_clear_peer() failed to for staID %d. "
+ "Status= %d [0x%08X]", staId, cdf_status, cdf_status);
+ }
+
+ if (pAdapter->aStaInfo[staId].isUsed) {
+ spin_lock_bh(&pAdapter->staInfo_lock);
+ cdf_mem_zero(&pAdapter->aStaInfo[staId],
+ sizeof(hdd_station_info_t));
+ spin_unlock_bh(&pAdapter->staInfo_lock);
+ }
+ pHddCtx->sta_to_adapter[staId] = NULL;
+
+ return cdf_status;
+}
+
+/**
+ * hdd_softap_register_sta() - Register a SoftAP STA
+ * @pAdapter: pointer to adapter context
+ * @fAuthRequired: is additional authentication required?
+ * @fPrivacyBit: should 802.11 privacy bit be set?
+ * @staId: station ID assigned to this station
+ * @ucastSig: unicast security signature
+ * @bcastSig: broadcast security signature
+ * @pPeerMacAddress: station MAC address
+ * @fWmmEnabled: is WMM enabled for this STA?
+ *
+ * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error
+ */
+CDF_STATUS hdd_softap_register_sta(hdd_adapter_t *pAdapter,
+ bool fAuthRequired,
+ bool fPrivacyBit,
+ uint8_t staId,
+ uint8_t ucastSig,
+ uint8_t bcastSig,
+ struct cdf_mac_addr *pPeerMacAddress,
+ bool fWmmEnabled)
+{
+ CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE;
+ struct ol_txrx_desc_type staDesc = { 0 };
+ hdd_context_t *pHddCtx = pAdapter->pHddCtx;
+
+ /*
+ * Clean up old entry if it is not cleaned up properly
+ */
+ if (pAdapter->aStaInfo[staId].isUsed) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO,
+ "clean up old entry for STA %d", staId);
+ hdd_softap_deregister_sta(pAdapter, staId);
+ }
+ /* Get the Station ID from the one saved during the assocation. */
+
+ staDesc.sta_id = staId;
+
+ /*Save the pAdapter Pointer for this staId */
+ pHddCtx->sta_to_adapter[staId] = pAdapter;
+
+ cdf_status =
+ hdd_softap_init_tx_rx_sta(pAdapter, staId,
+ pPeerMacAddress);
+
+ staDesc.is_qos_enabled = fWmmEnabled;
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO,
+ "HDD SOFTAP register TL QoS_enabled=%d",
+ staDesc.is_qos_enabled);
+
+
+ cdf_status =
+ ol_txrx_register_peer(hdd_softap_rx_packet_cbk,
+ &staDesc);
+ if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "SOFTAP ol_txrx_register_peer() failed to register. Status= %d [0x%08X]",
+ cdf_status, cdf_status);
+ return cdf_status;
+ }
+
+ /* if ( WPA ), tell TL to go to 'connected' and after keys come to the
+ * driver then go to 'authenticated'. For all other authentication
+ * types (those that do not require upper layer authentication) we can
+ * put TL directly into 'authenticated' state
+ */
+
+ pAdapter->aStaInfo[staId].ucSTAId = staId;
+ pAdapter->aStaInfo[staId].isQosEnabled = fWmmEnabled;
+
+ if (!fAuthRequired) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO,
+ "open/shared auth StaId= %d. Changing TL state to AUTHENTICATED at Join time",
+ pAdapter->aStaInfo[staId].ucSTAId);
+
+ /* Connections that do not need Upper layer auth,
+ * transition TL directly to 'Authenticated' state.
+ */
+ cdf_status = hdd_change_peer_state(pAdapter, staDesc.sta_id,
+ ol_txrx_peer_state_auth, false);
+
+ pAdapter->aStaInfo[staId].tlSTAState = ol_txrx_peer_state_auth;
+ pAdapter->sessionCtx.ap.uIsAuthenticated = true;
+ } else {
+
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO,
+ "ULA auth StaId= %d. Changing TL state to CONNECTED at Join time",
+ pAdapter->aStaInfo[staId].ucSTAId);
+
+ cdf_status = hdd_change_peer_state(pAdapter, staDesc.sta_id,
+ ol_txrx_peer_state_conn, false);
+ pAdapter->aStaInfo[staId].tlSTAState = ol_txrx_peer_state_conn;
+
+ pAdapter->sessionCtx.ap.uIsAuthenticated = false;
+
+ }
+
+ /* Enable Tx queue */
+ hddLog(LOG1, FL("Enabling queues"));
+ wlan_hdd_netif_queue_control(pAdapter,
+ WLAN_START_ALL_NETIF_QUEUE_N_CARRIER,
+ WLAN_CONTROL_PATH);
+
+ return cdf_status;
+}
+
+/**
+ * hdd_softap_register_bc_sta() - Register the SoftAP broadcast STA
+ * @pAdapter: pointer to adapter context
+ * @fPrivacyBit: should 802.11 privacy bit be set?
+ *
+ * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error
+ */
+CDF_STATUS hdd_softap_register_bc_sta(hdd_adapter_t *pAdapter,
+ bool fPrivacyBit)
+{
+ CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE;
+ hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+ struct cdf_mac_addr broadcastMacAddr =
+ CDF_MAC_ADDR_BROADCAST_INITIALIZER;
+ hdd_ap_ctx_t *pHddApCtx;
+
+ pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pAdapter);
+
+ pHddCtx->sta_to_adapter[WLAN_RX_BCMC_STA_ID] = pAdapter;
+#ifdef WLAN_FEATURE_MBSSID
+ pHddCtx->sta_to_adapter[pHddApCtx->uBCStaId] = pAdapter;
+#else
+ pHddCtx->sta_to_adapter[WLAN_RX_SAP_SELF_STA_ID] = pAdapter;
+#endif
+ cdf_status =
+ hdd_softap_register_sta(pAdapter, false, fPrivacyBit,
+ (WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->
+ uBCStaId, 0, 1, &broadcastMacAddr, 0);
+
+ return cdf_status;
+}
+
+/**
+ * hdd_softap_deregister_bc_sta() - Deregister the SoftAP broadcast STA
+ * @pAdapter: pointer to adapter context
+ *
+ * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error
+ */
+CDF_STATUS hdd_softap_deregister_bc_sta(hdd_adapter_t *pAdapter)
+{
+ return hdd_softap_deregister_sta(pAdapter,
+ (WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->
+ uBCStaId);
+}
+
+/**
+ * hdd_softap_stop_bss() - Stop the BSS
+ * @pAdapter: pointer to adapter context
+ *
+ * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error
+ */
+CDF_STATUS hdd_softap_stop_bss(hdd_adapter_t *pAdapter)
+{
+ CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE;
+ uint8_t staId = 0;
+ hdd_context_t *pHddCtx;
+ pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+
+ /* bss deregister is not allowed during wlan driver loading or
+ * unloading
+ */
+ if ((pHddCtx->isLoadInProgress) || (pHddCtx->isUnloadInProgress)) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s:Loading_unloading in Progress. Ignore!!!",
+ __func__);
+ return CDF_STATUS_E_PERM;
+ }
+
+ cdf_status = hdd_softap_deregister_bc_sta(pAdapter);
+
+ if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: Failed to deregister BC sta Id %d", __func__,
+ (WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->uBCStaId);
+ }
+
+ for (staId = 0; staId < WLAN_MAX_STA_COUNT; staId++) {
+ /* This excludes BC sta as it is already deregistered */
+ if (pAdapter->aStaInfo[staId].isUsed) {
+ cdf_status = hdd_softap_deregister_sta(pAdapter, staId);
+ if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA,
+ CDF_TRACE_LEVEL_ERROR,
+ "%s: Failed to deregister sta Id %d",
+ __func__, staId);
+ }
+ }
+ }
+ return cdf_status;
+}
+
+/**
+ * hdd_softap_change_sta_state() - Change the state of a SoftAP station
+ * @pAdapter: pointer to adapter context
+ * @pDestMacAddress: MAC address of the station
+ * @state: new state of the station
+ *
+ * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error
+ */
+CDF_STATUS hdd_softap_change_sta_state(hdd_adapter_t *pAdapter,
+ struct cdf_mac_addr *pDestMacAddress,
+ enum ol_txrx_peer_state state)
+{
+ uint8_t ucSTAId = WLAN_MAX_STA_COUNT;
+ CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
+
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO,
+ "%s: enter", __func__);
+
+ if (CDF_STATUS_SUCCESS !=
+ hdd_softap_get_sta_id(pAdapter,
+ pDestMacAddress, &ucSTAId)) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: Failed to find right station", __func__);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (false ==
+ cdf_is_macaddr_equal(&pAdapter->aStaInfo[ucSTAId].macAddrSTA,
+ pDestMacAddress)) {
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
+ "%s: Station MAC address does not matching",
+ __func__);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ cdf_status =
+ hdd_change_peer_state(pAdapter, ucSTAId, state, false);
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO,
+ "%s: change station to state %d succeed", __func__, state);
+
+ if (CDF_STATUS_SUCCESS == cdf_status) {
+ pAdapter->aStaInfo[ucSTAId].tlSTAState =
+ ol_txrx_peer_state_auth;
+ }
+
+ CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO,
+ "%s exit", __func__);
+
+ return cdf_status;
+}
+
+/*
+ * hdd_softap_get_sta_id() - Find station ID from MAC address
+ * @pAdapter: pointer to adapter context
+ * @pDestMacAddress: MAC address of the destination
+ * @staId: Station ID associated with the MAC address
+ *
+ * Return: CDF_STATUS_SUCCESS if a match was found, in which case
+ * staId is populated, CDF_STATUS_E_FAILURE if a match is
+ * not found
+ */
+CDF_STATUS hdd_softap_get_sta_id(hdd_adapter_t *pAdapter,
+ struct cdf_mac_addr *pMacAddress,
+ uint8_t *staId)
+{
+ uint8_t i;
+
+ for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
+ if (cdf_mem_compare
+ (&pAdapter->aStaInfo[i].macAddrSTA, pMacAddress,
+ CDF_MAC_ADDR_SIZE) && pAdapter->aStaInfo[i].isUsed) {
+ *staId = i;
+ return CDF_STATUS_SUCCESS;
+ }
+ }
+
+ return CDF_STATUS_E_FAILURE;
+}