/*
 * Copyright (c) 2011-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.
 */

/*
 * This file lim_timer_utils.cc contains the utility functions
 * LIM uses for handling various timers.
 * Author:        Chandra Modumudi
 * Date:          02/13/02
 * History:-
 * Date           Modified by    Modification Information
 * --------------------------------------------------------------------
 */

#include "lim_types.h"
#include "lim_utils.h"
#include "lim_assoc_utils.h"
#include "lim_security_utils.h"
#include <lim_api.h>

/* channel Switch Timer in ticks */
#define LIM_CHANNEL_SWITCH_TIMER_TICKS           1
/* Lim Quite timer in ticks */
#define LIM_QUIET_TIMER_TICKS                    100
/* Lim Quite BSS timer interval in ticks */
#define LIM_QUIET_BSS_TIMER_TICK                 100
/* Lim KeepAlive timer default (3000)ms */
#define LIM_KEEPALIVE_TIMER_MS                   3000
/* Lim JoinProbeRequest Retry  timer default (200)ms */
#define LIM_JOIN_PROBE_REQ_TIMER_MS              200
/* Lim Periodic Auth Retry timer default 60 ms */
#define LIM_AUTH_RETRY_TIMER_MS   60


/* This timer is a periodic timer which expires at every 1 sec to
   convert  ACTIVE DFS channel to DFS channels */
#define ACTIVE_TO_PASSIVE_CONVERISON_TIMEOUT     1000

static bool lim_create_non_ap_timers(tpAniSirGlobal pMac)
{
	uint32_t cfgValue;
	/* Create Channel Switch Timer */
	if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimChannelSwitchTimer,
			    "CHANNEL SWITCH TIMER",
			    lim_channel_switch_timer_handler, 0,
			    LIM_CHANNEL_SWITCH_TIMER_TICKS,
			    0, TX_NO_ACTIVATE) != TX_SUCCESS) {
		pe_err("failed to create Ch Switch timer");
		return false;
	}
	/* Create Quiet Timer
	 * This is used on the STA to go and shut-off Tx/Rx "after" the
	 * specified quiteInterval
	 */
	if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimQuietTimer,
			    "QUIET TIMER", lim_quiet_timer_handler,
			    SIR_LIM_QUIET_TIMEOUT, LIM_QUIET_TIMER_TICKS,
			    0, TX_NO_ACTIVATE) != TX_SUCCESS) {
		pe_err("failed to create Quiet Begin Timer");
		return false;
	}
	/* Create Quiet BSS Timer
	 * After the specified quiteInterval, determined by gLimQuietTimer, this
	 * timer, gLimQuietBssTimer, trigger and put the STA to sleep for the
	 * specified gLimQuietDuration
	 */
	if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimQuietBssTimer,
			    "QUIET BSS TIMER", lim_quiet_bss_timer_handler,
			    SIR_LIM_QUIET_BSS_TIMEOUT, LIM_QUIET_BSS_TIMER_TICK,
			    0, TX_NO_ACTIVATE) != TX_SUCCESS) {
		pe_err("failed to create Quiet Bss Timer");
		return false;
	}

	if (wlan_cfg_get_int(pMac, WNI_CFG_JOIN_FAILURE_TIMEOUT,
			     &cfgValue) != eSIR_SUCCESS)
		pe_err("could not retrieve JoinFailureTimeout value");
	cfgValue = SYS_MS_TO_TICKS(cfgValue);
	/* Create Join failure timer and activate it later */
	if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimJoinFailureTimer,
			    "JOIN FAILURE TIMEOUT",
			    lim_timer_handler, SIR_LIM_JOIN_FAIL_TIMEOUT,
			    cfgValue, 0,
			    TX_NO_ACTIVATE) != TX_SUCCESS) {
		/* / Could not create Join failure timer. */
		/* Log error */
		pe_err("could not create Join failure timer");
		return false;
	}
	/* Send unicast probe req frame every 200 ms */
	if (tx_timer_create(pMac,
			    &pMac->lim.limTimers.gLimPeriodicJoinProbeReqTimer,
			    "Periodic Join Probe Request Timer",
			    lim_timer_handler,
			    SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT,
			    SYS_MS_TO_TICKS(LIM_JOIN_PROBE_REQ_TIMER_MS), 0,
			    TX_NO_ACTIVATE) != TX_SUCCESS) {
		pe_err("could not create Periodic Join Probe Request tmr");
		return false;
	}

	/* Send Auth frame every 60 ms */
	if ((tx_timer_create(pMac,
		&pMac->lim.limTimers.g_lim_periodic_auth_retry_timer,
		"Periodic AUTH Timer",
		lim_timer_handler, SIR_LIM_AUTH_RETRY_TIMEOUT,
		SYS_MS_TO_TICKS(LIM_AUTH_RETRY_TIMER_MS), 0,
		TX_NO_ACTIVATE)) != TX_SUCCESS) {
		pe_err("could not create Periodic AUTH Timer");
		return false;
	}

	if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT,
			     &cfgValue) != eSIR_SUCCESS)
		pe_err("could not retrieve AssocFailureTimeout value");

	cfgValue = SYS_MS_TO_TICKS(cfgValue);
	/* Create Association failure timer and activate it later */
	if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimAssocFailureTimer,
			    "ASSOC FAILURE TIMEOUT",
			    lim_assoc_failure_timer_handler, LIM_ASSOC,
			    cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) {
		pe_err("could not create Association failure timer");
		return false;
	}

	if (wlan_cfg_get_int(pMac, WNI_CFG_ADDTS_RSP_TIMEOUT, &cfgValue)
			     != eSIR_SUCCESS)
		pe_err("Fail to get WNI_CFG_ADDTS_RSP_TIMEOUT");

	cfgValue = SYS_MS_TO_TICKS(cfgValue);

	/* Create Addts response timer and activate it later */
	if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimAddtsRspTimer,
			    "ADDTS RSP TIMEOUT",
			    lim_addts_response_timer_handler,
			    SIR_LIM_ADDTS_RSP_TIMEOUT,
			    cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) {
		pe_err("could not create Addts response timer");
		return false;
	}

	if (wlan_cfg_get_int(pMac, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT,
			     &cfgValue) != eSIR_SUCCESS)
		pe_err("could not retrieve AuthFailureTimeout value");

	cfgValue = SYS_MS_TO_TICKS(cfgValue);
	/* Create Auth failure timer and activate it later */
	if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimAuthFailureTimer,
			    "AUTH FAILURE TIMEOUT",
			    lim_timer_handler,
			    SIR_LIM_AUTH_FAIL_TIMEOUT,
			    cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) {
		pe_err("could not create Auth failure timer");
		return false;
	}

	if (wlan_cfg_get_int(pMac, WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT,
			     &cfgValue) != eSIR_SUCCESS)
		pe_err("could not retrieve PROBE_AFTER_HB_FAIL_TIMEOUT value");

	/* Change timer to reactivate it in future */
	cfgValue = SYS_MS_TO_TICKS(cfgValue);
	if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimProbeAfterHBTimer,
			    "Probe after Heartbeat TIMEOUT",
			    lim_timer_handler,
			    SIR_LIM_PROBE_HB_FAILURE_TIMEOUT,
			    cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) {
		pe_err("unable to create ProbeAfterHBTimer");
		return false;
	}

	return true;
}
/**
 * lim_create_timers()
 *
 * @pMac : Pointer to Global MAC structure
 *
 * This function is called upon receiving
 * 1. SME_START_REQ for STA in ESS role
 * 2. SME_START_BSS_REQ for AP role & STA in IBSS role
 *
 * @return : status of operation
 */

