/****************************************************************************
 * Ralink Tech Inc.
 * Taiwan, R.O.C.
 *
 * (c) Copyright 2002, Ralink Technology, Inc.
 *
 * All rights reserved. Ralink's source code is an unpublished work and the
 * use of a copyright notice does not imply otherwise. This source code
 * contains confidential trade secret material of Ralink Tech. Any attemp
 * or participation in deciphering, decoding, reverse engineering or in any
 * way altering the source code is stricitly prohibited, unless the prior
 * written consent of Ralink Technology, Inc. is obtained.
 ***************************************************************************/

/****************************************************************************

	Abstract:

	All related IEEE802.11r Resource Information Container body.

***************************************************************************/

#ifdef DOT11R_FT_SUPPORT


#include "rt_config.h"


#define TYPE_FUNC

#ifdef CONFIG_STA_SUPPORT
/* ----- RIC Linked List ----- */
/* insert a resource request of a AP */
#define FT_RIC_AP_LIST_INSERT_TAIL(__pAd, __pList, __pEntry)		\
	{																\
		RTMP_SEM_LOCK(&(__pAd)->FT_RicLock);						\
		insertTailList((__pList), (RT_LIST_ENTRY *)(__pEntry));		\
		RTMP_SEM_UNLOCK(&(__pAd)->FT_RicLock);						\
	}

/* get a resource request from the head of list */
#define FT_RIC_AP_LIST_REMOVE_HEAD(__pAd, __pList, __pEntry)		\
	{																\
		RTMP_SEM_LOCK(&(__pAd)->FT_RicLock);						\
		__pEntry = (FT_RIC_AP *)removeHeadList((__pList));			\
		RTMP_SEM_UNLOCK(&(__pAd)->FT_RicLock);						\
	}

/* get number of resource request */
#define FT_RIC_AP_LIST_SIZE_GET(__pAd, __pList, __Size)				\
	{																\
		RTMP_SEM_LOCK(&(__pAd)->FT_RicLock);						\
		__Size = getListSize((__pList));							\
		RTMP_SEM_UNLOCK(&(__pAd)->FT_RicLock);						\
	}

/* get a resource request by AP MAC */
#define FT_RIC_AP_LIST_ENTRY_GET(__pAd, __pList, __pApMac, __FlgIsFound, __pEntry)\
	{																\
		UINT32 __Size, __IdEntry;									\
		FT_RIC_AP *__pRscAp;										\
		RTMP_SEM_LOCK(&(__pAd)->FT_RicLock);						\
		__Size = getListSize((__pList));							\
		__FlgIsFound = FALSE;										\
		for(__IdEntry=0; __IdEntry<__Size; __IdEntry++)				\
		{															\
			__pRscAp = (FT_RIC_AP *)removeHeadList((__pList));		\
			if (memcmp(__pRscAp->AP_MAC, __pApMac, ETH_ALEN) == 0)	\
			{														\
				memcpy(__pEntry, __pRscAp, sizeof(FT_RIC_AP));		\
				insertTailList((__pList), (RT_LIST_ENTRY *)(__pRscAp));\
				__FlgIsFound = TRUE;								\
				break;												\
			}														\
			insertTailList((__pList), (RT_LIST_ENTRY *)(__pRscAp));	\
		}															\
		RTMP_SEM_UNLOCK(&(__pAd)->FT_RicLock);						\
	}

/* set status to a resource request by AP MAC */
#define FT_RIC_AP_LIST_ENTRY_SET(__pAd, __pList, __pApMac, __pEntry)\
	{																\
		UINT32 __Size, __IdEntry;									\
		FT_RIC_AP *__pRscAp;										\
		RTMP_SEM_LOCK(&(__pAd)->FT_RicLock);						\
		__Size = getListSize((__pList));							\
		for(__IdEntry=0; __IdEntry<__Size; __IdEntry++)				\
		{															\
			__pRscAp = (FT_RIC_AP *)removeHeadList((__pList));		\
			if (memcmp(__pRscAp->AP_MAC, __pApMac, ETH_ALEN) == 0)	\
			{														\
				memcpy(__pRscAp, __pEntry, sizeof(FT_RIC_AP));		\
				insertTailList((__pList), (RT_LIST_ENTRY *)(__pRscAp));\
				break;												\
			}														\
			insertTailList((__pList), (RT_LIST_ENTRY *)(__pRscAp));	\
		}															\
		RTMP_SEM_UNLOCK(&(__pAd)->FT_RicLock);						\
	}

/* delete a resource request by AP MAC */
#define FT_RIC_AP_LIST_ENTRY_DEL(__pAd, __pList, __pApMac)			\
	{																\
		UINT32 __Size, __IdEntry;									\
		FT_RIC_AP *__pRscAp;										\
		RTMP_SEM_LOCK(&(__pAd)->FT_RicLock);						\
		__Size = getListSize((__pList));							\
		for(__IdEntry=0; __IdEntry<__Size; __IdEntry++)				\
		{															\
			__pRscAp = (FT_RIC_AP *)removeHeadList((__pList));		\
			if (memcmp(__pRscAp->AP_MAC, __pApMac, ETH_ALEN) == 0)	\
			{														\
				os_free_mem(NULL, __pRscAp);						\
				break;												\
			}														\
			insertTailList((__pList), (RT_LIST_ENTRY *)(__pRscAp));	\
		}															\
		RTMP_SEM_UNLOCK(&(__pAd)->FT_RicLock);						\
	}

