/*******************************************************************************
 * (c) Copyright 2015 Microsemi Corporation.  All rights reserved.
 *
 *
 *
 * SVN $Revision: $
 * SVN $Date: $
 */

#ifndef MRLINKTRACE_H_
#define MRLINKTRACE_H_

/* ----------------------------------------------------------------------------------------------------------------------------------*/
// Include dependent header files
/* ----------------------------------------------------------------------------------------------------------------------------------*/
#include <api_oam_sdk/common/types/inc/mr_api_types.h>
#include <api_oam_sdk/maintenance_association/inc/ma.h>

#define	MR_PORT_ID_SIZE			(32)				// Sets the storage size of the portID data field in LT reply TLVs
#define MR_MAX_SID_TLV_SIZE		(64)
#define MR_MAX_ORG_TLV_SIZE		(64)

#define	MR_LINKTRACE_USE_FBD_ONLY_FLAG	0x80		// MIPs should use their forwarding database only
#define	MR_LINKTRACE_FWD_YES_FLAG		0x40		// Set in the LTR if the MIP forwarded the LTM
#define	MR_LINKTRACE_TERMINAL_MEP_FLAG	0x20		// Set in the LTR if the MEP is the end point for the LTM
#define	MR_LINKTRACE_RESERVED_FLAGS		0x1F		// Reserved for future use.

#define	MR_MAX_LTM_REPLY_LIST_LENGTH	1			// The max number of simultaneous LTMs that can be active
#define	MR_MAX_LTR_REPLY_LIST_LENGTH	10			// The max number of LTRs that can be recorded for every active LTM

typedef struct
{
	macAddress_t 	destMac;
	mepId_t 		targetMepId;
	boolean_t 		tagetIsMepId;
	uint8_t 		flags;
	uint8_t 		ttl;
} ltmTxInfo_t;

typedef struct
{
	uint32_t		ltmTransmitted;		// The total number LTMs transmitted by this MEP
	uint32_t		ltmReceived;		// The total number LTMs received by this MEP
	uint32_t		ltrTransmitted;		// The total number LTRs transmitted by this MEP
	uint32_t		ltrReceived;		// The total number LTRs received by this MEP
} mepLtMefInfo_t;

typedef struct
{
	uint32_t		ltmNextSeqNumber;								// Next transaction id/sequence number to be sent in a LTM. This sequence number can be zero because it wraps around
	uint32_t		unexpectedLtrIn;								// The total number of unexpected LTRs received
	uint32_t		txLtmSeqNumber;									// The LTM Transaction Id (ltmNextSeqNumber) of the LTM sent. The value returned is undefined if txLtmResult is false.
	mepLtMefInfo_t	mepLtMefInfo;									// Augmented information required by MEF
	bool			txLtmStatus;									// True if ready to send another LTM
	bool			txLtmResult;									// Indicates the result of the operation: -true:The Linktrace Message will be (or has been) sent. -false:The Linktrace Message will not be sent
	uint8_t			txLtmEgressId[8];								// Identifies the MEP Linktrace Initiator that is originating, or the Linktrace Responder that is forwarding, this LTM
	uint8_t			replyIdxList[MR_MAX_LTR_REPLY_LIST_LENGTH + 1];	// A list of available reply order indices. Indices start at 1. 0 indicates the end of the list. Typically 1,2,3..10. but if more than 10 replies then oldest indices are overwritten, e.g 11,12,3,4..10
} mepLtInfo_t;

typedef struct ltrReplyEntry_s
{
	uint8_t		rxOrderIdx;							// receive order
	uint8_t		flags;								// extracted from LTR header
	uint8_t		replyTtl;							// extracted from LTR header
	uint8_t		lastEgressId[8];					// extracted from LTR Egress Id TLV
	uint8_t		nextEgressId[8];					// extracted from LTR Egress Id TLV
	uint8_t		relayAction;						// extracted from LTR header
	uint8_t		ingressAction;						// extracted from reply ingress TLV (0 if no tlv)
	uint8_t		ingressAddress[6];					// extracted from reply ingress TLV (x if no tlv)
	uint8_t		ingressPortIdSubtype;				// extracted from reply ingress TLV (x if no tlv)
	uint8_t		ingressPortIdLen;					// extracted from reply ingress TLV (x if no tlv). Indicates the number of bytes valid in ingressPortId[]
	uint8_t		ingressPortId[MR_PORT_ID_SIZE];		// extracted from reply ingress TLV (x if no tlv)
	uint8_t		egressAction;						// extracted from reply egress TLV (0 if no tlv)
	uint8_t		egressAddress[6];					// extracted from reply egress TLV (x if no tlv)
	uint8_t		egressPortIdSubtype;				// extracted from reply egress TLV (x if no tlv)
	uint8_t		egressPortIdLen;					// extracted from reply egress TLV (x if no tlv). Indicates the number of bytes valid in egressPortId[]
	uint8_t		egressPortId[MR_PORT_ID_SIZE];		// extracted from reply egress TLV (x if no tlv)
	uint8_t		senderIdTlv[MR_MAX_SID_TLV_SIZE];
	uint8_t		orgTlv[MR_MAX_ORG_TLV_SIZE];
} ltrReplyEntry_t;

