/**
 * @file maputils.h
 *
 * @copyright
 * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
 *
 * @author Vivek <vivek.dutta@iopsys.eu>
 *
 * @brief This header file consists APIs that can be
 * used with MultiAP CMDUs and TLVs
 * See LICENSE file for license related information.
 *
 * Document References:
 * [1]: https://www.wi-fi.org/file/multi-ap-specification
 */

#ifndef MAPUTILS_H_
#define MAPUTILS_H_
#include "map2.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief API to get the relay specific information based on cmdu_type
 *
 * @param cmdu_type number based on map specification
 *
 * @return true if cmdu needs to be relayed
 * @return false if cmdu is for local node
 */
bool map_get_relay_bit(uint16_t cmdu_type);

/**
 * @brief API to validate if a message type is valid map cmdu type
 *
 * @param cmdu_type number based on map specification
 *
 * @return true if cmdu_type is valid map cmdu message_type
 * @return false if cmdu_type is not a valid map cmdu message_type
 */
bool map_validate_type(uint16_t cmdu_type);

/**
 * @brief API to get the type of transmission required for specific cmdu type
 *
 * @param cmdu_type number based on map specification
 *
 * @return 0 if required transmission is Unicast
 * @return 1 if required transmission is Reliable multicast
 * @return 2 if required transmission is Relayed multicast
 */
uint8_t map_get_transmission_type(uint16_t cmdu_type);

/**
 * @brief API to convert cmdu type numbers to human readable strings
 *
 * @param cmdu_type number based on map specification
 *
 * @return cmdu_string Human readable string corresponds to the cmdu_type
 */
char *map_stringify_cmdu_type(uint16_t cmdu_type);

/**
 * @brief API to convert human readable cmdu strings to cmdu_type, this API
 *        can only convert/transform stings matching with strings generated
 *        using map_stringify_cmdu_type
 *
 * @param cmdu_string Human readable cmdu string
 * @param cmdu_type cmdu_type will be updated if conversion is successful
 *
 * @return 1(true) if conversion is successful
 * @return 2(false) if conversion fails
 */
bool map_cmdu_string_to_type(char *cmdu_string, uint16_t *cmdu_type);

/**
 * @brief API to validate the cmdu stream structure, if it has all the required
 *        TLVs as per the selected profile and role
 *
 * @param p cmdu stream structure
 * @param profile 1 (PROFILE_1) validate against profile 1 type TLVs
 *                2 (PROFILE_2) validate against profile 2 type of TLVs
 * @param controller 0 (false), validation for map-agent
 *                   1 (true), validation for map-controller
 *
 * @return true if cmdu has all the required tlvs as per profile
 *               and controller
 *         false if cmdu has missing or extra tlvs as per profile
 *                and controller
 */
bool map_validate_cmdu_stream(const struct cmdu_stream *p,
			      uint8_t profile,
			      bool controller);

/**
 * @brief API to get profile type and map mode from TLV binary stream
 *        list, this API could be useful to find the profile and mode
 *        of incoming packets based on TLVs it have.
 *
 * @param p cmdu stream structure
 * @param profile This is an output parameter (NULL can be passed)
 *                 1(PROFILE_1), if cmdu has profile 1 type tlvs
 *                 2(PROFILE_2), if cmdu has profile 2 type of tlvs
 *                 0xff, profile not determined
 * @param mode This is an output parameter (NULL can be passed)
 *              0, if cmdu contains tlvs valid for map-agent
 *              1, if cmdu contains tlvs valid for map-controller
 *              0xff, mode not determined
 *
 * @return  true if cmdu has all the required tlvs
 *          false if cmdu has missing or extra tlvs
 */
bool map_get_profile_mode_cmdu_stream(const struct cmdu_stream *p,
				      uint8_t *profile,
				      uint8_t *mode);

/**
 * @brief API to free dynamically allocated cmdu c structure
 *
 * @param memory_structure cmdu c structure
 *
 */
void map_free_cmdu(struct cmdu_cstruct *memory_structure);

/**
 * @brief API to free tlv stream list used in cmdu stream
 *
 * @param packet_streams Dynamically allocated TLV binary array list
 * @param nbr_streams Number of streams to be freed
 *
 */
void map_free_tlv_stream_list(uint8_t **packet_streams, uint8_t nbr_streams);

/**
 * @brief API to compare two cmdu c structures
 *
 * @param cmdu_1 cmdu c structure
 * @param cmdu_2 cmdu c structure
 *
 * @return true if cmdu c-structures are equal
 */
