text: /**
  * MIT License
  *
  * Copyright (c) 2018 Infineon Technologies AG
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  * copies of the Software, and to permit persons to whom the Software is
  * furnished to do so, subject to the following conditions:
  *
  * The above copyright notice and this permission notice shall be included in all
  * copies or substantial portions of the Software.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE
  *
  *
   * \file DtlsTransportLayer.c
   *
   * \brief This file provides APIs for the transport layer functionalities.
   *
   * \ingroup grOCP
   * @{ 
   *
   */
  
  #include "optiga/dtls/DtlsTransportLayer.h"
  #include "optiga/common/MemoryMgmt.h"
  
  #ifdef MODULE_ENABLE_DTLS_MUTUAL_AUTH
  
  /// @cond hidden
  
  /// @endcond
  /**
   * This API initialises transport layer communication structure.
   *
   * \param[in,out]  PpsTL Pointer to the transport layer communication structure
   *
   * \return  #OCP_TL_OK on successful execution
   * \return  #OCP_TL_ERROR on failure
   * \return  #OCP_TL_NULL_PARAM on parameter received is NULL
   * \return  #E_COMMS_UDP_ALLOCATE_FAILURE on failure to allocate memory
   */
  int32_t DtlsTL_Init(sTL_d* PpsTL)
  {
      int32_t i4Status = (int32_t)OCP_TL_ERROR;
      do
      {
          //NULL check
          if((NULL == PpsTL) || (NULL == PpsTL->pzIpAddress))
          {
              i4Status = (int32_t)OCP_TL_NULL_PARAM;
              break;
          }
  		
          //Allocate the memory for the ethernet communication structure
          PpsTL->phTLHdl = (pal_socket_t*)OCP_MALLOC(sizeof(pal_socket_t));
          if(NULL == PpsTL->phTLHdl)
          {
              i4Status = (int32_t)OCP_TL_MALLOC_FAILURE;
              break;
          }
  /// @cond hidden
  #define PS_COMMS_HANDLE ((pal_socket_t*)PpsTL->phTLHdl)
  /// @endcond
          
          PS_COMMS_HANDLE->wPort = PpsTL->wPort;
          
          //Converting IP address from string format to hex format
          i4Status = pal_socket_assign_ip_address(PpsTL->pzIpAddress,&(PS_COMMS_HANDLE->sIPAddress));
          if(i4Status != E_COMMS_SUCCESS)
          {
              break;
          }
          
          //Assigning the timeout value
          PS_COMMS_HANDLE->wTimeout = PpsTL->wTimeout ;
          
          //Non Blockage receive mode
          PS_COMMS_HANDLE->bMode = (uint8_t)PpsTL->eCallType;
          
          //Add logging
          LOG_TRANSPORTMSG("Initializing UDP Connection",eInfo);
          
          //Initialize the communication handle with the parameters 
          i4Status = pal_socket_init(PS_COMMS_HANDLE);
          if(E_COMMS_SUCCESS != i4Status)
          {
              break;
          }
          i4Status = (int32_t)OCP_TL_OK;
      }while(FALSE);
  	if(OCP_TL_OK != i4Status)
  	{
          if((NULL != PpsTL)&& (NULL != PpsTL->phTLHdl))
          {
              OCP_FREE(PpsTL->phTLHdl);
              PpsTL->phTLHdl = NULL;
          }
  	}
  /// @cond hidden
  #undef PS_COMMS_HANDLE
  /// @endcond
      return i4Status;
  }
  
  /**
   * This API creates client port
   *
   * \param[in,out]  PpsTL     Pointer to the transport layer communication structure
   *
   * \return  #OCP_TL_OK on successful execution
   * \return  #OCP_TL_NULL_PARAM on parameter received is NULL
   * \return  #E_COMMS_UDP_BINDING_FAILURE on port binding failure
   * \return  #OCP_TL_ERROR on failure
   */
  int32_t DtlsTL_Connect(sTL_d* PpsTL)
  {
      int32_t i4Status = (int32_t)OCP_TL_ERROR;
      do
      {
          //NULL check
          if((NULL == PpsTL) || (NULL == PpsTL->phTLHdl))
          {
              i4Status = (int32_t)OCP_TL_NULL_PARAM;
              break;
          }
  /// @cond hidden
  #define PS_COMMS_HANDLE ((pal_socket_t*)PpsTL->phTLHdl)
  /// @endcond                
          //Logging
          LOG_TRANSPORTMSG("Connecting to UDP",eInfo);
  
          //Open the client port with the port number initialised
          i4Status = pal_socket_connect(PS_COMMS_HANDLE, PS_COMMS_HANDLE->wPort);
          if(E_COMMS_SUCCESS != i4Status)
          {
              LOG_TRANSPORTMSG("Error connecting to UDP",eError);
              break;
          }
  
          PpsTL->eIsConnected = eConnected;
          i4Status = (int32_t)OCP_TL_OK;
      }while(FALSE);
  /// @cond hidden
  #undef PS_COMMS_HANDLE
  /// @endcond    
      return i4Status;
  }
  
  /**
   * This API transmits the data to the server.
   *
   * \param[in,out]  PpsTL               Pointer to the transport layer communication structure
   * \param[in]      PpbBuffer           Pointer to buffer containing data to be transmitted
   * \param[in]      PdwLen              Length of the data to be transmitted
   *
   * \return  #OCP_TL_OK on successful execution
   * \return  #OCP_TL_NULL_PARAM on parameter received is NULL
   * \return  #E_COMMS_UDP_NO_DATA_TO_SEND on no date present to send
   * \return  #E_COMMS_INSUFFICIENT_MEMORY on out of memory failure
   * \return  #E_COMMS_UDP_ROUTING_FAILURE on failure to route the UDP packet
   * \return  #E_COMMS_UDP_DEALLOCATION_FAILURE on failure to deallocate
   * \return  #OCP_TL_ERROR on failure
   */
  int32_t DtlsTL_Send(const sTL_d* PpsTL,uint8_t* PpbBuffer,uint16_t PdwLen)
  {
      int32_t i4Status = (int32_t)OCP_TL_ERROR;
      
      do
      {
          //NULL check
          if((NULL == PpsTL) || (NULL == PpsTL->phTLHdl) ||(NULL == PpbBuffer))
          {
              i4Status = (int32_t)OCP_TL_NULL_PARAM;
              break;
          }
          
          LOG_TRANSPORTDBARY("Sending Data over UDP", PpbBuffer, PdwLen, eInfo);
          
          //Send the data over IP address and Port initialized 
  /// @cond hidden
  #define PS_COMMS_HANDLE ((pal_socket_t*)PpsTL->phTLHdl)
  /// @endcond        
          i4Status = pal_socket_send(PS_COMMS_HANDLE, PpbBuffer, PdwLen);
          if (E_COMMS_SUCCESS != i4Status)
          {
              LOG_TRANSPORTMSG("Error while sending data",eError);
              break;
          }
          i4Status = (int32_t)OCP_TL_OK;
      }while(FALSE);
  /// @cond hidden    
  #undef PS_COMMS_HANDLE
  /// @endcond    
      return i4Status;
  }
  
  /**
   * This API receives the data from the server
   *
   * \param[in]       PpsTL               Pointer to the transport layer communication structure
   * \param[in,out]   PpbBuffer           Pointer to buffer where data is to be received
   * \param[in,out]   PpdwLen             Length of the buffer/Length of the received data
   *
   * \return  #OCP_TL_OK on successful execution
   * \return  #OCP_TL_NULL_PARAM on parameter received is NULL
   * \return  #OCP_TL_NO_DATA on no data received from the target
   * \return  #E_COMMS_INSUFFICIENT_BUF_SIZE on insufficient buffer size
   * \return  #OCP_TL_ERROR on failure
   */
  int32_t DtlsTL_Recv(const sTL_d* PpsTL,uint8_t* PpbBuffer,uint16_t* PpdwLen)
  {
      int32_t i4Status = (int32_t)OCP_TL_ERROR;
      uint32_t dwRecvLen;
      
      do
      {
          //NULL check
          if((NULL == PpsTL) || (NULL == PpsTL->phTLHdl) || (NULL == PpbBuffer))
          {
              i4Status = (int32_t)OCP_TL_NULL_PARAM;
              break;
          }
          //logging
          LOG_TRANSPORTMSG("Receiving over UDP",eInfo);
  /// @cond hidden        
  #define PS_COMMS_HANDLE ((pal_socket_t*)PpsTL->phTLHdl)
  /// @endcond
          
          PS_COMMS_HANDLE->wTimeout = PpsTL->wTimeout;
          
          dwRecvLen = *PpdwLen;
          
          //Listen the server port and receive the data
          i4Status = pal_socket_listen(PS_COMMS_HANDLE, PpbBuffer, &dwRecvLen);
          if ((int32_t)E_COMMS_UDP_NO_DATA_RECEIVED == i4Status)
          {
              i4Status = (int32_t)OCP_TL_NO_DATA;
              LOG_TRANSPORTMSG("No data received over UDP",eError);
              break;
          }
          
          if (E_COMMS_SUCCESS != i4Status)
          {
              LOG_TRANSPORTMSG("Error while receiving data over UDP",eError);
              break;
          }
          
          LOG_TRANSPORTMSG("Received Data",eInfo);
          LOG_TRANSPORTDBARY("Received Data over UDP", PpbBuffer, dwRecvLen, eInfo);
          
          *PpdwLen = (uint16_t)dwRecvLen;
          
          i4Status = (int32_t)OCP_TL_OK;
      }while(FALSE);
  /// @cond hidden    
  #undef PS_COMMS_HANDLE
  /// @endcond    
      return i4Status;
  }
  
  /**
   * This API closes the UDP communication and releases all the resources
   *
   * \param[in,out]  PpsTL     Pointer to the transport layer communication structure
   *
   * \return  None
   */
  Void DtlsTL_Disconnect(sTL_d* PpsTL)
  {
      
      //NULL check
      if(NULL != PpsTL)
      {
          if(NULL != PpsTL->phTLHdl)
          {
              //logging
              LOG_TRANSPORTMSG("Closing UDP Connection",eInfo);
  /// @cond hidden              
  #define PS_COMMS_HANDLE ((pal_socket_t*)PpsTL->phTLHdl)
  /// @endcond
              
              //Close the UDP connection
              pal_socket_close(PS_COMMS_HANDLE);
              
              //Free the allocated memory for ethernet structure
              OCP_FREE(PS_COMMS_HANDLE);
              
              PpsTL->phTLHdl = NULL;
              
  			PpsTL->eIsConnected = eDisconnected;
  /// @cond hidden 
  #undef PS_COMMS_HANDLE
  /// @endcond
          }
      }
  }
  
  /**
  * @}
  */
  #endif /*MODULE_ENABLE_DTLS_MUTUAL_AUTH*/
  