/* clear all resource requests */
#define FT_RIC_AP_LIST_EMPTY(__pAd, __pList)						\
	{																\
		FT_RIC_AP *__pEntry;										\
		RTMP_SEM_LOCK(&(__pAd)->FT_RicLock);						\
		__pEntry = (FT_RIC_AP *)removeHeadList((__pList));			\
		while(__pEntry != NULL)										\
		{															\
			os_free_mem(NULL, __pEntry);							\
			__pEntry = (FT_RIC_AP *)removeHeadList((__pList));		\
		}															\
		RTMP_SEM_UNLOCK(&(__pAd)->FT_RicLock);						\
	}
#endif /* CONFIG_STA_SUPPORT */




/*
========================================================================
Routine Description:
	Initialize FT RIC Module.

Arguments:
	pAd				- WLAN control block pointer

Return Value:
	None

Note:
========================================================================
*/
VOID TYPE_FUNC FT_RIC_Init(
	IN	PRTMP_ADAPTER		pAd)
{
	DBGPRINT(RT_DEBUG_TRACE, ("ap_ftrc> Initialize FT RIC Module...\n"));

#ifdef CONFIG_STA_SUPPORT
	/* allocate control block */
	if (pAd->pFT_RIC_Ctrl_BK == NULL)
	{
		os_alloc_mem(pAd, (UCHAR **)&pAd->pFT_RIC_Ctrl_BK,
						sizeof(FT_RIC_CTRL_BLOCK));

		if (pAd->pFT_RIC_Ctrl_BK == NULL)
		{
			DBGPRINT(RT_DEBUG_ERROR, ("ap_ftrc> Allocate control block fail!\n"));
			return;
		} /* End of if */

		/* init spin lock */
		NdisAllocateSpinLock(pAd, &(pAd->FT_RicLock));

		/* init resource list */
		initList(&(FT_RIC_CB->ResourceList));
	} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
} /* End of FT_RIC_Init */


/*
========================================================================
Routine Description:
	Release FT RIC Module.

Arguments:
	pAd				- WLAN control block pointer

Return Value:
	None

Note:
========================================================================
*/
VOID TYPE_FUNC FT_RIC_Release(
	IN	PRTMP_ADAPTER		pAd)
{
	DBGPRINT(RT_DEBUG_TRACE, ("ap_ftrc> Release FT RIC Module...\n"));

#ifdef CONFIG_STA_SUPPORT
	if (pAd->pFT_RIC_Ctrl_BK != NULL)
	{
		/* free resource list */
		FT_RIC_AP_LIST_EMPTY(pAd, &(FT_RIC_CB->ResourceList));

		/* free spin lock */
		NdisFreeSpinLock(&(pAd->FT_RicLock));

		os_free_mem(pAd, pAd->pFT_RIC_Ctrl_BK);
		pAd->pFT_RIC_Ctrl_BK = NULL;
	} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
} /* End of FT_KDP_Release */


#ifdef CONFIG_STA_SUPPORT
/*
========================================================================
Routine Description:
	Start to do resource request for other APs.

Arguments:
	pAd				- WLAN control block pointer

Return Value:
	TRUE			- successfully
	FALSE			- no any resource is needed to request

Note:
	1. After the function is called, no any new TSPEC can be issued from us.
========================================================================
*/
BOOLEAN TYPE_FUNC FT_RIC_ResourceRequestStart(
	IN	PRTMP_ADAPTER			pAd)
{
	BOOLEAN Status = TRUE;

#ifdef WMM_ACM_SUPPORT
	/* sanity check */
	if (ACMP_StreamNumGet(pAd,
							ACM_SM_CATEGORY_PEER,
							ACM_ACCESS_POLICY_EDCA,
							ACMR_AP_ADDR_GET(pAd)) <= 0)
	{
		/* no any TSPEC exists */
		Status = FALSE;
	} /* End of if */

	/*
		We can not send any new TSPEC now or these new TSPECs will be deleted
		after QSTA reassociates to the new AP even no TSPEC exists currently.
	*/
	ACMP_FSM_Suspend(pAd);
#endif /* WMM_ACM_SUPPORT */

	FT_RIC_AP_LIST_EMPTY(pAd, &FT_RIC_CB->ResourceList);
	return Status;
} /* End of FT_RIC_ResourceRequestStart */