//--------------------------
// Function Prototypes
//--------------------------
/*
 * @brief Send an LTM from the specified MEP at a specified target
 *
 * @param[in] mdIndexThe MD index of the parent MD
 * @param[in] maIndex The MA index of the parent MA
 * @param[in] lMepId The MEPID of the local MEP to read from
 * @param[in] ltmTxInfo A pointer to a ltmTxInfo_t data type that specifies the TTL, flags and target MEP used.
 * @param[out] transIdUsed This value will be set to the value of the transaction ID used for this LTM request (device level incrementing value)
 *
 * @returns
 * \li  1: Invalid mep index
 * \li  2: The MAC address of tmepLtDbInfohe target MEPID is not yet known (must turn on CCM)
 * \li  3: Success
 * \li -1: Not enough RAM
 */
int	sendLTM(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, ltmTxInfo_t *ltmTxInfo, uint32_t *transIdUsed);

/*
 * @brief Retrieve any available reply information from a specified LTM
 *
 * LT replies for a given MEP + transitId can be retrieved using this function.
 * The reply database has only space for MR_MAX_LTR_REPLY_LIST_LENGTH entries. If
 * more than that are received then the oldest values are overwritten.
 *
 * @param[in] mdIndexThe MD index of the parent MD.
 * @param[in] maIndex The MA index of the parent MA.
 * @param[in] lMepId The MEPID of the local MEP to read from.
 * @param[in] transitId Specify the transaction ID of the specific LTM to retrieve the reply information on.
 * @param[out] ltmTxInfo A pointer to a ltmTxInfo_t that will be populate with the transmit configuration information used to send the LTM only if the function is successful.
 * @param[out] ltrReply A pointer to a ltrReplyListEntry_t type that will be populated with the reply information only if the function is successful.
 *
 * @returns
 * \li  1: There is no record of any LTM
 * \li  2: There is no record with a matching transit ID
 * \li  3: The reply List is empty
 * \li  5: Reply with index <ReplyIdx> not yet received
 * \li  5: Reply with index <ReplyIdx> has been overwritten
 * \li  6: Success
 */
int	getLTMReply(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId ,uint32_t transitId, uint8_t replyIdx, ltmTxInfo_t *ltmTxInfo, ltrReplyEntry_t *ltrReply);

/*
 * @brief Read the current link trace stats for a given MEP
 *
 * The Stats provide information for determining if a LTM can be sent or if the reply to a previous LTM have been received and if so what
 * sequence number was used. The getLTMReply() function can then be used to get the full reply results.
 * The stats also provide counts of valid send and received LTM and LTR and unexpected LTRs.
 *
 * @param[in] mdIndexThe MD index of the parent MD.
 * @param[in] maIndex The MA index of the parent MA.
 * @param[in] lMepId The MEPID of the local MEP to read from.
 * @param[out] mepLtInfo A pointer to a mepLtInfo_t struct that will be updated with the latest info if the function is successful.
 *
 * @returns
 * \li  1: The MEPID provided was invalid
 * \li  2: NULL pointer provided for mepLtInfo
 * \li  3: Success the value in mepLtInfo is valid
 */
int readLinktraceStats(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, mepLtInfo_t *mepLtInfo);

#if 0
/*
 * @brief Get the next Link trace transit ID in the reply database for a MEP
 *
 * If no results are available then a transit
 *
 * @param[in] mdIndexThe MD index of the parent MD.
 * @param[in] maIndex The MA index of the parent MA.
 * @param[in] lMepId The MEPID of the local MEP to read from.
 * @param[out] transitId A pointer to a uint32_t type that will be updated with the next Transit ID.
 *
 * @returns
 * true if there is a next transit ID.
 * false if there is no more available transit IDs for this MEP.
 */
bool getNextTransitId(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, uint32_t *transitId);
#endif
#endif /* MRLINKTRACE_H_ */
