/*
 * Copyright (c) 2012-2017, 2019 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 schBeaconGen.cc contains beacon generation related
 * functions
 *
 * Author:      Sandesh Goel
 * Date:        02/25/02
 * History:-
 * Date            Modified by    Modification Information
 * --------------------------------------------------------------------
 *
 */

#include "palTypes.h"
#include "wni_cfg.h"
#include "aniGlobal.h"
#include "sirMacProtDef.h"

#include "limUtils.h"
#include "limApi.h"


#include "halMsgApi.h"
#include "cfgApi.h"
#include "pmmApi.h"
#include "schApi.h"

#include "parserApi.h"

#include "schDebug.h"

//
// March 15, 2006
// Temporarily (maybe for all of Alpha-1), assuming TIM = 0
//

const tANI_U8 P2pOui[] = {0x50, 0x6F, 0x9A, 0x9};


tSirRetStatus schGetP2pIeOffset(tANI_U8 *pExtraIe, tANI_U32 extraIeLen, tANI_U16 *pP2pIeOffset)
{
    tSirRetStatus status = eSIR_FAILURE;
    *pP2pIeOffset = 0;

    // Extra IE is not present
    if(0 == extraIeLen)
    {
        return status;
    }

    // Calculate the P2P IE Offset
    do
    {
        if(*pExtraIe == 0xDD)
        {
            if ( vos_mem_compare ( (void *)(pExtraIe+2), &P2pOui, sizeof(P2pOui) ) )
            {
                status = eSIR_SUCCESS;
                break;
            }
        }

        (*pP2pIeOffset)++;
        pExtraIe++;
     }while(--extraIeLen > 0);

     return status;
}

tSirRetStatus schAppendAddnIE(tpAniSirGlobal pMac, tpPESession psessionEntry,
                                     tANI_U8 *pFrame, tANI_U32 maxBeaconSize,
                                     tANI_U32 *nBytes, uint8_t *addn_ie,
                                     uint16_t addn_ielen)
{
    tSirRetStatus status = eSIR_FAILURE;
    tANI_U8 addIE[WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN];

    if(addn_ielen <= WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN && addn_ielen &&
      ((addn_ielen + *nBytes) <= maxBeaconSize))
    {

        vos_mem_copy(&addIE[0], addn_ie, addn_ielen);

        {
            tANI_U8* pP2pIe = limGetP2pIEPtr(pMac, &addIE[0], addn_ielen);
            if ((pP2pIe != NULL) && !pMac->beacon_offload)
            {
                tANI_U8 noaLen = 0;
                tANI_U8 noaStream[SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN];
                //get NoA attribute stream P2P IE
                noaLen = limGetNoaAttrStream(pMac, noaStream, psessionEntry);
                if(noaLen)
                {
                    if ((noaLen + addn_ielen) <=
                                    WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN) {
                        vos_mem_copy(&addIE[addn_ielen], noaStream, noaLen);
                        addn_ielen += noaLen;
                        /* Update IE Len */
                        pP2pIe[1] += noaLen;
                    }
                    else
                    {
                        schLog(pMac, LOGE,
                           FL("Not able to insert NoA because of addn_ielength constraint"));
                    }
                }
            }
            if(addn_ielen <= WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN)
            {
                vos_mem_copy(pFrame, &addIE[0], addn_ielen);
                *nBytes = *nBytes + addn_ielen;
            }
            else
            {
                schLog(pMac, LOGW, FL("Not able to insert because of"
                    " addn_ielength constraint %d"), addn_ielen);
            }
        }
    }

    return status;
}

// --------------------------------------------------------------------
/**
 * schSetFixedBeaconFields
 *
 * FUNCTION:
 *
 * LOGIC:
 *
 * ASSUMPTIONS:
 *
 * NOTE:
 *
 * @param None
 * @return None
 */