/*
========================================================================
Routine Description:
	End to do resource request for other APs.

Arguments:
	pAd				- WLAN control block pointer
	*pApMac			- the new AP MAC

Return Value:
	None

Note:
	1. After the function is called, no any new TSPEC can be issued from us.
========================================================================
*/
VOID TYPE_FUNC FT_RIC_ResourceRequestEnd(
	IN	PRTMP_ADAPTER			pAd,
	IN	UCHAR					*pApMac)
{
#ifdef WMM_ACM_SUPPORT
	FT_RIC_AP RscAp, *pRscAp;
	UINT32 IdTid;
	BOOLEAN FlgIsFound;


	/* delete some TSPECs which are not accepted in new AP */
	pRscAp = &RscAp;

	FT_RIC_AP_LIST_ENTRY_GET(pAd, &FT_RIC_CB->ResourceList, \
							pApMac, FlgIsFound, pRscAp);

	if (FlgIsFound == TRUE)
	{
		for(IdTid=0; IdTid<ACM_STA_TID_MAX_NUM; IdTid++)
		{
			if ((pRscAp->ResourceTspec[IdTid].FlgIsValid == TRUE) &&
				(pRscAp->ResourceTspec[IdTid].FlgIsAccepted == FALSE))
			{
				/* the TSPEC is not accepted in new AP so deleting it */
				DBGPRINT(RT_DEBUG_TRACE,
							("ft_ric> TSID %d is not accepted!\n", IdTid));

				ACMP_TC_DeleteOneSilently(pAd, pApMac, IdTid);
			} /* End of if */
		} /* End of for */
	} /* End of if */

	/* we can send any new TSPEC after associating to the new AP */
	ACMP_FSM_Resume(pAd);
#endif /* WMM_ACM_SUPPORT */

	/* empty all backup resource request entries */
	FT_RIC_AP_LIST_EMPTY(pAd, &FT_RIC_CB->ResourceList);
} /* End of FT_RIC_ResourceRequestEnd */


