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/TL/src/wlan_qct_tl.c b/CORE/TL/src/wlan_qct_tl.c
index 10459f2..9b56815 100644
--- a/CORE/TL/src/wlan_qct_tl.c
+++ b/CORE/TL/src/wlan_qct_tl.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.
  *
@@ -61,6 +61,7 @@
 
   when        who     what, where, why
 ----------    ---    --------------------------------------------------------
+2013-08-19    rajekuma Added RMC support
 2010-07-13    c_shinde Fixed an issue where WAPI rekeying was failing because 
                       WAI frame sent out during rekeying had the protected bit
                       set to 1.
@@ -563,6 +564,16 @@
   }
 #endif
 
+#ifdef WLAN_FEATURE_RMC
+   status = WLANTL_RmcInit(pvosGCtx);
+   if (!VOS_IS_STATUS_SUCCESS(status))
+   {
+    TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+              "RMC module init fail"));
+    return status;
+  }
+#endif
+
   pTLCb->isBMPS = VOS_FALSE;
   pmcRegisterDeviceStateUpdateInd( smeContext,
                                    WLANTL_PowerStateChangedCB, pvosGCtx );
@@ -820,6 +831,14 @@
   }
 #endif
 
+#ifdef WLAN_FEATURE_RMC
+  if(VOS_STATUS_SUCCESS != WLANTL_RmcDeInit(pvosGCtx))
+  {
+    TLLOGW(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN,
+               "RMC module DeInit fail"));
+  }
+#endif
+
   /*------------------------------------------------------------------------
     Cleanup TL control block.
    ------------------------------------------------------------------------*/
@@ -1451,6 +1470,10 @@
         pTLCb->ucTdlsPeerCount++;
 #endif
   }
+#ifdef WLAN_FEATURE_RMC
+  vos_lock_init(&pClientSTA->mcLock);
+#endif /* WLAN_FEATURE_RMC */
+
   return VOS_STATUS_SUCCESS;
 }/* WLANTL_RegisterSTAClient */
 
@@ -1555,6 +1578,15 @@
              "WLAN TL:Clearing STA Client ID: %d", ucSTAId ));
   WLANTL_CleanSTA(pTLCb->atlSTAClients[ucSTAId], 1 /*empty packets*/);
 
+#ifdef WLAN_FEATURE_RMC
+  /*--------------------------------------------------------------------
+    Delete multicast entries for duplicate detection
+    --------------------------------------------------------------------*/
+  WLANTL_McastDeleteAllEntries(pTLCb->atlSTAClients[ucSTAId]);
+
+  vos_lock_destroy(&pTLCb->atlSTAClients[ucSTAId]->mcLock);
+#endif /* WLAN_FEATURE_RMC */
+
   TLLOG2(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH,
              "WLAN TL:Clearing STA Reset History RSSI and Region number"));
   pTLCb->hoSupport.currentHOState.historyRSSI = 0;
@@ -8796,6 +8828,25 @@
   }
   }
 
+#ifdef WLAN_FEATURE_RMC
+  if (pTLCb->multicastDuplicateDetectionEnabled &&
+      (WLAN_STA_IBSS == pClientSTA->wSTADesc.wSTAType) &&
+       WLANTL_IS_DATA_FRAME(WDA_GET_RX_TYPE_SUBTYPE(aucBDHeader)))
+  {
+    /*
+     * Multicast duplicate detection is only for frames received in
+     * IBSS mode.
+     */
+    if (VOS_TRUE == WLANTL_IsDuplicateMcastFrm(pClientSTA, vosDataBuff))
+    {
+         pTLCb->mcastDupCnt++;
+         /* Duplicate multicast data packet, drop the packet */
+         vos_pkt_return_packet(vosDataBuff);
+         return VOS_STATUS_SUCCESS;
+    }
+  }
+#endif /* WLAN_FEATURE_RMC */
+
 #ifdef FEATURE_WLAN_WAPI
   if ( pClientSTA->wSTADesc.ucIsWapiSta )
   {
@@ -13294,3 +13345,618 @@
 
     return VOS_STATUS_SUCCESS;
 }/* WLANTL_GetSTALinkCapacity */