tSirRetStatus schSetFixedBeaconFields(tpAniSirGlobal pMac,tpPESession psessionEntry)
{
    tpAniBeaconStruct pBeacon = (tpAniBeaconStruct)
                          psessionEntry->pSchBeaconFrameBegin;
    tpSirMacMgmtHdr mac;
    tANI_U16        offset;
    tANI_U8        *ptr;
    tDot11fBeacon1 *pBcn1;
    tDot11fBeacon2 *pBcn2;
    tANI_U32        i, nStatus, nBytes;
    tANI_U32        wpsApEnable=0, tmp;
    tDot11fIEWscProbeRes      *pWscProbeRes;
    tANI_U8  *pExtraIe = NULL;
    tANI_U32 extraIeLen =0;
    tANI_U16 extraIeOffset = 0;
    tANI_U16 p2pIeOffset = 0;
    tSirRetStatus status = eSIR_SUCCESS;
    tANI_BOOLEAN  isVHTEnabled = eANI_BOOLEAN_FALSE;
    uint16_t addn_ielen = 0;
    uint8_t *addn_ie = NULL;
    tDot11fIEExtCap extracted_extcap;
    bool extcap_present = true, addnie_present = false;

    pBcn1 = vos_mem_malloc(sizeof(tDot11fBeacon1));
    if ( NULL == pBcn1 )
    {
        schLog(pMac, LOGE, FL("Failed to allocate memory") );
        return eSIR_FAILURE;
    }

    pBcn2 = vos_mem_malloc(sizeof(tDot11fBeacon2));
    if ( NULL == pBcn2 )
    {
        schLog(pMac, LOGE, FL("Failed to allocate memory") );
        vos_mem_free(pBcn1);
        return eSIR_FAILURE;
    }

    pWscProbeRes = vos_mem_malloc(sizeof(tDot11fIEWscProbeRes));
    if ( NULL == pWscProbeRes )
    {
        schLog(pMac, LOGE, FL("Failed to allocate memory") );
        vos_mem_free(pBcn1);
        vos_mem_free(pBcn2);
        return eSIR_FAILURE;
    }

    PELOG1(schLog(pMac, LOG1, FL("Setting fixed beacon fields"));)

    /*
     * First set the fixed fields
     */

    // set the TFP headers

    // set the mac header
    vos_mem_set(( tANI_U8*) &pBeacon->macHdr, sizeof( tSirMacMgmtHdr ),0);
    mac = (tpSirMacMgmtHdr) &pBeacon->macHdr;
    mac->fc.type = SIR_MAC_MGMT_FRAME;
    mac->fc.subType = SIR_MAC_MGMT_BEACON;

    for (i=0; i<6; i++)
        mac->da[i] = 0xff;

    vos_mem_copy(mac->sa, psessionEntry->selfMacAddr, sizeof(psessionEntry->selfMacAddr));
    vos_mem_copy(mac->bssId, psessionEntry->bssId, sizeof (psessionEntry->bssId));

    mac->fc.fromDS = 0;
    mac->fc.toDS = 0;

    /*
     * Now set the beacon body
     */

    vos_mem_set(( tANI_U8*) pBcn1, sizeof( tDot11fBeacon1 ), 0);

    /* Skip over the time stamp (it'll be updated later). */

    pBcn1->BeaconInterval.interval = psessionEntry->beaconParams.beaconInterval;
    PopulateDot11fCapabilities( pMac, &pBcn1->Capabilities, psessionEntry );
    if (psessionEntry->ssidHidden)
    {
       pBcn1->SSID.present = 1; /* Rest of the fields are 0 for hidden ssid */
       if((psessionEntry->ssId.length) &&
          (psessionEntry->ssidHidden == eHIDDEN_SSID_ZERO_CONTENTS))
          pBcn1->SSID.num_ssid = psessionEntry->ssId.length;
    }
    else
    {
       PopulateDot11fSSID( pMac, &psessionEntry->ssId, &pBcn1->SSID );
    }


    PopulateDot11fSuppRates( pMac, POPULATE_DOT11F_RATES_OPERATIONAL, &pBcn1->SuppRates,psessionEntry);
    PopulateDot11fDSParams( pMac, &pBcn1->DSParams, psessionEntry->currentOperChannel, psessionEntry);
    PopulateDot11fIBSSParams( pMac, &pBcn1->IBSSParams,psessionEntry);

    offset = sizeof( tAniBeaconStruct );
    ptr    = psessionEntry->pSchBeaconFrameBegin + offset;

    if (LIM_IS_AP_ROLE(psessionEntry)) {
        /* Initialize the default IE bitmap to zero */
        vos_mem_set(( tANI_U8* )&(psessionEntry->DefProbeRspIeBitmap), (sizeof( tANI_U32 ) * 8), 0);

        /* Initialize the default IE bitmap to zero */
        vos_mem_set(( tANI_U8* )&(psessionEntry->probeRespFrame),
                    sizeof(psessionEntry->probeRespFrame), 0);

        if (vos_is_probe_rsp_offload_enabled()) {
            /* Can be efficiently updated whenever new IE added
             * in Probe response in future
             */
            if (limUpdateProbeRspTemplateIeBitmapBeacon1(pMac, pBcn1,
                   psessionEntry) != eSIR_SUCCESS) {
                       schLog(pMac, LOGE,
                           FL("Failed to build ProbeRsp template"));
            }
        }
    }

    nStatus = dot11fPackBeacon1( pMac, pBcn1, ptr,
                                 SCH_MAX_BEACON_SIZE - offset,
                                 &nBytes );
    if ( DOT11F_FAILED( nStatus ) )
    {
      schLog( pMac, LOGE, FL("Failed to packed a tDot11fBeacon1 (0x%0"
                             "8x.)."), nStatus );
      vos_mem_free(pBcn1);
      vos_mem_free(pBcn2);
      vos_mem_free(pWscProbeRes);
      return eSIR_FAILURE;
    }
    else if ( DOT11F_WARNED( nStatus ) )
    {
      schLog( pMac, LOGE, FL("There were warnings while packing a tDo"
                             "t11fBeacon1 (0x%08x.)."), nStatus );
    }
    /*changed  to correct beacon corruption */
    vos_mem_set(( tANI_U8*) pBcn2, sizeof( tDot11fBeacon2 ), 0);
    psessionEntry->schBeaconOffsetBegin = offset + ( tANI_U16 )nBytes;
    schLog( pMac, LOG1, FL("Initialized beacon begin, offset %d"), offset );

    /*
     * Initialize the 'new' fields at the end of the beacon
     */

    if ((psessionEntry->limSystemRole == eLIM_AP_ROLE) &&
       psessionEntry->dfsIncludeChanSwIe == VOS_TRUE) {
           if (!CHAN_HOP_ALL_BANDS_ENABLE ||
               psessionEntry->lim_non_ecsa_cap_num == 0)
                   populate_dot_11_f_ext_chann_switch_ann(
                       pMac, &pBcn2->ext_chan_switch_ann, psessionEntry);
           else
                   PopulateDot11fChanSwitchAnn(pMac, &pBcn2->ChanSwitchAnn,
                                               psessionEntry);
    }

    populate_dot11_supp_operating_classes(pMac, &pBcn2->SuppOperatingClasses,
                                          psessionEntry);
    PopulateDot11fCountry( pMac, &pBcn2->Country, psessionEntry);
    if(pBcn1->Capabilities.qos)
    {
        PopulateDot11fEDCAParamSet( pMac, &pBcn2->EDCAParamSet, psessionEntry);
    }

    if(psessionEntry->lim11hEnable)
    {
      PopulateDot11fPowerConstraints( pMac, &pBcn2->PowerConstraints );
      PopulateDot11fTPCReport( pMac, &pBcn2->TPCReport, psessionEntry);

      /* Need to insert channel switch announcement here */
      if ((LIM_IS_AP_ROLE(psessionEntry) ||
           LIM_IS_P2P_DEVICE_GO(psessionEntry)) &&
           psessionEntry->dfsIncludeChanSwIe == VOS_TRUE) {
         /* Channel switch announcement only if radar is detected
          * and SAP has instructed to announce channel switch IEs
          * in beacon and probe responses
          */
          if (!CHAN_HOP_ALL_BANDS_ENABLE)
                  PopulateDot11fChanSwitchAnn(pMac, &pBcn2->ChanSwitchAnn,
                                              psessionEntry);

#ifdef WLAN_FEATURE_11AC
         /* TODO: If in 11AC mode, wider bw channel switch announcement needs
          * to be called
          */
         /*PopulateDot11fWiderBWChanSwitchAnn(pMac, &pBcn2->WiderBWChanSwitchAnn,
                                            psessionEntry);*/
#endif
         /*
          * Populate the Channel Switch Wrapper Element if
          * SAP operates in 40/80 Mhz Channel Width.
          */
         if (VOS_TRUE == psessionEntry->dfsIncludeChanWrapperIe)
         {
            PopulateDot11fChanSwitchWrapper(pMac,
                                     &pBcn2->ChannelSwitchWrapper,
                                     psessionEntry);
         }
      }
    }

#ifdef FEATURE_AP_MCC_CH_AVOIDANCE
    /* populate proprietary IE for MDM device operating in AP-MCC */
    populate_dot11f_avoid_channel_ie(pMac, &pBcn2->QComVendorIE, psessionEntry);
#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */

    populate_dot11f_sub_20_channel_width_ie(
        pMac, &pBcn2->QComVendorIE, psessionEntry);

    if (psessionEntry->dot11mode != WNI_CFG_DOT11_MODE_11B)
        PopulateDot11fERPInfo( pMac, &pBcn2->ERPInfo, psessionEntry );

    if(psessionEntry->htCapability)
    {
        PopulateDot11fHTCaps( pMac,psessionEntry, &pBcn2->HTCaps );
        PopulateDot11fHTInfo( pMac, &pBcn2->HTInfo, psessionEntry );
    }
#ifdef WLAN_FEATURE_11AC
    if(psessionEntry->vhtCapability)
    {
        schLog( pMac, LOGW, FL("Populate VHT IEs in Beacon"));
        PopulateDot11fVHTCaps( pMac, psessionEntry, &pBcn2->VHTCaps );
        PopulateDot11fVHTOperation( pMac, psessionEntry, &pBcn2->VHTOperation);
        isVHTEnabled = eANI_BOOLEAN_TRUE;
        // we do not support multi users yet
        //PopulateDot11fVHTExtBssLoad( pMac, &bcn2.VHTExtBssLoad);
        if(psessionEntry->gLimOperatingMode.present)
            PopulateDot11fOperatingMode( pMac, &pBcn2->OperatingMode, psessionEntry );
    }
#endif

    if (psessionEntry->limSystemRole != eLIM_STA_IN_IBSS_ROLE)
        PopulateDot11fExtCap(pMac, isVHTEnabled, &pBcn2->ExtCap, psessionEntry);

    PopulateDot11fExtSuppRates( pMac, POPULATE_DOT11F_RATES_OPERATIONAL,
                                &pBcn2->ExtSuppRates, psessionEntry );

    if( psessionEntry->pLimStartBssReq != NULL )
    {
          PopulateDot11fWPA( pMac, &psessionEntry->pLimStartBssReq->rsnIE,
                       &pBcn2->WPA );
          PopulateDot11fRSNOpaque( pMac, &psessionEntry->pLimStartBssReq->rsnIE,
                       &pBcn2->RSNOpaque );
#ifdef SAP_AUTH_OFFLOAD
        /* Software AP Authentication Offload feature
         * only support WPA2-PSK AES and we
         * need to update RSNIE for beacon
         */
        sap_auth_offload_update_rsn_ie(pMac, &pBcn2->RSNOpaque);
#endif
    }

    if(psessionEntry->limWmeEnabled)
    {
        PopulateDot11fWMM( pMac, &pBcn2->WMMInfoAp, &pBcn2->WMMParams, &pBcn2->WMMCaps, psessionEntry);
    }
    if (LIM_IS_AP_ROLE(psessionEntry)) {
        if(psessionEntry->wps_state != SAP_WPS_DISABLED)
        {
            PopulateDot11fBeaconWPSIEs( pMac, &pBcn2->WscBeacon, psessionEntry);
        }
    }
    else
    {
        if (wlan_cfgGetInt(pMac, (tANI_U16) WNI_CFG_WPS_ENABLE, &tmp) != eSIR_SUCCESS)
            schLog(pMac, LOGP,"Failed to cfg get id %d", WNI_CFG_WPS_ENABLE );

        wpsApEnable = tmp & WNI_CFG_WPS_ENABLE_AP;

        if (wpsApEnable)
        {
            PopulateDot11fWsc(pMac, &pBcn2->WscBeacon);
        }

        if (pMac->lim.wscIeInfo.wscEnrollmentState == eLIM_WSC_ENROLL_BEGIN)
        {
            PopulateDot11fWscRegistrarInfo(pMac, &pBcn2->WscBeacon);
            pMac->lim.wscIeInfo.wscEnrollmentState = eLIM_WSC_ENROLL_IN_PROGRESS;
        }

        if (pMac->lim.wscIeInfo.wscEnrollmentState == eLIM_WSC_ENROLL_END)
        {
            DePopulateDot11fWscRegistrarInfo(pMac, &pBcn2->WscBeacon);
            pMac->lim.wscIeInfo.wscEnrollmentState = eLIM_WSC_ENROLL_NOOP;
        }
    }

    if (LIM_IS_AP_ROLE(psessionEntry)) {
        if (vos_is_probe_rsp_offload_enabled()) {
            /* Can be efficiently updated whenever new IE added  in Probe response in future */
            limUpdateProbeRspTemplateIeBitmapBeacon2(pMac,pBcn2,&psessionEntry->DefProbeRspIeBitmap[0],
                                                     &psessionEntry->probeRespFrame);
        }

        /* update probe response WPS IE instead of beacon WPS IE
        * */
        if(psessionEntry->wps_state != SAP_WPS_DISABLED)
        {
            if(psessionEntry->APWPSIEs.SirWPSProbeRspIE.FieldPresent)
            {
                PopulateDot11fProbeResWPSIEs(pMac, pWscProbeRes, psessionEntry);
            }
            else
            {
                pWscProbeRes->present = 0;
            }
            if(pWscProbeRes->present)
            {
                SetProbeRspIeBitmap(&psessionEntry->DefProbeRspIeBitmap[0],SIR_MAC_WPA_EID);
                vos_mem_copy((void *)&psessionEntry->probeRespFrame.WscProbeRes,
                             (void *)pWscProbeRes,
                             sizeof(tDot11fIEWscProbeRes));
            }
        }

    }

    addnie_present = (psessionEntry->addIeParams.probeRespBCNDataLen != 0);
    if (addnie_present) {
        addn_ielen = psessionEntry->addIeParams.probeRespBCNDataLen;
        addn_ie = vos_mem_malloc(addn_ielen);
        if (!addn_ie) {
             schLog(pMac, LOGE, FL("addn_ie malloc failed"));
             vos_mem_free(pBcn1);
             vos_mem_free(pBcn2);
             vos_mem_free(pWscProbeRes);
             return eSIR_MEM_ALLOC_FAILED;
        }
        vos_mem_copy(addn_ie, psessionEntry->addIeParams.probeRespBCNData_buff,
                     addn_ielen);

        vos_mem_set((uint8_t *)&extracted_extcap, sizeof(tDot11fIEExtCap), 0);
        status = lim_strip_extcap_update_struct(pMac, addn_ie, &addn_ielen,
                                                &extracted_extcap);
        if (eSIR_SUCCESS != status) {
            extcap_present = false;
            schLog(pMac, LOG1, FL("extcap not extracted"));
        }
        /* merge extcap IE */
        if (extcap_present &&
            psessionEntry->limSystemRole != eLIM_STA_IN_IBSS_ROLE)
            lim_merge_extcap_struct(&pBcn2->ExtCap, &extracted_extcap, true);

    }

    nStatus = dot11fPackBeacon2( pMac, pBcn2,
                                 psessionEntry->pSchBeaconFrameEnd,
                                 SCH_MAX_BEACON_SIZE, &nBytes );
    if ( DOT11F_FAILED( nStatus ) )
    {
      schLog( pMac, LOGE, FL("Failed to packed a tDot11fBeacon2 (0x%0"
                             "8x.)."), nStatus );
      vos_mem_free(pBcn1);
      vos_mem_free(pBcn2);
      vos_mem_free(pWscProbeRes);
      vos_mem_free(addn_ie);
      return eSIR_FAILURE;
    }
    else if ( DOT11F_WARNED( nStatus ) )
    {
      schLog( pMac, LOGE, FL("There were warnings while packing a tDo"
                             "t11fBeacon2 (0x%08x.)."), nStatus );
    }

    pExtraIe = psessionEntry->pSchBeaconFrameEnd + nBytes;
    extraIeOffset = nBytes;

    if (addn_ielen > 0)
        schAppendAddnIE(pMac, psessionEntry,
                    psessionEntry->pSchBeaconFrameEnd + nBytes,
                    SCH_MAX_BEACON_SIZE, &nBytes, addn_ie, addn_ielen);

    psessionEntry->schBeaconOffsetEnd = ( tANI_U16 )nBytes;

    extraIeLen = nBytes - extraIeOffset;

    //Get the p2p Ie Offset
    status = schGetP2pIeOffset(pExtraIe, extraIeLen, &p2pIeOffset);

    if(eSIR_SUCCESS == status)
    {
       //Update the P2P Ie Offset
       pMac->sch.schObject.p2pIeOffset =
                    psessionEntry->schBeaconOffsetBegin + TIM_IE_SIZE +
                    extraIeOffset + p2pIeOffset;
    }
    else
    {
       pMac->sch.schObject.p2pIeOffset = 0;
    }

    schLog( pMac, LOG1, FL("Initialized beacon end, offset %d"),
            psessionEntry->schBeaconOffsetEnd );

    pMac->sch.schObject.fBeaconChanged = 1;
    vos_mem_free(pBcn1);
    vos_mem_free(pBcn2);
    vos_mem_free(pWscProbeRes);
    vos_mem_free(addn_ie);
    return eSIR_SUCCESS;
}