uint32_t lim_create_timers(tpAniSirGlobal pMac)
{
	uint32_t cfgValue, i = 0;
	uint32_t cfgValue1;

	pe_debug("Creating Timers used by LIM module in Role: %d",
	       pMac->lim.gLimSystemRole);
	/* Create timers required for host roaming feature */
	if (TX_SUCCESS != lim_create_timers_host_roam(pMac))
		return TX_TIMER_ERROR;

	if (wlan_cfg_get_int(pMac, WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME,
			     &cfgValue) != eSIR_SUCCESS) {
		pe_err("could not retrieve MinChannelTimeout value");
	}
	cfgValue = SYS_MS_TO_TICKS(cfgValue);
	/* Periodic probe request timer value is half of the Min channel
	 * timer. Probe request sends periodically till min/max channel
	 * timer expires
	 */
	cfgValue1 = cfgValue / 2;
	/* Create periodic probe request timer and activate them later */
	if (cfgValue1 >= 1
	    && (tx_timer_create(pMac,
			&pMac->lim.limTimers.gLimPeriodicProbeReqTimer,
			"Periodic Probe Request Timer", lim_timer_handler,
			SIR_LIM_PERIODIC_PROBE_REQ_TIMEOUT, cfgValue1, 0,
			TX_NO_ACTIVATE) != TX_SUCCESS)) {
		pe_err("could not create periodic probe timer");
		goto err_timer;
	}

	if (wlan_cfg_get_int(pMac, WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME,
			     &cfgValue) != eSIR_SUCCESS)
		pe_err("could not retrieve MAXChannelTimeout value");

	cfgValue = SYS_MS_TO_TICKS(cfgValue);
	/* Limiting max numm of probe req for each channel scan */
	pMac->lim.maxProbe = (cfgValue / cfgValue1);

	if (pMac->lim.gLimSystemRole != eLIM_AP_ROLE)
		if (false == lim_create_non_ap_timers(pMac))
			goto err_timer;

	/* Create all CNF_WAIT Timers upfront */
	if (wlan_cfg_get_int(pMac, WNI_CFG_WT_CNF_TIMEOUT, &cfgValue)
		!= eSIR_SUCCESS) {
		pe_err("could not retrieve CNF timeout value");
	}

	cfgValue = SYS_MS_TO_TICKS(cfgValue);
	for (i = 0; i < (pMac->lim.maxStation + 1); i++) {
		if (tx_timer_create(pMac,
				    &pMac->lim.limTimers.gpLimCnfWaitTimer[i],
				    "CNF_MISS_TIMEOUT",
				    lim_cnf_wait_tmer_handler,
				    (uint32_t) i, cfgValue,
				    0, TX_NO_ACTIVATE) != TX_SUCCESS) {
			pe_err("Cannot create CNF wait timer");
			goto err_timer;
		}
	}

	/* Alloc and init table for the preAuth timer list */
	if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_NUM_PRE_AUTH,
			     &cfgValue) != eSIR_SUCCESS)
		pe_err("could not retrieve mac preauth value");
	pMac->lim.gLimPreAuthTimerTable.numEntry = cfgValue;
	pMac->lim.gLimPreAuthTimerTable.pTable =
		qdf_mem_malloc(cfgValue * sizeof(tLimPreAuthNode *));

	if (pMac->lim.gLimPreAuthTimerTable.pTable == NULL) {
		pe_err("AllocateMemory failed!");
		goto err_timer;
	}

	for (i = 0; i < cfgValue; i++) {
		pMac->lim.gLimPreAuthTimerTable.pTable[i] =
					qdf_mem_malloc(sizeof(tLimPreAuthNode));
		if (pMac->lim.gLimPreAuthTimerTable.pTable[i] == NULL) {
			pMac->lim.gLimPreAuthTimerTable.numEntry = 0;
			pe_err("AllocateMemory failed!");
			goto err_timer;
		}
	}

	lim_init_pre_auth_timer_table(pMac, &pMac->lim.gLimPreAuthTimerTable);
	pe_debug("alloc and init table for preAuth timers");

	if (wlan_cfg_get_int(pMac, WNI_CFG_OLBC_DETECT_TIMEOUT,
			     &cfgValue) != eSIR_SUCCESS)
		pe_err("could not retrieve OLBD detect timeout value");

	cfgValue = SYS_MS_TO_TICKS(cfgValue);
	if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimUpdateOlbcCacheTimer,
			    "OLBC UPDATE CACHE TIMEOUT",
			    lim_update_olbc_cache_timer_handler,
			    SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT, cfgValue,
			    cfgValue, TX_NO_ACTIVATE) != TX_SUCCESS) {
		pe_err("Cannot create update OLBC cache tmr");
		goto err_timer;
	}
	cfgValue = 1000;
	cfgValue = SYS_MS_TO_TICKS(cfgValue);
	if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimRemainOnChannelTimer,
			    "FT PREAUTH RSP TIMEOUT",
			    lim_timer_handler, SIR_LIM_REMAIN_CHN_TIMEOUT,
			    cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) {
		pe_err("could not create Join failure timer");
		goto err_timer;
	}

	cfgValue = 1000;
	cfgValue = SYS_MS_TO_TICKS(cfgValue);
	if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimDisassocAckTimer,
			    "DISASSOC ACK TIMEOUT",
			    lim_timer_handler, SIR_LIM_DISASSOC_ACK_TIMEOUT,
			    cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) {
		pe_err("could not DISASSOC ACK TIMEOUT timer");
		goto err_timer;
	}

	cfgValue = 1000;
	cfgValue = SYS_MS_TO_TICKS(cfgValue);
	if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimDeauthAckTimer,
			    "DISASSOC ACK TIMEOUT",
			    lim_timer_handler, SIR_LIM_DEAUTH_ACK_TIMEOUT,
			    cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) {
		pe_err("could not create DEAUTH ACK TIMEOUT timer");
		goto err_timer;
	}

	/* (> no of BI* no of TUs per BI * 1TU in msec +
	 * p2p start time offset*1 TU in msec = 2*100*1.024 + 5*1.024
	 * = 204.8 + 5.12 = 209.20)
	 */
	cfgValue = LIM_INSERT_SINGLESHOTNOA_TIMEOUT_VALUE;
	cfgValue = SYS_MS_TO_TICKS(cfgValue);
	if (tx_timer_create(pMac,
		&pMac->lim.limTimers.gLimP2pSingleShotNoaInsertTimer,
		"Single Shot NOA Insert timeout", lim_timer_handler,
		SIR_LIM_INSERT_SINGLESHOT_NOA_TIMEOUT, cfgValue, 0,
		TX_NO_ACTIVATE) != TX_SUCCESS) {
		pe_err("Can't create Single Shot NOA Insert Timeout tmr");
		goto err_timer;
	}

	cfgValue = ACTIVE_TO_PASSIVE_CONVERISON_TIMEOUT;
	cfgValue = SYS_MS_TO_TICKS(cfgValue);
	if (tx_timer_create(pMac,
		&pMac->lim.limTimers.gLimActiveToPassiveChannelTimer,
		"ACTIVE TO PASSIVE CHANNEL", lim_timer_handler,
		SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE, cfgValue, 0,
		TX_NO_ACTIVATE) != TX_SUCCESS) {
		pe_warn("could not create timer for passive channel to active channel");
		goto err_timer;
	}

	return TX_SUCCESS;

