Wlan: Extended IBSS feature on prima
Changes to enable extended IBSS feature on prima open
source branch.
Change-Id: Iacaad2627d241fa6b71717d0cfbba960f0fd5d5f
CRs-Fixed: 766181
diff --git a/CORE/MAC/src/pe/lim/limApi.c b/CORE/MAC/src/pe/lim/limApi.c
index 99969da..84bbedc 100644
--- a/CORE/MAC/src/pe/lim/limApi.c
+++ b/CORE/MAC/src/pe/lim/limApi.c
@@ -762,6 +762,10 @@
limFTOpen(pMac);
#endif
+#ifdef WLAN_FEATURE_RMC
+ limRmcInit(pMac);
+#endif /* WLAN_FEATURE_RMC */
+
vos_list_init(&pMac->lim.gLimMgmtFrameRegistratinQueue);
#if 0
@@ -857,6 +861,10 @@
limCleanupMlm(pMac);
limCleanupLmm(pMac);
+#ifdef WLAN_FEATURE_RMC
+ limRmcCleanup(pMac);
+#endif /* WLAN_FEATURE_RMC */
+
// free up preAuth table
if (pMac->lim.gLimPreAuthTimerTable.pTable != NULL)
{
diff --git a/CORE/MAC/src/pe/lim/limIbssPeerMgmt.c b/CORE/MAC/src/pe/lim/limIbssPeerMgmt.c
index 51d5ed9..4ca42d3 100644
--- a/CORE/MAC/src/pe/lim/limIbssPeerMgmt.c
+++ b/CORE/MAC/src/pe/lim/limIbssPeerMgmt.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -49,6 +49,9 @@
#include "limSendMessages.h"
#include "limSession.h"
#include "limIbssPeerMgmt.h"
+#ifdef WLAN_FEATURE_RMC
+#include "limRMC.h"
+#endif
/**
@@ -820,6 +823,10 @@
limIbssDelete(
tpAniSirGlobal pMac,tpPESession psessionEntry)
{
+#ifdef WLAN_FEATURE_RMC
+ limRmcIbssDelete(pMac);
+#endif /* WLAN_FEATURE_RMC */
+
limIbssDeleteAllPeers(pMac,psessionEntry);
ibss_coalesce_free(pMac);
@@ -1177,6 +1184,10 @@
ucUcastSig = pStaDs->ucUcastSig;
ucBcastSig = pStaDs->ucBcastSig;
+#ifdef WLAN_FEATURE_RMC
+ limRmcTransmitterDelete(pMac, pStaDs->staAddr);
+#endif /* WLAN_FEATURE_RMC */
+
/* Send DEL STA only if STA id is valid, mean ADD STA was
* success.
*/
@@ -1277,6 +1288,11 @@
pStaDs->ucUcastSig, pStaDs->ucBcastSig,
eWNI_SME_IBSS_NEW_PEER_IND,
psessionEntry->smeSessionId);
+
+#ifdef WLAN_FEATURE_RMC
+ limRmcTriggerRulerSelection(pMac, psessionEntry->selfMacAddr);
+#endif
+
vos_mem_free(pAddStaParams);
return eSIR_SUCCESS;
@@ -1692,6 +1708,10 @@
ucUcastSig = pStaDs->ucUcastSig;
ucBcastSig = pStaDs->ucBcastSig;
+#ifdef WLAN_FEATURE_RMC
+ limRmcTransmitterDelete(pMac, pStaDs->staAddr);
+#endif /* WLAN_FEATURE_RMC */
+
(void) limDelSta(pMac, pStaDs, false /*asynchronous*/,psessionEntry);
limDeleteDphHashEntry(pMac, pStaDs->staAddr, peerIdx,psessionEntry);
limReleasePeerIdx(pMac, peerIdx, psessionEntry);
diff --git a/CORE/MAC/src/pe/lim/limLogDump.c b/CORE/MAC/src/pe/lim/limLogDump.c
index 8c642b8..9280c7d 100644
--- a/CORE/MAC/src/pe/lim/limLogDump.c
+++ b/CORE/MAC/src/pe/lim/limLogDump.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -57,6 +57,10 @@
#endif
#include "smeInside.h"
#include "wlan_qct_wda.h"
+#ifdef WLAN_FEATURE_RMC
+#include "wlan_qct_tl.h"
+#include "limRMC.h"
+#endif
#include "wlan_qct_wdi_dts.h"
void WDA_TimerTrafficStatsInd(tWDA_CbContext *pWDA);
@@ -1208,7 +1212,7 @@
state = (tSirMacHTMIMOPowerSaveState) arg1;
pMBMsg = vos_mem_malloc(WNI_CFG_MB_HDR_LEN + sizeof(tSirMacHTMIMOPowerSaveState));
- if(NULL == pMBMsg)
+ if (NULL == pMBMsg)
{
p += log_sprintf( pMac,p, "pMBMsg is NULL\n");
return p;
@@ -2368,6 +2372,102 @@
}
#endif
+#ifdef WLAN_FEATURE_RMC
+
+static char *
+dump_lim_enable_rmc_data_path
+(
+ tpAniSirGlobal pMac,
+ tANI_U32 arg1,
+ tANI_U32 arg2,
+ tANI_U32 arg3,
+ tANI_U32 arg4,
+ char *p
+)
+{
+ v_MACADDR_t rmcTransmitterAddr;
+ v_VOID_t * pVosContext = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
+
+ rmcTransmitterAddr.bytes[0] = (tANI_U8)((arg1 & 0xFF000000) >> 24);
+ rmcTransmitterAddr.bytes[1] = (tANI_U8)((arg1 & 0x00FF0000) >> 16);
+ rmcTransmitterAddr.bytes[2] = (tANI_U8)((arg1 & 0x0000FF00) >> 8);
+ rmcTransmitterAddr.bytes[3] = (tANI_U8)((arg1 & 0x000000FF));
+ rmcTransmitterAddr.bytes[4] = (tANI_U8)((arg2 & 0xFF000000) >> 24);
+ rmcTransmitterAddr.bytes[5] = (tANI_U8)((arg2 & 0x00FF0000) >> 16);
+
+ limLog(pMac, LOGE,
+ FL("Enable RMC data path for MCAST transmitter:" MAC_ADDRESS_STR),
+ MAC_ADDR_ARRAY( rmcTransmitterAddr.bytes));
+
+ /*Input format is in MAC address fromat for example
+ iwpriv wlan0 dump 0xaabbccdd 0xeeff0000 translates into enable RMC for
+ MAC address 0xaa:0xbb:0xcc:0xdd:0xee:0xff*/
+
+ /*Enable TL data path*/
+ WLANTL_EnableRMC( pVosContext, &rmcTransmitterAddr );
+
+ return p;
+}
+
+static char *
+dump_lim_disable_rmc_data_path
+(
+ tpAniSirGlobal pMac,
+ tANI_U32 arg1,
+ tANI_U32 arg2,
+ tANI_U32 arg3,
+ tANI_U32 arg4,
+ char *p
+)
+{
+ v_MACADDR_t rmcTransmitterAddr;
+ v_VOID_t * pVosContext = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
+
+ rmcTransmitterAddr.bytes[0] = (tANI_U8)((arg1 & 0xFF000000) >> 24);
+ rmcTransmitterAddr.bytes[1] = (tANI_U8)((arg1 & 0x00FF0000) >> 16);
+ rmcTransmitterAddr.bytes[2] = (tANI_U8)((arg1 & 0x0000FF00) >> 8);
+ rmcTransmitterAddr.bytes[3] = (tANI_U8)((arg1 & 0x000000FF));
+ rmcTransmitterAddr.bytes[4] = (tANI_U8)((arg2 & 0xFF000000) >> 24);
+ rmcTransmitterAddr.bytes[5] = (tANI_U8)((arg2 & 0x00FF0000) >> 16);
+
+
+ limLog(pMac, LOGE,
+ FL("Disable RMC data path for MCAST transmitter:" MAC_ADDRESS_STR),
+ MAC_ADDR_ARRAY( rmcTransmitterAddr.bytes));
+
+ /*Input format is in MAC address fromat for example
+ iwpriv wlan0 dump 0xaabbccdd 0xeeff0000 translates into enable RMC for
+ MAC address 0xaa:0xbb:0xcc:0xdd:0xee:0xff*/
+
+ /*Disable TL data path*/
+ WLANTL_DisableRMC( pVosContext, &rmcTransmitterAddr );
+
+ return p;
+}
+
+static char *
+dump_lim_rmc_status(tpAniSirGlobal pMac, tANI_U32 arg1, tANI_U32 arg2,
+ tANI_U32 arg3, tANI_U32 arg4, char *p)
+{
+ limRmcDumpStatus(pMac);
+ return p;
+}
+
+static char *
+dump_set_mcast_dup_detect(tpAniSirGlobal pMac, tANI_U32 arg1, tANI_U32 arg2,
+ tANI_U32 arg3, tANI_U32 arg4, char *p)
+{
+ v_VOID_t * pVosContext = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
+ v_U8_t enable;
+
+ enable = (tANI_U8)arg1;
+
+ /* Enable or Disable Multicast Duplicate Detection */
+ WLANTL_SetMcastDuplicateDetection( pVosContext, enable);
+
+ return p;
+}
+#endif /* WLAN_FEATURE_RMC */
static char *
dump_set_max_probe_req(tpAniSirGlobal pMac, tANI_U32 arg1, tANI_U32 arg2,
@@ -2467,7 +2567,17 @@
{369, "PE.LIM: pkts/rateIdx: iwpriv wlan0 dump 368 <staId> <boolean to flush counter>", dump_lim_get_pkts_rcvd_per_rate_idx},
{370, "PE.LIM: pkts/rssi: : iwpriv wlan0 dump 369 <staId> <boolean to flush counter>", dump_lim_get_pkts_rcvd_per_rssi_values},
#endif
+#ifdef WLAN_FEATURE_RMC
+ {371, "PE.LIM: Enable RMC data path in TL for input MCAST addr",
+ dump_lim_enable_rmc_data_path },
+ {372, "PE.LIM: Disable RMC data path in TL for input MCAST addr",
+ dump_lim_disable_rmc_data_path },
+ {373, "PE.LIM: Dump RMC transmitter and ruler status", dump_lim_rmc_status },
+#endif /* WLAN_FEATURE_RMC */
{374, "PE.LIM: MAS RX stats MAC eff <MAC eff in percentage>", dump_limRateInfoBasedOnMacEff},
+#ifdef WLAN_FEATURE_RMC
+ {375, "PE.LIM: Enable(1)/Disable(0) RMC duplicate detection", dump_set_mcast_dup_detect },
+#endif /* WLAN_FEATURE_RMC */
{376, "PE.LIM: max number of probe per scan", dump_set_max_probe_req },
};
diff --git a/CORE/MAC/src/pe/lim/limProcessActionFrame.c b/CORE/MAC/src/pe/lim/limProcessActionFrame.c
index ff2d70e..ddff1c1 100644
--- a/CORE/MAC/src/pe/lim/limProcessActionFrame.c
+++ b/CORE/MAC/src/pe/lim/limProcessActionFrame.c
@@ -59,6 +59,9 @@
#include "rrmApi.h"
#endif
#include "limSessionUtils.h"
+#ifdef WLAN_FEATURE_RMC
+#include "limRMC.h"
+#endif
#if defined(FEATURE_WLAN_ESE) && !defined(FEATURE_WLAN_ESE_UPLOAD)
#include "eseApi.h"
@@ -2455,7 +2458,8 @@
}
break;
#endif
-#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR)
+#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) \
+ || defined (WLAN_FEATURE_RMC)
case SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY:
{
tpSirMacVendorSpecificFrameHdr pVendorSpecific = (tpSirMacVendorSpecificFrameHdr) pActionHdr;
@@ -2479,6 +2483,57 @@
pRxPacketInfo,
psessionEntry, 0);
}
+#if defined (WLAN_FEATURE_RMC)
+ else if ((eLIM_STA_IN_IBSS_ROLE == psessionEntry->limSystemRole) &&
+ ((VOS_TRUE == vos_mem_compare(SIR_MAC_RMC_MCAST_ADDRESS,
+ &pHdr->da[0], sizeof(tSirMacAddr))) ||
+ (VOS_TRUE == vos_mem_compare(psessionEntry->selfMacAddr,
+ &pHdr->da[0], sizeof(tSirMacAddr)))) &&
+ vos_mem_compare(pVendorSpecific->Oui, SIR_MAC_RMC_OUI, 3))
+ {
+ tANI_U8 MagicCode[] =
+ { 0x4f, 0x58, 0x59, 0x47, 0x45, 0x4e };
+ tpSirMacIbssExtNetworkFrameHdr pIbssExtHdr =
+ (tpSirMacIbssExtNetworkFrameHdr) pActionHdr;
+
+ if (vos_mem_compare(pIbssExtHdr->MagicCode,
+ MagicCode, sizeof(MagicCode)) &&
+ pIbssExtHdr->version == SIR_MAC_RMC_VER )
+ {
+ switch (pIbssExtHdr->actionID)
+ {
+ default:
+ PELOGE(limLog(pMac, LOGE,
+ FL("Action RMC actionID %d not handled"),
+ pIbssExtHdr->actionID);)
+ break;
+ case SIR_MAC_RMC_RULER_INFORM_SELECTED:
+ limLog(pMac, LOG1,
+ FL("Action RMC RULER_INFORM_SELECTED."));
+ limProcessRMCMessages(pMac,
+ eLIM_RMC_OTA_RULER_INFORM_SELECTED,
+ (tANI_U32 *)pRxPacketInfo);
+ break;
+ case SIR_MAC_RMC_RULER_INFORM_CANCELLED:
+ limLog(pMac, LOG1,
+ FL("Action RMC RULER_INFORM_CANCELLED."));
+ limProcessRMCMessages(pMac,
+ eLIM_RMC_OTA_RULER_INFORM_CANCELLED,
+ (tANI_U32 *)pRxPacketInfo);
+ break;
+ }
+ }
+ else
+ {
+ limLog( pMac, LOG1,
+ FL("Dropping the vendor specific action frame in IBSS "
+ "mode because of Ibss Ext Magic mismatch "
+ MAC_ADDRESS_STR " or Version mismatch = %d"),
+ MAC_ADDR_ARRAY(pIbssExtHdr->MagicCode),
+ pIbssExtHdr->version );
+ }
+ }
+#endif /* WLAN_FEATURE_RMC */
else
{
limLog( pMac, LOG1,
@@ -2492,7 +2547,8 @@
}
}
break;
-#endif
+#endif /* WLAN_FEATURE_VOWIFI_11R || FEATURE_WLAN_ESE ||
+ FEATURE_WLAN_LFR || WLAN_FEATURE_RMC */
case SIR_MAC_ACTION_PUBLIC_USAGE:
switch(pActionHdr->actionID) {
case SIR_MAC_ACTION_VENDOR_SPECIFIC:
diff --git a/CORE/MAC/src/pe/lim/limProcessMessageQueue.c b/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
index a47669e..93cd651 100644
--- a/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
+++ b/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
@@ -75,6 +75,10 @@
#include "wmmApsd.h"
#endif
+#ifdef WLAN_FEATURE_RMC
+#include "limRMC.h"
+#endif
+
#include "vos_types.h"
#include "vos_packet.h"
#include "vos_memory.h"
@@ -1607,6 +1611,17 @@
limMsg->bodyptr = NULL;
break;
+#ifdef WLAN_FEATURE_RMC
+ case eWNI_SME_ENABLE_RMC_REQ:
+ case eWNI_SME_DISABLE_RMC_REQ:
+ /*
+ * These messages are from HDD
+ * No need to response to hdd
+ */
+ limProcessSmeReqMessages(pMac,limMsg);
+ break;
+#endif /* WLAN_FEATURE_RMC */
+
case SIR_HAL_P2P_NOA_START_IND:
{
tpPESession psessionEntry = &pMac->lim.gpSession[0];
@@ -2292,6 +2307,28 @@
limMsg->bodyptr = NULL;
break;
}
+#ifdef WLAN_FEATURE_RMC
+ case WDA_RMC_BECOME_RULER:
+ limProcessRMCMessages(pMac, eLIM_RMC_BECOME_RULER_RESP,
+ (void *)limMsg->bodyptr);
+ vos_mem_free((v_VOID_t*)limMsg->bodyptr);
+ limMsg->bodyptr = NULL;
+ break ;
+
+ case WDA_RMC_RULER_SELECT_RESP:
+ limProcessRMCMessages(pMac, eLIM_RMC_RULER_SELECT_RESP,
+ (void *)limMsg->bodyptr);
+ vos_mem_free((v_VOID_t*)limMsg->bodyptr);
+ limMsg->bodyptr = NULL;
+ break ;
+
+ case WDA_RMC_UPDATE_IND:
+ limProcessRMCMessages(pMac, eLIM_RMC_RULER_PICK_NEW,
+ (void *)limMsg->bodyptr);
+ vos_mem_free((v_VOID_t*)limMsg->bodyptr);
+ limMsg->bodyptr = NULL;
+ break ;
+#endif /* WLAN_FEATURE_RMC */
case WDA_SPOOF_MAC_ADDR_RSP:
limProcessMlmSpoofMacAddrRsp(pMac, (tSirRetStatus)limMsg->bodyval);
diff --git a/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c b/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
index 3a33168..f1378bf 100644
--- a/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
+++ b/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
@@ -59,6 +59,10 @@
#include "limApi.h"
#include "wmmApsd.h"
+#ifdef WLAN_FEATURE_RMC
+#include "limRMC.h"
+#endif
+
#include "sapApi.h"
#if defined WLAN_FEATURE_VOWIFI
@@ -5843,6 +5847,16 @@
limSendSetTxPowerReq(pMac, pMsgBuf);
break ;
+#ifdef WLAN_FEATURE_RMC
+ case eWNI_SME_ENABLE_RMC_REQ:
+ limProcessRMCMessages(pMac, eLIM_RMC_ENABLE_REQ, pMsgBuf);
+ break ;
+
+ case eWNI_SME_DISABLE_RMC_REQ:
+ limProcessRMCMessages(pMac, eLIM_RMC_DISABLE_REQ, pMsgBuf);
+ break ;
+#endif /* WLAN_FEATURE_RMC */
+
case eWNI_SME_MAC_SPOOF_ADDR_IND:
__limProcessSmeSpoofMacAddrRequest(pMac, pMsgBuf);
break ;
diff --git a/CORE/MAC/src/pe/lim/limRMC.c b/CORE/MAC/src/pe/lim/limRMC.c
new file mode 100644
index 0000000..86b302e
--- /dev/null
+++ b/CORE/MAC/src/pe/lim/limRMC.c
@@ -0,0 +1,1382 @@
+/*
+ * Copyright (c) 2013-2016 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.
+ */
+
+/*
+ * This file limRMC.c contains the code
+ * for processing RMC messages
+ *
+ */
+#include "wniApi.h"
+#include "wniCfg.h"
+#include "cfgApi.h"
+#include "sirApi.h"
+#include "schApi.h"
+#include "utilsApi.h"
+#include "limUtils.h"
+#include "limTimerUtils.h"
+#include "limSendMessages.h"
+#include "limSendMessages.h"
+#include "limSession.h"
+#include "limSessionUtils.h"
+#include "wlan_qct_wda.h"
+#include "wlan_qct_tli.h"
+#include "limRMC.h"
+
+#ifdef WLAN_FEATURE_RMC
+
+static tANI_U8
+__rmcGroupHashFunction(tSirMacAddr transmitter)
+{
+ tANI_U16 hash;
+
+ /*
+ * Generate a hash using transmitter address
+ */
+ hash = transmitter[0] + transmitter[1] + transmitter[2] +
+ transmitter[3] + transmitter[4] + transmitter[5];
+
+ return hash & (RMC_MCAST_GROUPS_HASH_SIZE - 1);
+}
+
+
+static tLimRmcGroupContext *
+__rmcGroupLookupHashEntry(tpAniSirGlobal pMac, tSirMacAddr transmitter)
+{
+ tANI_U8 index;
+ tLimRmcGroupContext *entry;
+
+ index = __rmcGroupHashFunction(transmitter);
+
+ /* Pick the correct hash table based on role */
+ entry = pMac->rmcContext.rmcGroupRxHashTable[index];
+
+ PELOG1(limLog(pMac, LOG1, FL("RMC: Hash Lookup:[%d] transmitter "
+ MAC_ADDRESS_STR ), index,
+ MAC_ADDR_ARRAY(transmitter));)
+ while (entry)
+ {
+ if (vos_mem_compare(transmitter, entry->transmitter,
+ sizeof(v_MACADDR_t)))
+ {
+ return entry;
+ }
+
+ entry = entry->next;
+ }
+
+ return NULL;
+}
+
+static tLimRmcGroupContext *
+__rmcGroupInsertHashEntry(tpAniSirGlobal pMac, tSirMacAddr transmitter)
+{
+ tANI_U8 index;
+ tLimRmcGroupContext *entry;
+ tLimRmcGroupContext **head;
+
+ index = __rmcGroupHashFunction(transmitter);
+
+ PELOG1(limLog(pMac, LOG1, FL("RMC: Hash Insert:[%d] group " MAC_ADDRESS_STR
+ " transmitter " MAC_ADDRESS_STR), index,
+ MAC_ADDR_ARRAY(mcastGroupAddr),
+ MAC_ADDR_ARRAY(transmitter));)
+
+ head = &pMac->rmcContext.rmcGroupRxHashTable[index];
+
+ entry = __rmcGroupLookupHashEntry(pMac, transmitter);
+
+ if (entry)
+ {
+ /* If the entry exists, return it at the end */
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Hash Insert:"
+ MAC_ADDRESS_STR "exists"), MAC_ADDR_ARRAY(transmitter));)
+ }
+ else
+ {
+ entry = (tLimRmcGroupContext *)vos_mem_malloc(sizeof(*entry));
+
+ PELOG1(limLog(pMac, LOG1, FL("RMC: Hash Insert:new entry %p"), entry);)
+
+ if (entry)
+ {
+ vos_mem_copy(entry->transmitter, transmitter, sizeof(tSirMacAddr));
+ entry->isRuler = eRMC_IS_NOT_A_RULER;
+
+ /* chain this entry */
+ entry->next = *head;
+ *head = entry;
+ }
+ else
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Hash Insert:" MAC_ADDRESS_STR
+ " alloc failed"), MAC_ADDR_ARRAY(transmitter));)
+ }
+ }
+
+ return entry;
+}
+
+/**
+ * __rmcGroupDeleteHashEntry()
+ *
+ *FUNCTION:
+ * This function is called to delete a RMC group entry
+ *
+ *LOGIC:
+ *
+ *ASSUMPTIONS:
+ * Should be called with lkRmcLock held.
+ *
+ *NOTE:
+ * Make sure (for the transmitter role) that the entry is
+ * not in the Pending Response queue.
+ *
+ * @param transmitter - address of multicast transmitter
+ *
+ * @return status
+ */
+static tSirRetStatus
+__rmcGroupDeleteHashEntry(tpAniSirGlobal pMac, tSirMacAddr transmitter)
+{
+ tSirRetStatus status = eSIR_FAILURE;
+ tANI_U8 index;
+ tLimRmcGroupContext *entry, *prev, **head;
+
+ index = __rmcGroupHashFunction(transmitter);
+
+ head = &pMac->rmcContext.rmcGroupRxHashTable[index];
+ entry = *head;
+ prev = NULL;
+
+ while (entry)
+ {
+ if (vos_mem_compare(transmitter, entry->transmitter,
+ sizeof(v_MACADDR_t)))
+ {
+ if (*head == entry)
+ {
+ *head = entry->next;
+ }
+ else
+ {
+ prev->next = entry->next;
+ }
+
+ PELOG1(limLog(pMac, LOG1, FL("RMC: Hash Delete: entry %p "
+ " transmitter " MAC_ADDRESS_STR), entry
+ MAC_ADDR_ARRAY(transmitter));)
+
+ /* free the group entry */
+ vos_mem_free(entry);
+
+ status = eSIR_SUCCESS;
+ break;
+ }
+
+ prev = entry;
+ entry = entry->next;
+ }
+
+ return status;
+}
+
+static void
+__rmcGroupDeleteAllEntries(tpAniSirGlobal pMac)
+{
+ tLimRmcGroupContext *entry, **head;
+ int index;
+
+ PELOG1(limLog(pMac, LOG1, FL("RMC: Hash_Delete_All"),);)
+
+ for (index = 0; index < RMC_MCAST_GROUPS_HASH_SIZE; index++)
+ {
+ head = &pMac->rmcContext.rmcGroupRxHashTable[index];
+
+ entry = *head;
+
+ while (entry)
+ {
+ *head = entry->next;
+ /* free the group entry */
+ vos_mem_free(entry);
+ entry = *head;
+ }
+ }
+}
+
+static void
+__limPostMsgRulerReq ( tpAniSirGlobal pMac,
+ tANI_U8 cmd,
+ tSirMacAddr mcastTransmitter)
+{
+ tSirMsgQ msg;
+ tSirRmcRulerReq *pRulerReq;
+
+ pRulerReq = vos_mem_malloc(sizeof(*pRulerReq));
+ if (NULL == pRulerReq)
+ {
+ limLog(pMac, LOGE, FL("AllocateMemory() failed"));
+ return;
+ }
+
+ pRulerReq->cmd = cmd;
+
+ vos_mem_copy(pRulerReq->mcastTransmitter, mcastTransmitter,
+ sizeof(tSirMacAddr));
+
+ /* Initialize black list */
+ vos_mem_zero(pRulerReq->blacklist, sizeof(pRulerReq->blacklist));
+
+ if (eRMC_SUGGEST_RULER_CMD == cmd)
+ {
+ /* TODO - Set the black list. */
+ }
+
+ msg.type = WDA_RMC_RULER_REQ;
+ msg.bodyptr = pRulerReq;
+ msg.bodyval = 0;
+
+ MTRACE(macTraceMsgTx(pMac, NO_SESSION, msg.type));
+ if (eSIR_SUCCESS != wdaPostCtrlMsg(pMac, &msg))
+ {
+ vos_mem_free(pRulerReq);
+ limLog(pMac, LOGE, FL("wdaPostCtrlMsg() failed"));
+ }
+
+ return;
+}
+
+static void
+__limPostMsgUpdateInd ( tpAniSirGlobal pMac,
+ tANI_U8 indication,
+ tANI_U8 role,
+ tSirMacAddr mcastTransmitter,
+ tSirMacAddr mcastRuler)
+{
+ tSirMsgQ msg;
+ tSirRmcUpdateInd *pUpdateInd;
+
+ pUpdateInd = vos_mem_malloc(sizeof(*pUpdateInd));
+ if ( NULL == pUpdateInd )
+ {
+ limLog(pMac, LOGE, FL("AllocateMemory() failed"));
+ return;
+ }
+
+ vos_mem_zero(pUpdateInd, sizeof(*pUpdateInd));
+
+ pUpdateInd->indication = indication;
+ pUpdateInd->role = role;
+
+ vos_mem_copy(pUpdateInd->mcastTransmitter,
+ mcastTransmitter, sizeof(tSirMacAddr));
+
+ vos_mem_copy(pUpdateInd->mcastRuler,
+ mcastRuler, sizeof(tSirMacAddr));
+
+ msg.type = WDA_RMC_UPDATE_IND;
+ msg.bodyptr = pUpdateInd;
+ msg.bodyval = 0;
+
+ MTRACE(macTraceMsgTx(pMac, NO_SESSION, msg.type));
+ if (eSIR_SUCCESS != wdaPostCtrlMsg(pMac, &msg))
+ {
+ vos_mem_free(pUpdateInd);
+ limLog(pMac, LOGE, FL("wdaPostCtrlMsg() failed"));
+ }
+
+ return;
+}
+
+static char *
+__limRulerMessageToString(eRmcMessageType msgType)
+{
+ switch (msgType)
+ {
+ default:
+ return "Invalid";
+ case eLIM_RMC_ENABLE_REQ:
+ return "RMC_ENABLE_REQ";
+ case eLIM_RMC_DISABLE_REQ:
+ return "RMC_DISABLE_REQ";
+ case eLIM_RMC_RULER_SELECT_RESP:
+ return "RMC_RULER_SELECT_RESP";
+ case eLIM_RMC_RULER_PICK_NEW:
+ return "RMC_RULER_PICK_NEW";
+ case eLIM_RMC_OTA_RULER_INFORM_ACK:
+ return "RMC_OTA_RULER_INFORM_ACK";
+ case eLIM_RMC_OTA_RULER_INFORM_SELECTED:
+ return "RMC_OTA_RULER_INFORM_SELECTED";
+ case eLIM_RMC_BECOME_RULER_RESP:
+ return "RMC_BECOME_RULER_RESP";
+ case eLIM_RMC_OTA_RULER_INFORM_CANCELLED:
+ return "RMC_OTA_RULER_INFORM_CANCELLED";
+ }
+}
+
+static char *
+__limRulerStateToString(eRmcRulerState state)
+{
+ switch (state)
+ {
+ default:
+ return "Invalid";
+ case eRMC_IS_NOT_A_RULER:
+ return "Device Not a Ruler";
+ case eRMC_RULER_PENDING:
+ return "Pending firmware resp";
+ case eRMC_IS_A_RULER:
+ return "Device is Ruler";
+ }
+}
+
+static char *
+__limMcastTxStateToString(eRmcMcastTxState state)
+{
+ switch (state)
+ {
+ default:
+ return "Invalid";
+ case eRMC_RULER_NOT_SELECTED:
+ return "Not Selected";
+ case eRMC_RULER_ENABLE_REQUESTED:
+ return "Enable Requested";
+ case eRMC_RULER_OTA_REQUEST_SENT:
+ return "OTA Request Sent";
+ case eRMC_RULER_ACTIVE:
+ return "Active";
+ }
+}
+
+/**
+ * __rmcRulerSelectTimerHandler()
+ *
+ *FUNCTION:
+ * This function is called upon timer expiry.
+ *
+ *
+ *ASSUMPTIONS:
+ * NA
+ *
+ *NOTE:
+ * Only one entry is processed for every invocation if this routine.
+ * This allows us to use a single timer and makes sure we do not
+ * timeout a request too early.
+ *
+ * @param param - Message corresponding to the timer that expired
+ *
+ * @return None
+ */
+
+void
+__rmcRulerSelectTimerHandler(void *pMacGlobal, tANI_U32 param)
+{
+ tpAniSirGlobal pMac = (tpAniSirGlobal)pMacGlobal;
+ tSirMacAddr zeroMacAddr = { 0, 0, 0, 0, 0, 0 };
+ tSirRetStatus status;
+ tSirRMCInfo RMC;
+ tpPESession psessionEntry;
+ tANI_U32 cfgValue;
+
+ /*
+ * This API relies on a single active IBSS session.
+ */
+ psessionEntry = limIsIBSSSessionActive(pMac);
+ if (NULL == psessionEntry)
+ {
+ PELOGE(limLog(pMac, LOGE,
+ FL("RMC:__rmcRulerSelectTimerHandler:No active IBSS"));)
+ return;
+ }
+
+ if (wlan_cfgGetInt(pMac, WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
+ &cfgValue) != eSIR_SUCCESS)
+ {
+ /**
+ * Could not get Action Period Frequency value
+ * from CFG. Log error.
+ */
+ limLog(pMac, LOGE, FL("could not retrieve ActionPeriodFrequency"));
+ }
+
+ cfgValue = SYS_MS_TO_TICKS(cfgValue);
+
+ if (pMac->rmcContext.rmcTimerValInTicks != cfgValue)
+ {
+ limLog(pMac, LOG1, FL("RMC RulerSelect timer value changed"));
+ if (tx_timer_change(&pMac->rmcContext.gRmcRulerSelectTimer,
+ cfgValue, 0) != TX_SUCCESS)
+ {
+ limLog(pMac, LOGE,
+ FL("Unable to change RulerSelect Timer val"));
+ }
+ pMac->rmcContext.rmcTimerValInTicks = cfgValue;
+ }
+
+ /*
+ * If we are in the scanning state then we need to return
+ * from this function without any further processing
+ */
+ if (eLIM_HAL_SCANNING_STATE == pMac->lim.gLimHalScanState)
+ {
+ limLog(pMac, LOG1, FL("In scanning state, can't send action frm"));
+ if (tx_timer_activate(&pMac->rmcContext.gRmcRulerSelectTimer) !=
+ TX_SUCCESS)
+ {
+ limLog(pMac, LOGE, FL("In scanning state, "
+ "couldn't activate RMC RulerSelect timer"));
+ }
+ return;
+ }
+
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE,
+ FL("__rmcRulerSelectTimerHandler lock acquire failed"));
+ if (tx_timer_activate(&pMac->rmcContext.gRmcRulerSelectTimer)!= TX_SUCCESS)
+ {
+ limLog(pMac, LOGE, FL("could not activate RMC RulerSelect timer"));
+ }
+ return;
+ }
+
+ vos_mem_copy(&RMC.mcastRuler, &pMac->rmcContext.ruler,
+ sizeof(tSirMacAddr));
+
+ if (VOS_FALSE == vos_mem_compare(&zeroMacAddr,
+ &pMac->rmcContext.ruler, sizeof(tSirMacAddr)))
+ {
+ limLog(pMac, LOG1,
+ FL("RMC Periodic Ruler_Select Ruler " MAC_ADDRESS_STR),
+ MAC_ADDR_ARRAY(pMac->rmcContext.ruler));
+ /*
+ * Re-arm timer
+ */
+ if (tx_timer_activate(&pMac->rmcContext.gRmcRulerSelectTimer)!=
+ TX_SUCCESS)
+ {
+ limLog(pMac, LOGE, FL("could not activate RMC Response timer"));
+ }
+
+ if (!VOS_IS_STATUS_SUCCESS
+ (vos_lock_release(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE,
+ FL("RMC: __rmcRulerSelectTimerHandler lock release failed"));
+ }
+ }
+ else
+ {
+ limLog(pMac, LOGE,
+ FL("RMC Deactivating timer because no ruler was selected"));
+
+ if (!VOS_IS_STATUS_SUCCESS
+ (vos_lock_release(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE,
+ FL("RMC: __rmcRulerSelectTimerHandler lock release failed"));
+ }
+
+ return;
+ }
+
+ RMC.dialogToken = 0;
+ RMC.action = SIR_MAC_RMC_RULER_INFORM_SELECTED;
+
+ status = limSendRMCActionFrame(pMac,
+ SIR_MAC_RMC_MCAST_ADDRESS,
+ &RMC,
+ psessionEntry);
+
+ if (eSIR_FAILURE == status)
+ {
+ PELOGE(limLog(pMac, LOGE,
+ FL("RMC:__rmcRulerSelectTimerHandler Action frame send failed"));)
+ }
+
+ return;
+}
+
+static void
+__limProcessRMCEnableRequest(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf)
+{
+ tSirSetRMCReq *setRmcReq = (tSirSetRMCReq *)pMsgBuf;
+ tpPESession psessionEntry;
+
+ if (!setRmcReq)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Enable:NULL message") );)
+ return;
+ }
+
+ pMac->rmcContext.rmcEnabled = TRUE;
+
+ /*
+ * This API relies on a single active IBSS session.
+ */
+ psessionEntry = limIsIBSSSessionActive(pMac);
+ if (NULL == psessionEntry)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC:Enable RMC request no active IBSS"));)
+ pMac->rmcContext.state = eRMC_RULER_NOT_SELECTED;
+ return;
+ }
+
+ /* Send RULER_REQ to f/w */
+ __limPostMsgRulerReq(pMac, eRMC_SUGGEST_RULER_CMD,
+ setRmcReq->mcastTransmitter);
+
+ pMac->rmcContext.state = eRMC_RULER_ENABLE_REQUESTED;
+}
+
+static void
+__limProcessRMCDisableRequest(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf)
+{
+ tpPESession psessionEntry;
+ tSirRMCInfo RMC;
+ tSirSetRMCReq *setRmcReq = (tSirSetRMCReq *)pMsgBuf;
+ tSirRetStatus status;
+ v_PVOID_t pvosGCtx;
+ VOS_STATUS vos_status;
+ v_MACADDR_t vosMcastTransmitter;
+
+ pMac->rmcContext.rmcEnabled = FALSE;
+
+ /*
+ * This API relies on a single active IBSS session.
+ */
+ psessionEntry = limIsIBSSSessionActive(pMac);
+ if (NULL == psessionEntry)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Disable:No active IBSS"));)
+ return;
+ }
+
+ if (!setRmcReq)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Disable:NULL message") );)
+ return;
+ }
+
+ /* Cancel pending timer */
+ tx_timer_deactivate(&pMac->rmcContext.gRmcRulerSelectTimer);
+
+ vosMcastTransmitter.bytes[0] = psessionEntry->selfMacAddr[0];
+ vosMcastTransmitter.bytes[1] = psessionEntry->selfMacAddr[1];
+ vosMcastTransmitter.bytes[2] = psessionEntry->selfMacAddr[2];
+ vosMcastTransmitter.bytes[3] = psessionEntry->selfMacAddr[3];
+ vosMcastTransmitter.bytes[4] = psessionEntry->selfMacAddr[4];
+ vosMcastTransmitter.bytes[5] = psessionEntry->selfMacAddr[5];
+
+ pvosGCtx = vos_get_global_context(VOS_MODULE_ID_PE, (v_VOID_t *) pMac);
+ vos_status = WLANTL_DisableRMC(pvosGCtx, &vosMcastTransmitter);
+
+ if (VOS_STATUS_SUCCESS != vos_status)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC:Disable: TL disable failed"));)
+ }
+
+ if (pMac->rmcContext.state == eRMC_RULER_ACTIVE)
+ {
+ RMC.dialogToken = 0;
+ RMC.action = SIR_MAC_RMC_RULER_INFORM_CANCELLED;
+ vos_mem_copy(&RMC.mcastRuler, &pMac->rmcContext.ruler, sizeof(tSirMacAddr));
+
+ status = limSendRMCActionFrame(pMac, pMac->rmcContext.ruler,
+ &RMC, psessionEntry);
+ if (eSIR_FAILURE == status)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC:Disable: Action frame send failed"));)
+ }
+
+ pMac->rmcContext.state = eRMC_RULER_NOT_SELECTED;
+ }
+
+ __limPostMsgUpdateInd(pMac, eRMC_RULER_CANCELLED, eRMC_TRANSMITTER_ROLE,
+ setRmcReq->mcastTransmitter, pMac->rmcContext.ruler);
+
+ vos_mem_zero(pMac->rmcContext.ruler, sizeof(tSirMacAddr));
+
+}
+
+static void
+__limProcessRMCRulerSelectResponse(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf)
+{
+ tSirRmcRulerSelectInd *pRmcRulerSelectInd;
+ tpPESession psessionEntry;
+ tSirRetStatus status;
+ v_PVOID_t pvosGCtx;
+ VOS_STATUS vos_status;
+ v_MACADDR_t vosMcastTransmitter;
+ tSirRMCInfo RMC;
+
+ if (NULL == pMsgBuf)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Select_Resp:NULL message"));)
+ return;
+ }
+
+ /*
+ * This API relies on a single active IBSS session.
+ */
+ psessionEntry = limIsIBSSSessionActive(pMac);
+ if (NULL == psessionEntry)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC:Ruler_Select_Resp:No active IBSS"));)
+ pMac->rmcContext.state = eRMC_RULER_NOT_SELECTED;
+ return;
+ }
+
+ pRmcRulerSelectInd = (tSirRmcRulerSelectInd *)pMsgBuf;
+
+ if (pMac->rmcContext.state != eRMC_RULER_ENABLE_REQUESTED)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Select_Resp:Bad state %s"),
+ __limMcastTxStateToString(pMac->rmcContext.state) );)
+ return;
+ }
+
+ if (pRmcRulerSelectInd->status)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC:Ruler_Select_Resp:FW Status %d"),
+ pRmcRulerSelectInd->status);)
+ pMac->rmcContext.state = eRMC_RULER_NOT_SELECTED;
+ return;
+ }
+
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE, FL("RMC:Ruler_Select_Resp:lock acquire failed"));
+ pMac->rmcContext.state = eRMC_RULER_NOT_SELECTED;
+ return;
+ }
+
+ vos_mem_copy(&pMac->rmcContext.ruler, &pRmcRulerSelectInd->ruler[0],
+ sizeof(tSirMacAddr));
+
+ if (!VOS_IS_STATUS_SUCCESS
+ (vos_lock_release(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE, FL("RMC: Ruler_Select_Resp: lock release failed"));
+ }
+
+ RMC.dialogToken = 0;
+ RMC.action = SIR_MAC_RMC_RULER_INFORM_SELECTED;
+ vos_mem_copy(&RMC.mcastRuler, &pRmcRulerSelectInd->ruler[0],
+ sizeof(tSirMacAddr));
+
+ PELOG1(limLog(pMac, LOG1, FL("RMC: Ruler_Select :ruler " MAC_ADDRESS_STR),
+ MAC_ADDR_ARRAY(pRmcRulerSelectInd->ruler[0]));)
+
+ status = limSendRMCActionFrame(pMac,
+ SIR_MAC_RMC_MCAST_ADDRESS,
+ &RMC,
+ psessionEntry);
+
+ if (eSIR_FAILURE == status)
+ {
+ PELOGE(limLog(pMac, LOGE,
+ FL("RMC: Ruler_Select_Resp: Action send failed"));)
+ }
+
+ __limPostMsgUpdateInd(pMac, eRMC_RULER_ACCEPTED, eRMC_TRANSMITTER_ROLE,
+ psessionEntry->selfMacAddr, pMac->rmcContext.ruler);
+
+ vosMcastTransmitter.bytes[0] = psessionEntry->selfMacAddr[0];
+ vosMcastTransmitter.bytes[1] = psessionEntry->selfMacAddr[1];
+ vosMcastTransmitter.bytes[2] = psessionEntry->selfMacAddr[2];
+ vosMcastTransmitter.bytes[3] = psessionEntry->selfMacAddr[3];
+ vosMcastTransmitter.bytes[4] = psessionEntry->selfMacAddr[4];
+ vosMcastTransmitter.bytes[5] = psessionEntry->selfMacAddr[5];
+
+ /* Enable TL */
+ pvosGCtx = vos_get_global_context(VOS_MODULE_ID_PE, (v_VOID_t *) pMac);
+ vos_status = WLANTL_EnableRMC(pvosGCtx, &vosMcastTransmitter);
+
+ pMac->rmcContext.state = eRMC_RULER_ACTIVE;
+
+ if (tx_timer_activate(&pMac->rmcContext.gRmcRulerSelectTimer)!= TX_SUCCESS)
+ {
+ limLog(pMac, LOGE,
+ FL("Ruler_Select_Resp:Activate RMC Response timer failed"));
+ }
+}
+
+static void
+__limProcessRMCRulerPickNew(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf)
+{
+ tSirRmcUpdateInd *pRmcUpdateInd;
+ tpPESession psessionEntry;
+ tSirRetStatus status;
+ tSirRMCInfo RMC;
+ v_PVOID_t pvosGCtx;
+ VOS_STATUS vos_status;
+ v_MACADDR_t vosMcastTransmitter;
+ tSirMacAddr zeroMacAddr = { 0, 0, 0, 0, 0, 0 };
+
+ if (NULL == pMsgBuf)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Pick_New:NULL message"));)
+ return;
+ }
+
+ /*
+ * This API relies on a single active IBSS session.
+ */
+ psessionEntry = limIsIBSSSessionActive(pMac);
+ if (NULL == psessionEntry)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Pick_New:No active IBSS"));)
+ return;
+ }
+
+ pvosGCtx = vos_get_global_context(VOS_MODULE_ID_PE, (v_VOID_t *) pMac);
+
+ pRmcUpdateInd = (tSirRmcUpdateInd *)pMsgBuf;
+
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE, FL("RMC:Ruler_Pick_New:lock acquire failed"));
+ return;
+ }
+
+
+ /* Fill out Action frame parameters */
+ RMC.dialogToken = 0;
+
+ if (VOS_FALSE == vos_mem_compare(&zeroMacAddr,
+ &pRmcUpdateInd->mcastRuler,
+ sizeof(tSirMacAddr)))
+ {
+
+ vos_mem_copy(&RMC.mcastRuler, &pRmcUpdateInd->mcastRuler,
+ sizeof(tSirMacAddr));
+
+ RMC.action = SIR_MAC_RMC_RULER_INFORM_CANCELLED;
+ status = limSendRMCActionFrame(pMac,
+ pRmcUpdateInd->mcastRuler,
+ &RMC, psessionEntry);
+ if (eSIR_FAILURE == status)
+ {
+ PELOGE(limLog(pMac, LOGE,
+ FL("RMC:Ruler_Pick_New: Inform_Cancel Action send failed"));)
+ goto done;
+ }
+
+ vosMcastTransmitter.bytes[0] = psessionEntry->selfMacAddr[0];
+ vosMcastTransmitter.bytes[1] = psessionEntry->selfMacAddr[1];
+ vosMcastTransmitter.bytes[2] = psessionEntry->selfMacAddr[2];
+ vosMcastTransmitter.bytes[3] = psessionEntry->selfMacAddr[3];
+ vosMcastTransmitter.bytes[4] = psessionEntry->selfMacAddr[4];
+ vosMcastTransmitter.bytes[5] = psessionEntry->selfMacAddr[5];
+
+ vos_status = WLANTL_DisableRMC(pvosGCtx, &vosMcastTransmitter);
+
+ if (VOS_STATUS_SUCCESS != vos_status)
+ {
+ PELOGE(limLog(pMac, LOGE,
+ FL("RMC:Ruler_Pick_New: TL disable failed"));)
+ }
+ }
+
+ vos_mem_copy(pMac->rmcContext.ruler, pRmcUpdateInd->ruler[0],
+ sizeof(tSirMacAddr));
+
+ pMac->rmcContext.state = eRMC_RULER_NOT_SELECTED;
+
+ if (VOS_TRUE == vos_mem_compare(&zeroMacAddr,
+ pMac->rmcContext.ruler,
+ sizeof(tSirMacAddr)))
+ {
+ PELOGE(limLog(pMac, LOGE,
+ FL("RMC:Ruler_Pick_New: No candidate rulers available"));)
+ goto done;
+ }
+
+
+ RMC.action = SIR_MAC_RMC_RULER_INFORM_SELECTED;
+ vos_mem_copy(&RMC.mcastRuler, &pMac->rmcContext.ruler,
+ sizeof(tSirMacAddr));
+ status = limSendRMCActionFrame(pMac, SIR_MAC_RMC_MCAST_ADDRESS,
+ &RMC, psessionEntry);
+ if (eSIR_FAILURE == status)
+ {
+ PELOGE(limLog(pMac, LOGE,
+ FL("RMC:Ruler_Pick_New: Inform_Selected Action send failed"));)
+ goto done;
+ }
+
+ __limPostMsgUpdateInd(pMac, eRMC_RULER_ACCEPTED, eRMC_TRANSMITTER_ROLE,
+ psessionEntry->selfMacAddr, pMac->rmcContext.ruler);
+
+ vosMcastTransmitter.bytes[0] = psessionEntry->selfMacAddr[0];
+ vosMcastTransmitter.bytes[1] = psessionEntry->selfMacAddr[1];
+ vosMcastTransmitter.bytes[2] = psessionEntry->selfMacAddr[2];
+ vosMcastTransmitter.bytes[3] = psessionEntry->selfMacAddr[3];
+ vosMcastTransmitter.bytes[4] = psessionEntry->selfMacAddr[4];
+ vosMcastTransmitter.bytes[5] = psessionEntry->selfMacAddr[5];
+
+ /* Enable TL */
+ vos_status = WLANTL_EnableRMC(pvosGCtx, &vosMcastTransmitter);
+
+ if (VOS_STATUS_SUCCESS != vos_status)
+ {
+ PELOGE(limLog(pMac, LOGE,
+ FL("RMC:Ruler_Pick_New: TL enable failed"));)
+ goto done;
+ }
+
+ pMac->rmcContext.state = eRMC_RULER_ACTIVE;
+
+ if (tx_timer_activate(&pMac->rmcContext.gRmcRulerSelectTimer)!= TX_SUCCESS)
+ {
+ limLog(pMac, LOGE,
+ FL("Ruler_Pick_New:Activate RMC Response timer failed"));
+ }
+
+done:
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_release(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE,
+ FL("RMC: Ruler_Pick_New: lock release failed"));
+ }
+}
+
+static void
+__limProcessRMCRulerInformSelected(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf)
+{
+ tpSirMacMgmtHdr pHdr;
+ tANI_U8 *pFrameData;
+ tANI_U32 frameLen;
+ tLimRmcGroupContext *entry;
+ tpPESession psessionEntry;
+ tSirRetStatus status;
+
+ if (!pMsgBuf)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Inform:NULL msg"));)
+ return;
+ }
+
+ /*
+ * This API relies on a single active IBSS session.
+ */
+ psessionEntry = limIsIBSSSessionActive(pMac);
+ if (NULL == psessionEntry)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC:Become_Ruler_Resp:No active IBSS"));)
+ return;
+ }
+
+ /*
+ * Get the frame header
+ */
+ pHdr = WDA_GET_RX_MAC_HEADER((tANI_U8 *)pMsgBuf);
+
+ frameLen = WDA_GET_RX_PAYLOAD_LEN((tANI_U8 *)pMsgBuf);
+ if (frameLen < sizeof(tSirMacIbssExtNetworkFrameHdr))
+ {
+ PELOGE(limLog(pMac, LOGE,
+ FL("RMC: Ruler_Inform:Bad length %d "), frameLen);)
+ return;
+ }
+
+ pFrameData = WDA_GET_RX_MPDU_DATA((tANI_U8 *)pMsgBuf) +
+ sizeof(tSirMacIbssExtNetworkFrameHdr);
+
+ if (!pFrameData)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Inform:NULL data"));)
+ return;
+ }
+
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE, FL("RMC:Become_Ruler_Resp:lock acquire failed"));
+ return;
+ }
+
+ /*
+ * Check if this transmitter exists in our database.
+ */
+ entry = __rmcGroupLookupHashEntry(pMac, pHdr->sa);
+
+ if (VOS_FALSE == vos_mem_compare(pFrameData, psessionEntry->selfMacAddr,
+ sizeof(tSirMacAddr)))
+ {
+ if (entry)
+ {
+ PELOG1(limLog(pMac, LOG1,
+ FL("RMC: Ruler_Inform: Ruler Cancelled"));)
+
+ __limPostMsgUpdateInd(pMac, eRMC_RULER_CANCELLED,
+ eRMC_RULER_ROLE, pHdr->sa, psessionEntry->selfMacAddr);
+
+ /*
+ * Delete hash entry for this Group address.
+ */
+ status = __rmcGroupDeleteHashEntry(pMac, pHdr->sa);
+ if (eSIR_FAILURE == status)
+ {
+ PELOGE(limLog(pMac, LOGE,
+ FL("RMC: Ruler_Inform:hash delete failed"));)
+ }
+ }
+ }
+ else
+ {
+ if (NULL == entry)
+ {
+ /* Add the transmitter address to the hash */
+ entry = __rmcGroupInsertHashEntry(pMac, pHdr->sa);
+ if (entry)
+ {
+ if (entry->isRuler != eRMC_RULER_PENDING)
+ {
+ __limPostMsgRulerReq(pMac, eRMC_BECOME_RULER_CMD,
+ pHdr->sa);
+ entry->isRuler = eRMC_RULER_PENDING;
+ }
+ }
+ else
+ {
+ PELOGE(limLog(pMac, LOGE,
+ FL("RMC: Ruler_Inform:Hash insert failed"));)
+ }
+
+ }
+ }
+
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_release(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE,
+ FL("RMC: Ruler_Inform: lock release failed"));
+ }
+
+}
+
+static void
+__limProcessRMCBecomeRulerResp(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf)
+{
+ tSirRmcBecomeRulerInd *pRmcBecomeRulerInd;
+ tLimRmcGroupContext *entry;
+ tSirRetStatus status = eSIR_SUCCESS;
+
+ if (NULL == pMsgBuf)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Become_Ruler_Resp:NULL message"));)
+ return;
+ }
+
+ pRmcBecomeRulerInd = (tSirRmcBecomeRulerInd *)pMsgBuf;
+
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE, FL("RMC:Become_Ruler_Resp:lock acquire failed"));
+ return;
+ }
+
+ /*
+ * Find the entry for this Group Address.
+ */
+ entry = __rmcGroupLookupHashEntry(pMac,
+ pRmcBecomeRulerInd->mcastTransmitter);
+ if (NULL == entry)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Become_Ruler_Resp: No entry"));)
+ goto done;
+ }
+
+ if (pRmcBecomeRulerInd->status)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC:Become_Ruler_Resp:FW Status %d"),
+ pRmcBecomeRulerInd->status);)
+ status = eSIR_FAILURE;
+ goto done;
+ }
+
+ if (entry->isRuler != eRMC_RULER_PENDING)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Become_Ruler_Resp:Bad state: %s"),
+ __limRulerStateToString(entry->isRuler) );)
+ status = eSIR_FAILURE;
+ goto done;
+ }
+
+ entry->isRuler = eRMC_IS_A_RULER;
+
+done:
+ if (eSIR_FAILURE == status)
+ {
+ status = __rmcGroupDeleteHashEntry(pMac,
+ pRmcBecomeRulerInd->mcastTransmitter);
+ if (eSIR_FAILURE == status)
+ {
+ PELOGE(limLog(pMac, LOGE,
+ FL("RMC: Become_Ruler_Resp:hash delete failed"));)
+ }
+ }
+
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_release(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE,
+ FL("RMC: Become_Ruler_Resp: lock release failed"));
+ }
+
+ return;
+}
+
+static void
+__limProcessRMCRulerInformCancelled(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf)
+{
+ tpSirMacMgmtHdr pHdr;
+ tANI_U8 *pFrameData;
+ tANI_U32 frameLen;
+ tSirRetStatus status;
+ tLimRmcGroupContext *entry;
+ tpPESession psessionEntry;
+
+ if (!pMsgBuf)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Inform_Cancel:NULL msg"));)
+ return;
+ }
+
+ /*
+ * This API relies on a single active IBSS session.
+ */
+ psessionEntry = limIsIBSSSessionActive(pMac);
+ if (NULL == psessionEntry)
+ {
+ PELOGE(limLog(pMac, LOGE,
+ FL("RMC:Ruler_Inform_Cancel:No active IBSS"));)
+ return;
+ }
+
+ pHdr = WDA_GET_RX_MAC_HEADER((tANI_U8 *)pMsgBuf);
+
+ frameLen = WDA_GET_RX_PAYLOAD_LEN((tANI_U8 *)pMsgBuf);
+ if (frameLen < sizeof(tSirMacIbssExtNetworkFrameHdr))
+ {
+ PELOGE(limLog(pMac, LOGE,
+ FL("RMC: Ruler_Inform:Bad length %d "), frameLen);)
+ return;
+ }
+
+ pFrameData = WDA_GET_RX_MPDU_DATA((tANI_U8 *)pMsgBuf) +
+ sizeof(tSirMacIbssExtNetworkFrameHdr);
+
+ if (!pFrameData)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Inform_Cancel:NULL data"));)
+ return;
+ }
+
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE, FL("RMC:Ruler_Inform_Cancel lock acquire failed"));
+ return;
+ }
+
+ /*
+ * Find the entry for this Group Address.
+ */
+ entry = __rmcGroupLookupHashEntry(pMac, pHdr->sa);
+ if (NULL == entry)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Inform_Cancel: No entry"));)
+ goto done;
+ }
+
+ __limPostMsgUpdateInd(pMac, eRMC_RULER_CANCELLED,
+ eRMC_RULER_ROLE, pHdr->sa, psessionEntry->selfMacAddr);
+
+ /*
+ * Delete hash entry for this Group address.
+ */
+ status = __rmcGroupDeleteHashEntry(pMac, pHdr->sa);
+ if (eSIR_FAILURE == status)
+ {
+ PELOGE(limLog(pMac, LOGE,
+ FL("RMC: Ruler_Inform_Cancel:hash delete failed"));)
+ }
+
+done:
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_release(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE,
+ FL("RMC: Ruler_Inform_Cancel: lock release failed"));
+ }
+ return;
+}
+
+void
+limProcessRMCMessages(tpAniSirGlobal pMac, eRmcMessageType msgType,
+ tANI_U32 *pMsgBuf)
+{
+
+ if (pMsgBuf == NULL)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: Buffer is Pointing to NULL"));)
+ return;
+ }
+
+ limLog(pMac, LOG1, FL("RMC: limProcessRMCMessages: %s"),
+ __limRulerMessageToString(msgType));
+
+ switch (msgType)
+ {
+ case eLIM_RMC_ENABLE_REQ:
+ __limProcessRMCEnableRequest(pMac, pMsgBuf);
+ break;
+
+ case eLIM_RMC_DISABLE_REQ:
+ __limProcessRMCDisableRequest(pMac, pMsgBuf);
+ break;
+
+ case eLIM_RMC_RULER_SELECT_RESP:
+ __limProcessRMCRulerSelectResponse(pMac, pMsgBuf);
+ break;
+
+ case eLIM_RMC_RULER_PICK_NEW:
+ __limProcessRMCRulerPickNew(pMac, pMsgBuf);
+ break;
+
+ case eLIM_RMC_OTA_RULER_INFORM_SELECTED:
+ __limProcessRMCRulerInformSelected(pMac, pMsgBuf);
+ break;
+
+ case eLIM_RMC_BECOME_RULER_RESP:
+ __limProcessRMCBecomeRulerResp(pMac, pMsgBuf);
+ break;
+
+ case eLIM_RMC_OTA_RULER_INFORM_CANCELLED:
+ __limProcessRMCRulerInformCancelled(pMac, pMsgBuf);
+ break;
+
+
+ default:
+ break;
+ } // switch (msgType)
+ return;
+} /*** end limProcessRMCMessages() ***/
+
+void
+limRmcInit(tpAniSirGlobal pMac)
+{
+ tANI_U32 cfgValue;
+
+ if (wlan_cfgGetInt(pMac, WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY,
+ &cfgValue) != eSIR_SUCCESS)
+ {
+ /**
+ * Could not get Action Period Frequency value
+ * from CFG. Log error.
+ */
+ limLog(pMac, LOGP, FL("could not retrieve ActionPeriodFrequency"));
+ }
+
+ cfgValue = SYS_MS_TO_TICKS(cfgValue);
+
+ vos_mem_zero(&pMac->rmcContext, sizeof(pMac->rmcContext));
+
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_init(&pMac->rmcContext.lkRmcLock)))
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC lock init failed!"));)
+ }
+
+ if (tx_timer_create(&pMac->rmcContext.gRmcRulerSelectTimer,
+ "RMC RSP TIMEOUT",
+ __rmcRulerSelectTimerHandler,
+ 0 /* param */,
+ cfgValue, 0,
+ TX_NO_ACTIVATE) != TX_SUCCESS)
+ {
+ limLog(pMac, LOGE, FL("could not create RMC response timer"));
+ }
+
+ pMac->rmcContext.rmcTimerValInTicks = cfgValue;
+}
+
+void
+limRmcCleanup(tpAniSirGlobal pMac)
+{
+ limRmcIbssDelete(pMac);
+
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_destroy(&pMac->rmcContext.lkRmcLock)))
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC lock destroy failed!"));)
+ }
+
+ tx_timer_delete(&pMac->rmcContext.gRmcRulerSelectTimer);
+}
+
+void
+limRmcTransmitterDelete(tpAniSirGlobal pMac, tSirMacAddr transmitter)
+{
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE,
+ FL("RMC: limRMCTransmitterDelete lock acquire failed"));
+ return;
+ }
+
+ __rmcGroupDeleteHashEntry(pMac, transmitter);
+
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_release(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE,
+ FL("RMC: limRMCTransmitterDelete lock release failed"));
+ }
+
+ limLog(pMac, LOG1, FL("RMC: limRmcTransmitterDelete complete"));
+}
+
+void
+limRmcIbssDelete(tpAniSirGlobal pMac)
+{
+ tpPESession psessionEntry;
+ tSirMacAddr zeroMacAddr = { 0, 0, 0, 0, 0, 0 };
+
+ /*
+ * This API relies on a single active IBSS session.
+ */
+ psessionEntry = limIsIBSSSessionActive(pMac);
+ if (NULL == psessionEntry)
+ {
+ PELOGE(limLog(pMac, LOGE, FL("RMC: limRmcIbssDelete:No active IBSS"));)
+ return;
+ }
+
+ if (VOS_FALSE == vos_mem_compare(&zeroMacAddr,
+ &pMac->rmcContext.ruler, sizeof(tSirMacAddr)))
+ {
+ __limPostMsgUpdateInd(pMac, eRMC_RULER_CANCELLED,
+ eRMC_TRANSMITTER_ROLE, psessionEntry->selfMacAddr,
+ pMac->rmcContext.ruler);
+ }
+
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE,
+ FL("RMC: limRmcIbssDelete lock acquire failed"));
+ return;
+ }
+
+ /* Cancel pending timer */
+ tx_timer_deactivate(&pMac->rmcContext.gRmcRulerSelectTimer);
+
+ /* Delete all entries from Ruler database. */
+ __rmcGroupDeleteAllEntries(pMac);
+
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_release(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE,
+ FL("RMC: limRmcIbssDelete lock release failed"));
+ }
+
+ limLog(pMac, LOG1, FL("RMC: limRmcIbssDelete complete"));
+}
+
+void
+limRmcDumpStatus(tpAniSirGlobal pMac)
+{
+ tLimRmcGroupContext *entry;
+ int index, count;
+
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE,
+ FL("RMC: limRmcDumpStatus lock acquire failed"));
+ return;
+ }
+
+
+ limLog(pMac, LOGE, FL(" ----- RMC Transmitter Information ----- \n"));
+ limLog(pMac, LOGE,
+ FL(" Ruler Address | RMC State \n"));
+
+ if (pMac->rmcContext.state != eRMC_RULER_NOT_SELECTED)
+ {
+ limLog(pMac,LOGE, FL( MAC_ADDRESS_STR " | %s\n"),
+ MAC_ADDR_ARRAY(pMac->rmcContext.ruler),
+ __limMcastTxStateToString(pMac->rmcContext.state));
+ }
+
+ limLog( pMac,LOGE, FL(" ----- RMC Ruler Information ----- \n"));
+ limLog( pMac,LOGE, FL(" Transmitter Address\n"));
+
+ count = 0;
+ for (index = 0; index < RMC_MCAST_GROUPS_HASH_SIZE; index++)
+ {
+ entry = pMac->rmcContext.rmcGroupRxHashTable[index];
+
+ while (entry)
+ {
+ count++;
+ limLog( pMac,LOGE, FL("%d. " MAC_ADDRESS_STR " \n"),
+ count, MAC_ADDR_ARRAY(entry->transmitter));
+ entry = entry->next;
+ }
+ }
+
+ if (!VOS_IS_STATUS_SUCCESS(vos_lock_release(&pMac->rmcContext.lkRmcLock)))
+ {
+ limLog(pMac, LOGE,
+ FL("RMC: limRmcDumpStatus lock release failed"));
+ }
+
+ return;
+
+}
+
+VOS_STATUS
+limRmcTriggerRulerSelection(tpAniSirGlobal pMac, tSirMacAddr macAddr)
+{
+ if ((TRUE == pMac->rmcContext.rmcEnabled) &&
+ (eRMC_RULER_NOT_SELECTED == pMac->rmcContext.state))
+ {
+ limLog(pMac, LOG1,
+ FL("Ruler selection trigerred in FW"));
+
+ __limPostMsgRulerReq(pMac, eRMC_SUGGEST_RULER_CMD, macAddr);
+
+ pMac->rmcContext.state = eRMC_RULER_ENABLE_REQUESTED;
+
+ return VOS_STATUS_SUCCESS;
+ }
+ else
+ {
+ limLog(pMac, LOG1,
+ FL("Could not trigger ruler selection: RMC state %d rmcEnabled %d"),
+ pMac->rmcContext.state, pMac->rmcContext.rmcEnabled);
+
+ return VOS_STATUS_E_FAILURE;
+ }
+}
+
+#endif /* WLAN_FEATURE_RMC */
diff --git a/CORE/MAC/src/pe/lim/limRMC.h b/CORE/MAC/src/pe/lim/limRMC.h
new file mode 100644
index 0000000..1ebf0de
--- /dev/null
+++ b/CORE/MAC/src/pe/lim/limRMC.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2013-2016 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.
+ */
+
+/*
+ *
+ * Date: 08/15/13
+ * History:-
+ * Date Modified by Modification Information
+ * --------------------------------------------------------------------
+ */
+#ifndef __LIM_RMC_H
+#define __LIM_RMC_H
+
+#ifdef WLAN_FEATURE_RMC
+
+typedef enum {
+ eLIM_RMC_ENABLE_REQ = 0,
+ eLIM_RMC_DISABLE_REQ = 1,
+ eLIM_RMC_BECOME_RULER_RESP = 2,
+ eLIM_RMC_RULER_SELECT_RESP = 3,
+ eLIM_RMC_RULER_PICK_NEW = 4,
+ eLIM_RMC_OTA_RULER_INFORM_CANCELLED = 5,
+ eLIM_RMC_OTA_RULER_INFORM_ACK = 6,
+ eLIM_RMC_OTA_RULER_INFORM_SELECTED = 7,
+} eRmcMessageType;
+
+typedef enum {
+ eRMC_RULER_NOT_SELECTED = 0,
+ eRMC_RULER_ENABLE_REQUESTED = 1,
+ eRMC_RULER_OTA_REQUEST_SENT = 2,
+ eRMC_RULER_ACTIVE = 3,
+} eRmcMcastTxState;
+
+typedef enum {
+ eRMC_IS_NOT_A_RULER = 0,
+ eRMC_RULER_PENDING = 1,
+ eRMC_IS_A_RULER = 2,
+} eRmcRulerState;
+
+enum {
+ eRMC_SUGGEST_RULER_CMD = 0,
+ eRMC_BECOME_RULER_CMD = 1,
+};
+
+enum {
+ eRMC_RULER_ACCEPTED = 0, //Host-->FW
+ eRMC_RULER_CANCELLED = 1, //Host-->FW
+ eRMC_RULER_PICK_NEW = 2, //FW-->Host
+};
+
+/* tRoleType; */
+typedef enum
+{
+ eRMC_RULER_ROLE,
+ eRMC_TRANSMITTER_ROLE,
+} eRmcRole;
+
+#define RMC_MCAST_GROUPS_HASH_SIZE 32
+
+typedef struct sLimRmcGroupContext
+{
+ tSirMacAddr transmitter;
+ eRmcRulerState isRuler;
+ struct sLimRmcGroupContext *next;
+} tLimRmcGroupContext, *tpLimRmcGroupContext;
+
+typedef struct sLimRmcContext
+{
+ tANI_BOOLEAN rmcEnabled;
+ tSirMacAddr ruler;
+ eRmcMcastTxState state;
+ TX_TIMER gRmcRulerSelectTimer;
+ tANI_U32 rmcTimerValInTicks;
+ vos_lock_t lkRmcLock;
+ tLimRmcGroupContext *rmcGroupRxHashTable[RMC_MCAST_GROUPS_HASH_SIZE];
+} tLimRmcContext, *tpLimRmcContext;
+
+
+void limRmcInit(tpAniSirGlobal pMac);
+void limRmcCleanup(tpAniSirGlobal pMac);
+void limRmcTransmitterDelete(tpAniSirGlobal pMac, tSirMacAddr transmitter);
+void limRmcIbssDelete(tpAniSirGlobal pMac);
+void limRmcDumpStatus(tpAniSirGlobal pMac);
+
+VOS_STATUS
+limRmcTriggerRulerSelection(tpAniSirGlobal pMac, tSirMacAddr macAddr);
+#endif /* WLAN_FEATURE_RMC */
+
+#endif /* __LIM_RMC_H */
diff --git a/CORE/MAC/src/pe/lim/limSendManagementFrames.c b/CORE/MAC/src/pe/lim/limSendManagementFrames.c
index 8d40677..ab8e86c 100644
--- a/CORE/MAC/src/pe/lim/limSendManagementFrames.c
+++ b/CORE/MAC/src/pe/lim/limSendManagementFrames.c
@@ -7026,3 +7026,140 @@
return nSirStatus;
} // End limSendSaQueryResponseFrame
#endif
+
+#ifdef WLAN_FEATURE_RMC
+tSirRetStatus
+limSendRMCActionFrame(tpAniSirGlobal pMac,
+ tSirMacAddr peerMacAddr,
+ tSirRMCInfo *pRMC,
+ tpPESession psessionEntry)
+{
+ tSirRetStatus nSirStatus;
+ tANI_U8 *pFrame;
+ tDot11fRMC RMC;
+ tANI_U32 nPayload, nBytes, nStatus;
+ tpSirMacMgmtHdr pMacHdr;
+ void *pPacket;
+ eHalStatus halstatus;
+ tANI_U8 txFlag = 0;
+ tANI_U8 MagicCode[] = { 0x4f, 0x58, 0x59, 0x47, 0x45, 0x4e };
+
+ if (NULL == psessionEntry)
+ {
+ return eSIR_FAILURE;
+ }
+
+ vos_mem_set(( tANI_U8* )&RMC, sizeof( RMC ), 0);
+
+ RMC.Action.action = pRMC->action;
+ RMC.RMCDialogToken.token = pRMC->dialogToken;
+ RMC.Category.category = SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY;
+ RMC.RMCVersion.version = SIR_MAC_RMC_VER;
+
+ vos_mem_copy(&RMC.RMCOUI.oui, SIR_MAC_RMC_OUI, SIR_MAC_RMC_OUI_SIZE);
+ vos_mem_copy(&RMC.MagicCode.magic, MagicCode, sizeof(MagicCode));
+
+ vos_mem_copy(&RMC.Ruler.mac, pRMC->mcastRuler, sizeof(tSirMacAddr));
+
+ nStatus = dot11fGetPackedRMCSize( pMac, &RMC, &nPayload );
+ if ( DOT11F_FAILED( nStatus ) )
+ {
+ limLog( pMac, LOGE, FL("Failed to calculate the packed size for "
+ "an RMC (0x%08x)."),
+ nStatus );
+ // We'll fall back on the worst case scenario:
+ nPayload = sizeof( tDot11fRMC );
+ }
+ else if ( DOT11F_WARNED( nStatus ) )
+ {
+ limLog( pMac, LOGW, FL("There were warnings while calculating "
+ "the packed size for an RMC Action Frame"
+ " (0x%08x)."), nStatus );
+ }
+
+ nBytes = nPayload + sizeof( tSirMacMgmtHdr );
+
+ halstatus = palPktAlloc( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT,
+ ( tANI_U16 )nBytes, ( void** ) &pFrame,
+ ( void** ) &pPacket );
+ if ( ! HAL_STATUS_SUCCESS ( halstatus ) )
+ {
+ limLog( pMac, LOGP, FL("Failed to allocate %d bytes for an RMC "
+ "Action Frame."), nBytes );
+ return eSIR_FAILURE;
+ }
+
+ // Paranoia:
+ vos_mem_set( pFrame, nBytes, 0 );
+
+ // Next, we fill out the buffer descriptor:
+ nSirStatus = limPopulateMacHeader( pMac, pFrame, SIR_MAC_MGMT_FRAME,
+ SIR_MAC_MGMT_ACTION, peerMacAddr,
+ psessionEntry->selfMacAddr);
+ if ( eSIR_SUCCESS != nSirStatus )
+ {
+ limLog( pMac, LOGE, FL("Failed to populate the buffer descriptor "
+ "for an RMC Action Frame (%d)."),
+ nSirStatus );
+ palPktFree( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT,
+ ( void* ) pFrame, ( void* ) pPacket );
+ return nSirStatus;
+ }
+
+ // Update A3 with the BSSID
+ pMacHdr = ( tpSirMacMgmtHdr ) pFrame;
+ sirCopyMacAddr(pMacHdr->bssId,psessionEntry->bssId);
+
+ // That done, pack the struct:
+ nStatus = dot11fPackRMC( pMac, &RMC,
+ pFrame + sizeof(tSirMacMgmtHdr),
+ nPayload, &nPayload );
+ if ( DOT11F_FAILED( nStatus ) )
+ {
+ limLog( pMac, LOGE, FL("Failed to pack an RMC "
+ "(0x%08x)."),
+ nStatus );
+ palPktFree( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT, ( void* ) pFrame,
+ ( void* ) pPacket );
+ return eSIR_FAILURE;
+ }
+ else if ( DOT11F_WARNED( nStatus ) )
+ {
+ limLog( pMac, LOGW, FL("There were warnings while packing "
+ "an RMC (0x%08x)."), nStatus );
+ }
+
+ limLog( pMac, LOG1, FL("Sending an RMC Action frame to "
+ MAC_ADDRESS_STR), MAC_ADDR_ARRAY(peerMacAddr));
+
+ /*
+ * With this masking, RMC action frames will be sent
+ * at self-sta rates for both 2G and 5G bands.
+ */
+ txFlag |= HAL_USE_SELF_STA_REQUESTED_MASK;
+
+ MTRACE(macTrace(pMac, TRACE_CODE_TX_MGMT,
+ psessionEntry->peSessionId,
+ pMacHdr->fc.subType));
+ // Queue RMC Action frame in high priority WQ
+ halstatus = halTxFrame( pMac, pPacket, ( tANI_U16 ) nBytes,
+ HAL_TXRX_FRM_802_11_MGMT,
+ ANI_TXDIR_TODS,
+ 7,//SMAC_SWBD_TX_TID_MGMT_HIGH,
+ limTxComplete, pFrame, txFlag );
+ MTRACE(macTrace(pMac, TRACE_CODE_TX_COMPLETE,
+ psessionEntry->peSessionId,
+ halstatus));
+ if ( ! HAL_STATUS_SUCCESS ( halstatus ) )
+ {
+ limLog( pMac, LOGE, FL( "*** Could not send an RMC Action frame"
+ " (%X) ***" ), halstatus );
+ //Pkt will be freed up by the callback
+ return eSIR_FAILURE;
+ }
+
+ return eSIR_SUCCESS;
+
+} // End limSendRMCActionFrame.
+
+#endif /* WLAN_FEATURE_RMC */
diff --git a/CORE/MAC/src/pe/lim/limTypes.h b/CORE/MAC/src/pe/lim/limTypes.h
index 04bbcc2..8747a4d 100644
--- a/CORE/MAC/src/pe/lim/limTypes.h
+++ b/CORE/MAC/src/pe/lim/limTypes.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -872,6 +872,15 @@
tSirRetStatus limSendSaQueryResponseFrame( tpAniSirGlobal pMac,
tANI_U8 *transId, tSirMacAddr peer,tpPESession psessionEntry);
#endif
+
+#ifdef WLAN_FEATURE_RMC
+void limProcessRMCMessages(tpAniSirGlobal pMac, eRmcMessageType msgType,
+ tANI_U32 *pMsgBuf);
+tSirRetStatus limSendRMCActionFrame(tpAniSirGlobal pMac,
+ tSirMacAddr peerMacAddr, tSirRMCInfo *pRMC,
+ tpPESession psessionEntry);
+#endif /* WLAN_FEATURE_RMC */
+
// Inline functions
/**