/*
========================================================================
Routine Description:
	Issue resource requests.

Arguments:
	pAd				- WLAN control block pointer
	*pApMac			- the AP MAC
	*pBufReq		- the request packet buffer
	ReqMaxLen		- the maximum remain length of request packet buffer

Return Value:
	filled element length

Note:
	1. Same resource type for all resource descriptors in the RDIE.
	2. Suppose RDIEs are continual.
	3. If pDescpBlk != NULL, skip current TSPEC.

	4. 11A.11.3 Creation and handling of a resource request (11r D9.0)
		(1) In using TSPECs for requesting QoS resources, the TSPECs in the
			request need not belong to only active Traffic Streams;
		(2) The non-AP STA can send TSPECs for any Traffic Stream that it
			intends to use after the transition, and request the same resources
			that would be requested by a later ADDTS exchange.

		==> We do NOT support the function.

	5. Resource request usage for QSTA:
		Case 1:
		(1) Scan or get neighbor report of other QAPs;
		(2) Maybe signal is bad with current AP and good for other QAPs;

		-- FT_RIC_ResourceRequestStart()
			No new TSPEC can be issued.

		-- FT_RIC_ResourceRequest()
			Build current TSPEC to the QAP1.

		(3) FT confirm to QAP1;

		-- FT_RIC_ResourceResponseHandle() for QAP1.

		(4) Handle FT ACK from QAP1;

		(6) a. Signal is still bad so determining to reassociate a QAP;
			b. Maybe signal is good again with current QAP, no roaming is needed;

		-- FT_RIC_ResourceRequestEnd(ptr to TSPEC status)

		Case 2:
		(1) Scan or get neighbor report of other QAPs;
		(2) Maybe signal is bad with current AP and good for other QAPs;

		-- FT_RIC_ResourceRequestStart()
			No new TSPEC can be issued.

		-- FT_RIC_ResourceRequest()
			Build current TSPEC to the QAP1.

		(3) FT confirm to QAP1;

		-- FT_RIC_ResourceRequest()
			Build current TSPEC to the QAP2.

		(4) FT confirm to QAP2;

		-- (get success percentage) FT_RIC_ResourceResponseHandle(ptr to TSPEC status) for QAP1.
		-- (get success percentage) FT_RIC_ResourceResponseHandle(ptr to TSPEC status) for QAP2.

		(5) Handle FT ACK from different QAPs;
		(6) a. Signal is still bad so determining to reassociate a QAP;
			b. Maybe signal is good again with current QAP, no roaming is needed;
			c. Select the best resource allocation;

		-- FT_RIC_ResourceRequestEnd(ptr to TSPEC status)
			New TSPECs can be issued.
========================================================================
*/
UINT32 TYPE_FUNC FT_RIC_ResourceRequest(
	IN	PRTMP_ADAPTER			pAd,
	IN	UCHAR					*pApMac,
	IN	UCHAR					*pBufReq,
	IN	UINT32					ReqMaxLen)
{
	FT_RIC_DESCP_BLOCK_ACK DescpBlk, *pDescpBlk;
	FT_RIC_AP *pRscAp;
	UINT32 FilledLen;

#ifdef WMM_ACM_SUPPORT
	FT_ELM_RIC_DATA_INFO *pElmDataInfo;
	FT_ELM_RIC_DESCP_INFO *pElmDescpInfo;
	ACM_STREAM_INFO *pStream, *pStreamNext;
	ACM_TS_INFO *pTsInfo;
	UINT32 NumOfStream, SizeOfBuf;
	UINT32 IdRdie, NumOfRdie;
	UINT32 IdTid, RscLen;
#endif /* WMM_ACM_SUPPORT */


	FT_RIC_AP_LIST_ENTRY_DEL(pAd, &FT_RIC_CB->ResourceList, pApMac);

	FilledLen = 0;

	/* allocate a resource record for the AP */
	os_alloc_mem(NULL, (UCHAR **)&pRscAp, sizeof(FT_RIC_AP));
	if (pRscAp == NULL)
		return 0;

	memset(pRscAp, 0, sizeof(FT_RIC_AP));
	memcpy(pRscAp->AP_MAC, pApMac, ETH_ALEN);

#ifdef WMM_ACM_SUPPORT
	for(IdTid=0; IdTid<ACM_STA_TID_MAX_NUM; IdTid++)
		pRscAp->ResourceTspec[IdTid].FlgIsValid = FALSE;
#endif /* WMM_ACM_SUPPORT */

	/* fill BLOCK ACK resource request */
	pRscAp->FlgHasBaResource = FALSE;
	pDescpBlk = &DescpBlk;

	/* try to get and fill BLOCK ACK resource */
	/* yet implement */

#ifdef WMM_ACM_SUPPORT
	/* fill TSPEC resource request */
	/* get current TSPECs */
	pStream = NULL;
	NumOfStream = ACMP_StreamNumGet(pAd, ACM_SM_CATEGORY_PEER,
									1, ACMR_AP_ADDR_GET(pAd));

	DBGPRINT(RT_DEBUG_TRACE,
				("ft_ric> NumOfStream = %d\n", NumOfStream));

	if (NumOfStream != 0)
	{
		if (ReqMaxLen < (NumOfStream * (sizeof(FT_ELM_RIC_DATA_INFO) +\
							ACM_ELM_TSPEC_LEN)))
		{
			os_free_mem(NULL, pStream);
			return 0;
		}

		SizeOfBuf = sizeof(ACM_STREAM_INFO) * NumOfStream;
		os_alloc_mem(NULL, (UCHAR **)&pStream, SizeOfBuf);

		if (pStream == NULL)
		{
			os_free_mem(NULL, pStream);
			return 0;
		}

		if (ACMP_StreamsGet(pAd, ACM_SM_CATEGORY_PEER, 1,
							&NumOfStream, ACMR_AP_ADDR_GET(pAd),
							pStream) != ACM_RTN_OK)
		{
			os_free_mem(NULL, pStream);
			return 0;
		}

		pStreamNext = pStream;
		NumOfRdie = NumOfStream;

		/* fill each (RDIE vs Resource Request) */
		for(IdRdie=0; IdRdie<NumOfRdie; IdRdie++)
		{
			pElmDataInfo = (FT_ELM_RIC_DATA_INFO *)pBufReq;

			pElmDataInfo->ElmID = FT_ELM_ID_RIC_DATA_INFO;
			pElmDataInfo->ElmLen = FT_ELM_LEN_RIC_DATA_INFO;
			pElmDataInfo->RDIE_Identifier = FT_RIC_CB->RDIE_Identifier;
			pElmDataInfo->RD_Count = 1;
			pElmDataInfo->StatusCode = 0;

			FT_RIC_CB->RDIE_Identifier ++;
			FilledLen += sizeof(FT_ELM_RIC_DATA_INFO);

			/* init RIC Resource */
			pElmDescpInfo = (FT_ELM_RIC_DESCP_INFO *)\
									(pBufReq + sizeof(FT_ELM_RIC_DATA_INFO));

			/* fill TSPEC resource */
			RscLen = ACMP_WME_TSPEC_ElementFill(pAd,
												(UCHAR *)pElmDescpInfo,
												&(pStreamNext->Tspec));
			FilledLen += RscLen;

			/* record some resource information */
			pTsInfo = &pStreamNext->Tspec.TsInfo;
			pRscAp->ResourceTspec[pTsInfo->TSID].FlgIsValid = TRUE;
			pRscAp->ResourceTspec[pTsInfo->TSID].RDIE_Identifier = \
											pElmDataInfo->RDIE_Identifier;
			pRscAp->ResourceTspec[pTsInfo->TSID].MedimumTime = \
											pStreamNext->Tspec.MediumTime;
			pRscAp->TspecNumberOfRequested ++;

			DBGPRINT(RT_DEBUG_TRACE,
						("ft_ric> Request a TSPEC resource: Medium Time = %dus\n",
						pStreamNext->Tspec.MediumTime));

			/* try to fill next element */
			pStreamNext ++;
			pBufReq += sizeof(FT_ELM_RIC_DATA_INFO) + RscLen;
		}
	}
#endif /* WMM_ACM_SUPPORT */

	/* backup the resource record */
	if (FilledLen > 0)
	{
		FT_RIC_AP_LIST_INSERT_TAIL(pAd, &FT_RIC_CB->ResourceList, pRscAp);
	}
	else
	{
#ifdef WMM_ACM_SUPPORT
		if (pStream != NULL)
		{
			/* no any resource request is needed */
			os_free_mem(NULL, pStream);
		}
#endif /* WMM_ACM_SUPPORT */
	}

	DBGPRINT(RT_DEBUG_TRACE,
				("ft_ric> FilledLen = %d\n", FilledLen));

	return FilledLen;
}


