#ifndef SMPC_API_H_
#define SMPC_API_H_

/**
 ****************************************************************************************
 * @addtogroup SMPC_API Task
 * @ingroup SMPC
 * @brief Provides a SMP API for controller tasks.
 *
 * The SMPC api is responsible for all security protocol and secure connections handling.
 *
 * @{
 ****************************************************************************************
 */
/*
 * INCLUDE FILES
 ****************************************************************************************
 */


#include "rwip_config.h"
#if (BLE_SMPC)
#include "../smp_common.h"
#include "gap.h"
#include "gapc_task.h"
#include "l2cc_pdu.h"

/*
 * DEFINES
 ****************************************************************************************
 */


/// check if flag is set
#define SMPC_IS_FLAG_SET(conidx, flag)        ((gapc_env[conidx]->smpc.timer_state & flag) == flag)

#define SMPC_TIMER_SET_FLAG(conidx, flag)     (gapc_env[conidx]->smpc.timer_state |= flag)

#define SMPC_TIMER_UNSET_FLAG(conidx, flag)   (gapc_env[conidx]->smpc.timer_state &= ~flag)


/**
 * Timer State Masks
 */
/// Timeout Timer
#define SMPC_TIMER_TIMEOUT_FLAG                 (0x01)
/// Repeated Attempts Timer
#define SMPC_TIMER_REP_ATT_FLAG                 (SMPC_TIMER_TIMEOUT_FLAG << 1)
/// Blocked because of SMP Timeout
#define SMPC_TIMER_TIMEOUT_BLOCKED_FLAG         (SMPC_TIMER_REP_ATT_FLAG << 1)


/// SMPC Internal State Code
enum smpc_state
{
    SMPC_STATE_RESERVED     = 0x00,

    /********************************************************
     * Pairing Procedure
     ********************************************************/

    /**------------------------------------**
     * Pairing Features Exchange Phase      *
     **------------------------------------**/
    /// Is waiting for the pairing response
    SMPC_PAIRING_RSP_WAIT,
    /// Is waiting for the pairing features
    SMPC_PAIRING_FEAT_WAIT,

    /**------------------------------------**
     * Legacy (Pre BT 4.2 ) Authentication and Encryption Phase  *
     **------------------------------------**/

    /// Is waiting for the TK
    SMPC_PAIRING_TK_WAIT,
    /// Is waiting for the TK, peer confirm value has been received
    SMPC_PAIRING_TK_WAIT_CONF_RCV,
    /// Calculate the Random Number, part 1
    SMPC_PAIRING_GEN_RAND_P1,
    /// Calculate the Random Number, part 2
    SMPC_PAIRING_GEN_RAND_P2,
    /// The first part of the device's confirm value is being generated
    SMPC_PAIRING_CFM_P1,
    /// The device's confirm value is being generated
    SMPC_PAIRING_CFM_P2,
    /// The first part of the peer device's confirm value is being generated
    SMPC_PAIRING_REM_CFM_P1,
    /// The peer device's confirm value is being generated
    SMPC_PAIRING_REM_CFM_P2,
    /// The device is waiting for the confirm value generated by the peer device
    SMPC_PAIRING_WAIT_CONFIRM,
    /// The device is waiting for the random value generated by the peer device
    SMPC_PAIRING_WAIT_RAND,
    /// The STK is being generated
    SMPC_PAIRING_GEN_STK,

    #if (SECURE_CONNECTIONS)
    /**------------------------------------**
     * Secure Connections (BT 4.2 ) Authentication and Encryption Phase  *
     **------------------------------------**/
     SMPC_PAIRING_SC_W4_PEER_PUBLIC_KEY,

     // Just Works and Numeric Comparison
     //---------------------------------

     // In Just Works/Numeric Comparison - this state is used while
     // we are waiting for the LL to generate a Rand.
     SMPC_PAIRING_SC_W4_LOCAL_RAND_N_P1,
     SMPC_PAIRING_SC_W4_LOCAL_RAND_N_P2,
     // Used in Slave during F4 while waiting for AES_CMAC
     SMPC_PAIRING_SC_W4_F4_COMMITMENT_DETERMINATION,

     // Used in Master to Wait for Peer Commitment Cb
     SMPC_PAIRING_SC_W4_PEER_COMMITMENT,

     // Used in Master/Slave to Wait for Random Number From peer.
     SMPC_PAIRING_SC_W4_PEER_RAND,

     // Used in Slave to wait for Random Number Na from Master
    // SMPC_PAIRING_SC_W4_PAIRING_Na,

     // Used in Master during F4 calculation for Commitment Check
     SMPC_PAIRING_SC_W4_F4_COMMITMENT_CHECK,

     // Numeric Comparison
     // States specific to Secure Commenctions - numeric comparison

