| /* |
| FreeRTOS+TCP V2.0.11 |
| Copyright (C) 2017 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 ) ) ) ) |
| { |
| 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 ); |
| if( pcap_sendpacket( pxOpenedInterfaceHandle, ucBuffer, xLength ) != 0 ) |
| { |
| ulWinPCAPSendFailures++; |
| } |
| } |
| } |
| } |
| /*-----------------------------------------------------------*/ |
| |
| 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. */ |
| pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( pxHeader->len, 0 ); |
| |
| 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 formap 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; |
| } |