err_timer:
	tx_timer_delete(&pMac->lim.limTimers.gLimDeauthAckTimer);
	tx_timer_delete(&pMac->lim.limTimers.gLimDisassocAckTimer);
	tx_timer_delete(&pMac->lim.limTimers.gLimRemainOnChannelTimer);
	tx_timer_delete(&pMac->lim.limTimers.gLimFTPreAuthRspTimer);
	tx_timer_delete(&pMac->lim.limTimers.gLimUpdateOlbcCacheTimer);
	while (((int32_t)-- i) >= 0) {
		tx_timer_delete(&pMac->lim.limTimers.gpLimCnfWaitTimer[i]);
	}
	tx_timer_delete(&pMac->lim.limTimers.gLimProbeAfterHBTimer);
	tx_timer_delete(&pMac->lim.limTimers.gLimAuthFailureTimer);
	tx_timer_delete(&pMac->lim.limTimers.gLimAddtsRspTimer);
	tx_timer_delete(&pMac->lim.limTimers.gLimReassocFailureTimer);
	tx_timer_delete(&pMac->lim.limTimers.gLimAssocFailureTimer);
	tx_timer_delete(&pMac->lim.limTimers.gLimJoinFailureTimer);
	tx_timer_delete(&pMac->lim.limTimers.gLimPeriodicJoinProbeReqTimer);
	tx_timer_delete(&pMac->lim.limTimers.g_lim_periodic_auth_retry_timer);
	tx_timer_delete(&pMac->lim.limTimers.gLimQuietBssTimer);
	tx_timer_delete(&pMac->lim.limTimers.gLimQuietTimer);
	tx_timer_delete(&pMac->lim.limTimers.gLimChannelSwitchTimer);
	tx_timer_delete(&pMac->lim.limTimers.gLimPeriodicProbeReqTimer);
	tx_timer_delete(&pMac->lim.limTimers.gLimP2pSingleShotNoaInsertTimer);
	tx_timer_delete(&pMac->lim.limTimers.gLimActiveToPassiveChannelTimer);

	if (NULL != pMac->lim.gLimPreAuthTimerTable.pTable) {
		for (i = 0; i < pMac->lim.gLimPreAuthTimerTable.numEntry; i++)
			qdf_mem_free(pMac->lim.gLimPreAuthTimerTable.pTable[i]);
		qdf_mem_free(pMac->lim.gLimPreAuthTimerTable.pTable);
		pMac->lim.gLimPreAuthTimerTable.pTable = NULL;
	}
	return TX_TIMER_ERROR;
} /****** end lim_create_timers() ******/