tSirRetStatus limUpdateProbeRspTemplateIeBitmapBeacon1(tpAniSirGlobal pMac,
                                              tDot11fBeacon1* beacon1,
                                              tpPESession psessionEntry)
{
    tANI_U32* DefProbeRspIeBitmap;
    tDot11fProbeResponse* prb_rsp;

    if (!psessionEntry) {
        schLog(pMac, LOGE, FL("PESession is null!"));
        return eSIR_FAILURE;
    }

    DefProbeRspIeBitmap = &psessionEntry->DefProbeRspIeBitmap[0];
    prb_rsp = &psessionEntry->probeRespFrame;

    prb_rsp->BeaconInterval = beacon1->BeaconInterval;
    vos_mem_copy((void *)&prb_rsp->Capabilities, (void *)&beacon1->Capabilities,
                 sizeof(beacon1->Capabilities));

    /* SSID */
    if(beacon1->SSID.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_SSID_EID);
        /* populating it, because probe response has to go with
         * SSID even in hidden case
         */
        PopulateDot11fSSID(pMac, &psessionEntry->ssId, &prb_rsp->SSID);
    }
    /* supported rates */
    if(beacon1->SuppRates.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_RATESET_EID);
        vos_mem_copy((void *)&prb_rsp->SuppRates, (void *)&beacon1->SuppRates,
                     sizeof(beacon1->SuppRates));

    }
    /* DS Parameter set */
    if(beacon1->DSParams.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_DS_PARAM_SET_EID);
        vos_mem_copy((void *)&prb_rsp->DSParams, (void *)&beacon1->DSParams,
                      sizeof(beacon1->DSParams));

    }

    /* IBSS params will not be present in the Beacons transmitted by AP */

    return eSIR_SUCCESS;
}

