336 lines
12 KiB
C
336 lines
12 KiB
C
|
/*
|
||
|
* FreeRTOS V202212.00
|
||
|
* 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.
|
||
|
*
|
||
|
* https://www.FreeRTOS.org
|
||
|
* https://github.com/FreeRTOS
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/* WinPCap includes. */
|
||
|
#include "pcap.h"
|
||
|
#include "remote-ext.h"
|
||
|
|
||
|
/* uIP includes. */
|
||
|
#include "net/uip.h"
|
||
|
#include "net/uip_arp.h"
|
||
|
#include "net/clock-arch.h"
|
||
|
|
||
|
/* FreeRTOS includes. */
|
||
|
#include "FreeRTOS.h"
|
||
|
#include "task.h"
|
||
|
#include "queue.h"
|
||
|
|
||
|
/*
|
||
|
* Query the computer the simulation is being executed on to find the network
|
||
|
* interfaces it has installed.
|
||
|
*/
|
||
|
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 );
|
||
|
|
||
|
/*
|
||
|
* 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 );
|
||
|
|
||
|
pcap_t *pxOpenedInterfaceHandle = NULL;
|
||
|
LARGE_INTEGER freq, sys_start_time;
|
||
|
|
||
|
#define archNUM_BUFFERS 5
|
||
|
#define archNUM_BUFFER_POINTERS ( archNUM_BUFFERS - 1 )
|
||
|
|
||
|
static void prvInterruptSimulator( void *pvParameters );
|
||
|
|
||
|
static unsigned char ucEthernetBuffer[ archNUM_BUFFERS ][ UIP_CONF_BUFFER_SIZE ];
|
||
|
static unsigned char *pucEthernetBufferPointers[ archNUM_BUFFER_POINTERS ];
|
||
|
|
||
|
static long lLengthOfDataInBuffer[ archNUM_BUFFER_POINTERS ] = { 0 };
|
||
|
static unsigned char ucNextBufferToFill = 0U, ucNextBufferToProcess = 0U;
|
||
|
|
||
|
unsigned char *uip_buf = NULL;
|
||
|
char cErrorBuffer[PCAP_ERRBUF_SIZE];
|
||
|
|
||
|
void vNetifTx( void )
|
||
|
{
|
||
|
pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len );
|
||
|
pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len );
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
unsigned portBASE_TYPE uxNetifRx( void )
|
||
|
{
|
||
|
unsigned portBASE_TYPE xDataLen;
|
||
|
unsigned char *pucTemp;
|
||
|
|
||
|
/* Check there is really data available. */
|
||
|
xDataLen = lLengthOfDataInBuffer[ ucNextBufferToProcess ];
|
||
|
if( xDataLen != 0L )
|
||
|
{
|
||
|
|
||
|
/* The buffer pointed to by uip_buf is going to change. Remember which
|
||
|
buffer uip_buf is currently pointing to. */
|
||
|
pucTemp = uip_buf;
|
||
|
|
||
|
/* Point uip_buf at the next buffer that contains data. */
|
||
|
uip_buf = pucEthernetBufferPointers[ ucNextBufferToProcess ];
|
||
|
|
||
|
/* The buffer pointed to by
|
||
|
pucEthernetBufferPointeres[ ucNextBufferToProcess ] is now in use by
|
||
|
uip_buf, but the buffer uip_buf was pointing to on entry to this
|
||
|
function is free. Set
|
||
|
pucEthernetBufferPointeres[ ucNextBufferToProcess ] to the free
|
||
|
buffer. */
|
||
|
pucEthernetBufferPointers[ ucNextBufferToProcess ] = pucTemp;
|
||
|
lLengthOfDataInBuffer[ ucNextBufferToProcess ] = 0L;
|
||
|
|
||
|
ucNextBufferToProcess++;
|
||
|
if( ucNextBufferToProcess >= archNUM_BUFFER_POINTERS )
|
||
|
{
|
||
|
ucNextBufferToProcess = 0L;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return xDataLen;
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
portBASE_TYPE xNetifInit( void )
|
||
|
{
|
||
|
portBASE_TYPE x;
|
||
|
pcap_if_t *pxAllNetworkInterfaces;
|
||
|
|
||
|
/* Allocate a free buffer to each buffer pointer. */
|
||
|
for( x = 0; x < sizeof( pucEthernetBufferPointers ) / sizeof( unsigned char * ); x++ )
|
||
|
{
|
||
|
pucEthernetBufferPointers[ x ] = &( ucEthernetBuffer[ x ][ 0 ] );
|
||
|
}
|
||
|
|
||
|
/* Start with uip_buf pointing to a buffer that is not referenced from the
|
||
|
pucEthernetBufferPointers[] array. */
|
||
|
uip_buf = &( ucEthernetBuffer[ archNUM_BUFFERS - 1 ][ 0 ] );
|
||
|
|
||
|
/* 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 );
|
||
|
}
|
||
|
|
||
|
|
||
|
return x;
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
static pcap_if_t * prvPrintAvailableNetworkInterfaces( void )
|
||
|
{
|
||
|
pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface;
|
||
|
long lInterfaceNumber = 1;
|
||
|
|
||
|
if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 )
|
||
|
{
|
||
|
printf( "\r\nCould not obtain a list of network interfaces\r\n%s\r\n", cErrorBuffer );
|
||
|
pxAllNetworkInterfaces = NULL;
|
||
|
}
|
||
|
|
||
|
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 )
|
||
|
{
|
||
|
printf( "%d. %s", lInterfaceNumber, xInterface->name );
|
||
|
|
||
|
if( xInterface->description != NULL )
|
||
|
{
|
||
|
printf( " (%s)\r\n", xInterface->description );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf( " (No description available)\r\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( " \r\nNo network interfaces were found.\r\n" );
|
||
|
pxAllNetworkInterfaces = NULL;
|
||
|
}
|
||
|
|
||
|
printf( "\r\nThe interface that will be opened is set by configNETWORK_INTERFACE_TO_USE which should be defined in FreeRTOSConfig.h\r\n" );
|
||
|
printf( "Attempting to open interface number %d.\r\n", configNETWORK_INTERFACE_TO_USE );
|
||
|
|
||
|
if( ( configNETWORK_INTERFACE_TO_USE < 1L ) || ( configNETWORK_INTERFACE_TO_USE > lInterfaceNumber ) )
|
||
|
{
|
||
|
printf("\r\nconfigNETWORK_INTERFACE_TO_USE is not in the valid range.\r\n" );
|
||
|
|
||
|
if( pxAllNetworkInterfaces != NULL )
|
||
|
{
|
||
|
/* Free the device list, as no devices are going to be opened. */
|
||
|
pcap_freealldevs( pxAllNetworkInterfaces );
|
||
|
pxAllNetworkInterfaces = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pxAllNetworkInterfaces;
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces )
|
||
|
{
|
||
|
pcap_if_t *xInterface;
|
||
|
long x;
|
||
|
|
||
|
/* Walk the list of devices until the selected device is located. */
|
||
|
xInterface = pxAllNetworkInterfaces;
|
||
|
for( x = 0L; x < ( configNETWORK_INTERFACE_TO_USE - 1L ); x++ )
|
||
|
{
|
||
|
xInterface = xInterface->next;
|
||
|
}
|
||
|
|
||
|
/* Open the selected interface. */
|
||
|
pxOpenedInterfaceHandle = pcap_open( xInterface->name, /* The name of the selected interface. */
|
||
|
UIP_CONF_BUFFER_SIZE, /* The size of the packet to capture. */
|
||
|
PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscious mode as the MAC and
|
||
|
IP address is going to be "simulated", and
|
||
|
not be the real MAC and IP address. This allows
|
||
|
trafic to the simulated IP address to be routed
|
||
|
to uIP, and trafic to the real IP address to be
|
||
|
routed to the Windows TCP/IP stack. */
|
||
|
0xfffffffL, /* The read time out. This is going to block
|
||
|
until data is available. */
|
||
|
NULL, /* No authentication is required as this is
|
||
|
not a remote capture session. */
|
||
|
cErrorBuffer
|
||
|
);
|
||
|
|
||
|
if ( pxOpenedInterfaceHandle == NULL )
|
||
|
{
|
||
|
printf( "\r\n%s is not supported by WinPcap and cannot be opened\r\n", xInterface->name );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Configure the capture filter to allow blocking reads, and to filter
|
||
|
out packets that are not of interest to this demo. */
|
||
|
prvConfigureCaptureBehaviour();
|
||
|
}
|
||
|
|
||
|
/* The device list is no longer required. */
|
||
|
pcap_freealldevs( pxAllNetworkInterfaces );
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
static void prvConfigureCaptureBehaviour( void )
|
||
|
{
|
||
|
struct bpf_program xFilterCode;
|
||
|
const long lMinBytesToCopy = 10L, lBlocking = 0L;
|
||
|
unsigned long ulNetMask;
|
||
|
|
||
|
/* Unblock a read as soon as anything is received. */
|
||
|
pcap_setmintocopy( pxOpenedInterfaceHandle, lMinBytesToCopy );
|
||
|
|
||
|
/* Allow blocking. */
|
||
|
pcap_setnonblock( pxOpenedInterfaceHandle, lBlocking, cErrorBuffer );
|
||
|
|
||
|
/* Set up a filter so only the packets of interest are passed to the uIP
|
||
|
stack. cErrorBuffer is used for convenience to create the string. Don't
|
||
|
confuse this with an error message. */
|
||
|
sprintf( cErrorBuffer, "broadcast or multicast or host %d.%d.%d.%d", configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 );
|
||
|
|
||
|
ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0;
|
||
|
|
||
|
if( pcap_compile(pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 )
|
||
|
{
|
||
|
printf("\r\nThe packet filter string is invalid\r\n" );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 )
|
||
|
{
|
||
|
printf( "\r\nAn error occurred setting the packet filter.\r\n" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Create a task that simulates an interrupt in a real system. This will
|
||
|
block waiting for packets, then send a message to the uIP task when data
|
||
|
is available. */
|
||
|
xTaskCreate( prvInterruptSimulator, "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, ( configuIP_TASK_PRIORITY - 1 ), NULL );
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
static void prvInterruptSimulator( void *pvParameters )
|
||
|
{
|
||
|
static struct pcap_pkthdr *pxHeader;
|
||
|
const unsigned char *pucPacketData;
|
||
|
extern QueueHandle_t xEMACEventQueue;
|
||
|
const unsigned long ulRxEvent = uipETHERNET_RX_EVENT;
|
||
|
long lResult;
|
||
|
|
||
|
/* Just to kill the compiler warning. */
|
||
|
( void ) pvParameters;
|
||
|
|
||
|
for( ;; )
|
||
|
{
|
||
|
/* Get the next packet. */
|
||
|
lResult = pcap_next_ex( pxOpenedInterfaceHandle, &pxHeader, &pucPacketData );
|
||
|
if( lResult )
|
||
|
{
|
||
|
/* Is the next buffer into which data should be placed free? */
|
||
|
if( lLengthOfDataInBuffer[ ucNextBufferToFill ] == 0L )
|
||
|
{
|
||
|
/* Copy the data from the captured packet into the buffer. */
|
||
|
memcpy( pucEthernetBufferPointers[ ucNextBufferToFill ], pucPacketData, pxHeader->len );
|
||
|
|
||
|
/* Note the amount of data that was copied. */
|
||
|
lLengthOfDataInBuffer[ ucNextBufferToFill ] = pxHeader->len;
|
||
|
|
||
|
/* Move onto the next buffer, wrapping around if necessary. */
|
||
|
ucNextBufferToFill++;
|
||
|
if( ucNextBufferToFill >= archNUM_BUFFER_POINTERS )
|
||
|
{
|
||
|
ucNextBufferToFill = 0U;
|
||
|
}
|
||
|
|
||
|
/* Data was received and stored. Send a message to the uIP task
|
||
|
to let it know. */
|
||
|
xQueueSendToBack( xEMACEventQueue, &ulRxEvent, portMAX_DELAY );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|