/**
 * lim_timer_handler()
 *
 ***FUNCTION:
 * This function is called upon
 * 1. MIN_CHANNEL, MAX_CHANNEL timer expiration during scanning
 * 2. JOIN_FAILURE timer expiration while joining a BSS
 * 3. AUTH_FAILURE timer expiration while authenticating with a peer
 * 4. Heartbeat timer expiration on STA
 * 5. Background scan timer expiration on STA
 * 6. AID release, Pre-auth cleanup and Link monitoring timer
 *    expiration on AP
 *
 ***LOGIC:
 *
 ***ASSUMPTIONS:
 * NA
 *
 ***NOTE:
 * NA
 *
 * @param  param - Message corresponding to the timer that expired
 *
 * @return None
 */

void lim_timer_handler(void *pMacGlobal, uint32_t param)
{
	uint32_t statusCode;
	struct scheduler_msg msg = {0};
	tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal;

	/* Prepare and post message to LIM Message Queue */

	msg.type = (uint16_t) param;
	msg.bodyptr = NULL;
	msg.bodyval = 0;

	statusCode = lim_post_msg_high_priority(pMac, &msg);
	if (statusCode != eSIR_SUCCESS)
		pe_err("posting message: %X to LIM failed, reason: %d",
			msg.type, statusCode);
} /****** end lim_timer_handler() ******/

/**
 * lim_addts_response_timer_handler()
 *
 ***FUNCTION:
 * This function is called upon Addts response timer expiration on sta
 *
 ***LOGIC:
 * Message SIR_LIM_ADDTS_RSP_TIMEOUT is posted to gSirLimMsgQ
 * when this function is executed.
 *
 ***ASSUMPTIONS:
 * NA
 *
 ***NOTE:
 * NA
 *
 * @param  param - pointer to pre-auth node
 *
 * @return None
 */

void lim_addts_response_timer_handler(void *pMacGlobal, uint32_t param)
{
	struct scheduler_msg msg = {0};
	tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal;

	/* Prepare and post message to LIM Message Queue */

	msg.type = SIR_LIM_ADDTS_RSP_TIMEOUT;
	msg.bodyval = param;
	msg.bodyptr = NULL;

	lim_post_msg_api(pMac, &msg);
} /****** end lim_auth_response_timer_handler() ******/

/**
 * lim_auth_response_timer_handler()
 *
 ***FUNCTION:
 * This function is called upon Auth response timer expiration on AP
 *
 ***LOGIC:
 * Message SIR_LIM_AUTH_RSP_TIMEOUT is posted to gSirLimMsgQ
 * when this function is executed.
 *
 ***ASSUMPTIONS:
 * NA
 *
 ***NOTE:
 * NA
 *
 * @param  param - pointer to pre-auth node
 *
 * @return None
 */

void lim_auth_response_timer_handler(void *pMacGlobal, uint32_t param)
{
	struct scheduler_msg msg = {0};
	tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal;

	/* Prepare and post message to LIM Message Queue */

	msg.type = SIR_LIM_AUTH_RSP_TIMEOUT;
	msg.bodyptr = NULL;
	msg.bodyval = (uint32_t) param;

	lim_post_msg_api(pMac, &msg);
} /****** end lim_auth_response_timer_handler() ******/

/**
 * lim_assoc_failure_timer_handler()
 *
 * @mac_global  : Pointer to Global MAC structure
 * @param       : Indicates whether this is assoc or reassoc failure timeout
 *
 * This function is called upon Re/Assoc failure timer expiration on STA.
 * Message SIR_LIM_ASSOC_FAIL_TIMEOUT is posted to gSirLimMsgQ when this
 * function is executed.
 *
 * Return void
 */