void limUpdateProbeRspTemplateIeBitmapBeacon2(tpAniSirGlobal pMac,
                                              tDot11fBeacon2* beacon2,
                                              tANI_U32* DefProbeRspIeBitmap,
                                              tDot11fProbeResponse* prb_rsp)
{
    /* IBSS parameter set - will not be present in probe response tx by AP */
    /* country */
    if(beacon2->Country.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_COUNTRY_EID);
        vos_mem_copy((void *)&prb_rsp->Country, (void *)&beacon2->Country,
                     sizeof(beacon2->Country));

    }
    /* Power constraint */
    if(beacon2->PowerConstraints.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_PWR_CONSTRAINT_EID);
        vos_mem_copy((void *)&prb_rsp->PowerConstraints, (void *)&beacon2->PowerConstraints,
                     sizeof(beacon2->PowerConstraints));

    }
    /* Channel Switch Announcement SIR_MAC_CHNL_SWITCH_ANN_EID */
    if(beacon2->ChanSwitchAnn.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_CHNL_SWITCH_ANN_EID);
        vos_mem_copy((void *)&prb_rsp->ChanSwitchAnn, (void *)&beacon2->ChanSwitchAnn,
                     sizeof(beacon2->ChanSwitchAnn));

    }

    /* EXT Channel Switch Announcement CHNL_EXTENDED_SWITCH_ANN_EID*/
    if (beacon2->ext_chan_switch_ann.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,
               SIR_MAC_CHNL_EXTENDED_SWITCH_ANN_EID);
        vos_mem_copy((void *)&prb_rsp->ext_chan_switch_ann,
            (void *)&beacon2->ext_chan_switch_ann,
             sizeof(beacon2->ext_chan_switch_ann));
    }
    /* Supported operating class */
    if(beacon2->SuppOperatingClasses.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_OPERATING_CLASS_EID);
        vos_mem_copy((void *)&prb_rsp->SuppOperatingClasses,
                     (void *)&beacon2->SuppOperatingClasses,
                     sizeof(beacon2->SuppOperatingClasses));
    }

    if(beacon2->QComVendorIE.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap, SIR_MAC_QCOM_VENDOR_EID);
        vos_mem_copy((void *)&prb_rsp->QComVendorIE,
                     (void *)&beacon2->QComVendorIE,
                     sizeof(beacon2->QComVendorIE));
    }

    /* ERP information */
    if(beacon2->ERPInfo.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_ERP_INFO_EID);
        vos_mem_copy((void *)&prb_rsp->ERPInfo, (void *)&beacon2->ERPInfo,
                     sizeof(beacon2->ERPInfo));

    }
    /* Extended supported rates */
    if(beacon2->ExtSuppRates.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_EXTENDED_RATE_EID);
        vos_mem_copy((void *)&prb_rsp->ExtSuppRates, (void *)&beacon2->ExtSuppRates,
                     sizeof(beacon2->ExtSuppRates));

    }

    /* WPA */
    if(beacon2->WPA.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_WPA_EID);
        vos_mem_copy((void *)&prb_rsp->WPA, (void *)&beacon2->WPA,
                     sizeof(beacon2->WPA));

    }

    /* RSN */
    if(beacon2->RSNOpaque.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_RSN_EID);
        vos_mem_copy((void *)&prb_rsp->RSNOpaque, (void *)&beacon2->RSNOpaque,
                     sizeof(beacon2->RSNOpaque));
    }

    /* EDCA Parameter set */
    if(beacon2->EDCAParamSet.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_EDCA_PARAM_SET_EID);
        vos_mem_copy((void *)&prb_rsp->EDCAParamSet, (void *)&beacon2->EDCAParamSet,
                     sizeof(beacon2->EDCAParamSet));

    }
    /* Vendor specific - currently no vendor specific IEs added */
    /* Requested IEs - currently we are not processing this will be added later */
    //HT capability IE
    if(beacon2->HTCaps.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_HT_CAPABILITIES_EID);
        vos_mem_copy((void *)&prb_rsp->HTCaps, (void *)&beacon2->HTCaps,
                     sizeof(beacon2->HTCaps));
    }
    // HT Info IE
    if(beacon2->HTInfo.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_HT_INFO_EID);
        vos_mem_copy((void *)&prb_rsp->HTInfo, (void *)&beacon2->HTInfo,
                     sizeof(beacon2->HTInfo));
    }

