wlan: Support SAP Auth Offload feature

For SAP Auth offload, station assoc and disassoc will happen
in firmware.
As soon driver is in waked up state, firmware
will send Assoc or disassoc indication to host.
In case of ADD STA indication, driver will parse all caps
of connected client and will register this client to TL and HDD.
In case of DEL STA indication, driver will remove entry for
this station and will start cleanup.

Change-Id: I8ab0cc906be97be6f1f61de3e2ac9359cb7d17b0
CRs-Fixed: 753731
diff --git a/CORE/MAC/src/pe/lim/limUtils.c b/CORE/MAC/src/pe/lim/limUtils.c
index f8c315a..4c08388 100644
--- a/CORE/MAC/src/pe/lim/limUtils.c
+++ b/CORE/MAC/src/pe/lim/limUtils.c
@@ -59,6 +59,9 @@
 #ifdef WLAN_FEATURE_11W
 #include "wniCfg.h"
 #endif
+#ifdef SAP_AUTH_OFFLOAD
+#include "limAssocUtils.h"
+#endif
 
 /* Static global used to mark situations where pMac->lim.gLimTriggerBackgroundScanDuringQuietBss is SET
  * and limTriggerBackgroundScanDuringQuietBss() returned failure.  In this case, we will stop data
@@ -8617,3 +8620,513 @@
           limLog(mac_ctx, LOG1, FL("Clearing Immed Blk Ack:no AP support"));
     }
 }
+#ifdef SAP_AUTH_OFFLOAD
+/**
+ * _sap_offload_parse_assoc_req - Parse assoc request and store it.
+ *
+ * @pmac: mac context
+ * @assoc_req: Assoc request
+ * @add_sta_req: Add Sta request
+ *
+ * This function process recieved add sta message and store it as
+ * sta ds entry. This function will add this sta entry to DPH as well.
+ *
+ * Return: DPH hash node
+ */
+static tpDphHashNode
+_sap_offload_parse_assoc_req(tpAniSirGlobal pmac,
+        tpSirAssocReq assoc_req,
+        tSapOfldAddStaIndMsg *add_sta_req)
+{
+    tpSirMacAssocReqFrame mac_assoc_req = NULL;
+    tpSirAssocReq temp_assoc_req;
+    tSirRetStatus status;
+    tpDphHashNode sta_ds = NULL;
+    uint8_t *frame_body = NULL;
+
+    tpPESession session_entry = limIsApSessionActive(pmac);
+
+    if (session_entry == NULL)
+    {
+        PELOGE(limLog(pmac, LOGE, FL(" Session not found"));)
+            return NULL;
+    }
+
+    /* Update Attribute and Remove IE for
+     * Software AP Authentication Offload
+     */
+    frame_body = (tANI_U8 *)add_sta_req->bufp;
+    mac_assoc_req = (tpSirMacAssocReqFrame)frame_body;
+    mac_assoc_req->capabilityInfo.privacy = 0;
+
+    status = sirConvertAssocReqFrame2Struct(pmac,
+            frame_body,
+            add_sta_req->data_len,
+            assoc_req);
+    if (status != eSIR_SUCCESS)
+    {
+        limLog(pmac, LOGW, FL("sap_offload_add_sta_req parse error"));
+        goto error;
+    }
+    /* For software AP Auth Offload feature
+     * Host will take it as none security station
+     * Force change to none security
+     */
+    assoc_req->rsnPresent = 0;
+    assoc_req->wpaPresent = 0;
+
+    sta_ds = dphAddHashEntry(pmac,
+            add_sta_req->peer_macaddr,
+            add_sta_req->assoc_id,
+            &session_entry->dph.dphHashTable);
+    if (sta_ds == NULL)
+    {
+        /* Could not add hash table entry at DPH */
+        limLog(pmac, LOGE,
+                FL("could not add hash entry at DPH for aid=%d, MacAddr:"
+                    MAC_ADDRESS_STR),
+                add_sta_req->assoc_id,MAC_ADDR_ARRAY(add_sta_req->peer_macaddr));
+        goto error;
+    }
+
+    if (session_entry->parsedAssocReq != NULL)
+    {
+        temp_assoc_req = session_entry->parsedAssocReq[sta_ds->assocId];
+        if (temp_assoc_req != NULL)
+        {
+            if (temp_assoc_req->assocReqFrame)
+            {
+                vos_mem_free(temp_assoc_req->assocReqFrame);
+                temp_assoc_req->assocReqFrame = NULL;
+                temp_assoc_req->assocReqFrameLength = 0;
+            }
+            vos_mem_free(temp_assoc_req);
+            temp_assoc_req = NULL;
+        }
+        session_entry->parsedAssocReq[sta_ds->assocId] = assoc_req;
+    }
+error:
+    return sta_ds;
+}
+
+/**
+ * _sap_offload_parse_sta_capability - Parse sta caps from assoc request
+ *
+ * @sta_ds: STA state node
+ * @assoc_req: Assoc request
+ * @add_sta_req: Add Sta request
+ *
+ * This function process recieved add sta message and store station's caps
+ * in station ds entry.
+ *
+ * Return: none
+ */
+static void
+_sap_offload_parse_sta_capability(tpDphHashNode sta_ds,
+        tpSirAssocReq assoc_req,
+        tSapOfldAddStaIndMsg *add_sta_req)
+
+{
+
+    sta_ds->mlmStaContext.htCapability = assoc_req->HTCaps.present;
+#ifdef WLAN_FEATURE_11AC
+    sta_ds->mlmStaContext.vhtCapability = assoc_req->VHTCaps.present;
+#endif
+    sta_ds->qos.addtsPresent = (assoc_req->addtsPresent==0) ? false : true;
+    sta_ds->qos.addts        = assoc_req->addtsReq;
+    sta_ds->qos.capability   = assoc_req->qosCapability;
+    sta_ds->versionPresent   = 0;
+    /* short slot and short preamble should be
+     * updated before doing limaddsta
+     */
+    sta_ds->shortPreambleEnabled =
+        (tANI_U8)assoc_req->capabilityInfo.shortPreamble;
+    sta_ds->shortSlotTimeEnabled =
+        (tANI_U8)assoc_req->capabilityInfo.shortSlotTime;
+
+    sta_ds->valid = 0;
+    /* The Auth Type of Software AP Authentication Offload
+     * is always Open System is host side
+     */
+    sta_ds->mlmStaContext.authType = eSIR_OPEN_SYSTEM;
+    sta_ds->staType = STA_ENTRY_PEER;
+
+    /* Assoc Response frame to requesting STA */
+    sta_ds->mlmStaContext.subType = 0;
+
+    sta_ds->mlmStaContext.listenInterval = assoc_req->listenInterval;
+    sta_ds->mlmStaContext.capabilityInfo = assoc_req->capabilityInfo;
+
+    /* The following count will be used to knock-off the station
+     * if it doesn't come back to receive the buffered data.
+     * The AP will wait for numTimSent number of beacons after
+     * sending TIM information for the station, before assuming that
+     * the station is no more associated and disassociates it
+     */
+
+    /* timWaitCount is used by PMM for monitoring the STA's in PS for LINK*/
+    sta_ds->timWaitCount =
+        (tANI_U8)GET_TIM_WAIT_COUNT(assoc_req->listenInterval);
+
+    /* Initialise the Current successful
+     * MPDU's tranfered to this STA count as 0
+     */
+    sta_ds->curTxMpduCnt = 0;
+}
+
+/**
+ * _sap_offload_parse_sta_vht - Parse sta's HT/VHT caps from assoc request
+ *
+ * @pmac: mac context
+ * @sta_ds: STA state node
+ * @assoc_req: Assoc request
+ *
+ * This function process recieved add sta message and store station's HT and
+ * and VHT caps and store them in station ds entry.
+ *
+ * Return: tSirRetStatus
+ */
+static tSirRetStatus
+_sap_offload_parse_sta_vht(tpAniSirGlobal pmac,
+        tpDphHashNode sta_ds,
+        tpSirAssocReq assoc_req)
+{
+    tpPESession session_entry = limIsApSessionActive(pmac);
+
+    if (IS_DOT11_MODE_HT(session_entry->dot11mode) &&
+            assoc_req->HTCaps.present && assoc_req->wmeInfoPresent)
+    {
+        sta_ds->htGreenfield = (tANI_U8)assoc_req->HTCaps.greenField;
+        sta_ds->htAMpduDensity = assoc_req->HTCaps.mpduDensity;
+        sta_ds->htDsssCckRate40MHzSupport =
+            (tANI_U8)assoc_req->HTCaps.dsssCckMode40MHz;
+        sta_ds->htLsigTXOPProtection =
+            (tANI_U8)assoc_req->HTCaps.lsigTXOPProtection;
+        sta_ds->htMaxAmsduLength =
+            (tANI_U8)assoc_req->HTCaps.maximalAMSDUsize;
+        sta_ds->htMaxRxAMpduFactor = assoc_req->HTCaps.maxRxAMPDUFactor;
+        sta_ds->htMIMOPSState = assoc_req->HTCaps.mimoPowerSave;
+        sta_ds->htShortGI20Mhz = (tANI_U8)assoc_req->HTCaps.shortGI20MHz;
+        sta_ds->htShortGI40Mhz = (tANI_U8)assoc_req->HTCaps.shortGI40MHz;
+        sta_ds->htSupportedChannelWidthSet =
+            (tANI_U8)assoc_req->HTCaps.supportedChannelWidthSet;
+        /* peer just follows AP; so when we are softAP/GO,
+         * we just store our session entry's secondary channel offset here
+         * in peer INFRA STA. However, if peer's 40MHz channel width support
+         * is disabled then secondary channel will be zero
+         */
+        sta_ds->htSecondaryChannelOffset =
+            (sta_ds->htSupportedChannelWidthSet) ?
+            session_entry->htSecondaryChannelOffset : 0;
+#ifdef WLAN_FEATURE_11AC
+        if (assoc_req->operMode.present)
+        {
+            sta_ds->vhtSupportedChannelWidthSet =
+                (tANI_U8)((assoc_req->operMode.chanWidth ==
+                            eHT_CHANNEL_WIDTH_80MHZ) ?
+                        WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ :
+                        WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ);
+            sta_ds->htSupportedChannelWidthSet =
+                (tANI_U8)(assoc_req->operMode.chanWidth ?
+                        eHT_CHANNEL_WIDTH_40MHZ : eHT_CHANNEL_WIDTH_20MHZ);
+        }
+        else if (assoc_req->VHTCaps.present)
+        {
+            /* Check if STA has enabled it's channel bonding mode.
+             * If channel bonding mode is enabled, we decide based on
+             * SAP's current configuration else, we set it to VHT20.
+             */
+            sta_ds->vhtSupportedChannelWidthSet =
+                (tANI_U8)((sta_ds->htSupportedChannelWidthSet ==
+                            eHT_CHANNEL_WIDTH_20MHZ) ?
+                        WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ :
+                        session_entry->vhtTxChannelWidthSet );
+            sta_ds->htMaxRxAMpduFactor = assoc_req->VHTCaps.maxAMPDULenExp;
+        }
+
+        /* Lesser among the AP and STA bandwidth of operation. */
+        sta_ds->htSupportedChannelWidthSet =
+            (sta_ds->htSupportedChannelWidthSet <
+             session_entry->htSupportedChannelWidthSet) ?
+            sta_ds->htSupportedChannelWidthSet :
+            session_entry->htSupportedChannelWidthSet ;
+#endif
+        sta_ds->baPolicyFlag = 0xFF;
+        sta_ds->htLdpcCapable = (tANI_U8)assoc_req->HTCaps.advCodingCap;
+    }
+
+    if (assoc_req->VHTCaps.present && assoc_req->wmeInfoPresent)
+        sta_ds->vhtLdpcCapable = (tANI_U8)assoc_req->VHTCaps.ldpcCodingCap;
+
+    if (!assoc_req->wmeInfoPresent)
+    {
+        sta_ds->mlmStaContext.htCapability = 0;
+#ifdef WLAN_FEATURE_11AC
+        sta_ds->mlmStaContext.vhtCapability = 0;
+#endif
+    }
+#ifdef WLAN_FEATURE_11AC
+    if (limPopulateMatchingRateSet(pmac,
+                sta_ds,
+                &(assoc_req->supportedRates),
+                &(assoc_req->extendedRates),
+                assoc_req->HTCaps.supportedMCSSet,
+                &(assoc_req->propIEinfo.propRates),
+                session_entry , &assoc_req->VHTCaps)
+            != eSIR_SUCCESS)
+    {
+#else
+        if (limPopulateMatchingRateSet(pmac,
+                    sta_ds,
+                    &(assoc_req->supportedRates),
+                    &(assoc_req->extendedRates),
+                    assoc_req->HTCaps.supportedMCSSet,
+                    &(assoc_req->propIEinfo.propRates),
+                    session_entry) != eSIR_SUCCESS)
+        {
+#endif
+            limLog(pmac, LOGE,
+                    FL("Rate set mismatched for aid=%d, MacAddr: "
+                        MAC_ADDRESS_STR),
+                    sta_ds->assocId, MAC_ADDR_ARRAY(sta_ds->staAddr));
+            goto error;
+        }
+        return eSIR_SUCCESS;
+error:
+        return eSIR_FAILURE;
+}
+
+/**
+ * _sap_offload_parse_sta_qos - Parse sta's QOS caps from assoc request
+ *
+ * @pmac: mac context
+ * @sta_ds: STA state node
+ * @assoc_req: Assoc request
+ *
+ * This function process recieved add sta message and store station's QOS
+ * store them in station ds entry.
+ *
+ * Return: none
+ */
+static void
+ _sap_offload_parse_sta_qos(tpAniSirGlobal pmac,
+            tpDphHashNode sta_ds,
+            tpSirAssocReq assoc_req)
+{
+    tHalBitVal qos_mode;
+    tHalBitVal wsm_mode, wme_mode;
+    tpPESession session_entry = limIsApSessionActive(pmac);
+
+    limGetQosMode(session_entry, &qos_mode);
+    sta_ds->qosMode    = eANI_BOOLEAN_FALSE;
+    sta_ds->lleEnabled = eANI_BOOLEAN_FALSE;
+
+    if (assoc_req->capabilityInfo.qos && (qos_mode == eHAL_SET))
+    {
+        sta_ds->lleEnabled = eANI_BOOLEAN_TRUE;
+        sta_ds->qosMode    = eANI_BOOLEAN_TRUE;
+    }
+
+    sta_ds->wmeEnabled = eANI_BOOLEAN_FALSE;
+    sta_ds->wsmEnabled = eANI_BOOLEAN_FALSE;
+    limGetWmeMode(session_entry, &wme_mode);
+    if ((!sta_ds->lleEnabled) && assoc_req->wmeInfoPresent &&
+            (wme_mode == eHAL_SET))
+    {
+        sta_ds->wmeEnabled = eANI_BOOLEAN_TRUE;
+        sta_ds->qosMode = eANI_BOOLEAN_TRUE;
+        limGetWsmMode(session_entry, &wsm_mode);
+        /* WMM_APSD - WMM_SA related processing should be
+         * separate; WMM_SA and WMM_APSD can coexist
+         */
+        if (assoc_req->WMMInfoStation.present)
+        {
+            /* check whether AP supports or not */
+            if ((session_entry->limSystemRole == eLIM_AP_ROLE)
+                    && (session_entry->apUapsdEnable == 0) &&
+                    (assoc_req->WMMInfoStation.acbe_uapsd
+                     || assoc_req->WMMInfoStation.acbk_uapsd
+                     || assoc_req->WMMInfoStation.acvo_uapsd
+                     || assoc_req->WMMInfoStation.acvi_uapsd))
+            {
+                /*
+                 * Received Re/Association Request from
+                 * STA when UPASD is not supported
+                 */
+                limLog( pmac, LOGE, FL( "AP do not support UAPSD so reply "
+                            "to STA accordingly" ));
+                /* update UAPSD and send it to LIM to add STA */
+                sta_ds->qos.capability.qosInfo.acbe_uapsd = 0;
+                sta_ds->qos.capability.qosInfo.acbk_uapsd = 0;
+                sta_ds->qos.capability.qosInfo.acvo_uapsd = 0;
+                sta_ds->qos.capability.qosInfo.acvi_uapsd = 0;
+                sta_ds->qos.capability.qosInfo.maxSpLen =   0;
+            }
+            else
+            {
+                /* update UAPSD and send it to LIM to add STA */
+                sta_ds->qos.capability.qosInfo.acbe_uapsd =
+                    assoc_req->WMMInfoStation.acbe_uapsd;
+                sta_ds->qos.capability.qosInfo.acbk_uapsd =
+                    assoc_req->WMMInfoStation.acbk_uapsd;
+                sta_ds->qos.capability.qosInfo.acvo_uapsd =
+                    assoc_req->WMMInfoStation.acvo_uapsd;
+                sta_ds->qos.capability.qosInfo.acvi_uapsd =
+                    assoc_req->WMMInfoStation.acvi_uapsd;
+                sta_ds->qos.capability.qosInfo.maxSpLen =
+                    assoc_req->WMMInfoStation.max_sp_length;
+            }
+        }
+        if (assoc_req->wsmCapablePresent && (wsm_mode == eHAL_SET))
+            sta_ds->wsmEnabled = eANI_BOOLEAN_TRUE;
+    }
+}
+
+/**
+ * lim_sap_offload_add_sta - Parse Add sta request from firmware
+ *
+ * @pmac: mac context
+ * @lim_msgq: Add Sta indication buffer
+ *
+ * This function will recieve buffer from firmware. This buffer will store
+ * information about connected client. driver will process this buffer and
+ * will register this client with driver. Driver will call limAddSta
+ *
+ * Return: none
+ */
+void lim_sap_offload_add_sta(tpAniSirGlobal pmac,
+        tSapOfldAddStaIndMsg *lim_msgq)
+{
+    tpSirAssocReq assoc_req = NULL;
+    tpDphHashNode sta_ds = NULL;
+
+    tSapOfldAddStaIndMsg  *add_sta_req = NULL;
+    tpPESession session_entry = limIsApSessionActive(pmac);
+
+    if (session_entry == NULL)
+    {
+        PELOGE(limLog(pmac, LOGE, FL(" Session not found"));)
+            return;
+    }
+    add_sta_req = lim_msgq;
+    assoc_req = vos_mem_malloc(sizeof(*assoc_req));
+    if (NULL == assoc_req) {
+        limLog(pmac, LOGP, FL("Allocate Memory failed in AssocReq"));
+        return;
+    }
+    vos_mem_set(assoc_req , sizeof(*assoc_req), 0);
+
+    /* parse Assoc req frame for station information */
+    sta_ds = _sap_offload_parse_assoc_req(pmac, assoc_req, add_sta_req);
+    if (sta_ds == NULL)
+    {
+        PELOGE(limLog(pmac, LOGE, FL("could not add hash entry for"));)
+            limPrintMacAddr(pmac, add_sta_req->peer_macaddr, LOGE);
+        vos_mem_free(assoc_req);
+        goto error;
+    }
+
+    /* Parse Station Capability */
+    _sap_offload_parse_sta_capability(sta_ds, assoc_req, add_sta_req);
+
+    /* Parse Station HT/VHT information */
+    if (_sap_offload_parse_sta_vht(pmac, sta_ds, assoc_req)
+            == eSIR_FAILURE)
+    {
+        PELOGE(limLog(pmac, LOGE, FL("mismatch ht/vht information for "));)
+            limPrintMacAddr(pmac, add_sta_req->peer_macaddr, LOGE);
+            vos_mem_free(assoc_req);
+        goto error;
+
+    }
+
+    /* Parse Station QOS information */
+    _sap_offload_parse_sta_qos(pmac, sta_ds, assoc_req);
+
+    session_entry->parsedAssocReq[sta_ds->assocId] = assoc_req;
+    sta_ds->staIndex = add_sta_req->staIdx;
+    sta_ds->dpuIndex = add_sta_req->dpuIndex;
+    sta_ds->bcastDpuIndex = add_sta_req->bcastDpuIndex;
+    sta_ds->bcastMgmtDpuIdx = add_sta_req->bcastMgmtDpuIdx;
+    sta_ds->ucUcastSig = add_sta_req->ucUcastSig;
+    sta_ds->ucBcastSig = add_sta_req->ucBcastSig;
+    sta_ds->ucMgmtSig = add_sta_req->ucMgmtSig;
+
+
+    if (limAddSta(pmac, sta_ds, false, session_entry) != eSIR_SUCCESS) {
+        limLog(pmac, LOGE, FL("could not Add STA with assocId=%d"),
+                sta_ds->assocId);
+    }
+
+error:
+    return;
+}
+
+/**
+ * lim_sap_offload_del_sta - Parse Del sta request from firmware
+ *
+ * @pmac: mac context
+ * @lim_msgq: Del Sta indication buffer
+ *
+ * This function will recieve buffer from firmware. This buffer will
+ * have information about clinet to remove with reason code.
+ * This function will call limSendSmeDisassocInd to do cleanup
+ * for station entry
+ *
+ * Return: none
+ */
+void
+lim_sap_offload_del_sta(tpAniSirGlobal pmac, tSapOfldDelStaIndMsg *lim_msgq)
+{
+    tSapOfldDelStaIndMsg *del_sta_req = NULL;
+    tpDphHashNode sta_ds = NULL;
+    tANI_U16 assoc_id = 0;
+    tpPESession psession_entry = limIsApSessionActive(pmac);
+
+    if (psession_entry == NULL)
+    {
+        PELOGE(limLog(pmac, LOGE, FL(" Session not found"));)
+            goto error;
+    }
+
+    del_sta_req = lim_msgq;
+    sta_ds = dphLookupHashEntry(pmac,
+            del_sta_req->peer_macaddr,
+            &assoc_id,
+            &psession_entry->dph.dphHashTable);
+    if (sta_ds == NULL)
+    {
+        /*
+         * Disassociating STA is not associated.
+         * Log error
+         */
+        PELOGE(limLog(pmac, LOGE,
+                    FL("received del sta event that sta not exist in table "
+                        "reasonCode=%d, addr "MAC_ADDRESS_STR),
+                    del_sta_req->reason,
+                    MAC_ADDR_ARRAY(del_sta_req->peer_macaddr));)
+            goto error;
+    }
+
+    if (assoc_id != (tANI_U16)del_sta_req->assoc_id)
+    {
+        /*
+         * Associate Id mismatch
+         * Log error
+         */
+        PELOGE(limLog(pmac, LOGE,
+                    FL("received del sta event that sta assoc Id mismatch"));)
+            goto error;
+    }
+
+    sta_ds->mlmStaContext.cleanupTrigger = eLIM_PEER_ENTITY_DISASSOC;
+    sta_ds->mlmStaContext.disassocReason =
+        (tSirMacReasonCodes) del_sta_req->reason;
+    sta_ds->mlmStaContext.updateContext = 1;
+
+    limSendSmeDisassocInd(pmac, sta_ds, psession_entry);
+
+error:
+    return;
+}
+#endif /* SAP_AUTH_OFFLOAD */