void lim_assoc_failure_timer_handler(void *mac_global, uint32_t param)
{
	struct scheduler_msg msg = {0};
	tpAniSirGlobal mac_ctx = (tpAniSirGlobal) mac_global;
	tpPESession session = NULL;

	session = mac_ctx->lim.pSessionEntry;
	if (LIM_REASSOC == param && NULL != session
	    && session->limMlmState == eLIM_MLM_WT_FT_REASSOC_RSP_STATE) {
		pe_err("Reassoc timeout happened");
		if (mac_ctx->lim.reAssocRetryAttempt <
		    LIM_MAX_REASSOC_RETRY_LIMIT) {
			lim_send_retry_reassoc_req_frame(mac_ctx,
			    session->pLimMlmReassocRetryReq, session);
			mac_ctx->lim.reAssocRetryAttempt++;
			pe_warn("Reassoc request retry is sent %d times",
				mac_ctx->lim.reAssocRetryAttempt);
			return;
		} else {
			pe_warn("Reassoc request retry MAX: %d reached",
				LIM_MAX_REASSOC_RETRY_LIMIT);
			if (NULL != session->pLimMlmReassocRetryReq) {
				qdf_mem_free(session->pLimMlmReassocRetryReq);
				session->pLimMlmReassocRetryReq = NULL;
			}
		}
	}
	/* Prepare and post message to LIM Message Queue */
	msg.type = SIR_LIM_ASSOC_FAIL_TIMEOUT;
	msg.bodyval = (uint32_t) param;
	msg.bodyptr = NULL;
	lim_post_msg_api(mac_ctx, &msg);
} /****** end lim_assoc_failure_timer_handler() ******/

/**
 * lim_update_olbc_cache_timer_handler()
 *
 ***FUNCTION:
 * This function is called upon update olbc cache timer expiration
 * on STA
 *
 ***LOGIC:
 * Message SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT is posted to gSirLimMsgQ
 * when this function is executed.
 *
 ***ASSUMPTIONS:
 * NA
 *
 ***NOTE:
 * NA
 *
 * @param
 *
 * @return None
 */
void lim_update_olbc_cache_timer_handler(void *pMacGlobal, uint32_t param)
{
	struct scheduler_msg msg = {0};
	tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal;

	/* Prepare and post message to LIM Message Queue */

	msg.type = SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT;
	msg.bodyval = 0;
	msg.bodyptr = NULL;

	lim_post_msg_api(pMac, &msg);
} /****** end lim_update_olbc_cache_timer_handler() ******/

/**
 * lim_deactivate_and_change_timer()
 *
 ***FUNCTION:
 * This function is called to deactivate and change a timer
 * for future re-activation
 *
 ***LOGIC:
 *
 ***ASSUMPTIONS:
 * NA
 *
 ***NOTE:
 * NA
 *
 * @param  pMac    - Pointer to Global MAC structure
 * @param  timerId - enum of timer to be deactivated and changed
 *                   This enum is defined in lim_utils.h file
 *
 * @return None
 */