#ifdef WLAN_FEATURE_11AC
    if(beacon2->VHTCaps.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_VHT_CAPABILITIES_EID);
        vos_mem_copy((void *)&prb_rsp->VHTCaps, (void *)&beacon2->VHTCaps,
                     sizeof(beacon2->VHTCaps));
    }
    if(beacon2->VHTOperation.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_VHT_OPERATION_EID);
        vos_mem_copy((void *)&prb_rsp->VHTOperation, (void *)&beacon2->VHTOperation,
                     sizeof(beacon2->VHTOperation));
    }
    if(beacon2->VHTExtBssLoad.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_VHT_EXT_BSS_LOAD_EID);
        vos_mem_copy((void *)&prb_rsp->VHTExtBssLoad, (void *)&beacon2->VHTExtBssLoad,
                     sizeof(beacon2->VHTExtBssLoad));
    }
#endif

    //WMM IE
    if(beacon2->WMMParams.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_WPA_EID);
        vos_mem_copy((void *)&prb_rsp->WMMParams, (void *)&beacon2->WMMParams,
                     sizeof(beacon2->WMMParams));
    }
    //WMM capability - most of the case won't be present
    if(beacon2->WMMCaps.present)
    {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_WPA_EID);
        vos_mem_copy((void *)&prb_rsp->WMMCaps, (void *)&beacon2->WMMCaps,
                     sizeof(beacon2->WMMCaps));
    }

    /* Extended Capability */
    if (beacon2->ExtCap.present) {
        SetProbeRspIeBitmap(DefProbeRspIeBitmap, DOT11F_EID_EXTCAP);
        vos_mem_copy((void *)&prb_rsp->ExtCap, (void *)&beacon2->ExtCap,
                     sizeof(beacon2->ExtCap));
    }

}

