2 * FreeRTOS+UDP V1.0.4
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software. If you wish to use our Amazon
\r
14 * FreeRTOS name, please do so in a fair use way that does not cause confusion.
\r
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
18 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
19 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
23 * http://www.FreeRTOS.org
\r
24 * http://aws.amazon.com/freertos
\r
26 * 1 tab == 4 spaces!
\r
29 /* WinPCap includes. */
\r
33 /* Standard includes. */
\r
36 /* FreeRTOS includes. */
\r
37 #include "FreeRTOS.h"
\r
42 /* FreeRTOS+UDP includes. */
\r
43 #include "FreeRTOS_UDP_IP.h"
\r
44 #include "FreeRTOS_IP_Private.h"
\r
45 #include "FreeRTOS_Sockets.h"
\r
46 #include "NetworkBufferManagement.h"
\r
48 /* Demo includes. */
\r
49 #include "NetworkInterface.h"
\r
51 /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
\r
52 driver will filter incoming packets and only pass the stack those packets it
\r
53 considers need processing. In this case ipCONSIDER_FRAME_FOR_PROCESSING() can
\r
54 be #defined away. If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 0
\r
55 then the Ethernet driver will pass all received packets to the stack, and the
\r
56 stack must do the filtering itself. In this case ipCONSIDER_FRAME_FOR_PROCESSING
\r
57 needs to call eConsiderFrameForProcessing. */
\r
58 #if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES != 1
\r
59 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
\r
61 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
\r
64 /*-----------------------------------------------------------*/
\r
67 * Print out a numbered list of network interfaces that are available on the
\r
70 static pcap_if_t * prvPrintAvailableNetworkInterfaces( void );
\r
73 * Open the network interface. The number of the interface to be opened is set
\r
74 * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
\r
76 static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces );
\r
79 * Configure the capture filter to allow blocking reads, and to filter out
\r
80 * packets that are not of interest to this demo.
\r
82 static void prvConfigureCaptureBehaviour( void );
\r
85 * A function that simulates Ethernet interrupts by periodically polling the
\r
86 * WinPCap interface for new data.
\r
88 static void prvInterruptSimulatorTask( void *pvParameters );
\r
90 /* The interface being used by WinPCap. */
\r
91 static pcap_t *pxOpenedInterfaceHandle = NULL;
\r
93 /*-----------------------------------------------------------*/
\r
95 /* Required by the WinPCap library. */
\r
96 static char cErrorBuffer[ PCAP_ERRBUF_SIZE ];
\r
98 /* When statically allocated network buffers are used (as opposed to having
\r
99 the buffer payloads allocated and freed as required) the actual buffer storage
\r
100 areas must be defined in the portable layer. This is because different
\r
101 microcontrollers have different location, size and alignment requirements. In
\r
102 this case the network buffers are declared in NetworkInterface.c because, as
\r
103 this file is only used on Windows machines, wasting a few bytes in buffers that
\r
104 never get used does not matter (the buffers will not get used if the dynamic
\r
105 payload allocation file is included in the project). */
\r
106 static uint8_t ucBuffers[ ipconfigNUM_NETWORK_BUFFERS ][ ipTOTAL_ETHERNET_FRAME_SIZE + ipBUFFER_PADDING ];
\r
108 /* The queue used to communicate Ethernet events with the IP task. */
\r
109 extern xQueueHandle xNetworkEventQueue;
\r
111 /* Protect the PCAP interface as it is accessed from two tasks (an interrupt
\r
112 simulator is used as real interrupts cannot be obtained from the Ethernet as
\r
113 would normally be the case). */
\r
114 xSemaphoreHandle xPCAPMutex = NULL;
\r
116 /*-----------------------------------------------------------*/
\r
118 BaseType_t xNetworkInterfaceInitialise( void )
\r
120 BaseType_t xReturn = pdFALSE;
\r
121 pcap_if_t *pxAllNetworkInterfaces;
\r
123 if( xPCAPMutex == NULL )
\r
125 xPCAPMutex = xSemaphoreCreateMutex();
\r
126 configASSERT( xPCAPMutex );
\r
129 /* Query the computer the simulation is being executed on to find the
\r
130 network interfaces it has installed. */
\r
131 pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces();
\r
133 /* Open the network interface. The number of the interface to be opened is
\r
134 set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
\r
135 Calling this function will set the pxOpenedInterfaceHandle variable. If,
\r
136 after calling this function, pxOpenedInterfaceHandle is equal to NULL, then
\r
137 the interface could not be opened. */
\r
138 if( pxAllNetworkInterfaces != NULL )
\r
140 prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces );
\r
143 if( pxOpenedInterfaceHandle != NULL )
\r
150 /*-----------------------------------------------------------*/
\r
152 #if updconfigLOOPBACK_ETHERNET_PACKETS == 1
\r
154 BaseType_t xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
156 xEthernetHeader_t *pxEthernetHeader;
\r
157 xIPStackEvent_t xRxEvent = { eEthernetRxEvent, NULL };
\r
158 extern uint8_t xDefaultPartUDPPacketHeader[];
\r
159 static const xMACAddress_t xBroadcastMACAddress = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
\r
160 BaseType_t xCanLoopback;
\r
162 pxEthernetHeader = ( xEthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer;
\r
164 if( memcmp( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &xBroadcastMACAddress, sizeof( xMACAddress_t ) ) == 0 )
\r
166 /* This is a broadcast. */
\r
167 xCanLoopback = pdTRUE;
\r
169 else if( memcmp( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) xDefaultPartUDPPacketHeader, sizeof( xMACAddress_t ) ) == 0 )
\r
171 /* This is being sent to itself. */
\r
172 xCanLoopback = pdTRUE;
\r
176 /* This is being sent externally. */
\r
177 xCanLoopback = pdFALSE;
\r
180 iptraceNETWORK_INTERFACE_TRANSMIT();
\r
182 if( xCanLoopback == pdTRUE )
\r
184 /* Just loop the frame back to the input queue. Here the loopback
\r
185 is sending a message to itself, so a block time cannot be used for
\r
186 fear of deadlocking. */
\r
187 xRxEvent.pvData = ( void * ) pxNetworkBuffer;
\r
188 if( xQueueSendToBack( xNetworkEventQueue, &xRxEvent, ( TickType_t ) 0 ) == pdFALSE )
\r
190 vNetworkBufferRelease( pxNetworkBuffer );
\r
191 iptraceETHERNET_RX_EVENT_LOST();
\r
195 iptraceNETWORK_INTERFACE_RECEIVE();
\r
200 /* Send the packet. */
\r
201 xSemaphoreTake( xPCAPMutex, portMAX_DELAY );
\r
203 pcap_sendpacket( pxOpenedInterfaceHandle, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
\r
205 xSemaphoreGive( xPCAPMutex );
\r
207 /* The buffer has been transmitted so can be released. */
\r
208 vNetworkBufferRelease( pxNetworkBuffer );
\r
214 #else /* updconfigLOOPBACK_ETHERNET_PACKETS == 1 */
\r
216 BaseType_t xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
218 xSemaphoreTake( xPCAPMutex, portMAX_DELAY );
\r
220 iptraceNETWORK_INTERFACE_TRANSMIT();
\r
221 pcap_sendpacket( pxOpenedInterfaceHandle, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
\r
223 xSemaphoreGive( xPCAPMutex );
\r
225 /* The buffer has been transmitted so can be released. */
\r
226 vNetworkBufferRelease( pxNetworkBuffer );
\r
231 #endif /* updconfigLOOPBACK_ETHERNET_PACKETS == 1 */
\r
232 /*-----------------------------------------------------------*/
\r
234 static pcap_if_t * prvPrintAvailableNetworkInterfaces( void )
\r
236 pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface;
\r
237 long lInterfaceNumber = 1;
\r
239 if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 )
\r
241 printf( "\r\nCould not obtain a list of network interfaces\r\n%s\r\n", cErrorBuffer );
\r
242 pxAllNetworkInterfaces = NULL;
\r
245 if( pxAllNetworkInterfaces != NULL )
\r
247 /* Print out the list of network interfaces. The first in the list
\r
248 is interface '1', not interface '0'. */
\r
249 for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next )
\r
251 printf( "%d. %s", lInterfaceNumber, xInterface->name );
\r
253 if( xInterface->description != NULL )
\r
255 printf( " (%s)\r\n", xInterface->description );
\r
259 printf( " (No description available)\r\n") ;
\r
262 lInterfaceNumber++;
\r
266 if( lInterfaceNumber == 1 )
\r
268 /* The interface number was never incremented, so the above for() loop
\r
269 did not execute meaning no interfaces were found. */
\r
270 printf( " \r\nNo network interfaces were found.\r\n" );
\r
271 pxAllNetworkInterfaces = NULL;
\r
274 printf( "\r\nThe interface that will be opened is set by configNETWORK_INTERFACE_TO_USE which should be defined in FreeRTOSConfig.h\r\n" );
\r
275 printf( "Attempting to open interface number %d.\r\n", configNETWORK_INTERFACE_TO_USE );
\r
277 if( ( configNETWORK_INTERFACE_TO_USE < 1L ) || ( configNETWORK_INTERFACE_TO_USE > lInterfaceNumber ) )
\r
279 printf("\r\nconfigNETWORK_INTERFACE_TO_USE is not in the valid range.\r\n" );
\r
281 if( pxAllNetworkInterfaces != NULL )
\r
283 /* Free the device list, as no devices are going to be opened. */
\r
284 pcap_freealldevs( pxAllNetworkInterfaces );
\r
285 pxAllNetworkInterfaces = NULL;
\r
289 return pxAllNetworkInterfaces;
\r
291 /*-----------------------------------------------------------*/
\r
293 static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces )
\r
295 pcap_if_t *xInterface;
\r
298 /* Walk the list of devices until the selected device is located. */
\r
299 xInterface = pxAllNetworkInterfaces;
\r
300 for( x = 0L; x < ( configNETWORK_INTERFACE_TO_USE - 1L ); x++ )
\r
302 xInterface = xInterface->next;
\r
305 /* Open the selected interface. */
\r
306 pxOpenedInterfaceHandle = pcap_open( xInterface->name, /* The name of the selected interface. */
\r
307 ipTOTAL_ETHERNET_FRAME_SIZE, /* The size of the packet to capture. */
\r
308 PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscious mode as the MAC and
\r
309 IP address is going to be "simulated", and
\r
310 not be the real MAC and IP address. This allows
\r
311 trafic to the simulated IP address to be routed
\r
312 to uIP, and trafic to the real IP address to be
\r
313 routed to the Windows TCP/IP stack. */
\r
314 0x00L, /* The read time out. */
\r
315 NULL, /* No authentication is required as this is
\r
316 not a remote capture session. */
\r
320 if ( pxOpenedInterfaceHandle == NULL )
\r
322 printf( "\r\n%s is not supported by WinPcap and cannot be opened\r\n", xInterface->name );
\r
326 /* Configure the capture filter to allow blocking reads, and to filter
\r
327 out packets that are not of interest to this demo. */
\r
328 prvConfigureCaptureBehaviour();
\r
331 /* The device list is no longer required. */
\r
332 pcap_freealldevs( pxAllNetworkInterfaces );
\r
334 /*-----------------------------------------------------------*/
\r
336 static void prvConfigureCaptureBehaviour( void )
\r
338 struct bpf_program xFilterCode;
\r
339 const long lMinBytesToCopy = 10L, lBlocking = 1L;
\r
340 unsigned long ulNetMask;
\r
342 /* Unblock a read as soon as anything is received. */
\r
343 pcap_setmintocopy( pxOpenedInterfaceHandle, lMinBytesToCopy );
\r
345 /* Allow blocking. */
\r
346 pcap_setnonblock( pxOpenedInterfaceHandle, lBlocking, cErrorBuffer );
\r
348 /* Set up a filter so only the packets of interest are passed to the IP
\r
349 stack. cErrorBuffer is used for convenience to create the string. Don't
\r
350 confuse this with an error message. *//*_RB_ This should not use the #defined constants. *//*_RB_ Constants should not be used, but passed through a generic network API. */
\r
351 sprintf( cErrorBuffer, "broadcast or multicast or ether host %x:%x:%x:%x:%x:%x", configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 );
\r
353 /*_RB_ Constants should not be used, but passed through a generic network API. */
\r
354 ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0;
\r
356 if( pcap_compile(pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 )
\r
358 printf("\r\nThe packet filter string is invalid\r\n" );
\r
362 if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 )
\r
364 printf( "\r\nAn error occurred setting the packet filter.\r\n" );
\r
368 /* Create a task that simulates an interrupt in a real system. This will
\r
369 block waiting for packets, then send a message to the uIP task when data
\r
371 xTaskCreate( prvInterruptSimulatorTask, "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, configMAC_ISR_SIMULATOR_PRIORITY, NULL );
\r
373 /*-----------------------------------------------------------*/
\r
375 static void prvInterruptSimulatorTask( void *pvParameters )
\r
377 static struct pcap_pkthdr *pxHeader;
\r
378 const uint8_t *pucPacketData;
\r
380 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
381 xIPStackEvent_t xRxEvent = { eEthernetRxEvent, NULL };
\r
382 eFrameProcessingResult_t eResult;
\r
384 /* Just to kill the compiler warning. */
\r
385 ( void ) pvParameters;
\r
389 /* Get the next packet. */
\r
390 xSemaphoreTake( xPCAPMutex, portMAX_DELAY );
\r
392 lResult = pcap_next_ex( pxOpenedInterfaceHandle, &pxHeader, &pucPacketData );
\r
394 xSemaphoreGive( xPCAPMutex );
\r
398 eResult = ipCONSIDER_FRAME_FOR_PROCESSING( pucPacketData );
\r
399 if( eResult == eProcessBuffer )
\r
401 /* Will the data fit into the frame buffer? */
\r
402 if( pxHeader->len <= ipTOTAL_ETHERNET_FRAME_SIZE )
\r
404 /* Obtain a buffer into which the data can be placed. This
\r
405 is only an interrupt simulator, not a real interrupt, so it
\r
406 is ok to call the task level function here. */
\r
407 xSemaphoreTake( xPCAPMutex, portMAX_DELAY );
\r
409 pxNetworkBuffer = pxNetworkBufferGet( pxHeader->len, 0 );
\r
411 xSemaphoreGive( xPCAPMutex );
\r
413 if( pxNetworkBuffer != NULL )
\r
415 memcpy( pxNetworkBuffer->pucEthernetBuffer, pucPacketData, pxHeader->len );
\r
416 pxNetworkBuffer->xDataLength = ( size_t ) pxHeader->len;
\r
417 xRxEvent.pvData = ( void * ) pxNetworkBuffer;
\r
419 /* Data was received and stored. Send a message to the IP
\r
420 task to let it know. */
\r
421 if( xQueueSendToBack( xNetworkEventQueue, &xRxEvent, ( TickType_t ) 0 ) == pdFALSE )
\r
423 /* The buffer could not be sent to the stack so
\r
424 must be released again. This is only an interrupt
\r
425 simulator, not a real interrupt, so it is ok to use
\r
426 the task level function here. */
\r
427 vNetworkBufferRelease( pxNetworkBuffer );
\r
428 iptraceETHERNET_RX_EVENT_LOST();
\r
432 iptraceNETWORK_INTERFACE_RECEIVE();
\r
437 iptraceETHERNET_RX_EVENT_LOST();
\r
442 /* Log that a packet was dropped because it would have
\r
443 overflowed the buffer. */
\r
449 /* There is no real way of simulating an interrupt. Make sure
\r
450 other tasks can run. */
\r
451 vTaskDelay( configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY );
\r
455 /*-----------------------------------------------------------*/
\r
457 #if configUSE_STATIC_BUFFERS == 1
\r
458 void vNetworkInterfaceAllocateRAMToBuffers( xNetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFERS ] )
\r
461 xNetworkBufferDescriptor_t **ppxStartOfBuffer;
\r
463 for( x = 0; x < ipconfigNUM_NETWORK_BUFFERS; x++ )
\r
465 /* Place a pointer to the network buffer structure at the beginning
\r
466 of the buffer that will be allocated to the structure. */
\r
467 ppxStartOfBuffer = ( xNetworkBufferDescriptor_t ** ) &( ucBuffers[ x ][ 0 ] );
\r
468 *ppxStartOfBuffer = &( pxNetworkBuffers[ x ] );
\r
470 /* Allocate the buffer to the network buffer structure, jumping over
\r
471 the bytes where the pointer to the network buffer is now stored. */
\r
472 pxNetworkBuffers[ x ].pucEthernetBuffer = &( ucBuffers[ x ][ ipBUFFER_PADDING ] );
\r
476 /*-----------------------------------------------------------*/
\r