text: /*
   * FreeRTOS+TCP V2.3.2
   * 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
   */
  
  /* WinPCap includes. */
  #define HAVE_REMOTE
  #include "pcap.h"
  
  /* FreeRTOS includes. */
  #include "FreeRTOS.h"
  #include "task.h"
  #include "semphr.h"
  
  /* FreeRTOS+TCP includes. */
  #include "FreeRTOS_IP.h"
  #include "FreeRTOS_IP_Private.h"
  #include "NetworkBufferManagement.h"
  
  /* Thread-safe circular buffers are being used to pass data to and from the PCAP
   * access functions. */
  #include "Win32-Extensions.h"
  #include "FreeRTOS_Stream_Buffer.h"
  
  /* Sizes of the thread safe circular buffers used to pass data to and from the
   * WinPCAP Windows threads. */
  #define xSEND_BUFFER_SIZE    32768
  #define xRECV_BUFFER_SIZE    32768
  
  /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
   * driver will filter incoming packets and only pass the stack those packets it
   * considers need processing. */
  #if ( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )
      #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer )    eProcessBuffer
  #else
      #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer )    eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
  #endif
  
  /* Used to insert test code only. */
  #define niDISRUPT_PACKETS    0
  
  /*-----------------------------------------------------------*/
  
  /*
   * Windows threads that are outside of the control of the FreeRTOS simulator are
   * used to interface with the WinPCAP libraries.
   */
  DWORD WINAPI prvWinPcapRecvThread( void * pvParam );
  DWORD WINAPI prvWinPcapSendThread( void * pvParam );
  
  /*
   * Print out a numbered list of network interfaces that are available on the
   * host computer.
   */
  static pcap_if_t * prvPrintAvailableNetworkInterfaces( void );
  
  /*
   * Open the network interface.  The number of the interface to be opened is set
   * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
   */
  static void prvOpenSelectedNetworkInterface( pcap_if_t * pxAllNetworkInterfaces );
  static int prvOpenInterface( const char * pucName );
  
  /*
   * Configure the capture filter to allow blocking reads, and to filter out
   * packets that are not of interest to this demo.
   */
  static void prvConfigureCaptureBehaviour( void );
  
  /*
   * A function that simulates Ethernet interrupts by periodically polling the
   * WinPCap interface for new data.
   */
  static void prvInterruptSimulatorTask( void * pvParameters );
  
  /*
   * Create the buffers that are used to pass data between the FreeRTOS simulator
   * and the Win32 threads that manage WinPCAP.
   */
  static void prvCreateThreadSafeBuffers( void );
  
  /*
   * Utility function used to format print messages only.
   */
  static const char * prvRemoveSpaces( char * pcBuffer,
                                       int aBuflen,
                                       const char * pcMessage );
  
  /*-----------------------------------------------------------*/
  
  /* Required by the WinPCap library. */
  static char cErrorBuffer[ PCAP_ERRBUF_SIZE ];
  
  /* An event used to wake up the Win32 thread that sends data through the WinPCAP
   * library. */
  static void * pvSendEvent = NULL;
  
  /* _HT_ made the PCAP interface number configurable through the program's
   * parameters in order to test in different machines. */
  static BaseType_t xConfigNetworkInterfaceToUse = configNETWORK_INTERFACE_TO_USE;
  
  /* Handles to the Windows threads that handle the PCAP IO. */
  static HANDLE vWinPcapRecvThreadHandle = NULL;
  static HANDLE vWinPcapSendThreadHandle = NULL;
  
  /* The interface being used by WinPCap. */
  static pcap_t * pxOpenedInterfaceHandle = NULL;
  
  /* Circular buffers used by the PCAP Win32 threads. */
  static StreamBuffer_t * xSendBuffer = NULL;
  static StreamBuffer_t * xRecvBuffer = NULL;
  
  /* The MAC address initially set to the constants defined in FreeRTOSConfig.h. */
  extern uint8_t ucMACAddress[ 6 ];
  
  /* Logs the number of WinPCAP send failures, for viewing in the debugger only. */
  static volatile uint32_t ulWinPCAPSendFailures = 0;
  
  /*-----------------------------------------------------------*/
  
  BaseType_t xNetworkInterfaceInitialise( void )
  {
      BaseType_t xReturn = pdFALSE;
      pcap_if_t * pxAllNetworkInterfaces;
  
      /* Query the computer the simulation is being executed on to find the
       * network interfaces it has installed. */
      pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces();
  
      /* Open the network interface.  The number of the interface to be opened is
       * set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
       * Calling this function will set the pxOpenedInterfaceHandle variable.  If,
       * after calling this function, pxOpenedInterfaceHandle is equal to NULL, then
       * the interface could not be opened. */
      if( pxAllNetworkInterfaces != NULL )
      {
          prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces );
      }
  
      if( pxOpenedInterfaceHandle != NULL )
      {
          xReturn = pdPASS;
      }
  
      return xReturn;
  }
  /*-----------------------------------------------------------*/
  
  static void prvCreateThreadSafeBuffers( void )
  {
      /* The buffer used to pass data to be transmitted from a FreeRTOS task to
       * the Win32 thread that sends via the WinPCAP library. */
      if( xSendBuffer == NULL )
      {
          xSendBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xSendBuffer ) - sizeof( xSendBuffer->ucArray ) + xSEND_BUFFER_SIZE + 1 );
          configASSERT( xSendBuffer );
          memset( xSendBuffer, '\0', sizeof( *xSendBuffer ) - sizeof( xSendBuffer->ucArray ) );
          xSendBuffer->LENGTH = xSEND_BUFFER_SIZE + 1;
      }
  
      /* The buffer used to pass received data from the Win32 thread that receives
       * via the WinPCAP library to the FreeRTOS task. */
      if( xRecvBuffer == NULL )
      {
          xRecvBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xRecvBuffer ) - sizeof( xRecvBuffer->ucArray ) + xRECV_BUFFER_SIZE + 1 );
          configASSERT( xRecvBuffer );
          memset( xRecvBuffer, '\0', sizeof( *xRecvBuffer ) - sizeof( xRecvBuffer->ucArray ) );
          xRecvBuffer->LENGTH = xRECV_BUFFER_SIZE + 1;
      }
  }
  /*-----------------------------------------------------------*/
  
  BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer,
                                      BaseType_t bReleaseAfterSend )
  {
      size_t xSpace;
  
      iptraceNETWORK_INTERFACE_TRANSMIT();
      configASSERT( xIsCallingFromIPTask() == pdTRUE );
  
      /* Both the length of the data being sent and the actual data being sent
       *  are placed in the thread safe buffer used to pass data between the FreeRTOS
       *  tasks and the Win32 thread that sends data via the WinPCAP library.  Drop
       *  the packet if there is insufficient space in the buffer to hold both. */
      xSpace = uxStreamBufferGetSpace( xSendBuffer );
  
      if( ( pxNetworkBuffer->xDataLength <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) &&
          ( xSpace >= ( pxNetworkBuffer->xDataLength + sizeof( pxNetworkBuffer->xDataLength ) ) ) )
      {
          /* First write in the length of the data, then write in the data
           * itself. */
          uxStreamBufferAdd( xSendBuffer, 0, ( const uint8_t * ) &( pxNetworkBuffer->xDataLength ), sizeof( pxNetworkBuffer->xDataLength ) );
          uxStreamBufferAdd( xSendBuffer, 0, ( const uint8_t * ) pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
      }
      else
      {
          FreeRTOS_debug_printf( ( "xNetworkInterfaceOutput: send buffers full to store %lu\n", pxNetworkBuffer->xDataLength ) );
      }
  
      /* Kick the Tx task in either case in case it doesn't know the buffer is
       * full. */
      SetEvent( pvSendEvent );
  
      /* The buffer has been sent so can be released. */
      if( bReleaseAfterSend != pdFALSE )
      {
          vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
      }
  
      return pdPASS;
  }
  /*-----------------------------------------------------------*/
  
  static pcap_if_t * prvPrintAvailableNetworkInterfaces( void )
  {
      pcap_if_t * pxAllNetworkInterfaces = NULL, * xInterface;
      int32_t lInterfaceNumber = 1;
      char cBuffer[ 512 ];
      static BaseType_t xInvalidInterfaceDetected = pdFALSE;
  
      if( xInvalidInterfaceDetected == pdFALSE )
      {
          if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 )
          {
              printf( "Could not obtain a list of network interfaces\n%s\n", cErrorBuffer );
              pxAllNetworkInterfaces = NULL;
          }
          else
          {
              printf( "\r\n\r\nThe following network interfaces are available:\r\n\r\n" );
          }
  
          if( pxAllNetworkInterfaces != NULL )
          {
              /* Print out the list of network interfaces.  The first in the list
               * is interface '1', not interface '0'. */
              for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next )
              {
                  /* The descriptions of the devices can be full of spaces, clean them
                   * a little.  printf() can only be used here because the network is not
                   * up yet - so no other network tasks will be running. */
                  printf( "Interface %d - %s\n", lInterfaceNumber, prvRemoveSpaces( cBuffer, sizeof( cBuffer ), xInterface->name ) );
                  printf( "              (%s)\n", prvRemoveSpaces( cBuffer, sizeof( cBuffer ), xInterface->description ? xInterface->description : "No description" ) );
                  printf( "\n" );
                  lInterfaceNumber++;
              }
          }
  
          if( lInterfaceNumber == 1 )
          {
              /* The interface number was never incremented, so the above for() loop
               * did not execute meaning no interfaces were found. */
              printf( " \nNo network interfaces were found.\n" );
              pxAllNetworkInterfaces = NULL;
          }
  
          printf( "\r\nThe interface that will be opened is set by " );
          printf( "\"configNETWORK_INTERFACE_TO_USE\", which\r\nshould be defined in FreeRTOSConfig.h\r\n" );
  
          if( ( xConfigNetworkInterfaceToUse < 1L ) || ( xConfigNetworkInterfaceToUse >= lInterfaceNumber ) )
          {
              printf( "\r\nERROR:  configNETWORK_INTERFACE_TO_USE is set to %d, which is an invalid value.\r\n", xConfigNetworkInterfaceToUse );
              printf( "Please set configNETWORK_INTERFACE_TO_USE to one of the interface numbers listed above,\r\n" );
              printf( "then re-compile and re-start the application.  Only Ethernet (as opposed to WiFi)\r\n" );
              printf( "interfaces are supported.\r\n\r\nHALTING\r\n\r\n\r\n" );
              xInvalidInterfaceDetected = pdTRUE;
  
              if( pxAllNetworkInterfaces != NULL )
              {
                  /* Free the device list, as no devices are going to be opened. */
                  pcap_freealldevs( pxAllNetworkInterfaces );
                  pxAllNetworkInterfaces = NULL;
              }
          }
          else
          {
              printf( "Attempting to open interface number %d.\n", xConfigNetworkInterfaceToUse );
          }
      }
  
      return pxAllNetworkInterfaces;
  }
  /*-----------------------------------------------------------*/
  
  static int prvOpenInterface( const char * pucName )
  {
      static char pucInterfaceName[ 256 ];
  
      if( pucName != NULL )
      {
          strncpy( pucInterfaceName, pucName, sizeof( pucInterfaceName ) );
      }
  
      pxOpenedInterfaceHandle = pcap_open( pucInterfaceName,            /* The name of the selected interface. */
                                           ipTOTAL_ETHERNET_FRAME_SIZE, /* The size of the packet to capture. */
                                           PCAP_OPENFLAG_PROMISCUOUS,   /* Open in promiscuous mode as the MAC and
                                                                         * IP address is going to be "simulated", and
                                                                         * not be the real MAC and IP address.  This allows
                                                                         * traffic to the simulated IP address to be routed
                                                                         * to uIP, and traffic to the real IP address to be
                                                                         * routed to the Windows TCP/IP stack. */
                                           100,
                                           NULL,                        /* No authentication is required as this is
                                                                         * not a remote capture session. */
                                           cErrorBuffer
                                           );
  
      if( pxOpenedInterfaceHandle == NULL )
      {
          printf( "\n%s is not supported by WinPcap and cannot be opened\n", pucInterfaceName );
          return 1;
      }
      else
      {
          /* Configure the capture filter to allow blocking reads, and to filter
           * out packets that are not of interest to this demo. */
          prvConfigureCaptureBehaviour();
      }
  
      return 0;
  }
  /*-----------------------------------------------------------*/
  
  static void prvOpenSelectedNetworkInterface( pcap_if_t * pxAllNetworkInterfaces )
  {
      pcap_if_t * pxInterface;
      int32_t x;
  
      /* Walk the list of devices until the selected device is located. */
      pxInterface = pxAllNetworkInterfaces;
  
      for( x = 0L; x < ( xConfigNetworkInterfaceToUse - 1L ); x++ )
      {
          pxInterface = pxInterface->next;
      }
  
      /* Open the selected interface. */
      if( prvOpenInterface( pxInterface->name ) == 0 )
      {
          printf( "Successfully opened interface number %d.\n", x + 1 );
      }
      else
      {
          printf( "Failed to open interface number %d.\n", x + 1 );
      }
  
      /* The device list is no longer required. */
      pcap_freealldevs( pxAllNetworkInterfaces );
  }
  /*-----------------------------------------------------------*/
  
  static void prvConfigureCaptureBehaviour( void )
  {
      struct bpf_program xFilterCode;
      uint32_t ulNetMask;
  
      /* Set up a filter so only the packets of interest are passed to the IP
       * stack.  cErrorBuffer is used for convenience to create the string.  Don't
       * confuse this with an error message. */
      sprintf( cErrorBuffer, "broadcast or multicast or ether host %x:%x:%x:%x:%x:%x",
               ucMACAddress[ 0 ], ucMACAddress[ 1 ], ucMACAddress[ 2 ], ucMACAddress[ 3 ], ucMACAddress[ 4 ], ucMACAddress[ 5 ] );
  
      ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0;
  
      if( pcap_compile( pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 )
      {
          printf( "\nThe packet filter string is invalid\n" );
      }
      else
      {
          if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 )
          {
              printf( "\nAn error occurred setting the packet filter.\n" );
          }
  
          /* When pcap_compile() succeeds, it allocates memory for the memory pointed to by the bpf_program struct
           * parameter.pcap_freecode() will free that memory. */
          pcap_freecode( &xFilterCode );
      }
  
      /* Create the buffers used to pass packets between the FreeRTOS simulator
       * and the Win32 threads that are handling WinPCAP. */
      prvCreateThreadSafeBuffers();
  
      if( pvSendEvent == NULL )
      {
          /* Create event used to signal the Win32 WinPCAP Tx thread. */
          pvSendEvent = CreateEvent( NULL, FALSE, TRUE, NULL );
  
          /* Create the Win32 thread that handles WinPCAP Rx. */
          vWinPcapRecvThreadHandle = CreateThread(
              NULL,                 /* Pointer to thread security attributes. */
              0,                    /* Initial thread stack size, in bytes. */
              prvWinPcapRecvThread, /* Pointer to thread function. */
              NULL,                 /* Argument for new thread. */
              0,                    /* Creation flags. */
              NULL );
  
          /* Use the cores that are not used by the FreeRTOS tasks. */
          SetThreadAffinityMask( vWinPcapRecvThreadHandle, ~0x01u );
  
          /* Create the Win32 thread that handlers WinPCAP Tx. */
          vWinPcapSendThreadHandle = CreateThread(
              NULL,                 /* Pointer to thread security attributes. */
              0,                    /* initial thread stack size, in bytes. */
              prvWinPcapSendThread, /* Pointer to thread function. */
              NULL,                 /* Argument for new thread. */
              0,                    /* Creation flags. */
              NULL );
  
          /* Use the cores that are not used by the FreeRTOS tasks. */
          SetThreadAffinityMask( vWinPcapSendThreadHandle, ~0x01u );
  
          /* Create a task that simulates an interrupt in a real system.  This will
           * block waiting for packets, then send a message to the IP task when data
           * is available. */
          xTaskCreate( prvInterruptSimulatorTask, "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, configMAC_ISR_SIMULATOR_PRIORITY, NULL );
      }
  }
  /*-----------------------------------------------------------*/
  
  /* WinPCAP function. */
  void pcap_callback( u_char * user,
                      const struct pcap_pkthdr * pkt_header,
                      const u_char * pkt_data )
  {
      ( void ) user;
  
      /* THIS IS CALLED FROM A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS
       * OR TO PRINT OUT MESSAGES HERE. */
  
      /* Pass data to the FreeRTOS simulator on a thread safe circular buffer. */
      if( ( pkt_header->caplen <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) &&
          ( uxStreamBufferGetSpace( xRecvBuffer ) >= ( ( ( size_t ) pkt_header->caplen ) + sizeof( *pkt_header ) ) ) )
      {
          /* The received packets will be written to a C source file,
           * only if 'ipconfigUSE_DUMP_PACKETS' is defined.
           * Otherwise, there is no action. */
          iptraceDUMP_PACKET( ( const uint8_t * ) pkt_data, ( size_t ) pkt_header->caplen, pdTRUE );
  
          uxStreamBufferAdd( xRecvBuffer, 0, ( const uint8_t * ) pkt_header, sizeof( *pkt_header ) );
          uxStreamBufferAdd( xRecvBuffer, 0, ( const uint8_t * ) pkt_data, ( size_t ) pkt_header->caplen );
      }
  }
  /*-----------------------------------------------------------*/
  
  DWORD WINAPI prvWinPcapRecvThread( void * pvParam )
  {
      ( void ) pvParam;
  
      /* THIS IS A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS	OR TO PRINT
       * OUT MESSAGES HERE. */
  
      for( ; ; )
      {
          pcap_dispatch( pxOpenedInterfaceHandle, 1, pcap_callback, ( u_char * ) "mydata" );
      }
  }
  /*-----------------------------------------------------------*/
  
  DWORD WINAPI prvWinPcapSendThread( void * pvParam )
  {
      size_t xLength;
      uint8_t ucBuffer[ ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ];
      static char cErrorMessage[ 1024 ];
      const DWORD xMaxMSToWait = 1000;
  
      /* THIS IS A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS	OR TO PRINT
       * OUT MESSAGES HERE. */
  
      /* Remove compiler warnings about unused parameters. */
      ( void ) pvParam;
  
      for( ; ; )
      {
          /* Wait until notified of something to send. */
          WaitForSingleObject( pvSendEvent, xMaxMSToWait );
  
          /* Is there more than the length value stored in the circular buffer
           * used to pass data from the FreeRTOS simulator into this Win32 thread? */
          while( uxStreamBufferGetSize( xSendBuffer ) > sizeof( xLength ) )
          {
              uxStreamBufferGet( xSendBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE );
              uxStreamBufferGet( xSendBuffer, 0, ( uint8_t * ) ucBuffer, xLength, pdFALSE );
  
              /* The packets sent will be written to a C source file,
               * only if 'ipconfigUSE_DUMP_PACKETS' is defined.
               * Otherwise, there is no action. */
              iptraceDUMP_PACKET( ucBuffer, xLength, pdFALSE );
  
              if( pcap_sendpacket( pxOpenedInterfaceHandle, ucBuffer, xLength ) != 0 )
              {
                  ulWinPCAPSendFailures++;
              }
          }
      }
  }
  /*-----------------------------------------------------------*/
  
  static BaseType_t xPacketBouncedBack( const uint8_t * pucBuffer )
  {
      EthernetHeader_t * pxEtherHeader;
      BaseType_t xResult;
  
      pxEtherHeader = ( EthernetHeader_t * ) pucBuffer;
  
      /* Sometimes, packets are bounced back by the driver and we need not process them. Check
       * whether this packet is one such packet. */
      if( memcmp( ucMACAddress, pxEtherHeader->xSourceAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 )
      {
          xResult = pdTRUE;
      }
      else
      {
          xResult = pdFALSE;
      }
  
      return xResult;
  }
  /*-----------------------------------------------------------*/
  
  static void prvInterruptSimulatorTask( void * pvParameters )
  {
      struct pcap_pkthdr xHeader;
      static struct pcap_pkthdr * pxHeader;
      const uint8_t * pucPacketData;
      uint8_t ucRecvBuffer[ ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ];
      NetworkBufferDescriptor_t * pxNetworkBuffer;
      IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
      eFrameProcessingResult_t eResult;
  
      /* Remove compiler warnings about unused parameters. */
      ( void ) pvParameters;
  
      for( ; ; )
      {
          /* Does the circular buffer used to pass data from the Win32 thread that
           * handles WinPCAP Rx into the FreeRTOS simulator contain another packet? */
          if( uxStreamBufferGetSize( xRecvBuffer ) > sizeof( xHeader ) )
          {
              /* Get the next packet. */
              uxStreamBufferGet( xRecvBuffer, 0, ( uint8_t * ) &xHeader, sizeof( xHeader ), pdFALSE );
              uxStreamBufferGet( xRecvBuffer, 0, ( uint8_t * ) ucRecvBuffer, ( size_t ) xHeader.len, pdFALSE );
              pucPacketData = ucRecvBuffer;
              pxHeader = &xHeader;
  
              iptraceNETWORK_INTERFACE_RECEIVE();
  
              /* Check for minimal size. */
              if( pxHeader->len >= sizeof( EthernetHeader_t ) )
              {
                  eResult = ipCONSIDER_FRAME_FOR_PROCESSING( pucPacketData );
              }
              else
              {
                  eResult = eReleaseBuffer;
              }
  
              if( eResult == eProcessBuffer )
              {
                  /* Will the data fit into the frame buffer? */
                  if( pxHeader->len <= ipTOTAL_ETHERNET_FRAME_SIZE )
                  {
                      /* Obtain a buffer into which the data can be placed.  This
                       * is only	an interrupt simulator, not a real interrupt, so it
                       * is ok to call the task level function here, but note that
                       * some buffer implementations cannot be called from a real
                       * interrupt. */
                      if( xPacketBouncedBack( pucPacketData ) == pdFALSE )
                      {
                          pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( pxHeader->len, 0 );
                      }
                      else
                      {
                          pxNetworkBuffer = NULL;
                      }
  
                      if( pxNetworkBuffer != NULL )
                      {
                          memcpy( pxNetworkBuffer->pucEthernetBuffer, pucPacketData, pxHeader->len );
                          pxNetworkBuffer->xDataLength = ( size_t ) pxHeader->len;
  
                          #if ( niDISRUPT_PACKETS == 1 )
                              {
                                  pxNetworkBuffer = vRxFaultInjection( pxNetworkBuffer, pucPacketData );
                              }
                          #endif /* niDISRUPT_PACKETS */
  
                          if( pxNetworkBuffer != NULL )
                          {
                              xRxEvent.pvData = ( void * ) pxNetworkBuffer;
  
                              /* Data was received and stored.  Send a message to
                               * the IP task to let it know. */
                              if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )
                              {
                                  /* The buffer could not be sent to the stack so
                                   * must be released again.  This is only an
                                   * interrupt simulator, not a real interrupt, so it
                                   * is ok to use the task level function here, but
                                   * note no all buffer implementations will allow
                                   * this function to be executed from a real
                                   * interrupt. */
                                  vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
                                  iptraceETHERNET_RX_EVENT_LOST();
                              }
                          }
                          else
                          {
                              /* The packet was already released or stored inside
                               * vRxFaultInjection().  Don't release it here. */
                          }
                      }
                      else
                      {
                          iptraceETHERNET_RX_EVENT_LOST();
                      }
                  }
                  else
                  {
                      /* Log that a packet was dropped because it would have
                       * overflowed the buffer, but there may be more buffers to
                       * process. */
                  }
              }
          }
          else
          {
              /* There is no real way of simulating an interrupt.  Make sure
               * other tasks can run. */
              vTaskDelay( configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY );
          }
      }
  }
  /*-----------------------------------------------------------*/
  
  static const char * prvRemoveSpaces( char * pcBuffer,
                                       int aBuflen,
                                       const char * pcMessage )
  {
      char * pcTarget = pcBuffer;
  
      /* Utility function used to format messages being printed only. */
      while( ( *pcMessage != 0 ) && ( pcTarget < ( pcBuffer + aBuflen - 1 ) ) )
      {
          *( pcTarget++ ) = *pcMessage;
  
          if( isspace( *pcMessage ) != pdFALSE )
          {
              while( isspace( *pcMessage ) != pdFALSE )
              {
                  pcMessage++;
              }
          }
          else
          {
              pcMessage++;
          }
      }
  
      *pcTarget = '\0';
  
      return pcBuffer;
  }
  