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.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
28 /* WinPCap includes. */
\r
32 /* Standard includes. */
\r
35 /* FreeRTOS includes. */
\r
36 #include "FreeRTOS.h"
\r
41 /* FreeRTOS+UDP includes. */
\r
42 #include "FreeRTOS_UDP_IP.h"
\r
43 #include "FreeRTOS_IP_Private.h"
\r
44 #include "FreeRTOS_Sockets.h"
\r
45 #include "NetworkBufferManagement.h"
\r
47 /* Demo includes. */
\r
48 #include "NetworkInterface.h"
\r
50 /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
\r
51 driver will filter incoming packets and only pass the stack those packets it
\r
52 considers need processing. In this case ipCONSIDER_FRAME_FOR_PROCESSING() can
\r
53 be #defined away. If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 0
\r
54 then the Ethernet driver will pass all received packets to the stack, and the
\r
55 stack must do the filtering itself. In this case ipCONSIDER_FRAME_FOR_PROCESSING
\r
56 needs to call eConsiderFrameForProcessing. */
\r
57 #if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES != 1
\r
58 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
\r
60 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
\r
63 /*-----------------------------------------------------------*/
\r
66 * Print out a numbered list of network interfaces that are available on the
\r
69 static pcap_if_t * prvPrintAvailableNetworkInterfaces( void );
\r
72 * Open the network interface. The number of the interface to be opened is set
\r
73 * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
\r
75 static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces );
\r
78 * Configure the capture filter to allow blocking reads, and to filter out
\r
79 * packets that are not of interest to this demo.
\r
81 static void prvConfigureCaptureBehaviour( void );
\r
84 * A function that simulates Ethernet interrupts by periodically polling the
\r
85 * WinPCap interface for new data.
\r
87 static void prvInterruptSimulatorTask( void *pvParameters );
\r
89 /* The interface being used by WinPCap. */
\r
90 static pcap_t *pxOpenedInterfaceHandle = NULL;
\r
92 /*-----------------------------------------------------------*/
\r
94 /* Required by the WinPCap library. */
\r
95 static char cErrorBuffer[ PCAP_ERRBUF_SIZE ];
\r
97 /* When statically allocated network buffers are used (as opposed to having
\r
98 the buffer payloads allocated and freed as required) the actual buffer storage
\r
99 areas must be defined in the portable layer. This is because different
\r
100 microcontrollers have different location, size and alignment requirements. In
\r
101 this case the network buffers are declared in NetworkInterface.c because, as
\r
102 this file is only used on Windows machines, wasting a few bytes in buffers that
\r
103 never get used does not matter (the buffers will not get used if the dynamic
\r
104 payload allocation file is included in the project). */
\r
105 static uint8_t ucBuffers[ ipconfigNUM_NETWORK_BUFFERS ][ ipTOTAL_ETHERNET_FRAME_SIZE + ipBUFFER_PADDING ];
\r
107 /* The queue used to communicate Ethernet events with the IP task. */
\r
108 extern xQueueHandle xNetworkEventQueue;
\r
110 /* Protect the PCAP interface as it is accessed from two tasks (an interrupt
\r
111 simulator is used as real interrupts cannot be obtained from the Ethernet as
\r
112 would normally be the case). */
\r
113 xSemaphoreHandle xPCAPMutex = NULL;
\r
115 /*-----------------------------------------------------------*/
\r
117 BaseType_t xNetworkInterfaceInitialise( void )
\r
119 BaseType_t xReturn = pdFALSE;
\r
120 pcap_if_t *pxAllNetworkInterfaces;
\r
122 if( xPCAPMutex == NULL )
\r
124 xPCAPMutex = xSemaphoreCreateMutex();
\r
125 configASSERT( xPCAPMutex );
\r
128 /* Query the computer the simulation is being executed on to find the
\r
129 network interfaces it has installed. */
\r
130 pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces();
\r
132 /* Open the network interface. The number of the interface to be opened is
\r
133 set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
\r
134 Calling this function will set the pxOpenedInterfaceHandle variable. If,
\r
135 after calling this function, pxOpenedInterfaceHandle is equal to NULL, then
\r
136 the interface could not be opened. */
\r
137 if( pxAllNetworkInterfaces != NULL )
\r
139 prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces );
\r
142 if( pxOpenedInterfaceHandle != NULL )
\r
149 /*-----------------------------------------------------------*/
\r
151 #if updconfigLOOPBACK_ETHERNET_PACKETS == 1
\r
153 BaseType_t xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
155 xEthernetHeader_t *pxEthernetHeader;
\r
156 xIPStackEvent_t xRxEvent = { eEthernetRxEvent, NULL };
\r
157 extern uint8_t xDefaultPartUDPPacketHeader[];
\r
158 static const xMACAddress_t xBroadcastMACAddress = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
\r
159 BaseType_t xCanLoopback;
\r
161 pxEthernetHeader = ( xEthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer;
\r
163 if( memcmp( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &xBroadcastMACAddress, sizeof( xMACAddress_t ) ) == 0 )
\r
165 /* This is a broadcast. */
\r
166 xCanLoopback = pdTRUE;
\r
168 else if( memcmp( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) xDefaultPartUDPPacketHeader, sizeof( xMACAddress_t ) ) == 0 )
\r
170 /* This is being sent to itself. */
\r
171 xCanLoopback = pdTRUE;
\r
175 /* This is being sent externally. */
\r
176 xCanLoopback = pdFALSE;
\r
179 iptraceNETWORK_INTERFACE_TRANSMIT();
\r
181 if( xCanLoopback == pdTRUE )
\r
183 /* Just loop the frame back to the input queue. Here the loopback
\r
184 is sending a message to itself, so a block time cannot be used for
\r
185 fear of deadlocking. */
\r
186 xRxEvent.pvData = ( void * ) pxNetworkBuffer;
\r
187 if( xQueueSendToBack( xNetworkEventQueue, &xRxEvent, ( TickType_t ) 0 ) == pdFALSE )
\r
189 vNetworkBufferRelease( pxNetworkBuffer );
\r
190 iptraceETHERNET_RX_EVENT_LOST();
\r
194 iptraceNETWORK_INTERFACE_RECEIVE();
\r
199 /* Send the packet. */
\r
200 xSemaphoreTake( xPCAPMutex, portMAX_DELAY );
\r
202 pcap_sendpacket( pxOpenedInterfaceHandle, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
\r
204 xSemaphoreGive( xPCAPMutex );
\r
206 /* The buffer has been transmitted so can be released. */
\r
207 vNetworkBufferRelease( pxNetworkBuffer );
\r
213 #else /* updconfigLOOPBACK_ETHERNET_PACKETS == 1 */
\r
215 BaseType_t xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
217 xSemaphoreTake( xPCAPMutex, portMAX_DELAY );
\r
219 iptraceNETWORK_INTERFACE_TRANSMIT();
\r
220 pcap_sendpacket( pxOpenedInterfaceHandle, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
\r
222 xSemaphoreGive( xPCAPMutex );
\r
224 /* The buffer has been transmitted so can be released. */
\r
225 vNetworkBufferRelease( pxNetworkBuffer );
\r
230 #endif /* updconfigLOOPBACK_ETHERNET_PACKETS == 1 */
\r
231 /*-----------------------------------------------------------*/
\r
233 static pcap_if_t * prvPrintAvailableNetworkInterfaces( void )
\r
235 pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface;
\r
236 long lInterfaceNumber = 1;
\r
238 if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 )
\r
240 printf( "\r\nCould not obtain a list of network interfaces\r\n%s\r\n", cErrorBuffer );
\r
241 pxAllNetworkInterfaces = NULL;
\r
244 if( pxAllNetworkInterfaces != NULL )
\r
246 /* Print out the list of network interfaces. The first in the list
\r
247 is interface '1', not interface '0'. */
\r
248 for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next )
\r
250 printf( "%d. %s", lInterfaceNumber, xInterface->name );
\r
252 if( xInterface->description != NULL )
\r
254 printf( " (%s)\r\n", xInterface->description );
\r
258 printf( " (No description available)\r\n") ;
\r
261 lInterfaceNumber++;
\r
265 if( lInterfaceNumber == 1 )
\r
267 /* The interface number was never incremented, so the above for() loop
\r
268 did not execute meaning no interfaces were found. */
\r
269 printf( " \r\nNo network interfaces were found.\r\n" );
\r
270 pxAllNetworkInterfaces = NULL;
\r
273 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
274 printf( "Attempting to open interface number %d.\r\n", configNETWORK_INTERFACE_TO_USE );
\r
276 if( ( configNETWORK_INTERFACE_TO_USE < 1L ) || ( configNETWORK_INTERFACE_TO_USE > lInterfaceNumber ) )
\r
278 printf("\r\nconfigNETWORK_INTERFACE_TO_USE is not in the valid range.\r\n" );
\r
280 if( pxAllNetworkInterfaces != NULL )
\r
282 /* Free the device list, as no devices are going to be opened. */
\r
283 pcap_freealldevs( pxAllNetworkInterfaces );
\r
284 pxAllNetworkInterfaces = NULL;
\r
288 return pxAllNetworkInterfaces;
\r
290 /*-----------------------------------------------------------*/
\r
292 static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces )
\r
294 pcap_if_t *xInterface;
\r
297 /* Walk the list of devices until the selected device is located. */
\r
298 xInterface = pxAllNetworkInterfaces;
\r
299 for( x = 0L; x < ( configNETWORK_INTERFACE_TO_USE - 1L ); x++ )
\r
301 xInterface = xInterface->next;
\r
304 /* Open the selected interface. */
\r
305 pxOpenedInterfaceHandle = pcap_open( xInterface->name, /* The name of the selected interface. */
\r
306 ipTOTAL_ETHERNET_FRAME_SIZE, /* The size of the packet to capture. */
\r
307 PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscious mode as the MAC and
\r
308 IP address is going to be "simulated", and
\r
309 not be the real MAC and IP address. This allows
\r
310 trafic to the simulated IP address to be routed
\r
311 to uIP, and trafic to the real IP address to be
\r
312 routed to the Windows TCP/IP stack. */
\r
313 0x00L, /* The read time out. */
\r
314 NULL, /* No authentication is required as this is
\r
315 not a remote capture session. */
\r
319 if ( pxOpenedInterfaceHandle == NULL )
\r
321 printf( "\r\n%s is not supported by WinPcap and cannot be opened\r\n", xInterface->name );
\r
325 /* Configure the capture filter to allow blocking reads, and to filter
\r
326 out packets that are not of interest to this demo. */
\r
327 prvConfigureCaptureBehaviour();
\r
330 /* The device list is no longer required. */
\r
331 pcap_freealldevs( pxAllNetworkInterfaces );
\r
333 /*-----------------------------------------------------------*/
\r
335 static void prvConfigureCaptureBehaviour( void )
\r
337 struct bpf_program xFilterCode;
\r
338 const long lMinBytesToCopy = 10L, lBlocking = 1L;
\r
339 unsigned long ulNetMask;
\r
341 /* Unblock a read as soon as anything is received. */
\r
342 pcap_setmintocopy( pxOpenedInterfaceHandle, lMinBytesToCopy );
\r
344 /* Allow blocking. */
\r
345 pcap_setnonblock( pxOpenedInterfaceHandle, lBlocking, cErrorBuffer );
\r
347 /* Set up a filter so only the packets of interest are passed to the IP
\r
348 stack. cErrorBuffer is used for convenience to create the string. Don't
\r
349 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
350 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
352 /*_RB_ Constants should not be used, but passed through a generic network API. */
\r
353 ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0;
\r
355 if( pcap_compile(pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 )
\r
357 printf("\r\nThe packet filter string is invalid\r\n" );
\r
361 if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 )
\r
363 printf( "\r\nAn error occurred setting the packet filter.\r\n" );
\r
367 /* Create a task that simulates an interrupt in a real system. This will
\r
368 block waiting for packets, then send a message to the uIP task when data
\r
370 xTaskCreate( prvInterruptSimulatorTask, "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, configMAC_ISR_SIMULATOR_PRIORITY, NULL );
\r
372 /*-----------------------------------------------------------*/
\r
374 static void prvInterruptSimulatorTask( void *pvParameters )
\r
376 static struct pcap_pkthdr *pxHeader;
\r
377 const uint8_t *pucPacketData;
\r
379 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
380 xIPStackEvent_t xRxEvent = { eEthernetRxEvent, NULL };
\r
381 eFrameProcessingResult_t eResult;
\r
383 /* Just to kill the compiler warning. */
\r
384 ( void ) pvParameters;
\r
388 /* Get the next packet. */
\r
389 xSemaphoreTake( xPCAPMutex, portMAX_DELAY );
\r
391 lResult = pcap_next_ex( pxOpenedInterfaceHandle, &pxHeader, &pucPacketData );
\r
393 xSemaphoreGive( xPCAPMutex );
\r
397 eResult = ipCONSIDER_FRAME_FOR_PROCESSING( pucPacketData );
\r
398 if( eResult == eProcessBuffer )
\r
400 /* Will the data fit into the frame buffer? */
\r
401 if( pxHeader->len <= ipTOTAL_ETHERNET_FRAME_SIZE )
\r
403 /* Obtain a buffer into which the data can be placed. This
\r
404 is only an interrupt simulator, not a real interrupt, so it
\r
405 is ok to call the task level function here. */
\r
406 xSemaphoreTake( xPCAPMutex, portMAX_DELAY );
\r
408 pxNetworkBuffer = pxNetworkBufferGet( pxHeader->len, 0 );
\r
410 xSemaphoreGive( xPCAPMutex );
\r
412 if( pxNetworkBuffer != NULL )
\r
414 memcpy( pxNetworkBuffer->pucEthernetBuffer, pucPacketData, pxHeader->len );
\r
415 pxNetworkBuffer->xDataLength = ( size_t ) pxHeader->len;
\r
416 xRxEvent.pvData = ( void * ) pxNetworkBuffer;
\r
418 /* Data was received and stored. Send a message to the IP
\r
419 task to let it know. */
\r
420 if( xQueueSendToBack( xNetworkEventQueue, &xRxEvent, ( TickType_t ) 0 ) == pdFALSE )
\r
422 /* The buffer could not be sent to the stack so
\r
423 must be released again. This is only an interrupt
\r
424 simulator, not a real interrupt, so it is ok to use
\r
425 the task level function here. */
\r
426 vNetworkBufferRelease( pxNetworkBuffer );
\r
427 iptraceETHERNET_RX_EVENT_LOST();
\r
431 iptraceNETWORK_INTERFACE_RECEIVE();
\r
436 iptraceETHERNET_RX_EVENT_LOST();
\r
441 /* Log that a packet was dropped because it would have
\r
442 overflowed the buffer. */
\r
448 /* There is no real way of simulating an interrupt. Make sure
\r
449 other tasks can run. */
\r
450 vTaskDelay( configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY );
\r
454 /*-----------------------------------------------------------*/
\r
456 #if configUSE_STATIC_BUFFERS == 1
\r
457 void vNetworkInterfaceAllocateRAMToBuffers( xNetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFERS ] )
\r
460 xNetworkBufferDescriptor_t **ppxStartOfBuffer;
\r
462 for( x = 0; x < ipconfigNUM_NETWORK_BUFFERS; x++ )
\r
464 /* Place a pointer to the network buffer structure at the beginning
\r
465 of the buffer that will be allocated to the structure. */
\r
466 ppxStartOfBuffer = ( xNetworkBufferDescriptor_t ** ) &( ucBuffers[ x ][ 0 ] );
\r
467 *ppxStartOfBuffer = &( pxNetworkBuffers[ x ] );
\r
469 /* Allocate the buffer to the network buffer structure, jumping over
\r
470 the bytes where the pointer to the network buffer is now stored. */
\r
471 pxNetworkBuffers[ x ].pucEthernetBuffer = &( ucBuffers[ x ][ ipBUFFER_PADDING ] );
\r
475 /*-----------------------------------------------------------*/
\r