void lim_deactivate_and_change_timer(tpAniSirGlobal pMac, uint32_t timerId)
{
	uint32_t val = 0;
	tpPESession  session_entry;

	switch (timerId) {
	case eLIM_REASSOC_FAIL_TIMER:
	case eLIM_FT_PREAUTH_RSP_TIMER:
		lim_deactivate_and_change_timer_host_roam(pMac, timerId);
		break;

	case eLIM_ADDTS_RSP_TIMER:
		pMac->lim.gLimAddtsRspTimerCount++;
		if (tx_timer_deactivate(&pMac->lim.limTimers.gLimAddtsRspTimer)
		    != TX_SUCCESS) {
			/* Could not deactivate AddtsRsp Timer */
			/* Log error */
			pe_err("Unable to deactivate AddtsRsp timer");
		}
		break;

	case eLIM_PERIODIC_PROBE_REQ_TIMER:
		if (tx_timer_deactivate
			    (&pMac->lim.limTimers.gLimPeriodicProbeReqTimer)
		    != TX_SUCCESS) {
			/* Could not deactivate min channel timer. */
			/* Log error */
			pe_err("Unable to deactivate periodic timer");
		}

		val =
			SYS_MS_TO_TICKS(pMac->lim.gpLimMlmScanReq->minChannelTime) /
			2;
		if (val) {
			if (tx_timer_change(
			    &pMac->lim.limTimers.gLimPeriodicProbeReqTimer,
			    val, 0) != TX_SUCCESS) {
				/* Could not change min channel timer. */
				/* Log error */
				pe_err("Unable to change periodic timer");
			}
		} else
			pe_err("Do not change gLimPeriodicProbeReqTimer values,"
			       "value: %d minchannel time: %d"
			       "maxchannel time: %d", val,
			       pMac->lim.gpLimMlmScanReq->minChannelTime,
			       pMac->lim.gpLimMlmScanReq->maxChannelTime);

		break;

	case eLIM_JOIN_FAIL_TIMER:
		if (tx_timer_deactivate
			    (&pMac->lim.limTimers.gLimJoinFailureTimer)
		    != TX_SUCCESS) {
			/**
			 * Could not deactivate Join Failure
			 * timer. Log error.
			 */
			pe_err("Unable to deactivate Join Failure timer");
		}

		if (wlan_cfg_get_int(pMac, WNI_CFG_JOIN_FAILURE_TIMEOUT,
				     &val) != eSIR_SUCCESS) {
			/**
			 * Could not get JoinFailureTimeout value
			 * from CFG. Log error.
			 */
			pe_err("could not retrieve JoinFailureTimeout value");
		}
		val = SYS_MS_TO_TICKS(val);

		if (tx_timer_change(&pMac->lim.limTimers.gLimJoinFailureTimer,
				    val, 0) != TX_SUCCESS) {
			/**
			 * Could not change Join Failure
			 * timer. Log error.
			 */
			pe_err("Unable to change Join Failure timer");
		}

		break;

	case eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER:
		if (tx_timer_deactivate
			    (&pMac->lim.limTimers.gLimPeriodicJoinProbeReqTimer)
		    != TX_SUCCESS) {
			/* Could not deactivate periodic join req Times. */
			pe_err("Unable to deactivate periodic join request timer");
		}

		val = SYS_MS_TO_TICKS(LIM_JOIN_PROBE_REQ_TIMER_MS);
		if (tx_timer_change
			    (&pMac->lim.limTimers.gLimPeriodicJoinProbeReqTimer, val,
			    0) != TX_SUCCESS) {
			/* Could not change periodic join req times. */
			/* Log error */
			pe_err("Unable to change periodic join request timer");
		}

		break;

	case eLIM_AUTH_FAIL_TIMER:
		if (tx_timer_deactivate
			    (&pMac->lim.limTimers.gLimAuthFailureTimer)
		    != TX_SUCCESS) {
			/* Could not deactivate Auth failure timer. */
			/* Log error */
			pe_err("Unable to deactivate auth failure timer");
		}
		/* Change timer to reactivate it in future */
		if (wlan_cfg_get_int(pMac, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT,
				     &val) != eSIR_SUCCESS) {
			/**
			 * Could not get AuthFailureTimeout value
			 * from CFG. Log error.
			 */
			pe_err("could not retrieve AuthFailureTimeout value");
		}
		val = SYS_MS_TO_TICKS(val);

		if (tx_timer_change(&pMac->lim.limTimers.gLimAuthFailureTimer,
				    val, 0) != TX_SUCCESS) {
			/* Could not change Authentication failure timer. */
			/* Log error */
			pe_err("unable to change Auth failure timer");
		}

		break;

	case eLIM_AUTH_RETRY_TIMER:

		if (tx_timer_deactivate
			  (&pMac->lim.limTimers.g_lim_periodic_auth_retry_timer)
							 != TX_SUCCESS) {
			/* Could not deactivate Auth Retry Timer. */
			pe_err("Unable to deactivate Auth Retry timer");
		}
		session_entry = pe_find_session_by_session_id(pMac,
			pMac->lim.limTimers.
				g_lim_periodic_auth_retry_timer.sessionId);
		if (NULL == session_entry) {
			pe_err("session does not exist for given SessionId : %d",
			pMac->lim.limTimers.
				g_lim_periodic_auth_retry_timer.sessionId);
			break;
		}
		/* 3/5 of the beacon interval */
		val = (session_entry->beaconParams.beaconInterval * 3) / 5;
		val = SYS_MS_TO_TICKS(val);
		if (tx_timer_change
			 (&pMac->lim.limTimers.g_lim_periodic_auth_retry_timer,
							val, 0) != TX_SUCCESS) {
			/* Could not change Auth Retry timer. */
			pe_err("Unable to change Auth Retry timer");
		}
		break;

	case eLIM_ASSOC_FAIL_TIMER:
		if (tx_timer_deactivate
			    (&pMac->lim.limTimers.gLimAssocFailureTimer) !=
		    TX_SUCCESS) {
			/* Could not deactivate Association failure timer. */
			/* Log error */
			pe_err("unable to deactivate Association failure timer");
		}
		/* Change timer to reactivate it in future */
		if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT,
				     &val) != eSIR_SUCCESS) {
			/**
			 * Could not get AssocFailureTimeout value
			 * from CFG. Log error.
			 */
			pe_err("could not retrieve AssocFailureTimeout value");
		}
		val = SYS_MS_TO_TICKS(val);

		if (tx_timer_change(&pMac->lim.limTimers.gLimAssocFailureTimer,
				    val, 0) != TX_SUCCESS) {
			/* Could not change Association failure timer. */
			/* Log error */
			pe_err("unable to change Assoc failure timer");
		}

		break;

	case eLIM_PROBE_AFTER_HB_TIMER:
		if (tx_timer_deactivate
			    (&pMac->lim.limTimers.gLimProbeAfterHBTimer) !=
		    TX_SUCCESS) {
			/* Could not deactivate Heartbeat timer. */
			/* Log error */
			pe_err("unable to deactivate probeAfterHBTimer");
		} else {
			pe_debug("Deactivated probe after hb timer");
		}

		if (wlan_cfg_get_int(pMac, WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT,
				     &val) != eSIR_SUCCESS) {
			/**
			 * Could not get PROBE_AFTER_HB_FAILURE
			 * value from CFG. Log error.
			 */
			pe_err("could not retrieve PROBE_AFTER_HB_FAIL_TIMEOUT value");
		}
		/* Change timer to reactivate it in future */
		val = SYS_MS_TO_TICKS(val);

		if (tx_timer_change(&pMac->lim.limTimers.gLimProbeAfterHBTimer,
				    val, 0) != TX_SUCCESS) {
			/* Could not change HeartBeat timer. */
			/* Log error */
			pe_err("unable to change ProbeAfterHBTimer");
		} else {
			pe_debug("Probe after HB timer value is changed: %u",
				val);
		}

		break;

	case eLIM_LEARN_DURATION_TIMER:
		break;

	case eLIM_REMAIN_CHN_TIMER:
		if (tx_timer_deactivate
			    (&pMac->lim.limTimers.gLimRemainOnChannelTimer) !=
		    TX_SUCCESS) {
			/**
			** Could not deactivate Join Failure
			** timer. Log error.
			**/
			pe_err("Unable to deactivate Remain on Chn timer");
			return;
		}
		val = 1000;
		val = SYS_MS_TO_TICKS(val);
		if (tx_timer_change
			    (&pMac->lim.limTimers.gLimRemainOnChannelTimer, val,
			    0) != TX_SUCCESS) {
			/**
			 * Could not change Join Failure
			 * timer. Log error.
			 */
			pe_err("Unable to change timer");
			return;
		}
		break;

	case eLIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE:
		if (tx_timer_deactivate
			    (&pMac->lim.limTimers.gLimActiveToPassiveChannelTimer) !=
		    TX_SUCCESS) {
			/**
			** Could not deactivate Active to passive channel timer.
			** Log error.
			**/
			pe_err("Unable to Deactivate Active to passive channel timer");
			return;
		}
		val = ACTIVE_TO_PASSIVE_CONVERISON_TIMEOUT;
		val = SYS_MS_TO_TICKS(val);
		if (tx_timer_change
			    (&pMac->lim.limTimers.gLimActiveToPassiveChannelTimer, val,
			    0) != TX_SUCCESS) {
			/**
			 * Could not change timer to check scan type for passive channel.
			 * timer. Log error.
			 */
			pe_err("Unable to change timer");
			return;
		}
		break;

	case eLIM_DISASSOC_ACK_TIMER:
		if (tx_timer_deactivate
			    (&pMac->lim.limTimers.gLimDisassocAckTimer) != TX_SUCCESS) {
			/**
			** Could not deactivate Join Failure
			** timer. Log error.
			**/
			pe_err("Unable to deactivate Disassoc ack timer");
			return;
		}
		val = 1000;
		val = SYS_MS_TO_TICKS(val);
		if (tx_timer_change(&pMac->lim.limTimers.gLimDisassocAckTimer,
				    val, 0) != TX_SUCCESS) {
			/**
			 * Could not change Join Failure
			 * timer. Log error.
			 */
			pe_err("Unable to change timer");
			return;
		}
		break;

	case eLIM_DEAUTH_ACK_TIMER:
		if (tx_timer_deactivate(&pMac->lim.limTimers.gLimDeauthAckTimer)
		    != TX_SUCCESS) {
			/**
			** Could not deactivate Join Failure
			** timer. Log error.
			**/
			pe_err("Unable to deactivate Deauth ack timer");
			return;
		}
		val = 1000;
		val = SYS_MS_TO_TICKS(val);
		if (tx_timer_change(&pMac->lim.limTimers.gLimDeauthAckTimer,
				    val, 0) != TX_SUCCESS) {
			/**
			 * Could not change Join Failure
			 * timer. Log error.
			 */
			pe_err("Unable to change timer");
			return;
		}
		break;

	case eLIM_INSERT_SINGLESHOT_NOA_TIMER:
		if (tx_timer_deactivate
			    (&pMac->lim.limTimers.gLimP2pSingleShotNoaInsertTimer) !=
		    TX_SUCCESS) {
			/**
			** Could not deactivate SingleShot NOA Insert
			** timer. Log error.
			**/
			pe_err("Unable to deactivate SingleShot NOA Insert timer");
			return;
		}
		val = LIM_INSERT_SINGLESHOTNOA_TIMEOUT_VALUE;
		val = SYS_MS_TO_TICKS(val);
		if (tx_timer_change
			    (&pMac->lim.limTimers.gLimP2pSingleShotNoaInsertTimer, val,
			    0) != TX_SUCCESS) {
			/**
			 * Could not change Single Shot NOA Insert
			 * timer. Log error.
			 */
			pe_err("Unable to change timer");
			return;
		}
		break;

	default:
		/* Invalid timerId. Log error */
		break;
	}
} /****** end lim_deactivate_and_change_timer() ******/

