diff options
Diffstat (limited to 'FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/linux')
-rw-r--r-- | FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/linux/NetworkInterface.c | 889 |
1 files changed, 889 insertions, 0 deletions
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/linux/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/linux/NetworkInterface.c new file mode 100644 index 000000000..41f28a0d2 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/linux/NetworkInterface.c @@ -0,0 +1,889 @@ +/* +FreeRTOS+TCP V2.0.11 +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 +*/ + +/* ========================= FreeRTOS includes ============================== */ +#include "FreeRTOS.h" +#include "event_groups.h" +#include "task.h" +#include "semphr.h" + +/* ========================= FreeRTOS+TCP includes ========================== */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_IP_Private.h" +#include "NetworkBufferManagement.h" +#include "FreeRTOS_Stream_Buffer.h" + +/* ======================== Standard Library inludes ======================== */ +#include <stdio.h> +#include <unistd.h> +#include <stdint.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <pthread.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/sysinfo.h> +#include <signal.h> +#include <pcap.h> + +/* ========================== Local includes =================================*/ +#include "utils/wait_for_event.h" + +/* ======================== Macro Definitions =============================== */ +#if ( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 ) + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer +#else + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) \ + eConsiderFrameForProcessing( ( pucEthernetBuffer ) ) +#endif + +/* ============================== Definitions =============================== */ +#define xSEND_BUFFER_SIZE 32768 +#define xRECV_BUFFER_SIZE 32768 +#define MAX_CAPTURE_LEN 65535 +#define IP_SIZE 100 + +/* ================== Static Function Prototypes ============================ */ +static int prvConfigureCaptureBehaviour( void ); +static int prvCreateThreadSafeBuffers( void ); +static void * prvLinuxPcapSendThread( void *pvParam ); +static void * prvLinuxPcapRecvThread( void *pvParam ); +static void prvInterruptSimulatorTask( void *pvParameters ); +static void prvPrintAvailableNetworkInterfaces( pcap_if_t * pxAllNetworkInterfaces ); +static pcap_if_t * prvGetAvailableNetworkInterfaces( void ); +static const char * prvRemoveSpaces( char *pcBuffer, + int aBuflen, + const char *pcMessage ); +static int prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ); +static int prvCreateWorkerThreads( void ); +static int prvSetDeviceModes( void ); +static void print_hex( unsigned const char * const bin_data, + size_t len ); + +/* ======================== Static Global Variables ========================= */ +static StreamBuffer_t *xSendBuffer = NULL; +static StreamBuffer_t *xRecvBuffer = NULL; +extern uint8_t ucMACAddress[ 6 ]; +static char errbuf[ PCAP_ERRBUF_SIZE ]; +static pcap_t *pxOpenedInterfaceHandle = NULL; +static struct event *pvSendEvent = NULL; +static uint32_t ulPCAPSendFailures = 0; +static BaseType_t xConfigNetworkInterfaceToUse = configNETWORK_INTERFACE_TO_USE; +static BaseType_t xInvalidInterfaceDetected = pdFALSE; + +/* ======================= API Function definitions ========================= */ + +/*! + * @brief API call, called from reeRTOS_IP.c to initialize the capture device + * to be able to send and receive packets + * @return pdPASS if successful else pdFAIL + */ +BaseType_t xNetworkInterfaceInitialise( void ) +{ +BaseType_t ret = pdFAIL; +pcap_if_t *pxAllNetworkInterfaces; + + /* Query the computer the simulation is being executed on to find the + network interfaces it has installed. */ + pxAllNetworkInterfaces = prvGetAvailableNetworkInterfaces(); + + if( pxAllNetworkInterfaces != NULL ) + { + prvPrintAvailableNetworkInterfaces( pxAllNetworkInterfaces ); + ret = prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces ); + + if( ret == pdPASS ) + { + ret = prvCreateThreadSafeBuffers(); + + if( ret == pdPASS ) + { + ret = prvCreateWorkerThreads(); + } + } + + /* The device list is no longer required. */ + pcap_freealldevs( pxAllNetworkInterfaces ); + } + + if( ( pxOpenedInterfaceHandle != NULL ) && ( ret == pdPASS ) ) + { + ret = pdPASS; + } + + return ret; +} + +/*! + * @brief API call, called from reeRTOS_IP.c to send a network packet over the + * selected interface + * @return pdTRUE if successful else pdFALSE + */ +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 pthread that sends data via the pcap 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_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. */ + event_signal( pvSendEvent ); + + /* The buffer has been sent so can be released. */ + if( bReleaseAfterSend != pdFALSE ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + } + + return pdPASS; +} + +/* ====================== Static Function definitions ======================= */ + +/*! + * @brief create thread safe buffers to send/receive packets between threads + * @returns + */ +static int prvCreateThreadSafeBuffers( void ) +{ +int ret = pdFAIL; + + /* The buffer used to pass data to be transmitted from a FreeRTOS task to + the linux thread that sends via the pcap library. */ + do + { + if( xSendBuffer == NULL ) + { + xSendBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xSendBuffer ) - sizeof( xSendBuffer->ucArray ) + xSEND_BUFFER_SIZE + 1 ); + + if( xSendBuffer == NULL ) + { + break; + } + + 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 pthread that receives + via the pcap library to the FreeRTOS task. */ + if( xRecvBuffer == NULL ) + { + xRecvBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xRecvBuffer ) - sizeof( xRecvBuffer->ucArray ) + xRECV_BUFFER_SIZE + 1 ); + + if( xRecvBuffer == NULL ) + { + break; + } + + configASSERT( xRecvBuffer ); + memset( xRecvBuffer, '\0', sizeof( *xRecvBuffer ) - sizeof( xRecvBuffer->ucArray ) ); + xRecvBuffer->LENGTH = xRECV_BUFFER_SIZE + 1; + } + + ret = pdPASS; + } while( 0 ); + + return ret; +} + +/*! + * @brief print network interfaces available on the system + * @param[in] pxAllNetworkInterfaces interface structure list to print + */ +static void prvPrintAvailableNetworkInterfaces( pcap_if_t * pxAllNetworkInterfaces ) +{ +pcap_if_t *xInterface; +int32_t lInterfaceNumber = 1; +char cBuffer[ 512 ]; + + 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 %ld, 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 %ld.\n", xConfigNetworkInterfaceToUse ); + } +} + +/*! + * @brief get network interfaces from the system + * @returns the structure list containing all found devices + */ +static pcap_if_t * prvGetAvailableNetworkInterfaces( void ) +{ +pcap_if_t * pxAllNetworkInterfaces = NULL; + + if( xInvalidInterfaceDetected == pdFALSE ) + { + int ret; + ret = pcap_findalldevs( &pxAllNetworkInterfaces, errbuf ); + + if( ret == PCAP_ERROR ) + { + FreeRTOS_printf( ( "Could not obtain a list of network interfaces\n%s\n", + errbuf ) ); + pxAllNetworkInterfaces = NULL; + } + else + { + printf( "\r\n\r\nThe following network interfaces are available:\r\n\r\n" ); + } + } + + return pxAllNetworkInterfaces; +} + +/*! + * @brief set device operation modes + * @returns pdPASS on success pdFAIL on failure + */ +static int prvSetDeviceModes() +{ +int ret = pdFAIL; + + /* + 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 Linux TCP/IP stack. + */ + FreeRTOS_debug_printf( ( "setting device modes of operation...\n" ) ); + + do + { + ret = pcap_set_promisc( pxOpenedInterfaceHandle, 1 ); + + if( ( ret != 0 ) && ( ret != PCAP_ERROR_ACTIVATED ) ) + { + FreeRTOS_printf( ( "coult not activate promisuous mode\n" ) ); + break; + } + + ret = pcap_set_snaplen( pxOpenedInterfaceHandle, + ipTOTAL_ETHERNET_FRAME_SIZE ); + + if( ( ret != 0 ) && ( ret != PCAP_ERROR_ACTIVATED ) ) + { + FreeRTOS_printf( ( "coult not set snaplen\n" ) ); + break; + } + + ret = pcap_set_timeout( pxOpenedInterfaceHandle, 200 ); + + if( ( ret != 0 ) && ( ret != PCAP_ERROR_ACTIVATED ) ) + { + FreeRTOS_printf( ( "coult not set timeout\n" ) ); + break; + } + + ret = pcap_set_buffer_size( pxOpenedInterfaceHandle, + ipTOTAL_ETHERNET_FRAME_SIZE * 1100 ); + + if( ( ret != 0 ) && ( ret != PCAP_ERROR_ACTIVATED ) ) + { + FreeRTOS_printf( ( "coult not set buffer size\n" ) ); + break; + } + + ret = pdPASS; + } while( 0 ); + + return ret; +} + +/*! + * @brief open selected interface given its name + * @param [in] pucName interface name to pen + * @returns pdPASS on success pdFAIL on failure + */ +static int prvOpenInterface( const char *pucName ) +{ +static char pucInterfaceName[ 256 ]; +int ret = pdFAIL; + + if( pucName != NULL ) + { + ( void ) strncpy( pucInterfaceName, pucName, sizeof( pucInterfaceName ) ); + pucInterfaceName[ sizeof( pucInterfaceName ) - ( size_t ) 1 ] = '\0'; + + FreeRTOS_debug_printf( ( "opening interface %s\n", pucInterfaceName ) ); + + pxOpenedInterfaceHandle = pcap_create( pucInterfaceName, errbuf ); + + if( pxOpenedInterfaceHandle != NULL ) + { + ret = prvSetDeviceModes(); + + if( ret == pdPASS ) + { + if( pcap_activate( pxOpenedInterfaceHandle ) == 0 ) + { + /* Configure the capture filter to allow blocking reads, and to filter + out packets that are not of interest to this demo. */ + ret = prvConfigureCaptureBehaviour(); + } + else + { + FreeRTOS_debug_printf( ( "pcap activate error %s\n", + pcap_geterr( pxOpenedInterfaceHandle ) ) ); + ret = pdFAIL; + } + } + } + else + { + FreeRTOS_printf( ( "\n%s is not supported by pcap and cannot be opened %s\n", + pucInterfaceName, errbuf ) ); + } + } + else + { + FreeRTOS_printf( ( "could not open interface: name is null\n" ) ); + } + + return ret; +} + +/*! + * @brief 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. + * @param [in] pxAllNetworkInterfaces network interface list to choose from + * @returns pdPASS on success or pdFAIL when something goes wrong + */ +static int prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ) +{ +pcap_if_t *pxInterface; +int32_t x; +int ret = pdFAIL; + + /* 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 ) == pdPASS ) + { + FreeRTOS_debug_printf( ( "Successfully opened interface number %d.\n", x + 1 ) ); + ret = pdPASS; + } + else + { + FreeRTOS_printf( ( "Failed to open interface number %d.\n", x + 1 ) ); + } + + return ret; +} + +/*! + * @brief launch 2 linux threads, one for Tx and one for Rx + * and one FreeRTOS thread that will simulate an interrupt + * and notify the tcp/ip stack of new data + * @return pdPASS on success otherwise pdFAIL + */ +static int prvCreateWorkerThreads( void ) +{ +pthread_t vPcapRecvThreadHandle; +pthread_t vPcapSendThreadHandle; +int ret = pdPASS; + + if( pvSendEvent == NULL ) + { + FreeRTOS_debug_printf( ( "Creating Threads ..\n" ) ); + ret = pdFAIL; + /* Create event used to signal the pcap Tx thread. */ + pvSendEvent = event_create(); + + do + { + /* Create the thread that handles pcap Rx. */ + ret = pthread_create( &vPcapRecvThreadHandle, + NULL, + prvLinuxPcapRecvThread, + NULL ); + + if( ret != 0 ) + { + FreeRTOS_printf( ( "pthread error %d", ret ) ); + break; + } + + /* Create the thread that handles pcap Tx. */ + ret = pthread_create( &vPcapSendThreadHandle, + NULL, + prvLinuxPcapSendThread, + NULL ); + + if( ret != 0 ) + { + FreeRTOS_printf( ( "pthread error %d", ret ) ); + break; + } + + ret = pdPASS; + } while( 0 ); + + /* 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. */ + if( xTaskCreate( prvInterruptSimulatorTask, + "MAC_ISR", + configMINIMAL_STACK_SIZE, + NULL, + configMAC_ISR_SIMULATOR_PRIORITY, + NULL ) != pdPASS ) + { + ret = pdFAIL; + FreeRTOS_printf( ( "xTaskCreate could not create a new task\n" ) ); + } + } + + return ret; +} + +/*! + * @brief Create the buffers used to pass packets between the FreeRTOS simulator + * and the pthreads that are handling pcap as well as the FreeRTOS task + * responsible of simulating an interrupt. + * @returns pdPASS when successful and pdFAIL when there is a failure + */ +static int prvConfigureCaptureBehaviour( void ) +{ + struct bpf_program xFilterCode; + uint32_t ulNetMask; + char pcap_filter[ 500 ]; + int ret = pdFAIL; + + FreeRTOS_debug_printf( ( "Configuring Capture behaviour\n" ) ); + + /* Set up a filter so only the packets of interest are passed to the IP + stack. errbuf is used for convenience to create the string. Don't + confuse this with an error message. */ + sprintf( pcap_filter, "broadcast or multicast or ether host %x:%x:%x:%x:%x:%x", + ucMACAddress[ 0 ], + ucMACAddress[ 1 ], + ucMACAddress[ 2 ], + ucMACAddress[ 3 ], + ucMACAddress[ 4 ], + ucMACAddress[ 5 ] ); + FreeRTOS_debug_printf( ( "pcap filter to compile: %s\n", pcap_filter ) ); + + ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0; + + ret = pcap_compile( pxOpenedInterfaceHandle, + &xFilterCode, + pcap_filter, + 1, + ulNetMask ); + + if( ret < 0 ) + { + ( void ) printf( "\nThe packet filter string is invalid %s\n", + pcap_geterr( pxOpenedInterfaceHandle ) ); + } + else + { + ret = pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ); + + if( ret < 0 ) + { + ( void ) printf( "\nAn error occurred setting the packet filter. %s\n", + pcap_geterr( pxOpenedInterfaceHandle ) ); + } + else + { + ret = pdPASS; + } + + /* 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 ); + } + + return ret; +} + +/*! + * @brief callback function called from pcap_dispatch function when new + * data arrives on the interface + * @param [in] user data sent to pcap_dispatch + * @param [in] pkt_header received packet header + * @param [in] pkt_data received packet data + * @warning this is called from a Linux thread, do not attempt any FreeRTOS calls + */ +static void pcap_callback( unsigned char *user, + const struct pcap_pkthdr *pkt_header, + const u_char *pkt_data ) +{ + FreeRTOS_debug_printf( ( "Receiving < =========== network callback user: %s len: %d caplen: %d\n", + user, + pkt_header->len, + pkt_header->caplen ) ); + print_hex( pkt_data, pkt_header->len ); + + /* 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 ); + } +} + +/*! + * @brief infinite loop pthread to read from pcap + * @param [in] pvParam not used + * @returns NULL + * @warning this is called from a Linux thread, do not attempt any FreeRTOS calls + * @remarks This function disables signal, to prevent it from being put into + * sleep byt the posix port + */ +static void * prvLinuxPcapRecvThread( void *pvParam ) +{ +int ret; + + ( void ) pvParam; + + /* Disable signals to this thread since this is a Linux pthread to be able to + * printf and other blocking operations without being interruped and put in + * suspension mode by the linux port signals + */ + sigset_t set; + sigfillset( &set ); + pthread_sigmask( SIG_SETMASK, &set, NULL ); + + for( ; ; ) + { + ret = pcap_dispatch( pxOpenedInterfaceHandle, 1, + pcap_callback, ( u_char * ) "mydata" ); + + if( ret == -1 ) + { + FreeRTOS_printf( ( "pcap_dispatch error received: %s\n", + pcap_geterr( pxOpenedInterfaceHandle ) ) ); + } + } + + return NULL; +} + +/*! + * @brief Infinite loop thread that waits for events when there is data + * available then sends the data on the interface + * @param [in] pvParam not used + * @returns NULL + * @warning this is called from a Linux thread, do not attempt any FreeRTOS calls + */ +static void * prvLinuxPcapSendThread( void *pvParam ) +{ +size_t xLength; +uint8_t ucBuffer[ ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ]; +const time_t xMaxMSToWait = 1000; + + ( void ) pvParam; + + /* disable signals to avoid treating this thread as a FreeRTOS task and puting + * it to sleep by the scheduler */ + sigset_t set; + sigfillset( &set ); + pthread_sigmask( SIG_SETMASK, &set, NULL ); + + for( ; ; ) + { + /* Wait until notified of something to send. */ + event_wait_timed( pvSendEvent, xMaxMSToWait ); + + /* Is there more than the length value stored in the circular buffer + used to pass data from the FreeRTOS simulator into this pthread?*/ + while( uxStreamBufferGetSize( xSendBuffer ) > sizeof( xLength ) ) + { + uxStreamBufferGet( xSendBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE ); + uxStreamBufferGet( xSendBuffer, 0, ( uint8_t * ) ucBuffer, xLength, pdFALSE ); + FreeRTOS_debug_printf( ( "Sending ========== > data pcap_sendpadcket %lu\n", xLength ) ); + print_hex( ucBuffer, xLength ); + + if( pcap_sendpacket( pxOpenedInterfaceHandle, ucBuffer, xLength ) != 0 ) + { + FreeRTOS_printf( ( "pcap_sendpackeet: send failed %d\n", ulPCAPSendFailures ) ); + ulPCAPSendFailures++; + } + } + } + + return NULL; +} + +/*! + * @brief FreeRTOS infinite loop thread that simulates a network interrupt to notify the + * network stack of the presence of new data + * @param [in] pvParameters not used + */ +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 pthread thread that + handles pacap 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 ); + } + } +} + +/*! + * @brief remove spacces from pcMessage into pcBuffer + * @param [out] pcBuffer buffer to fill up + * @param [in] aBuflen length of pcBuffer + * @param [in] pcMessage original message + * @returns + */ +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; +} + +/*! + * @brief print binary packet in hex + * @param [in] bin_daa data to print + * @param [in] len length of the data + */ +static void print_hex( unsigned const char * const bin_data, + size_t len ) +/*static void print_hex(unsigned char *bin_data, size_t len) */ +{ +size_t i; + + for( i = 0; i < len; ++i ) + { + FreeRTOS_debug_printf( ( "%.2X ", bin_data[ i ] ) ); + } + + FreeRTOS_debug_printf( ( "\n" ) ); +} |