/*
========================================================================
Routine Description:
	Handle resource responses.

Arguments:
	pAd				- WLAN control block pointer
	*pApMac			- the AP MAC
	*pBufRsp		- the response packet buffer
	RspLen			- the maximum remain length of response packet buffer
	*pRspStatus		- the status report

Return Value:
	handled length

Note:
	1. Same resource type for all resource descriptors in the RDIE.
	2. Suppose RDIEs are continual.
========================================================================
*/
UINT32 TYPE_FUNC FT_RIC_ResourceResponseHandle(
	IN	PRTMP_ADAPTER			pAd,
	IN	UCHAR					*pApMac,
	IN	UCHAR					*pBufRsp,
	IN	UINT32					RspLen,
	OUT	FT_RIC_STATUS			*pRspStatus)
{
	FT_ELM_RIC_DATA_INFO *pElmDataInfoRsp;
	UCHAR *pBufRspElm, *pElmRspDescp;
	FT_RIC_AP RscAp, *pRscAp;
	UINT32 DescpCnt;
	UINT32 HandledSize;
	UCHAR RDIE_Identifier;
	BOOLEAN FlgIsFound;

#ifdef WMM_ACM_SUPPORT
	FT_RIC_STATUS_TSPEC *pRscTspec;
	UINT32 MediumTime, TID, IdTid;
#endif /* WMM_ACM_SUPPORT */


	/* init */
	if (pRspStatus == NULL)
		return 0;
	/* End of if */

	memset(pRspStatus, 0, sizeof(FT_RIC_STATUS));
	pRscAp = &RscAp;

	/* sanity check resource request */
	FT_RIC_AP_LIST_ENTRY_GET(pAd, &FT_RIC_CB->ResourceList, \
							pApMac, FlgIsFound, pRscAp);

	if (FlgIsFound == FALSE)
	{
		/* no any resource requset is sent to the AP */
		DBGPRINT(RT_DEBUG_TRACE,
					("ft_ric> No any request resource is found!\n"));
		return 0;
	} /* End of if */

	/* init */
	pBufRspElm = pBufRsp;
	HandledSize = 0;

	memcpy(pRspStatus->AP_MAC, pApMac, sizeof(pRspStatus->AP_MAC));

	pRspStatus->FlgHasBaResource = FALSE;
	pRspStatus->FlgIsBaAccepted = FALSE;
	pRspStatus->TspecNumberOfRequested = 0;

#ifdef WMM_ACM_SUPPORT
	pRspStatus->TspecNumberOfRequested = pRscAp->TspecNumberOfRequested;
#endif /* WMM_ACM_SUPPORT */

	/* handle all RDIEs */
	/*
		The non-AP STA shall construct the RIC with a number of
		Resource Requests, each delineated by an RDIE.
	*/
	while(HandledSize < RspLen)
	{
		/* sanity check the RDIE */
		pElmDataInfoRsp = (FT_ELM_RIC_DATA_INFO *)pBufRspElm;

		if (pElmDataInfoRsp->ElmID != FT_ELM_ID_RIC_DATA_INFO)
			break;
		/* End of if */

		/* parsing the RIC descriptors */
		/*
			The Resource Count shall be set to the number of alternative
			Resource Descriptors that follow.
		*/
		RDIE_Identifier = pElmDataInfoRsp->RDIE_Identifier;
		DescpCnt = pElmDataInfoRsp->RD_Count; /* must be 0 or 1 */

		HandledSize += FT_ELM_HDR_LEN + pElmDataInfoRsp->ElmLen;
		pElmRspDescp = pBufRspElm + FT_ELM_HDR_LEN + pElmDataInfoRsp->ElmLen;

		if ((DescpCnt >= 1) &&
			((*pElmRspDescp) != FT_ELM_ID_RIC_DATA_INFO) &&
			(HandledSize < RspLen))
		{
			/* only one resource descriptor is accepted is enough */
			/*
				If there are multiple Resource Descriptors then these
				are treated as "choices" by the target AP.
			*/
			switch(*pElmRspDescp)
			{
				case FT_ELM_ID_RIC_DESCP_INFO:
					/* BLOCK ACK */
					DBGPRINT(RT_DEBUG_TRACE,
							("ft_ric> A resource BLOCK ACK response is found!\n"));

					HandledSize += (FT_ELM_HDR_LEN + *(pElmRspDescp+1));

					if ((pRscAp->FlgHasBaResource == TRUE) &&
						(RDIE_Identifier == pRscAp->RDIE_IdentifierBA))
					{
						if (pElmDataInfoRsp->StatusCode == 0)
						{
							pRspStatus->FlgHasBaResource = TRUE;
							pRspStatus->FlgIsBaAccepted = TRUE;
						} /* End of if */
					}
					else
						pRspStatus->UnknownRDIE ++;
					/* End of if */
					break;

				default:
					HandledSize += (FT_ELM_HDR_LEN + *(pElmRspDescp+1));

#ifdef WMM_ACM_SUPPORT
					if (ACMP_WME_TSPEC_ElementCheck(pElmRspDescp,
													&TID,
													&MediumTime) != TRUE)
					{
						DBGPRINT(RT_DEBUG_TRACE,
								("ft_ric> Not resource TSPEC!\n"));
						pRspStatus->UnknownRDIE ++;
						break;
					} /* End of if */

					DBGPRINT(RT_DEBUG_TRACE,
							("ft_ric> A resource TSPEC response is found!\n"));

					/* this is TSPEC element */
					pRscTspec = &pRscAp->ResourceTspec[TID];

					if (pRscTspec->FlgIsValid == FALSE)
					{
						pRspStatus->UnknownRDIE ++;
						break; /* the request does not exist */
					} /* End of if */

					if (RDIE_Identifier != pRscTspec->RDIE_Identifier)
					{
						pRspStatus->UnknownRDIE ++;
						break; /* error ID */
					} /* End of if */

					pRspStatus->TspecMediumTimeTotalCur += pRscTspec->MedimumTime;
					pRscTspec->FlgIsAccepted = FALSE;

					if (pElmDataInfoRsp->StatusCode != 0)
						break; /* be rejected */
					/* End of if */

					DBGPRINT(RT_DEBUG_TRACE,
							("ft_ric> Response status = %d, Medium Time = %d!\n",
							pElmDataInfoRsp->StatusCode,
							MediumTime));

					pRscTspec->FlgIsAccepted = TRUE;
					pRspStatus->TspecNumberOfAccepted ++;
					pRspStatus->TspecMediumTimeTotalNew += MediumTime;
#endif /* WMM_ACM_SUPPORT */
					break;
			} /* End of switch */

			/* check next RDIE */
			/* one RDIE + one Resource response (status == SUCCESS) */
			pElmRspDescp += FT_ELM_HDR_LEN + *(pElmRspDescp+1);
			pBufRspElm = pElmRspDescp;
		}
		else
		{
			/* only one RDIE (status != SUCCESS) */
			BOOLEAN FlgIsHandled = FALSE;

			/* check if the RDIE is for BA resource */
			if ((pRscAp->FlgHasBaResource == TRUE) &&
				(RDIE_Identifier == pRscAp->RDIE_IdentifierBA))
			{
				pRspStatus->FlgHasBaResource = TRUE;
				pRspStatus->FlgIsBaAccepted = FALSE;
				FlgIsHandled = TRUE;
			}
#ifdef WMM_ACM_SUPPORT
			else
			{
				if (pRscAp->TspecNumberOfRequested > 0)
				{
					for(IdTid=0; IdTid<ACM_STA_TID_MAX_NUM; IdTid++)
					{
						pRscTspec = &pRscAp->ResourceTspec[IdTid];

						if (pRscTspec->FlgIsValid == FALSE)
							continue; /* check next one */
						/* End of if */

						if (RDIE_Identifier == pRscTspec->RDIE_Identifier)
						{
							pRspStatus->TspecMediumTimeTotalCur += \
														pRscTspec->MedimumTime;
							pRscTspec->FlgIsAccepted = FALSE;
							FlgIsHandled = TRUE;
							break;
						} /* End of if */
					} /* End of for */
				} /* End of if */
			}
#endif /* WMM_ACM_SUPPORT */

			if (FlgIsHandled == FALSE)
				pRspStatus->UnknownRDIE ++;
			/* End of if */

			/* check next RDIE */
			pBufRspElm += (FT_ELM_HDR_LEN + pElmDataInfoRsp->ElmLen);
		} /* End of if */
	} /* End of while */

	/* save content */
	FT_RIC_AP_LIST_ENTRY_SET(pAd, &FT_RIC_CB->ResourceList, pApMac, pRscAp);
	return HandledSize;
} /* End of FT_RIC_ResourceResponseHandle */
#endif /* CONFIG_STA_SUPPORT */