/**
 * lim_deactivate_and_change_per_sta_id_timer()
 *
 *
 * @brief: This function is called to deactivate and change a per STA timer
 * for future re-activation
 *
 ***LOGIC:
 *
 ***ASSUMPTIONS:
 * NA
 *
 * @note   staId for eLIM_AUTH_RSP_TIMER is auth Node Index.
 *
 * @param  pMac    - Pointer to Global MAC structure
 * @param  timerId - enum of timer to be deactivated and changed
 *                   This enum is defined in lim_utils.h file
 * @param  staId   - staId
 *
 * @return None
 */

void
lim_deactivate_and_change_per_sta_id_timer(tpAniSirGlobal pMac, uint32_t timerId,
					   uint16_t staId)
{
	uint32_t val;

	switch (timerId) {
	case eLIM_CNF_WAIT_TIMER:

		if (tx_timer_deactivate
			    (&pMac->lim.limTimers.gpLimCnfWaitTimer[staId])
		    != TX_SUCCESS) {
			pe_err("unable to deactivate CNF wait timer");
		}
		/* Change timer to reactivate it in future */

		if (wlan_cfg_get_int(pMac, WNI_CFG_WT_CNF_TIMEOUT,
				     &val) != eSIR_SUCCESS) {
			/**
			 * Could not get cnf timeout value
			 * from CFG. Log error.
			 */
			pe_err("could not retrieve cnf timeout value");
		}
		val = SYS_MS_TO_TICKS(val);

		if (tx_timer_change
			    (&pMac->lim.limTimers.gpLimCnfWaitTimer[staId], val,
			    val) != TX_SUCCESS) {
			/* Could not change cnf timer. */
			/* Log error */
			pe_err("unable to change cnf wait timer");
		}

		break;

	case eLIM_AUTH_RSP_TIMER:
	{
		tLimPreAuthNode *pAuthNode;

		pAuthNode =
			lim_get_pre_auth_node_from_index(pMac,
							 &pMac->lim.
							 gLimPreAuthTimerTable,
							 staId);

		if (pAuthNode == NULL) {
			pe_err("Invalid Pre Auth Index passed :%d",
				staId);
			break;
		}

		if (tx_timer_deactivate(&pAuthNode->timer) !=
		    TX_SUCCESS) {
			/* Could not deactivate auth response timer. */
			/* Log error */
			pe_err("unable to deactivate auth response timer");
		}
		/* Change timer to reactivate it in future */

		if (wlan_cfg_get_int
			    (pMac, WNI_CFG_AUTHENTICATE_RSP_TIMEOUT,
			    &val) != eSIR_SUCCESS) {
			/**
			 * Could not get auth rsp timeout value
			 * from CFG. Log error.
			 */
			pe_err("could not retrieve auth response timeout value");
		}

		val = SYS_MS_TO_TICKS(val);

		if (tx_timer_change(&pAuthNode->timer, val, 0) !=
		    TX_SUCCESS) {
			/* Could not change auth rsp timer. */
			/* Log error */
			pe_err("unable to change auth rsp timer");
		}
	}
	break;

	default:
		/* Invalid timerId. Log error */
		break;

	}
}