     // Used in both Master/Slave to wait for the AES-CMAC calculation does to calculated the
     // PassCode for the user.

     SMPC_PAIRING_SC_W4_G2_AES_CMAC,

     // Wait for the user to enter Accept/Reject for the Numeric Value
     SMPC_PAIRING_SC_W4_NC_ACCEPT,
     // Used in both Master/Slave while waiting for the user Pass Code Confirmation.

     SMPC_PAIRING_SC_W4_USER_PASSCODE_CONFIRMATION,

     //-----------------------------
     // Secure Connections - Passkey
     //-----------------------------

    // Used in both Master/Slave while the user is entering the PassKey
    SMPC_PAIRING_SC_PASSKEY_W4_PASSKEY_RAND,

    // Used in both Master/Slave while Random numbers Nai,Nbi are being generated.
    SMPC_PAIRING_SC_PASSKEY_W4_LOCAL_RAND_N_P1,

    // Used in both Master/Slave while Random numbers Nai,Nbi are being generated.
    SMPC_PAIRING_SC_PASSKEY_W4_LOCAL_RAND_N_P2,

    // Used in both Master/Slave while waiting for the commitment value Cai,Cbi from the peer
    SMPC_PAIRING_SC_PASSKEY_W4_PEER_COMMITMENT,

    // Used in both Master/Slave while using AES_CMAC during F4 calculation of the commitment
    SMPC_PAIRING_SC_PASSKEY_W4_F4_COMMITMENT_DETERMINATION,

    // Used in both Master/Slave while waiting for the random number Nai,Nbi from the peer
    SMPC_PAIRING_SC_PASSKEY_W4_PEER_RAND,

    // Used in both Master/Slave while using AES_CMAC during F4 calculation for the commitment check
    SMPC_PAIRING_SC_PASSKEY_W4_F4_COMMITMENT_CHECK,


    // OOB
    SMPC_PAIRING_SC_OOB_W4_LOCAL_RAND_N_P1,

    SMPC_PAIRING_SC_OOB_W4_LOCAL_RAND_N_P2,

    SMPC_PAIRING_SC_OOB_W4_LOCAL_RAND_R_P1,

    SMPC_PAIRING_SC_OOB_W4_LOCAL_RAND_R_P2,

    SMPC_PAIRING_SC_OOB_W4_F4_COMMITMENT_DETERMINATION,

    SMPC_PAIRING_SC_OOB_W4_F4_COMMITMENT_CHECK,

    SMPC_PAIRING_SC_OOB_W4_PEER_RAND,

    // Wait for OOB data (A,Ca,Ra OR B,Cb,Rb) to be recieved from Peer.
    SMPC_PAIRING_SC_OOB_W4_OOB_DATA,

    // Secure Connections Authentication Phase 2

    // Wait for the AES_CMACsalt to generate T
    SMPC_PAIRING_SC_W4_F5_P1,

    // Wait for the AES_CMAC to generate MACKEY
    SMPC_PAIRING_SC_W4_F5_P2,

    // Wait for the AES_CMAC to generate LTK
    SMPC_PAIRING_SC_W4_F5_P3,

    // Wait for the AES_CMAC to complete the DHKEY check
    SMPC_PAIRING_SC_W4_F6_DHKEY_CHECK,

    // Wait for DHkey_Check from the peer
    SMPC_PAIRING_SC_W4_PEER_DHKEY_CHECK,

    SMPC_PAIRING_SC_W4_F6_DHKEY_VERIFICATION,

    SMPC_PAIRING_SC_W4_DHKEY_KEY_COMPLETE,

    SMPC_PAIRING_SC_W4_ENCRYPTION_START,

    SMPC_PAIRING_SC_W4_ENCRYPTION_CHANGE,

    #endif //  (SECURE_CONNECTIONS)
    /**------------------------------------**
     * Transport Keys Distribution Phase    *
     **------------------------------------**/

    /// Default pairing remote waiting state
    SMPC_PAIRING_APP_WAIT,
    /// Is waiting for the LTK from application
    SMPC_PAIRING_APP_LTK_WAIT,
    /// Is waiting for the Identity Resolving Key from application
    SMPC_PAIRING_APP_IRK_WAIT,
    /// Is waiting for the CSRK from application
    SMPC_PAIRING_APP_CSRK_WAIT,


    /// Default pairing remote waiting state
    SMPC_PAIRING_REM_WAIT,
    /// Is waiting for the remote LTK
    SMPC_PAIRING_REM_LTK_WAIT,
    /// Is waiting for the remote EDIV and Rand Value
    SMPC_PAIRING_REM_MST_ID_WAIT,
    /// Is waiting for the remote IRK
    SMPC_PAIRING_REM_IRK_WAIT,
    /// Is waiting for the remote BD Address
    SMPC_PAIRING_REM_BD_ADDR_WAIT,
    /// Is waiting for the remote CSRK
    SMPC_PAIRING_REM_CSRK_WAIT,