void SetProbeRspIeBitmap(tANI_U32* IeBitmap,tANI_U32 pos)
{
    tANI_U32 index,temp;

    index = pos >> 5;
    if(index >= 8 )
    {
        return;
    }
    temp = IeBitmap[index];

    temp |= 1 << (pos & 0x1F);

    IeBitmap[index] = temp;
}



// --------------------------------------------------------------------
/**
 * writeBeaconToMemory
 *
 * FUNCTION:
 *
 * LOGIC:
 *
 * ASSUMPTIONS:
 *
 * NOTE:
 *
 * @param None
 * @param size    Size of the beacon to write to memory
 * @param length Length field of the beacon to write to memory
 * @return None
 */

void writeBeaconToMemory(tpAniSirGlobal pMac, tANI_U16 size, tANI_U16 length, tpPESession psessionEntry)
{
    tANI_U16          i;
    tpAniBeaconStruct pBeacon;

    // copy end of beacon only if length > 0
    if (length > 0)
    {
        if (size + psessionEntry->schBeaconOffsetEnd > SCH_MAX_BEACON_SIZE) {
            schLog(pMac, LOGE,
                   FL("beacon template fail size %d BeaconOffsetEnd %d"),
                   size, psessionEntry->schBeaconOffsetEnd);
            return;
        }
        for (i=0; i < psessionEntry->schBeaconOffsetEnd; i++)
            psessionEntry->pSchBeaconFrameBegin[size++] = psessionEntry->pSchBeaconFrameEnd[i];
    }

    // Update the beacon length
    pBeacon = (tpAniBeaconStruct) psessionEntry->pSchBeaconFrameBegin;
    // Do not include the beaconLength indicator itself
    if (length == 0)
    {
        pBeacon->beaconLength = 0;
        // Dont copy entire beacon, Copy length field alone
        size = 4;
    }
    else
        pBeacon->beaconLength = (tANI_U32) size - sizeof( tANI_U32 );

    // write size bytes from pSchBeaconFrameBegin
    PELOG2(schLog(pMac, LOG2, FL("Beacon size - %d bytes"), size);)
    PELOG2(sirDumpBuf(pMac, SIR_SCH_MODULE_ID, LOG2, psessionEntry->pSchBeaconFrameBegin, size);)

    if (! pMac->sch.schObject.fBeaconChanged)
        return;

    pMac->sch.gSchGenBeacon = 1;
    if (pMac->sch.gSchGenBeacon)
    {
        pMac->sch.gSchBeaconsSent++;

        //
        // Copy beacon data to SoftMAC shared memory...
        // Do this by sending a message to HAL
        //

        size = (size + 3) & (~3);
        if( eSIR_SUCCESS != schSendBeaconReq( pMac, psessionEntry->pSchBeaconFrameBegin,
                                              size, psessionEntry))
            PELOGE(schLog(pMac, LOGE, FL("schSendBeaconReq() returned an error (zsize %d)"), size);)
        else
        {
            pMac->sch.gSchBeaconsWritten++;
        }
    }
    pMac->sch.schObject.fBeaconChanged = 0;
}