/**
 * lim_activate_cnf_timer()
 *
 ***FUNCTION:
 * This function is called to activate a per STA timer
 *
 ***LOGIC:
 *
 ***ASSUMPTIONS:
 * NA
 *
 ***NOTE:
 * NA
 *
 * @param  pMac    - Pointer to Global MAC structure
 * @param  StaId   - staId
 *
 * @return None
 */

void lim_activate_cnf_timer(tpAniSirGlobal pMac, uint16_t staId,
			    tpPESession psessionEntry)
{
	pMac->lim.limTimers.gpLimCnfWaitTimer[staId].sessionId =
		psessionEntry->peSessionId;
	if (tx_timer_activate(&pMac->lim.limTimers.gpLimCnfWaitTimer[staId])
	    != TX_SUCCESS) {
		pe_err("could not activate cnf wait timer");
	}
}

/**
 * lim_activate_auth_rsp_timer()
 *
 ***FUNCTION:
 * This function is called to activate a per STA timer
 *
 ***LOGIC:
 *
 ***ASSUMPTIONS:
 * NA
 *
 ***NOTE:
 * NA
 *
 * @param  pMac    - Pointer to Global MAC structure
 * @param  id      - id
 *
 * @return None
 */

void lim_activate_auth_rsp_timer(tpAniSirGlobal pMac, tLimPreAuthNode *pAuthNode)
{
	if (tx_timer_activate(&pAuthNode->timer) != TX_SUCCESS) {
		/* / Could not activate auth rsp timer. */
		/* Log error */
		pe_err("could not activate auth rsp timer");
	}
}

/**
 * limAssocCnfWaitTmerHandler()
 *
 ***FUNCTION:
 *        This function post a message to send a disassociate frame out.
 *
 ***LOGIC:
 *
 ***ASSUMPTIONS:
 *
 ***NOTE:
 * NA
 *
 * @param
 *
 * @return None
 */

void lim_cnf_wait_tmer_handler(void *pMacGlobal, uint32_t param)
{
	struct scheduler_msg msg = {0};
	uint32_t statusCode;
	tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal;

	msg.type = SIR_LIM_CNF_WAIT_TIMEOUT;
	msg.bodyval = (uint32_t) param;
	msg.bodyptr = NULL;

	statusCode = lim_post_msg_api(pMac, &msg);
	if (statusCode != eSIR_SUCCESS)
		pe_err("posting to LIM failed, reason: %d", statusCode);

}

void lim_channel_switch_timer_handler(void *pMacGlobal, uint32_t param)
{
	struct scheduler_msg msg = {0};
	tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal;

	pe_debug("ChannelSwitch Timer expired.  Posting msg to LIM");

	msg.type = SIR_LIM_CHANNEL_SWITCH_TIMEOUT;
	msg.bodyval = (uint32_t) param;
	msg.bodyptr = NULL;

	lim_post_msg_api(pMac, &msg);
}

void lim_quiet_timer_handler(void *pMacGlobal, uint32_t param)
{
	struct scheduler_msg msg = {0};
	tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal;

	msg.type = SIR_LIM_QUIET_TIMEOUT;
	msg.bodyval = (uint32_t) param;
	msg.bodyptr = NULL;

	pe_debug("Post SIR_LIM_QUIET_TIMEOUT msg");
	lim_post_msg_api(pMac, &msg);
}

void lim_quiet_bss_timer_handler(void *pMacGlobal, uint32_t param)
{
	struct scheduler_msg msg = {0};
	tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal;

	msg.type = SIR_LIM_QUIET_BSS_TIMEOUT;
	msg.bodyval = (uint32_t) param;
	msg.bodyptr = NULL;
	pe_debug("Post SIR_LIM_QUIET_BSS_TIMEOUT msg");
	lim_post_msg_api(pMac, &msg);
}

