/*
 * Copyright (c) 2012-2014, 2016-2017 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.
 */

/*
 * sysEntryFunc.cc - This file has all the system level entry functions
 *                   for all the defined threads at system level.
 * Author:    V. K. Kandarpa
 * Date:      01/16/2002
 * History:-
 * Date       Modified by            Modification Information
 * --------------------------------------------------------------------------
 *
 */
/* Standard include files */

/* Application Specific include files */
#include "sirCommon.h"
#include "aniGlobal.h"


#include "limApi.h"
#include "schApi.h"
#include "utilsApi.h"
#include "pmmApi.h"

#include "sysDebug.h"
#include "sysDef.h"
#include "sysEntryFunc.h"
#include "sysStartup.h"
#include "limTrace.h"
#include "wlan_qct_wda.h"

tSirRetStatus
postPTTMsgApi(tpAniSirGlobal pMac, tSirMsgQ *pMsg);

#include "vos_types.h"
#include "vos_packet.h"

#define MAX_DEAUTH_ALLOWED 5
// ---------------------------------------------------------------------------
/**
 * sysInitGlobals
 *
 * FUNCTION:
 *    Initializes system level global parameters
 *
 * LOGIC:
 *
 * ASSUMPTIONS:
 *
 * NOTE:
 *
 * @param tpAniSirGlobal Sirius software parameter struct pointer
 * @return None
 */

tSirRetStatus
sysInitGlobals(tpAniSirGlobal pMac)
{

    vos_mem_set((tANI_U8 *) &pMac->sys, sizeof(pMac->sys), 0);

    pMac->sys.gSysEnableScanMode        = 1;
    pMac->sys.gSysEnableLinkMonitorMode = 0;
    schInitGlobals(pMac);

    return eSIR_SUCCESS;
}

// ---------------------------------------------------------------------------
/**
 * sysBbtProcessMessageCore
 *
 * FUNCTION:
 * Process BBT messages
 *
 * LOGIC:
 *
 * ASSUMPTIONS:
 *
 * NOTE:
 *
 * @param tpAniSirGlobal A pointer to MAC params instance
 * @param pMsg message pointer
 * @param tANI_U32 type
 * @param tANI_U32 sub type
 * @return None
 */