bool map_compare_cmdu_cstruct(const struct cmdu_cstruct *cmdu_1,
			      const struct cmdu_cstruct *cmdu_2);

/**
 * @brief API to display the MAP cmdu validator, dump list of TLVs
 *        per CMDU along with profile
 */
void map_dump_cmdu_validator(void);

/**
 * @brief API to determine if the cmdu_type is a response message. This is
 * useful to know as the mid will be same for response message, whereas for
 * notifications and queries new mid will be used.
 *
 * @param cmdu_type cmdu type as described in map specification
 *
 * @return boolean true, if cmdu is a response message, false otherwise
 */
bool map_is_response_cmdu(uint16_t cmdu_type);

/**
 * @brief API to get the number of tlvs present in a binary stream when length
 * of binary stream is known
 *
 * @param tlv_stream Tlv binary stream
 * @param stream_len length of binary stream
 *
 * @return Count of tlvs present in the binary stream
 */
uint8_t map_count_tlvs_safe(uint8_t *tlv_stream, size_t stream_len);

/**
 * @brief API to get the number of tlvs present in a binary stream
 *
 * @param tlv_stream Tlv binary stream, tlv_stream must contain TLV_TYPE_END_OF_MESSAGE
 * at the end of the binary stream, if not present behaviour is unpredictable
 *
 * @return Count of tlvs present in the binary stream
 */
uint8_t map_count_tlvs_in_stream(uint8_t *tlv_stream);

/**
 * @brief API to convert a tlv binary stream into a tlv c structure
 *
 * @param packet_stream Binary tlv stream corresponding to one tlv
 *
 * @return NULL if conversion fails
 *         TLV C-structure if conversion succeeds
 *
 * @note 1. If more than one tlv present in binary packet_stream,
 *          API will only convert first one
 *	 2. TLV C structure is dynamically allocated and must freed
 *          by the caller after using it
 *       3. 'map_free_tlv_cstruct' API should be used with 'all'
 *          as true to free the returned TLV C-structure
 */
uint8_t *map_get_tlv_cstruct(uint8_t *packet_stream);

/**
 * @brief API to convert TLV C-structure to binary stream
 *
 * @param tlv_structure TLV C-structure
 * @param len Output parameter, contains length of tlv binary stream including
 * length of tlv_type and tlv_length fields. Null can be passed
 *
 * @return NULL if conversion fails
 * @return address base address of TLV binary array
 *
 * @note TLV binary array must be freed by the caller using 'free'
 */
uint8_t *map_put_tlv_cstruct(uint8_t *tlv_structure, uint16_t *len);

/**
 * @brief API to free dynamically allocated memory to tlv c strucure
 * including all the members
 *
 * @param tlv C structure of TLV to be freed
 */
void map_free_tlv_cstruct(uint8_t *tlv);

/**
 * @brief API to free dynamically allocated memory to the member of tlv c
 * strucure.
 *
 * @param tlv C structure of TLV whose members memory to be freed
 *
 */
void tlv_free_internal_members(uint8_t *tlv);

/**
 * @brief API to compare two tlv c structures
 *
 * @param tlv_1 tlv c structure
 * @param tlv_2 tlv c structure
 *
 * @return 0 (false), if tlv c structures are different
 * @return 1 (true), if tlv c structures are same
 */
bool map_compare_tlv_cstructs(uint8_t *tlv_1, uint8_t *tlv_2);

/**
 * @brief API to convert tlv type number to human readable string
 *
 * @param tlv_type, tlv type number as per the map specification
 *
 * @return Constant human readable string of tlv type, returned
 *         string should not be freed.
 */
char *map_stringify_tlv_type(uint8_t tlv_type);

/**
 * @brief API to get the length of TLV binary array, if more than one tlvs
 * present in tlv_stream, it will return the length of first tlv
 *
 * @param tlv_stream TLV binary stream
 *
 * @return length of complete binary TLV stream
 */
uint16_t map_get_first_tlv_length(uint8_t *tlv_stream);

/**
 * @brief Function to build a cmdu c-structure
 *
 * @param type cmdu message_type as defined in map specification
 * @param mid cmdu message_id as defined in map specs
 * @param rxif received interface name
 * @param srcmac source mac-address of received cmdu
 * @param tlvs Binary streams of tlvs associated with cmdu
 *
 * @return NULL if decoding fails
 * @return cmdu_cstruct if decoding succeeds
 */
 struct cmdu_cstruct *map_build_cmdu(uint16_t type, uint16_t mid,
				     const char *rxif, uint8_t *srcmac,
				     uint8_t *tlvs);

#ifdef __cplusplus
}
#endif

#endif				// END MAPUTILS_H_
