2 * FreeRTOS+UDP V1.0.0 (C) 2013 Real Time Engineers ltd.
\r
4 * This file is part of the FreeRTOS+UDP distribution. The FreeRTOS+UDP license
\r
5 * terms are different to the FreeRTOS license terms.
\r
7 * FreeRTOS+UDP uses a dual license model that allows the software to be used
\r
8 * under a standard GPL open source license, or a commercial license. The
\r
9 * standard GPL license (unlike the modified GPL license under which FreeRTOS
\r
10 * itself is distributed) requires that all software statically linked with
\r
11 * FreeRTOS+UDP is also distributed under the same GPL V2 license terms.
\r
12 * Details of both license options follow:
\r
14 * - Open source licensing -
\r
15 * FreeRTOS+UDP is a free download and may be used, modified, evaluated and
\r
16 * distributed without charge provided the user adheres to version two of the
\r
17 * GNU General Public License (GPL) and does not remove the copyright notice or
\r
18 * this text. The GPL V2 text is available on the gnu.org web site, and on the
\r
19 * following URL: http://www.FreeRTOS.org/gpl-2.0.txt.
\r
21 * - Commercial licensing -
\r
22 * Businesses and individuals that for commercial or other reasons cannot comply
\r
23 * with the terms of the GPL V2 license must obtain a commercial license before
\r
24 * incorporating FreeRTOS+UDP into proprietary software for distribution in any
\r
25 * form. Commercial licenses can be purchased from http://shop.freertos.org/udp
\r
26 * and do not require any source files to be changed.
\r
28 * FreeRTOS+UDP is distributed in the hope that it will be useful. You cannot
\r
29 * use FreeRTOS+UDP unless you agree that you use the software 'as is'.
\r
30 * FreeRTOS+UDP is provided WITHOUT ANY WARRANTY; without even the implied
\r
31 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
32 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
33 * implied, expressed, or statutory.
\r
35 * 1 tab == 4 spaces!
\r
37 * http://www.FreeRTOS.org
\r
38 * http://www.FreeRTOS.org/udp
\r
42 /* WinPCap includes. */
\r
46 /* Standard includes. */
\r
49 /* FreeRTOS includes. */
\r
50 #include "FreeRTOS.h"
\r
55 /* FreeRTOS+UDP includes. */
\r
56 #include "FreeRTOS_UDP_IP.h"
\r
57 #include "FreeRTOS_IP_Private.h"
\r
58 #include "FreeRTOS_Sockets.h"
\r
59 #include "NetworkBufferManagement.h"
\r
61 /* Demo includes. */
\r
62 #include "NetworkInterface.h"
\r
64 /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
\r
65 driver will filter incoming packets and only pass the stack those packets it
\r
66 considers need processing. In this case ipCONSIDER_FRAME_FOR_PROCESSING() can
\r
67 be #defined away. If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 0
\r
68 then the Ethernet driver will pass all received packets to the stack, and the
\r
69 stack must do the filtering itself. In this case ipCONSIDER_FRAME_FOR_PROCESSING
\r
70 needs to call eConsiderFrameForProcessing. */
\r
71 #if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES != 1
\r
72 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
\r
74 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
\r
77 /*-----------------------------------------------------------*/
\r
80 * Print out a numbered list of network interfaces that are available on the
\r
83 static pcap_if_t * prvPrintAvailableNetworkInterfaces( void );
\r
86 * Open the network interface. The number of the interface to be opened is set
\r
87 * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
\r
89 static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces );
\r
92 * Configure the capture filter to allow blocking reads, and to filter out
\r
93 * packets that are not of interest to this demo.
\r
95 static void prvConfigureCaptureBehaviour( void );
\r
98 * A function that simulates Ethernet interrupts by periodically polling the
\r
99 * WinPCap interface for new data.
\r
101 static void prvInterruptSimulatorTask( void *pvParameters );
\r
103 /* The interface being used by WinPCap. */
\r
104 static pcap_t *pxOpenedInterfaceHandle = NULL;
\r
106 /*-----------------------------------------------------------*/
\r
108 /* Required by the WinPCap library. */
\r
109 static char cErrorBuffer[ PCAP_ERRBUF_SIZE ];
\r
111 /* When statically allocated network buffers are used (as opposed to having
\r
112 the buffer payloads allocated and freed as required) the actual buffer storage
\r
113 areas must be defined in the portable layer. This is because different
\r
114 microcontrollers have different location, size and alignment requirements. In
\r
115 this case the network buffers are declared in NetworkInterface.c because, as
\r
116 this file is only used on Windows machines, wasting a few bytes in buffers that
\r
117 never get used does not matter (the buffers will not get used if the dynamic
\r
118 payload allocation file is included in the project). */
\r
119 static uint8_t ucBuffers[ ipconfigNUM_NETWORK_BUFFERS ][ ipTOTAL_ETHERNET_FRAME_SIZE ];
\r
121 /* The queue used to communicate Ethernet events with the IP task. */
\r
122 extern xQueueHandle xNetworkEventQueue;
\r
124 /* Protect the PCAP interface as it is accessed from two tasks (an interrupt
\r
125 simulator is used as real interrupts cannot be obtained from the Ethernet as
\r
126 would normally be the case). */
\r
127 xSemaphoreHandle xPCAPMutex = NULL;
\r
129 /*-----------------------------------------------------------*/
\r
131 portBASE_TYPE xNetworkInterfaceInitialise( void )
\r
133 portBASE_TYPE xReturn = pdFALSE;
\r
134 pcap_if_t *pxAllNetworkInterfaces;
\r
136 if( xPCAPMutex == NULL )
\r
138 xPCAPMutex = xSemaphoreCreateMutex();
\r
139 configASSERT( xPCAPMutex );
\r
142 /* Query the computer the simulation is being executed on to find the
\r
143 network interfaces it has installed. */
\r
144 pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces();
\r
146 /* Open the network interface. The number of the interface to be opened is
\r
147 set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
\r
148 Calling this function will set the pxOpenedInterfaceHandle variable. If,
\r
149 after calling this function, pxOpenedInterfaceHandle is equal to NULL, then
\r
150 the interface could not be opened. */
\r
151 if( pxAllNetworkInterfaces != NULL )
\r
153 prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces );
\r
156 if( pxOpenedInterfaceHandle != NULL )
\r
163 /*-----------------------------------------------------------*/
\r
165 #if updconfigLOOPBACK_ETHERNET_PACKETS == 1
\r
167 portBASE_TYPE xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
169 xEthernetHeader_t *pxEthernetHeader;
\r
170 xIPStackEvent_t xRxEvent = { eEthernetRxEvent, NULL };
\r
171 extern uint8_t xDefaultPartUDPPacketHeader[];
\r
172 static const xMACAddress_t xBroadcastMACAddress = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
\r
173 portBASE_TYPE xCanLoopback;
\r
175 pxEthernetHeader = ( xEthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer;
\r
177 if( memcmp( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &xBroadcastMACAddress, sizeof( xMACAddress_t ) ) == 0 )
\r
179 /* This is a broadcast. */
\r
180 xCanLoopback = pdTRUE;
\r
182 else if( memcmp( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) xDefaultPartUDPPacketHeader, sizeof( xMACAddress_t ) ) == 0 )
\r
184 /* This is being sent to itself. */
\r
185 xCanLoopback = pdTRUE;
\r
189 /* This is being sent externally. */
\r
190 xCanLoopback = pdFALSE;
\r
193 iptraceNETWORK_INTERFACE_TRANSMIT();
\r
195 if( xCanLoopback == pdTRUE )
\r
197 /* Just loop the frame back to the input queue. Here the loopback
\r
198 is sending a message to itself, so a block time cannot be used for
\r
199 fear of deadlocking. */
\r
200 xRxEvent.pvData = ( void * ) pxNetworkBuffer;
\r
201 if( xQueueSendToBack( xNetworkEventQueue, &xRxEvent, ( portTickType ) 0 ) == pdFALSE )
\r
203 vNetworkBufferRelease( pxNetworkBuffer );
\r
204 iptraceETHERNET_RX_EVENT_LOST();
\r
209 /* Send the packet. */
\r
210 xSemaphoreTake( xPCAPMutex, portMAX_DELAY );
\r
212 pcap_sendpacket( pxOpenedInterfaceHandle, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
\r
214 xSemaphoreGive( xPCAPMutex );
\r
216 /* The buffer has been transmitted so can be released. */
\r
217 vNetworkBufferRelease( pxNetworkBuffer );
\r
223 #else /* updconfigLOOPBACK_ETHERNET_PACKETS == 1 */
\r
225 portBASE_TYPE xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
227 xSemaphoreTake( xPCAPMutex, portMAX_DELAY );
\r
229 iptraceNETWORK_INTERFACE_TRANSMIT();
\r
230 pcap_sendpacket( pxOpenedInterfaceHandle, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
\r
232 xSemaphoreGive( xPCAPMutex );
\r
234 /* The buffer has been transmitted so can be released. */
\r
235 vNetworkBufferRelease( pxNetworkBuffer );
\r
240 #endif /* updconfigLOOPBACK_ETHERNET_PACKETS == 1 */
\r
241 /*-----------------------------------------------------------*/
\r
243 static pcap_if_t * prvPrintAvailableNetworkInterfaces( void )
\r
245 pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface;
\r
246 long lInterfaceNumber = 1;
\r
248 if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 )
\r
250 printf( "\r\nCould not obtain a list of network interfaces\r\n%s\r\n", cErrorBuffer );
\r
251 pxAllNetworkInterfaces = NULL;
\r
254 if( pxAllNetworkInterfaces != NULL )
\r
256 /* Print out the list of network interfaces. The first in the list
\r
257 is interface '1', not interface '0'. */
\r
258 for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next )
\r
260 printf( "%d. %s", lInterfaceNumber, xInterface->name );
\r
262 if( xInterface->description != NULL )
\r
264 printf( " (%s)\r\n", xInterface->description );
\r
268 printf( " (No description available)\r\n") ;
\r
271 lInterfaceNumber++;
\r
275 if( lInterfaceNumber == 1 )
\r
277 /* The interface number was never incremented, so the above for() loop
\r
278 did not execute meaning no interfaces were found. */
\r
279 printf( " \r\nNo network interfaces were found.\r\n" );
\r
280 pxAllNetworkInterfaces = NULL;
\r
283 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
284 printf( "Attempting to open interface number %d.\r\n", configNETWORK_INTERFACE_TO_USE );
\r
286 if( ( configNETWORK_INTERFACE_TO_USE < 1L ) || ( configNETWORK_INTERFACE_TO_USE > lInterfaceNumber ) )
\r
288 printf("\r\nconfigNETWORK_INTERFACE_TO_USE is not in the valid range.\r\n" );
\r
290 if( pxAllNetworkInterfaces != NULL )
\r
292 /* Free the device list, as no devices are going to be opened. */
\r
293 pcap_freealldevs( pxAllNetworkInterfaces );
\r
294 pxAllNetworkInterfaces = NULL;
\r
298 return pxAllNetworkInterfaces;
\r
300 /*-----------------------------------------------------------*/
\r
302 static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces )
\r
304 pcap_if_t *xInterface;
\r
307 /* Walk the list of devices until the selected device is located. */
\r
308 xInterface = pxAllNetworkInterfaces;
\r
309 for( x = 0L; x < ( configNETWORK_INTERFACE_TO_USE - 1L ); x++ )
\r
311 xInterface = xInterface->next;
\r
314 /* Open the selected interface. */
\r
315 pxOpenedInterfaceHandle = pcap_open( xInterface->name, /* The name of the selected interface. */
\r
316 ipTOTAL_ETHERNET_FRAME_SIZE, /* The size of the packet to capture. */
\r
317 PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscious mode as the MAC and
\r
318 IP address is going to be "simulated", and
\r
319 not be the real MAC and IP address. This allows
\r
320 trafic to the simulated IP address to be routed
\r
321 to uIP, and trafic to the real IP address to be
\r
322 routed to the Windows TCP/IP stack. */
\r
323 0x00L, /* The read time out. */
\r
324 NULL, /* No authentication is required as this is
\r
325 not a remote capture session. */
\r
329 if ( pxOpenedInterfaceHandle == NULL )
\r
331 printf( "\r\n%s is not supported by WinPcap and cannot be opened\r\n", xInterface->name );
\r
335 /* Configure the capture filter to allow blocking reads, and to filter
\r
336 out packets that are not of interest to this demo. */
\r
337 prvConfigureCaptureBehaviour();
\r
340 /* The device list is no longer required. */
\r
341 pcap_freealldevs( pxAllNetworkInterfaces );
\r
343 /*-----------------------------------------------------------*/
\r
345 static void prvConfigureCaptureBehaviour( void )
\r
347 struct bpf_program xFilterCode;
\r
348 const long lMinBytesToCopy = 10L, lBlocking = 1L;
\r
349 unsigned long ulNetMask;
\r
351 /* Unblock a read as soon as anything is received. */
\r
352 pcap_setmintocopy( pxOpenedInterfaceHandle, lMinBytesToCopy );
\r
354 /* Allow blocking. */
\r
355 pcap_setnonblock( pxOpenedInterfaceHandle, lBlocking, cErrorBuffer );
\r
357 /* Set up a filter so only the packets of interest are passed to the IP
\r
358 stack. cErrorBuffer is used for convenience to create the string. Don't
\r
359 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
360 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
362 /*_RB_ Constants should not be used, but passed through a generic network API. */
\r
363 ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0;
\r
365 if( pcap_compile(pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 )
\r
367 printf("\r\nThe packet filter string is invalid\r\n" );
\r
371 if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 )
\r
373 printf( "\r\nAn error occurred setting the packet filter.\r\n" );
\r
377 /* Create a task that simulates an interrupt in a real system. This will
\r
378 block waiting for packets, then send a message to the uIP task when data
\r
380 xTaskCreate( prvInterruptSimulatorTask, ( signed char * ) "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, configMAC_ISR_SIMULATOR_PRIORITY, NULL );
\r
382 /*-----------------------------------------------------------*/
\r
384 static void prvInterruptSimulatorTask( void *pvParameters )
\r
386 static struct pcap_pkthdr *pxHeader;
\r
387 const uint8_t *pucPacketData;
\r
389 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
390 xIPStackEvent_t xRxEvent = { eEthernetRxEvent, NULL };
\r
391 eFrameProcessingResult_t eResult;
\r
393 /* Just to kill the compiler warning. */
\r
394 ( void ) pvParameters;
\r
398 /* Get the next packet. */
\r
399 xSemaphoreTake( xPCAPMutex, portMAX_DELAY );
\r
401 lResult = pcap_next_ex( pxOpenedInterfaceHandle, &pxHeader, &pucPacketData );
\r
403 xSemaphoreGive( xPCAPMutex );
\r
407 eResult = ipCONSIDER_FRAME_FOR_PROCESSING( pucPacketData );
\r
408 if( eResult == eProcessBuffer )
\r
410 /* Will the data fit into the frame buffer? */
\r
411 if( pxHeader->len <= ipTOTAL_ETHERNET_FRAME_SIZE )
\r
413 /* Obtain a buffer into which the data can be placed. This
\r
414 is only an interrupt simulator, not a real interrupt, so it
\r
415 is ok to call the task level function here. */
\r
416 xSemaphoreTake( xPCAPMutex, portMAX_DELAY );
\r
418 pxNetworkBuffer = pxNetworkBufferGet( pxHeader->len, 0 );
\r
420 xSemaphoreGive( xPCAPMutex );
\r
422 if( pxNetworkBuffer != NULL )
\r
424 memcpy( pxNetworkBuffer->pucEthernetBuffer, pucPacketData, pxHeader->len );
\r
425 pxNetworkBuffer->xDataLength = ( size_t ) pxHeader->len;
\r
426 xRxEvent.pvData = ( void * ) pxNetworkBuffer;
\r
428 /* Data was received and stored. Send a message to the IP
\r
429 task to let it know. */
\r
430 if( xQueueSendToBack( xNetworkEventQueue, &xRxEvent, ( portTickType ) 0 ) == pdFALSE )
\r
432 /* The buffer could not be sent to the stack so
\r
433 must be released again. This is only an interrupt
\r
434 simulator, not a real interrupt, so it is ok to use
\r
435 the task level function here. */
\r
436 vNetworkBufferRelease( pxNetworkBuffer );
\r
437 iptraceETHERNET_RX_EVENT_LOST();
\r
442 iptraceETHERNET_RX_EVENT_LOST();
\r
447 /* Log that a packet was dropped because it would have
\r
448 overflowed the buffer. */
\r
454 /* There is no real way of simulating an interrupt. Make sure
\r
455 other tasks can run. */
\r
456 vTaskDelay( configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY );
\r
460 /*-----------------------------------------------------------*/
\r
462 #if configUSE_STATIC_BUFFERS == 1
\r
463 void vNetworkInterfaceAllocateRAMToBuffers( xNetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFERS ] )
\r
467 for( x = 0; x < ipconfigNUM_NETWORK_BUFFERS; x++ )
\r
469 pxNetworkBuffers[ x ].pucEthernetBuffer = &( ucBuffers[ x ][ 0 ] );
\r
473 /*-----------------------------------------------------------*/
\r