tSirRetStatus
sysBbtProcessMessageCore(tpAniSirGlobal pMac, tpSirMsgQ pMsg, tANI_U32 type,
                         tANI_U32 subType)
{
    tANI_U32 framecount;
    tSirRetStatus ret;
    void*         pBd;
    tMgmtFrmDropReason dropReason;
    vos_pkt_t  *pVosPkt = (vos_pkt_t *)pMsg->bodyptr;
    VOS_STATUS  vosStatus =
              WDA_DS_PeekRxPacketInfo( pVosPkt, (v_PVOID_t *)&pBd, VOS_FALSE );

    pMac->sys.gSysBbtReceived++;

    if ( !VOS_IS_STATUS_SUCCESS(vosStatus) )
    {
        goto fail;
    }

    sysLog(pMac, LOG3, FL("Rx Mgmt Frame Subtype: %d\n"), subType);
    sirDumpBuf(pMac, SIR_SYS_MODULE_ID, LOG3, (tANI_U8 *)WDA_GET_RX_MAC_HEADER(pBd), WDA_GET_RX_MPDU_LEN(pBd));
    sirDumpBuf(pMac, SIR_SYS_MODULE_ID, LOG3, WDA_GET_RX_MPDU_DATA(pBd), WDA_GET_RX_PAYLOAD_LEN(pBd));

    pMac->sys.gSysFrameCount[type][subType]++;
    framecount = pMac->sys.gSysFrameCount[type][subType];

    if(type == SIR_MAC_MGMT_FRAME)
    {
            tpSirMacMgmtHdr mac_hdr;
            /*
             * Drop beacon frames in deferred state to avoid VOSS run out of
             * message wrappers.
             */
            if ((subType == SIR_MAC_MGMT_BEACON) &&
                (!limIsSystemInScanState(pMac)) &&
                (true != GET_LIM_PROCESS_DEFD_MESGS(pMac)) &&
                !pMac->lim.gLimSystemInScanLearnMode) {
                sysLog(pMac, LOG1,
                          FL("dropping received beacon in deffered state"));
                goto fail;
            }

            dropReason = limIsPktCandidateForDrop(pMac, pBd, subType);
            if (dropReason != eMGMT_DROP_NO_DROP) {
                sysLog(pMac, LOG1,
                            FL("Mgmt Frame %d being dropped, reason: %d\n"),
                            subType, dropReason);
                MTRACE(macTrace(pMac, TRACE_CODE_RX_MGMT_DROP, NO_SESSION, dropReason));
                goto fail;
            }

            mac_hdr = WDA_GET_RX_MAC_HEADER(pBd);
            if (subType == SIR_MAC_MGMT_ASSOC_REQ) {
                sysLog(pMac, LOG1,
                       FL("ASSOC REQ frame allowed: da: " MAC_ADDRESS_STR ", sa: " MAC_ADDRESS_STR ", bssid: " MAC_ADDRESS_STR ", Assoc Req count so far: %d\n"),
                       MAC_ADDR_ARRAY(mac_hdr->da),
                       MAC_ADDR_ARRAY(mac_hdr->sa),
                       MAC_ADDR_ARRAY(mac_hdr->bssId),
                       pMac->sys.gSysFrameCount[type][subType]);
            }

            if (subType == SIR_MAC_MGMT_DEAUTH)
            {
                sysLog(pMac, LOG1,
                       FL("DEAUTH frame allowed: da: " MAC_ADDRESS_STR ", sa: " MAC_ADDRESS_STR ", bssid: " MAC_ADDRESS_STR ", DEAUTH count so far: %d\n"),
                       MAC_ADDR_ARRAY(mac_hdr->da),
                       MAC_ADDR_ARRAY(mac_hdr->sa),
                       MAC_ADDR_ARRAY(mac_hdr->bssId),
                       pMac->sys.gSysFrameCount[type][subType]);
            }
            if (subType == SIR_MAC_MGMT_DISASSOC)
            {
                sysLog(pMac, LOG1,
                       FL("DISASSOC frame allowed: da: " MAC_ADDRESS_STR ", sa: " MAC_ADDRESS_STR ", bssid: " MAC_ADDRESS_STR ", DISASSOC count so far: %d\n"),
                       MAC_ADDR_ARRAY(mac_hdr->da),
                       MAC_ADDR_ARRAY(mac_hdr->sa),
                       MAC_ADDR_ARRAY(mac_hdr->bssId),
                       pMac->sys.gSysFrameCount[type][subType]);
            }

            /*
             * Post the message to PE Queue. Prioritize the
             * Auth and assoc frames.
             */
            if ((subType == SIR_MAC_MGMT_AUTH) ||
               (subType == SIR_MAC_MGMT_ASSOC_RSP) ||
               (subType == SIR_MAC_MGMT_REASSOC_RSP) ||
               (subType == SIR_MAC_MGMT_ASSOC_REQ) ||
               (subType == SIR_MAC_MGMT_REASSOC_REQ))
                ret = (tSirRetStatus) lim_post_msg_high_pri(pMac, pMsg);
            else
                ret = (tSirRetStatus) limPostMsgApi(pMac, pMsg);
            if (ret != eSIR_SUCCESS)
            {
                /* Print only one debug failure out of 512 failure messages */
                if(pMac->sys.gSysBbtReceived & 0x0200)
                   sysLog(pMac, LOGE,
                       FL("posting to LIM2 failed, ret %d"), ret);
                goto fail;
            }
            pMac->sys.gSysBbtPostedToLim++;
    }
    else if (type == SIR_MAC_DATA_FRAME)
    {
#ifdef FEATURE_WLAN_ESE
        sysLog(pMac, LOGW, FL("IAPP Frame...\n"));
        //Post the message to PE Queue
        ret = (tSirRetStatus) limPostMsgApi(pMac, pMsg);
        if (ret != eSIR_SUCCESS)
        {
            sysLog(pMac, LOGE, FL("posting to LIM2 failed, ret %d\n"), ret);
            goto fail;
        }
        pMac->sys.gSysBbtPostedToLim++;
#endif
    }
    else
    {
        sysLog(pMac, LOG3, "BBT received Invalid type %d subType %d "
                   "LIM state %X. BD dump is:\n",
                   type, subType, limGetSmeState(pMac));
        sirDumpBuf(pMac, SIR_SYS_MODULE_ID, LOG3,
                       (tANI_U8 *) pBd, WLANHAL_RX_BD_HEADER_SIZE);

        goto fail;
    }

    return eSIR_SUCCESS;

fail:

    pMac->sys.gSysBbtDropped++;
    return eSIR_FAILURE;
}


void sysLog(tpAniSirGlobal pMac, tANI_U32 loglevel, const char *pString,...)
{
    // Verify against current log level
    if ( loglevel > pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE( SIR_SYS_MODULE_ID )] )
        return;
    else
    {
        va_list marker;

        va_start( marker, pString );     /* Initialize variable arguments. */

        logDebug(pMac, SIR_SYS_MODULE_ID, loglevel, pString, marker);

        va_end( marker );              /* Reset variable arguments.      */
    }
}