// --------------------------------------------------------------------
/**
 * @function: SchProcessPreBeaconInd
 *
 * @brief : Process the PreBeacon Indication from the Lim
 *
 * ASSUMPTIONS:
 *
 * NOTE:
 *
 * @param : pMac - tpAniSirGlobal
 *
 * @return None
 */

void
schProcessPreBeaconInd(tpAniSirGlobal pMac, tpSirMsgQ limMsg)
{
    tpBeaconGenParams  pMsg = (tpBeaconGenParams)limMsg->bodyptr;
    tANI_U32 beaconSize;
    tpPESession psessionEntry;
    tANI_U8 sessionId;

    if((psessionEntry = peFindSessionByBssid(pMac,pMsg->bssId, &sessionId))== NULL)
    {
        PELOGE(schLog(pMac, LOGE, FL("session lookup fails"));)
        goto end;
    }


    beaconSize = psessionEntry->schBeaconOffsetBegin;

    // If SME is not in normal mode, no need to generate beacon
    if (psessionEntry->limSmeState  != eLIM_SME_NORMAL_STATE)
    {
        PELOGE(schLog(pMac, LOG1, FL("PreBeaconInd received in invalid state: %d"), psessionEntry->limSmeState);)
        goto end;
    }

    switch(GET_LIM_SYSTEM_ROLE(psessionEntry)) {
    case eLIM_STA_IN_IBSS_ROLE:
    case eLIM_BT_AMP_AP_ROLE:
    case eLIM_BT_AMP_STA_ROLE:
        /* Generate IBSS parameter set */
        if(psessionEntry->statypeForBss == STA_ENTRY_SELF)
            writeBeaconToMemory(pMac, (tANI_U16) beaconSize,
                               (tANI_U16)beaconSize, psessionEntry);
        else
            PELOGE(schLog(pMac, LOGE, FL("can not send beacon for PEER session entry"));)
        break;

    case eLIM_AP_ROLE: {
         tANI_U8 *ptr = &psessionEntry->pSchBeaconFrameBegin[psessionEntry->schBeaconOffsetBegin];
         tANI_U16 timLength = 0;

         if ((psessionEntry->statypeForBss == STA_ENTRY_SELF) &&
             (!pMac->sap_tx_off)) {
             pmmGenerateTIM(pMac, &ptr, &timLength, psessionEntry->dtimPeriod);
             beaconSize += 2 + timLength;
             writeBeaconToMemory(pMac, (tANI_U16) beaconSize,
                                (tANI_U16)beaconSize, psessionEntry);
         } else
             PELOGE(schLog(pMac, LOGE, FL("can not send beacon for PEER session entry"));)
         }
         break;

    default:
        PELOGE(schLog(pMac, LOGE,
               FL("Error-PE has Receive PreBeconGenIndication when System is in %d role"),
               GET_LIM_SYSTEM_ROLE(psessionEntry));)
    }

end:
      vos_mem_free(pMsg);

}