    /********************************************************
     * Signing Procedure
     ********************************************************/
    /// Generation of L
    SMPC_SIGN_L_GEN,
    /// Generation of Ci
    SMPC_SIGN_Ci_GEN,

    /********************************************************
     * Encryption Procedure (STK or LTK)
     ********************************************************/
    /// Is waiting the change encryption event with LTK
    SMPC_START_ENC_LTK,
    /// Is waiting the change encryption event with STK
    SMPC_START_ENC_STK
};

/*
 * FUNCTION DEFINITION
 ****************************************************************************************
 */

#if (BLE_CENTRAL)
/**
 ****************************************************************************************
 * @brief Handles pairing request from GAP, start the pairing procedure
 *
 * @param[in] idx     Connection Index
 * @param[in] pairing Pairing Information
 *
 * @return Status of Pairing start
 ****************************************************************************************
 */
uint8_t smpc_pairing_start(uint8_t idx, struct gapc_pairing  *pairing);
#endif // (BLE_CENTRAL)


/**
 ****************************************************************************************
 * @brief Handles TK exchange part of pairing
 *
 * @param[in] idx     Connection Index
 * @param[in] accept  True if pairing is accepted, False else
 * @param[in] tk      The TK transmitted by application
 *
 * @return status of pairing
 ****************************************************************************************
 */
uint8_t smpc_pairing_tk_exch(uint8_t idx, bool accept,  struct gap_sec_key *tk);

/**
 ****************************************************************************************
 * @brief Handles LTK exchange part of pairing
 *
 * @param[in] idx     Connection Index
 * @param[in] ltk     The LTK transmitted by application
 *
 * @return status of pairing
 ****************************************************************************************
 */
uint8_t smpc_pairing_ltk_exch(uint8_t idx, struct gapc_ltk* ltk);


/**
 ****************************************************************************************
 * @brief Handles IRK exchange part of pairing
 *
 * @param[in] idx      Connection Index
 * @param[in] irk      The IRK transmitted by application
 * @param[in] identity Device identity address
 *
 * @return status of pairing
 ****************************************************************************************
 */
uint8_t smpc_pairing_irk_exch(uint8_t idx, struct gap_sec_key* irk, struct gap_bdaddr *identity);

/**
 ****************************************************************************************
 * @brief Handles CSRK exchange part of pairing
 *
 * @param[in] idx     Connection Index
 * @param[in] csrk    The CSRK transmitted by application
 *
 * @return status of pairing
 ****************************************************************************************
 */
uint8_t smpc_pairing_csrk_exch(uint8_t idx, struct gap_sec_key *csrk);

#if (SECURE_CONNECTIONS)
/**
 ****************************************************************************************
 * @brief Handles OOB exchange part of pairing
 *
 * @param[in] idx     Connection Index
 * @param[in] accept  Accept or Reject the OOB (reject if OOB reception not available on the device)
 * @param[in] csrk    The OOB Confirm and OOB Rand from the peer
 *
 * @return status of pairing
 ****************************************************************************************
 */

uint8_t smpc_pairing_oob_exch(uint8_t idx, bool accept, struct gapc_oob *oob);

/**
 ****************************************************************************************
 * @brief Handles Numeric Value Acceptance as part of pairing
 *
 * @param[in] idx     Connection Index
 * @param[in] accept  Accept or Reject the numeric comparison
 *
 * @return status of pairing
 ****************************************************************************************
 */

uint8_t smpc_pairing_nc_exch(uint8_t idx,uint8_t accept );

#endif //  (SECURE_CONNECTIONS)
/**
 ****************************************************************************************
 * @brief Handles reception of pairing response information
 *
 * @param[in] idx     Connection Index
 * @param[in] accept  True if pairing is accepted, False else
 * @param[in] feat    Pairing response feature information
 *
 * @return status of pairing
 ****************************************************************************************
 */
uint8_t smpc_pairing_rsp(uint8_t idx, bool accept, struct gapc_pairing *feat);


#if (BLE_PERIPHERAL)

/**
 ****************************************************************************************
 * @brief Handles reception of pairing request information
 *
 * @param[in] idx     Connection Index
 * @param[in] feat    Pairing request feature information
 ****************************************************************************************
 */
void smpc_pairing_req_handler(uint8_t idx, struct gapc_pairing *feat);

/**
 ****************************************************************************************
 * @brief Handles request to send a security request to peer device
 *
 * @param[in] idx     Connection Index
 * @param[in] auth    Requested Authentication Level
 *
 * @return status of the request
 ****************************************************************************************
 */
uint8_t smpc_security_req_send(uint8_t idx, uint8_t auth);
#endif // (BLE_PERIPHERAL)


