text: /*
   * FreeRTOS Secure Sockets for NXP54018_IoT_Module V1.0.0 Beta 4
   * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
   *
   * 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.
   *
   * http://aws.amazon.com/freertos
   * http://www.FreeRTOS.org
   */
  
  /*
   * Copyright (C) NXP 2017.
   */
  
  /* FreeRTOS includes. */
  #include "FreeRTOS.h"
  #include "iot_secure_sockets.h"
  #include "iot_tls.h"
  #include "task.h"
  
  /* Third-party wifi driver include. */
  #include "qcom_api.h"
  #include "iot_wifi.h"
  #include "custom_stack_offload.h"
  #include "atheros_stack_offload.h"
  
  /**
   * @brief Flag indicating that socket send operations are not permitted.
   *
   * If a WR shutdown in SOCKETS_Shutdown() is invoked, this flag is
   * set in the socket's xShutdownFlags member.
   */
  #define nxpsecuresocketsSOCKET_WRITE_CLOSED_FLAG    ( 1UL << 2 )
  
  /**
   * @brief Flag indicating that socket receive operations are not permitted.
   *
   * If a RD shutdown in SOCKETS_Shutdown() is invoked, this flag is
   * set in the socket's xShutdownFlags member.
   */
  #define nxpsecuresocketsSOCKET_READ_CLOSED_FLAG     ( 1UL << 1 )
  
  /**
   * @brief Delay used between network select attempts when effecting a receive timeout.
   *
   * Timeouts are mocked in the secure sockets layer, and this constant sets the
   * sleep time between each read attempt during the receive timeout period.
   */
  #define nxpsecuresocketsFIVE_MILLISECONDS           ( pdMS_TO_TICKS( 5 ) )
  
  /**
   * @brief The timeout supplied to the t_select function.
   *
   * Receive timeout are emulated in secure sockets layer and therefore we
   * do not want the Inventek module to block. Setting to zero means
   * no timeout, so one is the smallest value we can set it to.
   */
  #define nxpsecuresocketsONE_MILLISECOND             ( 1 )
  #define nxpsecuresocketsSOCKET_CONNECTED_FLAG       ( 1 )
  
  /* Internal context structure. */
  typedef struct SSOCKETContext
  {
      Socket_t xSocket;
      char * pcDestination;
      void * pvTLSContext;
      BaseType_t xRequireTLS;
      BaseType_t xSendFlags;
      BaseType_t xRecvFlags;
      BaseType_t xShutdownFlags;
      uint32_t ulSendTimeout;
      uint32_t ulRecvTimeout;
      char * pcServerCertificate;
      uint32_t ulServerCertificateLength;
      uint32_t ulState;
  } SSOCKETContext_t, * SSOCKETContextPtr_t;
  
  #define SOCKETS_INVALID_CONTEXT		( ( SSOCKETContextPtr_t ) ~0U )
  
  /*
   * Helper routines.
   */
  
  /*
   * @brief Network send callback.
   */
  static BaseType_t prvNetworkSend( void * pvContext,
                                    const unsigned char * pucData,
                                    size_t xDataLength )
  {
      SSOCKETContextPtr_t pxContext = ( SSOCKETContextPtr_t ) pvContext;
  
      /* Do not send data on unconnected socket */
      if( !( pxContext->ulState & nxpsecuresocketsSOCKET_CONNECTED_FLAG ) )
      {
          return -1;
      }
  
      char * sendBuf = custom_alloc( xDataLength );
  
      if( sendBuf == NULL )
      {
          return -1;
      }
  
      memcpy( sendBuf, pucData, xDataLength );
      int ret = qcom_send( ( int ) pxContext->xSocket,
                           sendBuf,
                           xDataLength,
                           pxContext->xSendFlags );
      custom_free( sendBuf );
  
      return ret;
  }
  
  
  
  /*-----------------------------------------------------------*/
  
  
  QCA_CONTEXT_STRUCT * wlan_get_context( void );
  
  /*
   * @brief Network receive callback.
   */
  static BaseType_t prvNetworkRecv( void * pvContext,
                                    unsigned char * pucReceiveBuffer,
                                    size_t xReceiveLength )
  {
      SSOCKETContextPtr_t pxContext = ( SSOCKETContextPtr_t ) pvContext;
      TickType_t xTimeOnEntering = xTaskGetTickCount();
  
      /* Do not receive data on unconnected socket */
      if( !( pxContext->ulState & nxpsecuresocketsSOCKET_CONNECTED_FLAG ) )
      {
          return -1;
      }
  
      QCA_CONTEXT_STRUCT * enetCtx = wlan_get_context();
      A_STATUS xStatus;
  
      char * buffLoc = NULL;
      int xRetVal = 0;
  
      for( ; ; )
      {
          /* Check if there is anything to be received on this socket. */
          xStatus = ( A_STATUS ) t_select( enetCtx,
                                           ( uint32_t ) pxContext->xSocket,
                                           nxpsecuresocketsONE_MILLISECOND );
  
          if( xStatus == A_OK ) /* Data available. */
          {
              xRetVal = qcom_recv( ( int ) pxContext->xSocket, &buffLoc, xReceiveLength, 0 );
  
              if( xRetVal > 0 ) /* Data received. */
              {
                  memcpy( pucReceiveBuffer, buffLoc, xRetVal );
                  break;
              }
              else /* Error occured. */
              {
                  /*int errno = t_errno( wlan_get_context(), ( uint32_t ) pxContext->xSocket ); */
                  xRetVal = SOCKETS_SOCKET_ERROR;
                  break;
              }
          }
          else if( xStatus == A_ERROR ) /* A_ERROR is returned from t_select on timeout. */
          {
              if( ( xTaskGetTickCount() - xTimeOnEntering ) < pxContext->ulRecvTimeout )
              {
                  vTaskDelay( nxpsecuresocketsFIVE_MILLISECONDS );
              }
              else
              {
                  xRetVal = 0;
                  break;
              }
          }
          else
          {
              xRetVal = SOCKETS_SOCKET_ERROR;
              break;
          }
      }
  
      if( buffLoc != NULL )
      {
          zero_copy_free( buffLoc );
      }
  
      return xRetVal;
  }
  /*-----------------------------------------------------------*/
  
  /*
   * Interface routines.
   */
  
  int32_t SOCKETS_Close( Socket_t xSocket )
  {
      SSOCKETContextPtr_t pxContext = ( SSOCKETContextPtr_t ) xSocket;
      int32_t lStatus = SOCKETS_ERROR_NONE;
  
      if( ( NULL != pxContext ) && ( SOCKETS_INVALID_CONTEXT != pxContext ) )
      {
          pxContext->ulState = 0;
  
          if( NULL != pxContext->pcDestination )
          {
              vPortFree( pxContext->pcDestination );
          }
  
          if( NULL != pxContext->pcServerCertificate )
          {
              vPortFree( pxContext->pcServerCertificate );
          }
  
          if( pdTRUE == pxContext->xRequireTLS )
          {
              TLS_Cleanup( pxContext->pvTLSContext );
          }
  
          qcom_socket_close( ( int ) pxContext->xSocket );
          vPortFree( pxContext );
      }
      else
      {
          lStatus = SOCKETS_EINVAL;
      }
  
      return lStatus;
  }
  /*-----------------------------------------------------------*/
  
  int32_t SOCKETS_Connect( Socket_t xSocket,
                           SocketsSockaddr_t * pxAddress,
                           Socklen_t xAddressLength )
  {
      int32_t xStatus = SOCKETS_ERROR_NONE;
      SSOCKETContextPtr_t pxContext = ( SSOCKETContextPtr_t ) xSocket;
      TLSParams_t xTLSParams = { 0 };
      SOCKADDR_T xTempAddress = { 0 };
  
      if( ( SOCKETS_INVALID_CONTEXT != pxContext ) && ( NULL != pxAddress ) && WIFI_IsConnected( NULL ))
      {
          /* Connect the wrapped socket. */
  
  
          /* The driver code expects the endianess of the address and port in host order and then swaps before
           * sending the connection data to the firmware. */
          xTempAddress.sin_addr.s_addr = SOCKETS_ntohl( pxAddress->ulAddress );
          xTempAddress.sin_family = pxAddress->ucSocketDomain;
          xTempAddress.sin_port = SOCKETS_ntohs( pxAddress->usPort );
          xStatus = qcom_connect( ( int ) pxContext->xSocket,
                                  ( struct sockaddr * ) &xTempAddress,
                                  xAddressLength );
  
          /* Keep socket state - connected */
          if( SOCKETS_ERROR_NONE == xStatus )
          {
              pxContext->ulState |= nxpsecuresocketsSOCKET_CONNECTED_FLAG;
          }
  
          /* Negotiate TLS if requested. */
          if( ( SOCKETS_ERROR_NONE == xStatus ) && ( pdTRUE == pxContext->xRequireTLS ) )
          {
              xTLSParams.ulSize = sizeof( xTLSParams );
              xTLSParams.pcDestination = pxContext->pcDestination;
              xTLSParams.pcServerCertificate = pxContext->pcServerCertificate;
              xTLSParams.ulServerCertificateLength = pxContext->ulServerCertificateLength;
              xTLSParams.pvCallerContext = pxContext;
              xTLSParams.pxNetworkRecv = prvNetworkRecv;
              xTLSParams.pxNetworkSend = prvNetworkSend;
              xStatus = TLS_Init( &pxContext->pvTLSContext, &xTLSParams );
  
              if( SOCKETS_ERROR_NONE == xStatus )
              {
                  xStatus = TLS_Connect( pxContext->pvTLSContext );
  
                  /* Report positive error codes as negative number */
                  xStatus = xStatus > 0 ? SOCKETS_TLS_HANDSHAKE_ERROR : xStatus;
              }
          }
      }
      else
      {
          xStatus = SOCKETS_SOCKET_ERROR;
      }
  
      return xStatus;
  }
  /*-----------------------------------------------------------*/
  
  
  /* Convert IP address in uint32_t to comma separated bytes. */
  #define UINT32_IPADDR_TO_CSV_BYTES( a )                     \
      ( ( ( a ) >> 24 ) & 0xFF ), ( ( ( a ) >> 16 ) & 0xFF ), \
      ( ( ( a ) >> 8 ) & 0xFF ), ( ( a ) & 0xFF )
  
  /*-----------------------------------------------------------*/
  
  uint32_t SOCKETS_GetHostByName( const char * pcHostName )
  {
      uint32_t ulAddr = 0;
  
      if( strlen( pcHostName ) <= ( size_t ) securesocketsMAX_DNS_NAME_LENGTH )
      {
          WIFI_GetHostIP( ( char * ) pcHostName, ( uint8_t * ) &ulAddr );
          configPRINTF( ( "Looked up %s as %d.%d.%d.%d\r\n",
                          pcHostName,
                          UINT32_IPADDR_TO_CSV_BYTES( ulAddr ) ) );
      }
      else
      {
          configPRINTF( ( "Malformed URL, Host name: %s is too long.", pcHostName ) );
      }
  
      /* This api is to return the address in network order. WIFI_GetHostIP returns the host IP
       * in host order.
       */
      ulAddr = SOCKETS_htonl( ulAddr );
  
      return ulAddr;
  }
  
  /*-----------------------------------------------------------*/
  
  int32_t SOCKETS_Recv( Socket_t xSocket,
                        void * pvBuffer,
                        size_t xBufferLength,
                        uint32_t ulFlags )
  {
      int32_t lStatus = SOCKETS_ERROR_NONE;
      SSOCKETContextPtr_t pxContext = ( SSOCKETContextPtr_t ) xSocket;
  
  
      if( ( SOCKETS_INVALID_SOCKET != xSocket ) &&
          ( NULL != pvBuffer ) &&
          ( ( nxpsecuresocketsSOCKET_READ_CLOSED_FLAG & pxContext->xShutdownFlags ) == 0UL ) &&
          ( pxContext->ulState & ( nxpsecuresocketsSOCKET_CONNECTED_FLAG ) )
          )
      {
          pxContext->xRecvFlags = ( BaseType_t ) ulFlags;
          if( pdTRUE == pxContext->xRequireTLS )
          {
              /* Receive through TLS pipe, if negotiated. */
              lStatus = TLS_Recv( pxContext->pvTLSContext, pvBuffer, xBufferLength );
          }
          else
          {
              /* Receive unencrypted. */
              lStatus = prvNetworkRecv( pxContext, pvBuffer, xBufferLength );
          }
      }
      else
      {
          lStatus = SOCKETS_SOCKET_ERROR;
      }
  
      return lStatus;
  }
  /*-----------------------------------------------------------*/
  
  int32_t SOCKETS_Send( Socket_t xSocket,
                        const void * pvBuffer,
                        size_t xDataLength,
                        uint32_t ulFlags )
  {
      /* The WiFi module refuses to send data if it exceeds this threshold defined in
       * atheros_stack_offload.h */
      uint32_t ulSendMaxLength = IPV4_FRAGMENTATION_THRESHOLD;
      int32_t lWritten = 0, lWrittenPerLoop = 0;
      SSOCKETContextPtr_t pxContext = ( SSOCKETContextPtr_t ) xSocket;
  
      if( ( SOCKETS_INVALID_CONTEXT != pxContext ) &&
          ( NULL != pvBuffer ) &&
          ( ( nxpsecuresocketsSOCKET_WRITE_CLOSED_FLAG & pxContext->xShutdownFlags ) == 0UL ) &&
          ( pxContext->ulState & ( nxpsecuresocketsSOCKET_CONNECTED_FLAG ) )
          )
      {
          pxContext->xSendFlags = ( BaseType_t ) ulFlags;
  
          if( pdTRUE == pxContext->xRequireTLS )
          {
              /* In case of TLS, reserve extra space for SSL meta data (header, maclen, ivlen, ... = 45B) */
              ulSendMaxLength = 1531;
  
              for(
                  uint32_t ulToRemain = xDataLength, ulBufferPos = 0, ulToSend = 0;
                  ulToRemain;
                  ulBufferPos += ulToSend, ulToRemain -= ulToSend
                  )
              {
                  ulToSend = ulToRemain > ulSendMaxLength ? ulSendMaxLength : ulToRemain;
                  /* Send through TLS pipe, if negotiated. */
                  lWrittenPerLoop = TLS_Send( pxContext->pvTLSContext,
                                              &( ( unsigned char const * ) pvBuffer )[ ulBufferPos ],
                                              ulToSend );
  
                  /* Error code < 0. */
                  if( lWrittenPerLoop < 0 )
                  {
                      /* Set the error code to be returned */
                      lWritten = lWrittenPerLoop;
                      break;
                  }
  
                  /* Number of lWritten bytes. */
                  lWritten += lWrittenPerLoop;
  
                  if( lWrittenPerLoop != ulToSend )
                  {
                      break;
                  }
              }
          }
          else
          {
              for(
                  uint32_t ulToRemain = xDataLength, ulBufferPos = 0, ulToSend = 0;
                  ulToRemain;
                  ulBufferPos += ulToSend, ulToRemain -= ulToSend
                  )
              {
                  ulToSend = ulToRemain > ulSendMaxLength ? ulSendMaxLength : ulToRemain;
                  lWrittenPerLoop = prvNetworkSend( pxContext,
                                                    &( ( unsigned char const * ) pvBuffer )[ ulBufferPos ],
                                                    ulToSend );
  
                  /* Error code < 0. */
                  if( lWrittenPerLoop < 0 )
                  {
                      /* Set the error code to be returned */
                      lWritten = lWrittenPerLoop;
                      break;
                  }
  
                  /* Number of lWritten bytes. */
                  lWritten += lWrittenPerLoop;
  
                  if( lWrittenPerLoop != ulToSend )
                  {
                      break;
                  }
              }
          }
      }
      else
      {
          lWritten = SOCKETS_SOCKET_ERROR;
      }
  
      return lWritten;
  }
  /*-----------------------------------------------------------*/
  
  int32_t SOCKETS_SetSockOpt( Socket_t xSocket,
                              int32_t lLevel,
                              int32_t lOptionName,
                              const void * pvOptionValue,
                              size_t xOptionLength )
  {
      int32_t lStatus = SOCKETS_ERROR_NONE;
      TickType_t xTimeout;
      SSOCKETContextPtr_t pxContext = ( SSOCKETContextPtr_t ) xSocket;
  
      if( ( NULL != pxContext ) && ( SOCKETS_INVALID_CONTEXT != pxContext ) )
      {
          switch( lOptionName )
          {
              case SOCKETS_SO_SERVER_NAME_INDICATION:
  
                  /* Secure socket option cannot be used on connected socket */
                  if( pxContext->ulState & ( nxpsecuresocketsSOCKET_CONNECTED_FLAG ) )
                  {
                      lStatus = SOCKETS_SOCKET_ERROR;
                      break;
                  }
  
                  /* Non-NULL destination string indicates that SNI extension should
                   * be used during TLS negotiation. */
                  if( NULL == ( pxContext->pcDestination =
                                    ( char * ) pvPortMalloc( 1 + xOptionLength ) ) )
                  {
                      lStatus = SOCKETS_ENOMEM;
                  }
                  else
                  {
                      memcpy( pxContext->pcDestination, pvOptionValue, xOptionLength );
                      pxContext->pcDestination[ xOptionLength ] = '\0';
                  }
  
                  break;
  
              case SOCKETS_SO_TRUSTED_SERVER_CERTIFICATE:
  
                  /* Secure socket option cannot be used on connected socket */
                  if( pxContext->ulState & ( nxpsecuresocketsSOCKET_CONNECTED_FLAG ) )
                  {
                      lStatus = SOCKETS_SOCKET_ERROR;
                      break;
                  }
  
                  /* Non-NULL server certificate field indicates that the default trust
                   * list should not be used. */
                  if( NULL == ( pxContext->pcServerCertificate =
                                    ( char * ) pvPortMalloc( xOptionLength ) ) )
                  {
                      lStatus = SOCKETS_ENOMEM;
                  }
                  else
                  {
                      memcpy( pxContext->pcServerCertificate, pvOptionValue, xOptionLength );
                      pxContext->ulServerCertificateLength = xOptionLength;
                  }
  
                  break;
  
              case SOCKETS_SO_REQUIRE_TLS:
  
                  /* Secure socket option cannot be used on connected socket */
                  if( pxContext->ulState & ( nxpsecuresocketsSOCKET_CONNECTED_FLAG ) )
                  {
                      lStatus = SOCKETS_SOCKET_ERROR;
                      break;
                  }
  
                  pxContext->xRequireTLS = pdTRUE;
                  break;
  
              case SOCKETS_SO_NONBLOCK:
  
                  if( pxContext->ulState & ( nxpsecuresocketsSOCKET_CONNECTED_FLAG ) )
                  {
                      xTimeout = 0;
                      /* TODO: Investigate the NONBLOCK compile time config. */
                      pxContext->ulSendTimeout = 1;
                      pxContext->ulRecvTimeout = 1;
                  }
                  else
                  {
                      lStatus = SOCKETS_SOCKET_ERROR;
                  }
  
                  break;
  
              case SOCKETS_SO_RCVTIMEO:
                  xTimeout = *( ( const TickType_t * ) pvOptionValue ); /*lint !e9087 pvOptionValue passed should be of TickType_t. */
  
                  if( xTimeout == 0U )
                  {
                      pxContext->ulRecvTimeout = portMAX_DELAY;
                  }
                  else
                  {
                      pxContext->ulRecvTimeout = xTimeout;
                  }
  
                  break;
  
              case SOCKETS_SO_SNDTIMEO:
                  /* Comply with Berkeley standard - a 0 timeout is wait forever. */
                  xTimeout = *( ( const TickType_t * ) pvOptionValue ); /*lint !e9087 pvOptionValue passed should be of TickType_t. */
  
                  if( xTimeout == 0U )
                  {
                      pxContext->ulSendTimeout = portMAX_DELAY;
                  }
                  else
                  {
                      pxContext->ulSendTimeout = xTimeout;
                  }
  
                  break;
  
              case SOCKETS_SO_ALPN_PROTOCOLS:
  
                  /* Secure socket option cannot be used on connected socket */
                  if( pxContext->ulState & ( nxpsecuresocketsSOCKET_CONNECTED_FLAG ) )
                  {
                      lStatus = SOCKETS_SOCKET_ERROR;
                      break;
                  }
  
                  /* NOT implemented ? */
                  break;
  
              default:
                  lStatus = qcom_setsockopt( ( int ) pxContext->xSocket,
                                             lLevel,
                                             lOptionName,
                                             ( void * ) pvOptionValue,
                                             xOptionLength );
                  break;
          }
      }
      else
      {
          lStatus = SOCKETS_SOCKET_ERROR;
      }
  
      return lStatus;
  }
  /*-----------------------------------------------------------*/
  
  int32_t SOCKETS_Shutdown( Socket_t xSocket,
                            uint32_t ulHow )
  {
      SSOCKETContextPtr_t pxSecureSocket = ( SSOCKETContextPtr_t ) xSocket;
      int32_t lRetVal = SOCKETS_SOCKET_ERROR;
  
      /* Ensure that a valid socket was passed. */
      if( ( SOCKETS_INVALID_CONTEXT != pxSecureSocket ) )
      {
          switch( ulHow )
          {
              case SOCKETS_SHUT_RD:
                  /* Further receive calls on this socket should return error. */
                  pxSecureSocket->xShutdownFlags |= nxpsecuresocketsSOCKET_READ_CLOSED_FLAG;
  
                  /* Return success to the user. */
                  lRetVal = SOCKETS_ERROR_NONE;
                  break;
  
              case SOCKETS_SHUT_WR:
                  /* Further send calls on this socket should return error. */
                  pxSecureSocket->xShutdownFlags |= nxpsecuresocketsSOCKET_WRITE_CLOSED_FLAG;
  
                  /* Return success to the user. */
                  lRetVal = SOCKETS_ERROR_NONE;
                  break;
  
              case SOCKETS_SHUT_RDWR:
                  /* Further send or receive calls on this socket should return error. */
                  pxSecureSocket->xShutdownFlags |= nxpsecuresocketsSOCKET_READ_CLOSED_FLAG;
                  pxSecureSocket->xShutdownFlags |= nxpsecuresocketsSOCKET_WRITE_CLOSED_FLAG;
  
                  /* Return success to the user. */
                  lRetVal = SOCKETS_ERROR_NONE;
                  break;
  
              default:
                  /* An invalid value was passed for ulHow. */
                  lRetVal = SOCKETS_EINVAL;
                  break;
          }
      }
      else
      {
          return SOCKETS_EINVAL;
      }
  
      return lRetVal;
  }
  /*-----------------------------------------------------------*/
  
  Socket_t SOCKETS_Socket( int32_t lDomain,
                           int32_t lType,
                           int32_t lProtocol )
  {
      int32_t lStatus = SOCKETS_ERROR_NONE;
      int32_t xSocket = 0;
      SSOCKETContextPtr_t pxContext = NULL;
  
      /* Ensure that only supported values are supplied. */
      configASSERT( lDomain == SOCKETS_AF_INET );
      configASSERT( lType == SOCKETS_SOCK_STREAM );
      configASSERT( lProtocol == SOCKETS_IPPROTO_TCP );
  
      /* Allocate the internal context structure. */
      pxContext = pvPortMalloc( sizeof( SSOCKETContext_t ) );
  
      if( pxContext != NULL )
      {
          memset( pxContext, 0, sizeof( SSOCKETContext_t ) );
  
          /* Create the wrapped socket. */
          xSocket = qcom_socket( ATH_AF_INET,
                                 SOCK_STREAM_TYPE,
                                 0 ); /*xProtocol*/
  
          if( xSocket != A_ERROR )
          {
              pxContext->xSocket = ( Socket_t ) xSocket;
              /* Set default timeouts. */
              pxContext->ulRecvTimeout = socketsconfigDEFAULT_RECV_TIMEOUT;
              pxContext->ulSendTimeout = socketsconfigDEFAULT_SEND_TIMEOUT;
          }
          else /* Driver could not allocate socket. */
          {
              lStatus = SOCKETS_SOCKET_ERROR;
              vPortFree( pxContext );
          }
      }
      else /* Malloc failed. */
      {
          lStatus = SOCKETS_ENOMEM;
      }
  
      if( lStatus != SOCKETS_ERROR_NONE )
      {
          pxContext = SOCKETS_INVALID_CONTEXT;
      }
  
      return ( Socket_t ) pxContext;
  }
  /*-----------------------------------------------------------*/
  
  BaseType_t SOCKETS_Init( void )
  {
      /* Empty initialization for NXP board. */
      return pdPASS;
  }
  