/**
* @file icss_learning.h
*
* @brief Include file for Learning/FDB implementation
*
* \par
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
* \par
*/

#ifndef _ICSS_LEARNING_H_
#define _ICSS_LEARNING_H_

/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "icss_common.h"
#include "icss_switch.h"
#include "icss_iSwitchDrv.h"

/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */
/**
* @def NUMBUCKETS
*      Number of Buckets in the learning table(per port)
*/
#define NUMBUCKETS 256
/**
* @def MAX_NUM_ENTRIES
*      Number of entries per Bucket
*/
#define MAX_NUM_ENTRIES 4
/**
* @def NUM_PORTS
*      Number of physical ports
*/
#define NUM_PORTS 2
/**
* @def AGEING_COUNT
*      used for ageing, higher value means entries age out slower, max value is 255
*/
#define AGEING_COUNT 4
/**
* @def COMPARE_MAC(x, y)
*
*/
#define COMPARE_MAC(x, y) !memcmp(x, y, 6)
/**
* @def COPY_MAC(dst, src)
*
*/
#define COPY_MAC(dst, src) memcpy(dst, src, 6);
/**
* @def COMPARE_MAC(x, y)
*
*/
#define COMPARE_MAC(x, y) !memcmp(x, y, 6)
/**
* @def COPY_MAC(dst, src)
*
*/
#define COPY_MAC(dst, src) memcpy(dst, src, 6);
/**
* @def tableSize
*
*/
#define tableSize 256


/**
* @brief Enum for different port states
*
*/
typedef enum {
	learning = 0,
	notLearning,
	locked

} portState;

/**
* @brief MAC ID
*
*/
typedef struct {
	Uint8 macId[6];       /**Mac ID stored as 6 unsigned char*/
} MAC;

/**
* @brief Structure for Individual bucket. A hash table is made up of several such buckets
*
*/
typedef struct {

	MAC mac[MAX_NUM_ENTRIES];			/**Four MAC Id per bucket*/
	Uint8 timerCount[MAX_NUM_ENTRIES];  /**Timer count used for ageing and conflict resolution*/
	Uint8 numEntries; 					/**Number of MAC entries in the bucket, 4 means it is full*/
} HashBucket;

/**
* @brief Structure for the Hash Table. To be declared as an array of two. One for each port
*
*/
typedef struct {

	uint32_t totalNumEntries;			/**Total number of entries in the hash table*/
	portState state;					/**State of the hash table, see enum portState above*/
	uint32_t  tableEpoch;				/**When the hash table was last renewed or updated, for DLR and other corner cases*/
	HashBucket  entries[NUMBUCKETS];	/**Number of bucket entries*/
} HashTable;

/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */

/**
* @brief Hash function for Learning/FDB algorithm
* @details Assumption is that the MAC is in little endian format
*
* @param  macId Stack src MAC ID of device
*
* @retval key hash key derived from the MAC ID
*/
Uint8 hashFuncGPMAC(const Uint8* macId);

/**
* @brief Update the learning table used to map MAC Id's and ports
*
* @param  macId MACID which is to be learned
* @param  portNum port number of incoming packet
*
* @retval none
*/
void updateHashTable(Uint8* macId, Uint8 portNum);
/**
* @brief Clear the Learning table associated with a given port
*
* @param portNum Port number whose learning table is to be flushed
*
* @retval none
*/
void purgeTable(Uint8 portNum);
/**
* @brief Remove old MAC entries from the table
*
* @param  portNum Portnumber whose learning table is to be flushed
*
* @retval none
*/
void ageingRoutine(Uint8 portNum);

/**
* @brief This takes in a hash key and the port number and removes the MAC ID if found in the other port
*
* @retval none
*/
void incrementCounter();

/**
* @brief Find given a MAC ID which port it exists
*
* @param  macId MAC ID which is to be found
*
* @retval portNumber where the MAC ID exists, 0 means not found 1 means port 0 and 2 means port 1
*/
Uint8 findMAC(const Uint8 * macId);
/**
* @brief Find given a MAC ID and remove it from the table
*
* @param  macId  MAC which is to be found
*
* @retval pass/fail. 0 means operation failed (mac not found)
*/
Uint8 removeMAC(Uint8 * macId);

/**
* @brief This takes in a hash key and the port number and removes the MAC ID if found in the other port
* @details This function contains an optimized subset of removeMAC. Used to remove duplicate MAC ID's
*
* @param  key  hash key for the MAC
* @param  macId  MAC which is to be removed from the other port
* @param  portNum  port number of the table which is being currently updated
*
* @retval pass or fail 0 means operation failed (mac not found)
*/
Uint8 checkDuplicateMAC(Uint8 key, Uint8* macId, Uint8 portNum);

/**
 * Name : hashFuncGPMAC_asm
 * The above function written in assembly
 */
Uint8 hashFuncGPMAC_asm(Uint8* macId);

/**
* @brief This takes in a hash key and the port number and removes the MAC ID if found in the other port
*
* @retval none
*/
void initLearningTable();

/*******************************************Port State Change Functions******************************/
/****************************************************************************************************/

/*Port State Change Functions*/

/**
* @brief Lock down the port from any changes, from NDK compatibility perspective
*
* @param  portNum port number
*
* @retval none
*/
void lockPort(Uint8 portNum);

/**
* @brief port is not learning any new addresses, deletions are allowed however
*         This is from NDK compatibility perspective
*
* @param  portNum port number
*
* @retval none
*/
void portNotLearning(Uint8 portNum);

/**
* @brief change the state to Learning. Port is now learning new addresses, this is the default state
*        This is from NDK compatibility perspective
*
* @param  portNum port number
*
* @retval none
*/
void portLearning(Uint8 portNum);
/**
* @brief API to copy Macaddress
*
* @param dst destination address
 * @param src source address
*
* @retval none
*/
void copyMAC(Uint8 *dst, Uint8 *src);
/**
* @brief Register the EIP callback for Supervisor learning exception
*
* @param  callBack call back function name
*
* @retval none
*/
void RegisterLearningCallBack(icssCallBackRet_t callBack);
/**
* @brief Register the EIP callback for Supervisor learning exception
*
* @param  callBack call back function name
*
* @retval none
*/
void RegisterLearningCallBack(icssCallBackRet_t callBack);

#endif /* _ICSS_LEARNING_H_ */