#if (BLE_CENTRAL)
/**
 ****************************************************************************************
 * @brief Master requests to start encryption
 *
 * @param[in] idx     Connection Index
 * @param[in] ltk     LTK information
 *
 * @return status of the request
 ****************************************************************************************
 */
uint8_t smpc_encrypt_start(uint8_t idx, struct gapc_ltk *ltk);
#endif //(BLE_CENTRAL)


#if (BLE_PERIPHERAL)

/**
 ****************************************************************************************
 * @brief Handles reception of encryption request
 *
 * @param[in] idx     Connection Index
 * @param[in] ltk     LTK to search information
 ****************************************************************************************
 */
void smpc_encrypt_start_handler(uint8_t idx, struct gapc_ltk *ltk);

/**
 ****************************************************************************************
 * @brief Slave respond to peer device encryption request
 *
 * @param[in] idx      Connection Index
 * @param[in] accept   Accept or not to start encryption
 * @param[in] ltk      LTK information
 * @param[in] key_size Encryption key size
 ****************************************************************************************
 */
void smpc_encrypt_cfm(uint8_t idx, bool accept, struct gap_sec_key *ltk, uint8_t key_size);
#endif //(BLE_PERIPHERAL)


/**
 ****************************************************************************************
 * @brief Request to sign an attribute packet or check signature
 *
 * @param[in] idx      Connection Index
 * @param[in] param    ATT packet information
 *
 * @return status of signature request
 ****************************************************************************************
 */
uint8_t smpc_sign_command(uint8_t idx, struct gapc_sign_cmd *param);


/**
 ****************************************************************************************
 * @brief Continue signature generation or check of an attribute packet after an AES.
 *
 * @param[in] idx      Connection Index
 * @param[in] aes_res  Result of AES calculation
 ****************************************************************************************
 */
void smpc_sign_cont(uint8_t idx, uint8_t* aes_res);

/**
 ****************************************************************************************
 * @brief Continue generation of rand number for confirm value.
 *
 * @param[in] idx      Connection Index
 * @param[in] randnb   Generated Random Number
 ****************************************************************************************
 */
void smpc_confirm_gen_rand(uint8_t idx, rand_nb_t* randnb);

/**
 ****************************************************************************************
 * @brief Continue Calculation of Confirm Value or STK after AES.
 *
 * @param[in] idx      Connection Index
 * @param[in] aes_res  Result of AES calculation
 ****************************************************************************************
 */
void smpc_calc_confirm_cont(uint8_t idx, uint8_t* aes_res);

/**
 ****************************************************************************************
 * @brief Send an KeyPress Notification Event to the Host
 *
 * @param[in] idx      Connection Index
 * @param[in] keypress KeyPress Type
 ****************************************************************************************
 */
void smpc_key_press_notification_ind(uint8_t idx, uint8_t keypress);

/**
 ****************************************************************************************
 * @brief Stop the timer used to detect a SMP Timeout
 *
 * @param[in] conidx        Connection Index
 ****************************************************************************************
 */
void smpc_clear_timeout_timer(uint8_t conidx);


/**
 ****************************************************************************************
 * @brief Handle reception of a SMP PDU sent by the peer device.
 *
 * @param[in] conidx        Connection Index
 * @param[in] pdu           Unpacked PDU
 ****************************************************************************************
 */
void smpc_pdu_recv(uint8_t conidx, struct l2cc_pdu *pdu);

/**
 ****************************************************************************************
 * @brief Send a SMP PDU to the peer device
 *
 * @param[in] conidx        Connection Index
 * @param[in] cmd_code      Code of the PDU to send
 * @param[in] value         Unpacked value
 ****************************************************************************************
 */
void smpc_pdu_send(uint8_t conidx, uint8_t cmd_code, void *value);


/**
 ****************************************************************************************
 * @brief Inform the HL that the pairing procedure currently in progress is over.
 *
 * @param[in] conidx          Connection Index
 * @param[in] role            Current role of the device
 * @param[in] status          Status
 * @param[in] start_ra_timer  Indicate if the repeated attempts timer shall be started in
 *                            the case of a pairing failed.
 ****************************************************************************************
 */
void smpc_pairing_end(uint8_t conidx, uint8_t role, uint8_t status, bool start_ra_timer);


/**
 ****************************************************************************************
 * @brief Handle reception of a DH Key from HCI
 *
 * @param[in] conidx        Connection Index
 * @param[in] status        Indicates if HCI request Succeeded or Failed
 * @param[in] dh_key        Diffie Helman Key - 32 Bytes
 ****************************************************************************************
 */
void smpc_handle_dh_key_check_complete(uint8_t conidx,const uint8_t* dh_key);

#endif // (BLE_SMPC)
#endif //(SMPC_API_H_)

/// @} SMPC_API