#ifdef CONFIG_AP_SUPPORT
/*
========================================================================
Routine Description:
	Handle the resource request.

Arguments:
	pAd				- WLAN control block pointer
	*pCdb			- the source QSTA
	*pBufReq		- the request packet buffer
	ReqLen			- the length of request packet buffer
	*pBufRsp		- the response packet buffer
	*pRspLen		- the length of response content

Return Value:
	non-zero		- the frame length we handled
	zero			- no request is found

Note:
	1. The start octet of the buffer is the element ID of RIC request or response.
	2. Same resource type for all resource descriptors in the RDIE.
	3. Suppose RDIEs are continual.
========================================================================
*/
UINT32 TYPE_FUNC FT_RIC_ResourceRequestHandle(
	IN	PRTMP_ADAPTER			pAd,
	IN	MAC_TABLE_ENTRY			*pCdb,
	IN	UCHAR					*pBufReq,
	IN	UINT32					ReqLen,
	OUT	UCHAR					*pBufRsp,
	OUT	UINT32					*pRspLen)
{
	FT_ELM_RIC_DATA_INFO *pElmDataInfoReq, *pElmDataInfoRsp;
	UCHAR *pBufReqElm, *pElmReqDescp;
	UCHAR *pBufRspElm;
	ULONG ElmLen, RspLen;
	UINT32 DescpCnt;
	UINT32 HandledSize;
	BOOLEAN FlgIsTspecAccepted;


	/* init */
	pBufReqElm = pBufReq;
	pBufRspElm = pBufRsp;
	*pRspLen = 0;
	HandledSize = 0;

	/* sanity check */
	if ((pCdb == NULL) ||
		(pBufReq == NULL) ||
		(pBufRsp == NULL) ||
		(pRspLen == NULL))
	{
		DBGPRINT(RT_DEBUG_ERROR,
				("ft_ric> (ResourceRequestHandle) Error! NULL pointer!\n"));
		return 0;
	} /* End of if */

	/* handle all RDIEs */
	/*
		The non-AP STA shall construct the RIC with a number of
		Resource Requests, each delineated by an RDIE.
	*/
	while(HandledSize < ReqLen)
	{
		/* sanity check the RDIE */
		pElmDataInfoReq = (FT_ELM_RIC_DATA_INFO *)pBufReqElm;

		if (pElmDataInfoReq->ElmID != FT_ELM_ID_RIC_DATA_INFO)
			break;
		/* End of if */

		/* make up reponse */
		/*
			The RIC Response shall comprise one RDIE for each RDIE in the
			RIC Request.
		*/
		pElmDataInfoRsp = (FT_ELM_RIC_DATA_INFO *)pBufRspElm;
		pElmDataInfoRsp->ElmID = FT_ELM_ID_RIC_DATA_INFO;
		pElmDataInfoRsp->ElmLen = FT_ELM_LEN_RIC_DATA_INFO;

		/*
			The RDIE Identifier in the RDIE shall be an arbitrary value
			chosen by the non-AP STA that uniquely identifies the RDIE
			within the RIC.
		*/
		pElmDataInfoRsp->RDIE_Identifier = pElmDataInfoReq->RDIE_Identifier;

		pBufRspElm += sizeof(FT_ELM_RIC_DATA_INFO);
		*pRspLen += sizeof(FT_ELM_RIC_DATA_INFO);


		/* parsing the RIC descriptors */
		/*
			The Resource Count shall be set to the number of alternative
			Resource Descriptors that follow.
		*/
		DescpCnt = pElmDataInfoReq->RD_Count;
		FlgIsTspecAccepted = FALSE;

		pElmReqDescp = ((UCHAR *)pElmDataInfoReq);
		pElmReqDescp += FT_ELM_HDR_LEN + pElmDataInfoReq->ElmLen;
		HandledSize += FT_ELM_HDR_LEN + pElmDataInfoReq->ElmLen;

		while(DescpCnt > 0)
		{
			if (FlgIsTspecAccepted == FALSE)
			{
				/* only one resource descriptor is accepted is enough */
				/*
					If there are multiple Resource Descriptors then these
					are treated as "choices" by the target AP.
				*/
				switch(*pElmReqDescp)
				{
					case IE_FT_RIC_DESCRIPTOR:
						/* BLOCK ACK */
						/* reject the resource */
						DBGPRINT(RT_DEBUG_TRACE,
								("ft_ric> Handle a resource request BLOCK ACK...\n"));

						if (BA_ResourceAllocate(pAd,
											pCdb,
											pElmReqDescp,
											pBufRspElm,
											&RspLen) == 0)
						{
							DBGPRINT(RT_DEBUG_TRACE, ("ft_ric> Accept BA.\n"));
							FlgIsTspecAccepted = TRUE;
						}
						break;

					default:
#ifdef WMM_ACM_SUPPORT
						/* only WMM TSPEC is supported */
						DBGPRINT(RT_DEBUG_TRACE,
								("ft_ric> Handle a resource request TSPEC...\n"));

						if (ACMP_ResourceAllocate(pAd,
											pCdb,
											pElmReqDescp,
											pBufRspElm,
											(UINT32 *)&RspLen) == ACM_RTN_OK)
						{
							DBGPRINT(RT_DEBUG_TRACE, ("ft_ric> Accept TSPEC.\n"));
							FlgIsTspecAccepted = TRUE;
						} /* End of if */
#endif /* WMM_ACM_SUPPORT */
						break;
				} /* End of switch */
			} /* End of if */

			/* find the next RD Descriptor element */
			ElmLen = *(pElmReqDescp+1);
			pElmReqDescp += FT_ELM_HDR_LEN + ElmLen;
			HandledSize += FT_ELM_HDR_LEN + ElmLen;

			DescpCnt --;
		} /* End of while */


		/* re-assign the reponse RD Count/status code of RDIE */
		if (FlgIsTspecAccepted == TRUE)
		{
			/*
				A resource request is considered successful by a non-AP STA
				if the Status Code 0 is returned in each RDIE.
			*/
			pElmDataInfoRsp->RD_Count = 1;
			pElmDataInfoRsp->StatusCode = 0;

			pBufRspElm += RspLen;
			*pRspLen += RspLen;

			DBGPRINT(RT_DEBUG_TRACE,
					("ft_ric> Accept a resource request (RspLen: %d).\n", *pRspLen));
		}
		else
		{
			/*
				Status Code non-zero indicates that the resources could not
				be accepted.

				In this case the AP may include a single Resource Descriptor
				following the RDIE indicating a suggested resource that could
				have been accepted.

				The Resource Count field shall be set to '0' or '1' depending
				whether the suggested Resource Descriptor is attached.

				A non-zero Status Code in an RDIE shall not cause a non-zero
				Status Code in the auth/assoc frame containing the RIC.
			*/

			/* we do NOT support suggested Resource Descriptor */

			pElmDataInfoRsp->RD_Count = 0; /* 0 or 1, we only support 0 */
			pElmDataInfoRsp->StatusCode = FT_STATUS_CODE_RESERVED;

			DBGPRINT(RT_DEBUG_TRACE, ("ft_ric> Resource request fails!\n"));
		} /* End of if */


		/* check next RDIE */
		pBufReqElm = pElmReqDescp;
	} /* End of while */

	return HandledSize;
} /* End of FT_RIC_ResourceRequestHandle */