+
+
+#ifdef WLAN_FEATURE_RMC
+VOS_STATUS WLANTL_RmcInit
+(
+    v_PVOID_t   pAdapter
+)
+{
+    WLANTL_CbType   *pTLCb = VOS_GET_TL_CB(pAdapter);
+    VOS_STATUS       status = VOS_STATUS_SUCCESS;
+    tANI_U8          count;
+
+    /*sanity check*/
+    if (NULL == pTLCb)
+    {
+        TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+            "Invalid TL handle"));
+        return VOS_STATUS_E_INVAL;
+    }
+
+    for ( count = 0; count < WLANTL_RMC_HASH_TABLE_SIZE; count++ )
+    {
+        pTLCb->rmcSession[count] = NULL;
+    }
+
+    vos_lock_init(&pTLCb->rmcLock);
+
+    pTLCb->multicastDuplicateDetectionEnabled = 1;
+    pTLCb->rmcDataPathEnabled = 0;
+
+    return status;
+}
+
+
+VOS_STATUS WLANTL_RmcDeInit
+(
+    v_PVOID_t   pAdapter
+)
+{
+    WLANTL_CbType   *pTLCb = VOS_GET_TL_CB(pAdapter);
+    VOS_STATUS       status = VOS_STATUS_SUCCESS;
+    tANI_U8          count;
+    WLANTL_RMC_SESSION *pNode;
+    WLANTL_RMC_SESSION *pPrev;
+
+    /*sanity check*/
+    if (NULL == pTLCb)
+    {
+        TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+            "Invalid TL handle"));
+        return VOS_STATUS_E_INVAL;
+    }
+
+    for ( count = 0; count < WLANTL_RMC_HASH_TABLE_SIZE; count++ )
+    {
+        pNode = pTLCb->rmcSession[count];
+        while (pNode)
+        {
+            pPrev = pNode;
+            pNode = pNode->next;
+            vos_mem_free((v_VOID_t * )pPrev);
+        }
+    }
+
+    vos_lock_destroy(&pTLCb->rmcLock);
+
+    return status;
+}
+
+
+tANI_U8 WLANTL_RmcHashRmcSession ( v_MACADDR_t   *pMcastAddr )
+{
+    tANI_U32 sum;
+    tANI_U8  hash;
+
+    sum = (pMcastAddr->bytes[0] + pMcastAddr->bytes[1] + pMcastAddr->bytes[2] +
+           pMcastAddr->bytes[3] + pMcastAddr->bytes[4] + pMcastAddr->bytes[5]);
+
+    hash = (tANI_U8)(sum & ((WLANTL_RMC_HASH_TABLE_SIZE - 1)));
+
+    return hash;
+}
+
+
+WLANTL_RMC_SESSION* WLANTL_RmcLookUpRmcSession
+(
+    WLANTL_RMC_SESSION *rmcSession[],
+    v_MACADDR_t     *pMcastAddr
+)
+{
+    WLANTL_RMC_SESSION *pNode;
+    tANI_U8               index;
+
+    /*sanity check*/
+    if (NULL == pMcastAddr)
+    {
+        TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+            "Sanity check failed pMcastAddr %p", pMcastAddr));
+        return NULL;
+    }
+
+    index = WLANTL_RmcHashRmcSession(pMcastAddr);
+    pNode = rmcSession[index];
+    while ( pNode )
+    {
+        if (vos_is_macaddr_equal( &(pNode->rmcAddr), pMcastAddr))
+        {
+            return pNode;
+        }
+        pNode = pNode->next;
+    }
+
+    return NULL;
+}
+
+WLANTL_RMC_SESSION *WLANTL_RmcAddRmcSession
+(
+  WLANTL_RMC_SESSION *rmcSession[],
+  v_MACADDR_t   *pMcastAddr
+)
+{
+    WLANTL_RMC_SESSION *pNode;
+    tANI_U8               index;
+
+    index = WLANTL_RmcHashRmcSession(pMcastAddr);
+    pNode = WLANTL_RmcLookUpRmcSession(rmcSession, pMcastAddr);
+    if ( NULL != pNode )
+    {
+        /*already exists*/
+        return NULL;
+    }
+    else
+    {
+        pNode = (WLANTL_RMC_SESSION *)vos_mem_malloc(sizeof(*pNode));
+        if (pNode)
+        {
+            vos_mem_copy( &(pNode->rmcAddr), pMcastAddr,
+                sizeof(pNode->rmcAddr) );
+            pNode->next = rmcSession[index];
+            rmcSession[index] = pNode;
+            return pNode;
+        }
+        else
+        {
+            VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                "%s: vos_mem_malloc failed can't enable RMC session",
+                __func__);
+            return NULL;
+        }
+    }
+}
+
+tANI_U8
+WLANTL_RmcDeleteRmcSession
+(
+  WLANTL_RMC_SESSION *rmcSession[],
+  v_MACADDR_t   *pMcastAddr
+)
+{
+    WLANTL_RMC_SESSION *pHead;
+    WLANTL_RMC_SESSION *pNode;
+    WLANTL_RMC_SESSION *pPrev;
+    tANI_U8               index;
+
+    index = WLANTL_RmcHashRmcSession(pMcastAddr);
+    pHead = pNode = rmcSession[index];
+    while (pNode)
+    {
+        if (vos_is_macaddr_equal( &(pNode->rmcAddr), pMcastAddr))
+        {
+            if (pHead == pNode)
+            {
+                rmcSession[index] = pNode->next;
+            }
+            else
+            {
+                pPrev->next = pNode->next;
+            }
+            vos_mem_free((v_VOID_t * )pNode);
+            return 1;
+        }
+        pPrev = pNode;
+        pNode = pNode->next;
+    }
+
+    return 0;
+}
+
+VOS_STATUS
+WLANTL_ProcessRmcCommand
+(
+    WLANTL_CbType*  pTLCb,
+    v_MACADDR_t    *pMcastAddr,
+    tANI_U32        command
+)
+{
+    VOS_STATUS status;
+    tANI_U32 count;
+    tANI_U32 rmcActive;
+
+    if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire( &(pTLCb->rmcLock))))
+    {
+        TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+            "%s Get Lock Fail", __func__));
+        return VOS_STATUS_E_FAILURE;
+    }
+
+    /*add or delete node from active rmc hash table*/
+    if (command)
+    {
+        /*add requested rmc session in active rmc session list*/
+        if (WLANTL_RmcAddRmcSession(pTLCb->rmcSession, pMcastAddr))
+        {
+            TLLOGE( VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+                "RMC session " MAC_ADDRESS_STR " added in TL hash table",
+                MAC_ADDR_ARRAY(pMcastAddr->bytes) ) );
+            pTLCb->rmcDataPathEnabled = TRUE;
+            status = VOS_STATUS_SUCCESS;
+        }
+        else
+        {
+            TLLOGE( VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+                "RMC session " MAC_ADDRESS_STR " already exists in TL hash"
+                " table", MAC_ADDR_ARRAY(pMcastAddr->bytes) ) );
+            status = VOS_STATUS_E_FAILURE;
+        }
+    }
+    else
+    {
+        /*delete requested rmc session from active rmc session list*/
+        if (WLANTL_RmcDeleteRmcSession(pTLCb->rmcSession, pMcastAddr))
+        {
+            TLLOGE( VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,
+                "RMC session " MAC_ADDRESS_STR " deleted from TL hash table",
+                MAC_ADDR_ARRAY(pMcastAddr->bytes)) );
+            status = VOS_STATUS_SUCCESS;
+            rmcActive = FALSE;
+            for ( count = 0; count < WLANTL_RMC_HASH_TABLE_SIZE; count++ )
+            {
+                if (pTLCb->rmcSession[count])
+                {
+                    rmcActive = TRUE;
+                    break;
+                }
+            }
+            if (TRUE == rmcActive)
+            {
+                pTLCb->rmcDataPathEnabled = TRUE;
+            }
+            else
+            {
+                pTLCb->rmcDataPathEnabled = FALSE;
+            }
+        }
+        else
+        {
+            TLLOGE( VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+                "RMC session " MAC_ADDRESS_STR " doesn't exist in TL hash"
+                " table", MAC_ADDR_ARRAY(pMcastAddr->bytes) ) );
+            status = VOS_STATUS_E_FAILURE;
+        }
+    }
+
+    if (!VOS_IS_STATUS_SUCCESS(vos_lock_release(&(pTLCb->rmcLock))))
+    {
+         TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+             "%s Release Lock Fail", __func__));
+         return VOS_STATUS_E_FAILURE;
+    }
+
+    return status;
+}/* End of WLANTL_ProcessRmcCommand */
+
+VOS_STATUS
+WLANTL_EnableRMC
+(
+    v_PVOID_t     pvosGCtx,
+    v_MACADDR_t   *pMcastTransmitterAddr
+)
+{
+    WLANTL_CbType*  pTLCb;
+    VOS_STATUS status;
+
+    /*sanity check*/
+    if ( (NULL == pvosGCtx) || (NULL == pMcastTransmitterAddr) )
+    {
+        TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+            "WLAN TL %s: Sanity check failed pvosGCtx %p aMcastAddr %p",
+            __func__, pvosGCtx, pMcastTransmitterAddr));
+        return VOS_STATUS_E_FAILURE;
+    }
+
+    /*sanity check*/
+    pTLCb = VOS_GET_TL_CB(pvosGCtx);
+    if ( NULL == pTLCb )
+    {
+        TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+            "WLAN TL %s: pTLCb is NULL", __func__));
+        return VOS_STATUS_E_FAILURE;
+    }
+
+    status = WLANTL_ProcessRmcCommand(pTLCb, pMcastTransmitterAddr , 1);
+
+    return status;
+} /* End of WLANTL_EnableRMC */
+
+
+VOS_STATUS
+WLANTL_DisableRMC
+(
+    v_PVOID_t     pvosGCtx,
+    v_MACADDR_t   *pMcastTransmitterAddr
+)
+{
+    WLANTL_CbType* pTLCb;
+    VOS_STATUS status;
+
+    /*Sanity check*/
+    if ((NULL == pvosGCtx) || (NULL == pMcastTransmitterAddr))
+    {
+        TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+            "WLAN TL %s: Sanity check failed pvosGCtx %p aMcastAddr %p",
+             __func__, pvosGCtx, pMcastTransmitterAddr));
+        return VOS_STATUS_E_FAILURE;
+    }
+
+    /*Sanity check*/
+    pTLCb = VOS_GET_TL_CB(pvosGCtx);
+    if (NULL == pTLCb)
+    {
+        TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+            "WLAN TL %s: pTLCb is NULL", __func__));
+        return VOS_STATUS_E_FAILURE;
+    }
+
+    status = WLANTL_ProcessRmcCommand(pTLCb, pMcastTransmitterAddr, 0);
+
+    return status;
+} /* End of WLANTL_DisableRMC */
+
+
+/*=============================================================================
+        Duplicate Multicast Detection Functions
+==============================================================================*/
+
+/*=============================================================================
+  FUNCTION    WLANTL_IsDuplicateMcastFrm
+
+  DESCRIPTION
+    This function checks for duplicast multicast frames and drops them.
+
+  DEPENDENCIES
+
+  PARAMETERS
+
+   IN
+
+   pClientSTA  : Pointer to WLANTL_STAClientType
+   aucBDHeader : Pointer to BD header
+
+  RETURN VALUE
+
+    VOS_FALSE:  This frame is not a duplicate
+
+    VOS_TRUE:   This frame is a duplicate
+
+==============================================================================*/
+v_U8_t
+WLANTL_IsDuplicateMcastFrm
+(
+    WLANTL_STAClientType *pClientSTA,
+    vos_pkt_t *vosDataBuff
+)
+{
+    v_U8_t duplicate = VOS_FALSE;
+    WLANTL_RMC_SESSION *pNode;
+    v_U16_t     usSeqCtrl;
+    v_MACADDR_t mcastAddr;
+    VOS_STATUS  vosStatus;
+    v_PVOID_t   pvPeekData;
+
+    /* Get address 1 of Data Frame */
+    vosStatus = vos_pkt_peek_data(vosDataBuff, WLANTL_MAC_ADDR_ALIGN(1),
+                                  (v_PVOID_t)&pvPeekData, VOS_MAC_ADDR_SIZE);
+
+    if ( VOS_STATUS_SUCCESS != vosStatus )
+    {
+        TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+                "WLAN TL: Failed to get Addr 1 of 80211 header from packet %d",
+                vosStatus));
+        return VOS_FALSE;
+    }
+
+    /* Copy address 1 of Data Frame */
+    vos_mem_copy(&mcastAddr.bytes, pvPeekData, VOS_MAC_ADDR_SIZE);
+
+    /*
+     * We perform duplicate detection for only multicast data frames
+     */
+    if (vos_is_macaddr_group(&mcastAddr) &&
+         !vos_is_macaddr_broadcast(&mcastAddr))
+    {
+        /* Get sequence control of Data Frame */
+        vosStatus = vos_pkt_peek_data(vosDataBuff,
+                    (WLANTL_MAC_ADDR_ALIGN(1) + (3 * VOS_MAC_ADDR_SIZE)),
+                      (v_PVOID_t)&pvPeekData, sizeof(v_U16_t));
+
+        if ( VOS_STATUS_SUCCESS != vosStatus )
+        {
+            TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+                    "WLAN TL: Failed to get Sequence Control from packet %d",
+                    vosStatus));
+            return VOS_FALSE;
+        }
+
+        /* Copy sequence control from the Data Frame */
+        usSeqCtrl = *(v_U16_t *)pvPeekData;
+
+        if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&(pClientSTA->mcLock))))
+        {
+            TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+                    "%s Get Lock Fail", __func__));
+            return VOS_FALSE;
+        }
+
+        pNode = WLANTL_RmcLookUpRmcSession(pClientSTA->mcastSession,
+                                                      &mcastAddr);
+        if (NULL == pNode)
+        {
+            /* If the session does not exist, add it. */
+            pNode = WLANTL_RmcAddRmcSession(pClientSTA->mcastSession,
+                                              &mcastAddr);
+            /* If we could not add a entry, skip duplicate detection */
+            if (NULL == pNode)
+            {
+                TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+                    "%s Failed to add multicast session", __func__));
+                if (!VOS_IS_STATUS_SUCCESS
+                     (vos_lock_release(&(pClientSTA->mcLock))))
+                {
+                    TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+                        "%s Release Lock Fail", __func__));
+                }
+                return VOS_FALSE;
+            }
+            /* Initialize the sequence control value. */
+            pNode->mcSeqCtl = usSeqCtrl;
+        }
+        else
+        {
+            /*
+             * Check if the sequence number of this frame matches the last
+             * we have seen.
+             */
+            if (pNode->mcSeqCtl == usSeqCtrl)
+            {
+                pNode->rxMCDupcnt++;
+                TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,
+                     "%s Rx Multicast Duplicate %d " MAC_ADDRESS_STR
+                     " (Seq %x)", __func__,
+                     pNode->rxMCDupcnt, MAC_ADDR_ARRAY(mcastAddr.bytes),
+                     usSeqCtrl));
+                duplicate = VOS_TRUE;
+            }
+            else
+            {
+                /* Update the last seen sequence number */
+                pNode->mcSeqCtl = usSeqCtrl;
+            }
+        }
+
+        if (!VOS_IS_STATUS_SUCCESS (vos_lock_release(&(pClientSTA->mcLock))))
+        {
+            TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+                    "%s Release Lock Fail", __func__));
+        }
+    }
+
+    return duplicate;
+}
+
+/*=============================================================================
+  FUNCTION    WLANTL_McastDeleteAllEntries
+
+  DESCRIPTION
+    This function removes all multicast entries used for duplicate detection
+
+  DEPENDENCIES
+
+  PARAMETERS
+
+   IN
+
+   pClientSTA  : Pointer to WLANTL_STAClientType
+
+  RETURN VALUE
+
+    None
+
+==============================================================================*/
+void
+WLANTL_McastDeleteAllEntries(WLANTL_STAClientType * pClientSTA)
+{
+    WLANTL_RMC_SESSION *pNode, **head;
+    int index;
+
+    TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,
+                        "%s Deleting all multicast entries", __func__));
+
+    if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&(pClientSTA->mcLock))))
+    {
+        TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+                "%s Get Lock Fail", __func__));
+        return;
+    }
+
+    for (index = 0; index < WLANTL_RMC_HASH_TABLE_SIZE; index++)
+    {
+        head = &pClientSTA->mcastSession[index];
+
+        pNode = *head;
+
+        while (pNode)
+        {
+            *head = pNode->next;
+            /* free the group entry */
+            vos_mem_free(pNode);
+            pNode = *head;
+        }
+    }
+
+    if (!VOS_IS_STATUS_SUCCESS (vos_lock_release(&(pClientSTA->mcLock))))
+    {
+        TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+                "%s Release Lock Fail", __func__));
+    }
+}
+
+/*=============================================================================
+  FUNCTION    WLANTL_SetMcastDuplicateDetection
+
+  DESCRIPTION
+    This function sets multicate duplicate detection operation.
+    If enable is 1, the detection is enabled, else it is disabled.
+
+  DEPENDENCIES
+
+  PARAMETERS
+
+   IN
+
+   pvosGCtx   : Pointer to VOS global context
+   enable : Boolean to enable or disable
+
+  RETURN VALUE
+    The result code associated with performing the operation
+
+    VOS_STATUS_E_FAULT:   Sanity check on input failed
+
+    VOS_STATUS_SUCCESS:   Everything is good :)
+
+   Other return values are possible coming from the called functions.
+   Please check API for additional info.
+
+  SIDE EFFECTS
+
+==============================================================================*/
+VOS_STATUS
+WLANTL_SetMcastDuplicateDetection
+(
+    v_PVOID_t     pvosGCtx,
+    v_U8_t        enable
+)
+{
+    WLANTL_CbType* pTLCb;
+
+    /*Sanity check*/
+    if (NULL == pvosGCtx)
+    {
+        TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+            "WLAN TL %s: Sanity check failed pvosGCtx %p",
+             __func__, pvosGCtx));
+        return VOS_STATUS_E_FAILURE;
+    }
+
+    /*Sanity check*/
+    pTLCb = VOS_GET_TL_CB(pvosGCtx);
+    if (NULL == pTLCb)
+    {
+        TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+            "WLAN TL %s: pTLCb is NULL", __func__));
+        return VOS_STATUS_E_FAILURE;
+    }
+
+    switch (enable)
+    {
+    default:
+        /*
+         * Any value other than 0 or 1 is used to dump the
+         * duplicate count.
+         */
+        TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+            "WLAN TL %s: Multicast Duplicate Count %d",
+             __func__, pTLCb->mcastDupCnt));
+        break;
+    case 0:
+    case 1:
+        pTLCb->multicastDuplicateDetectionEnabled = enable;
+        break;
+    }
+
+    return VOS_STATUS_SUCCESS;
+}
+
+#endif /* WLAN_FEATURE_RMC */