/*
========================================================================
Routine Description:
	Handle the resource request.

Arguments:
	pAd				- WLAN control block pointer
	*pMacEntry		- the source QSTA
	*pBufReq		- the request packet buffer
	ReqLen			- the length of request packet buffer
	*pBufRsp		- the response packet buffer
	*pRspLen		- the length of response content

Return Value:
	non-zero		- the frame length we handled
	zero			- no request is found

Note:
	1. The start octet of the buffer is the element ID of RIC request or response.
	2. Same resource type for all resource descriptors in the RDIE.
	3. Suppose RDIEs are continual.
========================================================================
*/
UINT32 BA_ResourceAllocate(
	IN PRTMP_ADAPTER pAd,
	IN MAC_TABLE_ENTRY *pMacEntry,
	IN UCHAR *pBufRscReq,
	OUT UCHAR *pBufRscRsp,
	OUT ULONG *pBufRspLen)
{
extern BOOLEAN BARecSessionAdd(
					   IN PRTMP_ADAPTER    pAd, 
					   IN MAC_TABLE_ENTRY  *pEntry,
					   IN PFRAME_ADDBA_REQ pFrame);

	UINT8 IEId = IE_FT_RIC_DESCRIPTOR;
	UINT8 RicType = FT_RIC_TYPE_BA;
	UINT8 Len = 7;
	UINT16 Status = 1;
	BA_PARM BaParm; /*0 - 2 */
	USHORT TimeOutValue;

	FRAME_ADDBA_REQ AddreqFrame;
	FT_ELM_RIC_DESCP_INFO *pRicDesInfo;
	FT_RIC_DESCP_BLOCK_ACK *pRicBaInfo;

	if ((pAd->CommonCfg.bBADecline == FALSE) && IS_HT_STA(pMacEntry))
	{
		UINT16 Value;
		pRicDesInfo = (FT_ELM_RIC_DESCP_INFO *)pBufRscReq;
		pRicBaInfo = (FT_RIC_DESCP_BLOCK_ACK *)pRicDesInfo->Container;
		Value = le2cpu16(*(UINT16 *)(&pRicBaInfo->BaParm));
		NdisMoveMemory((PUCHAR)&AddreqFrame.BaParm, &Value, sizeof(UINT16));
		AddreqFrame.TimeOutValue = le2cpu16(pRicBaInfo->TimeOutValue);
		AddreqFrame.BaStartSeq.word = le2cpu16(pRicBaInfo->BaStartSeq);

		DBGPRINT(RT_DEBUG_OFF, ("Rcv Wcid(%d) AddBAReq\n", pMacEntry->Aid));
		if (BARecSessionAdd(pAd, pMacEntry, &AddreqFrame))
			Status = 0;
		else
			Status = 38; /* more parameters have invalid values */
	}
	else
	{
		Status = 37; /* the request has been declined. */
	}

	if (Status != 0)
		return Status;

	BaParm.BAPolicy = IMMED_BA;
	BaParm.AMSDUSupported = 0;
	BaParm.TID = AddreqFrame.BaParm.TID;
	BaParm.BufSize = min(((UCHAR)AddreqFrame.BaParm.BufSize), (UCHAR)pAd->CommonCfg.BACapability.field.RxBAWinLimit);
	if (BaParm.BufSize == 0)
	{
		BaParm.BufSize = 64; 
	}
	TimeOutValue = 0;

	*(UINT16 *)(&BaParm) = cpu2le16(*(USHORT *)(&BaParm));
	Status = cpu2le16(Status);
	TimeOutValue = cpu2le16(TimeOutValue);

	MakeOutgoingFrame(	pBufRscRsp,	pBufRspLen,
						1,			&IEId,
						1,			&Len,
						1,			&RicType,
						2,			&Status,
						2,			(UCHAR *)&BaParm,
					  	2,  		&TimeOutValue,
						END_OF_ARGS);

	return Status;
}

#endif /* CONFIG_AP_SUPPORT */

#endif /* DOT11R_FT_SUPPORT */

/* End of ap_ftrc.c */
