1 /*
2 * FreeRTOS+TCP <DEVELOPMENT BRANCH>
3 * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * http://aws.amazon.com/freertos
25 * http://www.FreeRTOS.org
26 */
27
28 #include <stdlib.h>
29
30 /* WinPCap includes. */
31 #define HAVE_REMOTE
32 #include "pcap.h"
33
34 /* FreeRTOS includes. */
35 #include "FreeRTOS.h"
36 #include "task.h"
37 #include "semphr.h"
38
39 /* FreeRTOS+TCP includes. */
40 #include "FreeRTOS_IP.h"
41 #include "FreeRTOS_IP_Private.h"
42 #include "NetworkBufferManagement.h"
43 #include "FreeRTOS_Routing.h"
44
45 /* Thread-safe circular buffers are being used to pass data to and from the PCAP
46 * access functions. */
47 #include "Win32-Extensions.h"
48 #include "FreeRTOS_Stream_Buffer.h"
49
50
51 /* Sizes of the thread safe circular buffers used to pass data to and from the
52 * WinPCAP Windows threads. */
53 #define xSEND_BUFFER_SIZE 32768
54 #define xRECV_BUFFER_SIZE 32768
55
56 /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
57 * driver will filter incoming packets and only pass the stack those packets it
58 * considers need processing. */
59 #if ( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )
60 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
61 #else
62 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
63 #endif
64
65 /* Used to insert test code only. */
66 #define niDISRUPT_PACKETS 0
67
68 /*-----------------------------------------------------------*/
69
70 /*
71 * Windows threads that are outside of the control of the FreeRTOS simulator are
72 * used to interface with the WinPCAP libraries.
73 */
74 DWORD WINAPI prvWinPcapRecvThread( void * pvParam );
75 DWORD WINAPI prvWinPcapSendThread( void * pvParam );
76
77 /*
78 * A pointer to the network interface is needed later when receiving packets.
79 */
80 static NetworkInterface_t * pxMyInterface;
81
82 /*
83 * Print out a numbered list of network interfaces that are available on the
84 * host computer.
85 */
86 static pcap_if_t * prvPrintAvailableNetworkInterfaces( void );
87
88 /*
89 * Open the network interface. The number of the interface to be opened is set
90 * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
91 */
92 static void prvOpenSelectedNetworkInterface( pcap_if_t * pxAllNetworkInterfaces,
93 const NetworkInterface_t * pxInterface );
94
95 static int prvOpenInterface( const char * pucName,
96 const NetworkInterface_t * pxInterface );
97
98 /*
99 * Configure the capture filter to allow blocking reads, and to filter out
100 * packets that are not of interest to this demo.
101 */
102 static void prvConfigureCaptureBehaviour( const NetworkInterface_t * pxInterface );
103
104 /*
105 * A function that simulates Ethernet interrupts by periodically polling the
106 * WinPCap interface for new data.
107 */
108 static void prvInterruptSimulatorTask( void * pvParameters );
109
110 /*
111 * Create the buffers that are used to pass data between the FreeRTOS simulator
112 * and the Win32 threads that manage WinPCAP.
113 */
114 static void prvCreateThreadSafeBuffers( void );
115
116 /*
117 * This function is equivalent to uxStreamBufferAdd from
118 * FreeRTOS_Stream_Buffer.c in the case that the stream buffer is being used
119 * as a normal circular buffer (i.e. only the tail and head pointers are
120 * needed). Thus, this function does not take the offset argument, and does not
121 * update the front pointer of the stream buffer. This allows the removal of
122 * the calls to vTaskSuspendAll and xTaskResumeAll, as the head and front
123 * pointer no longer need to be atomically updated, allowing this function to be
124 * safely used by a Windows thread.
125 */
126 static size_t prvStreamBufferAdd( StreamBuffer_t * pxBuffer,
127 const uint8_t * pucData,
128 size_t uxByteCount );
129
130 /*
131 * Utility function used to format print messages only.
132 */
133 static const char * prvRemoveSpaces( char * pcBuffer,
134 int aBuflen,
135 const char * pcMessage );
136
137 /*
138 * This function will return pdTRUE if the packet is targeted at
139 * the MAC address of this device, in other words when is was bounced-
140 * back by the WinPCap interface.
141 */
142 static BaseType_t xPacketBouncedBack( const uint8_t * pucBuffer );
143
144 /*-----------------------------------------------------------*/
145
146 /* Required by the WinPCap library. */
147 static char cErrorBuffer[ PCAP_ERRBUF_SIZE ];
148
149 /* An event used to wake up the Win32 thread that sends data through the WinPCAP
150 * library. */
151 static void * pvSendEvent = NULL;
152
153 /* _HT_ made the PCAP interface number configurable through the program's
154 * parameters in order to test in different machines. */
155 static BaseType_t xConfigNetworkInterfaceToUse = configNETWORK_INTERFACE_TO_USE;
156
157 /* Handles to the Windows threads that handle the PCAP IO. */
158 static HANDLE vWinPcapRecvThreadHandle = NULL;
159 static HANDLE vWinPcapSendThreadHandle = NULL;
160
161 /* The interface being used by WinPCap. */
162 static pcap_t * pxOpenedInterfaceHandle = NULL;
163
164 /* Circular buffers used by the PCAP Win32 threads. */
165 static StreamBuffer_t * xSendBuffer = NULL;
166 static StreamBuffer_t * xRecvBuffer = NULL;
167
168 /* Logs the number of WinPCAP send failures, for viewing in the debugger only. */
169 static volatile uint32_t ulWinPCAPSendFailures = 0;
170
171 /*-----------------------------------------------------------*/
172
173 static BaseType_t xWinPcap_NetworkInterfaceInitialise( NetworkInterface_t * pxInterface );
174 static BaseType_t xWinPcap_NetworkInterfaceOutput( NetworkInterface_t * pxInterface,
175 NetworkBufferDescriptor_t * const pxNetworkBuffer,
176 BaseType_t bReleaseAfterSend );
177 static BaseType_t xWinPcap_GetPhyLinkStatus( NetworkInterface_t * pxInterface );
178
179 NetworkInterface_t * pxWinPcap_FillInterfaceDescriptor( BaseType_t xEMACIndex,
180 NetworkInterface_t * pxInterface );
181
182 /*-----------------------------------------------------------*/
183
xWinPcap_NetworkInterfaceInitialise(NetworkInterface_t * pxInterface)184 static BaseType_t xWinPcap_NetworkInterfaceInitialise( NetworkInterface_t * pxInterface )
185 {
186 BaseType_t xReturn = pdFALSE;
187 pcap_if_t * pxAllNetworkInterfaces;
188
189 ( void ) pxInterface;
190
191 /* Query the computer the simulation is being executed on to find the
192 * network interfaces it has installed. */
193 pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces();
194
195 /* Open the network interface. The number of the interface to be opened is
196 * set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
197 * Calling this function will set the pxOpenedInterfaceHandle variable. If,
198 * after calling this function, pxOpenedInterfaceHandle is equal to NULL, then
199 * the interface could not be opened. */
200 if( pxAllNetworkInterfaces != NULL )
201 {
202 prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces, pxInterface );
203 }
204
205 if( pxOpenedInterfaceHandle != NULL )
206 {
207 xReturn = pdPASS;
208 }
209
210 return xReturn;
211 }
212 /*-----------------------------------------------------------*/
213
prvCreateThreadSafeBuffers(void)214 static void prvCreateThreadSafeBuffers( void )
215 {
216 /* The buffer used to pass data to be transmitted from a FreeRTOS task to
217 * the Win32 thread that sends via the WinPCAP library. */
218 if( xSendBuffer == NULL )
219 {
220 xSendBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xSendBuffer ) - sizeof( xSendBuffer->ucArray ) + xSEND_BUFFER_SIZE + 1 );
221 configASSERT( xSendBuffer );
222 memset( xSendBuffer, '\0', sizeof( *xSendBuffer ) - sizeof( xSendBuffer->ucArray ) );
223 xSendBuffer->LENGTH = xSEND_BUFFER_SIZE + 1;
224 }
225
226 /* The buffer used to pass received data from the Win32 thread that receives
227 * via the WinPCAP library to the FreeRTOS task. */
228 if( xRecvBuffer == NULL )
229 {
230 xRecvBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xRecvBuffer ) - sizeof( xRecvBuffer->ucArray ) + xRECV_BUFFER_SIZE + 1 );
231 configASSERT( xRecvBuffer );
232 memset( xRecvBuffer, '\0', sizeof( *xRecvBuffer ) - sizeof( xRecvBuffer->ucArray ) );
233 xRecvBuffer->LENGTH = xRECV_BUFFER_SIZE + 1;
234 }
235 }
236
237 /*-----------------------------------------------------------*/
238
prvStreamBufferAdd(StreamBuffer_t * pxBuffer,const uint8_t * pucData,size_t uxByteCount)239 static size_t prvStreamBufferAdd( StreamBuffer_t * pxBuffer,
240 const uint8_t * pucData,
241 size_t uxByteCount )
242 {
243 size_t uxSpace, uxNextHead, uxFirst;
244 size_t uxCount = uxByteCount;
245
246 uxSpace = uxStreamBufferGetSpace( pxBuffer );
247
248 /* The number of bytes that can be written is the minimum of the number of
249 * bytes requested and the number available. */
250 uxCount = FreeRTOS_min_size_t( uxSpace, uxCount );
251
252 if( uxCount != 0U )
253 {
254 uxNextHead = pxBuffer->uxHead;
255
256 if( pucData != NULL )
257 {
258 /* Calculate the number of bytes that can be added in the first
259 * write - which may be less than the total number of bytes that need
260 * to be added if the buffer will wrap back to the beginning. */
261 uxFirst = FreeRTOS_min_size_t( pxBuffer->LENGTH - uxNextHead, uxCount );
262
263 /* Write as many bytes as can be written in the first write. */
264 ( void ) memcpy( &( pxBuffer->ucArray[ uxNextHead ] ), pucData, uxFirst );
265
266 /* If the number of bytes written was less than the number that
267 * could be written in the first write... */
268 if( uxCount > uxFirst )
269 {
270 /* ...then write the remaining bytes to the start of the
271 * buffer. */
272 ( void ) memcpy( pxBuffer->ucArray, &( pucData[ uxFirst ] ), uxCount - uxFirst );
273 }
274 }
275
276 uxNextHead += uxCount;
277
278 if( uxNextHead >= pxBuffer->LENGTH )
279 {
280 uxNextHead -= pxBuffer->LENGTH;
281 }
282
283 pxBuffer->uxHead = uxNextHead;
284 }
285
286 return uxCount;
287 }
288
289 /*-----------------------------------------------------------*/
290
xWinPcap_NetworkInterfaceOutput(NetworkInterface_t * pxInterface,NetworkBufferDescriptor_t * const pxNetworkBuffer,BaseType_t bReleaseAfterSend)291 static BaseType_t xWinPcap_NetworkInterfaceOutput( NetworkInterface_t * pxInterface,
292 NetworkBufferDescriptor_t * const pxNetworkBuffer,
293 BaseType_t bReleaseAfterSend )
294 {
295 size_t xSpace;
296
297 ( void ) pxInterface;
298
299 iptraceNETWORK_INTERFACE_TRANSMIT();
300 configASSERT( xIsCallingFromIPTask() == pdTRUE );
301
302 /* Both the length of the data being sent and the actual data being sent
303 * are placed in the thread safe buffer used to pass data between the FreeRTOS
304 * tasks and the Win32 thread that sends data via the WinPCAP library. Drop
305 * the packet if there is insufficient space in the buffer to hold both. */
306 xSpace = uxStreamBufferGetSpace( xSendBuffer );
307
308 if( ( pxNetworkBuffer->xDataLength <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) &&
309 ( xSpace >= ( pxNetworkBuffer->xDataLength + sizeof( pxNetworkBuffer->xDataLength ) ) ) )
310 {
311 /* First write in the length of the data, then write in the data
312 * itself. */
313 uxStreamBufferAdd( xSendBuffer, 0, ( const uint8_t * ) &( pxNetworkBuffer->xDataLength ), sizeof( pxNetworkBuffer->xDataLength ) );
314 uxStreamBufferAdd( xSendBuffer, 0, ( const uint8_t * ) pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
315 }
316 else
317 {
318 FreeRTOS_debug_printf( ( "xNetworkInterfaceOutput: send buffers full to store %lu\n", pxNetworkBuffer->xDataLength ) );
319 }
320
321 /* Kick the Tx task in either case in case it doesn't know the buffer is
322 * full. */
323 SetEvent( pvSendEvent );
324
325 /* The buffer has been sent so can be released. */
326 if( bReleaseAfterSend != pdFALSE )
327 {
328 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
329 }
330
331 return pdPASS;
332 }
333 /*-----------------------------------------------------------*/
334
xWinPcap_GetPhyLinkStatus(NetworkInterface_t * pxInterface)335 static BaseType_t xWinPcap_GetPhyLinkStatus( NetworkInterface_t * pxInterface )
336 {
337 BaseType_t xResult = pdFALSE;
338
339 ( void ) pxInterface;
340
341 if( pxOpenedInterfaceHandle != NULL )
342 {
343 xResult = pdTRUE;
344 }
345
346 return xResult;
347 }
348 /*-----------------------------------------------------------*/
349
350 #if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
351
352
353 /* Do not call the following function directly. It is there for downward compatibility.
354 * The function FreeRTOS_IPInit() will call it to initialice the interface and end-point
355 * objects. See the description in FreeRTOS_Routing.h. */
pxFillInterfaceDescriptor(BaseType_t xEMACIndex,NetworkInterface_t * pxInterface)356 NetworkInterface_t * pxFillInterfaceDescriptor( BaseType_t xEMACIndex,
357 NetworkInterface_t * pxInterface )
358 {
359 pxWinPcap_FillInterfaceDescriptor( xEMACIndex, pxInterface );
360 }
361
362 #endif
363 /*-----------------------------------------------------------*/
364
pxWinPcap_FillInterfaceDescriptor(BaseType_t xEMACIndex,NetworkInterface_t * pxInterface)365 NetworkInterface_t * pxWinPcap_FillInterfaceDescriptor( BaseType_t xEMACIndex,
366 NetworkInterface_t * pxInterface )
367 {
368 static char pcName[ 17 ];
369
370 /* This function pxWinPcap_FillInterfaceDescriptor() adds a network-interface.
371 * Make sure that the object pointed to by 'pxInterface'
372 * is declared static or global, and that it will remain to exist. */
373
374 pxMyInterface = pxInterface;
375
376 snprintf( pcName, sizeof( pcName ), "eth%ld", xEMACIndex );
377
378 memset( pxInterface, '\0', sizeof( *pxInterface ) );
379 pxInterface->pcName = pcName; /* Just for logging, debugging. */
380 pxInterface->pvArgument = ( void * ) xEMACIndex; /* Has only meaning for the driver functions. */
381 pxInterface->pfInitialise = xWinPcap_NetworkInterfaceInitialise;
382 pxInterface->pfOutput = xWinPcap_NetworkInterfaceOutput;
383 pxInterface->pfGetPhyLinkStatus = xWinPcap_GetPhyLinkStatus;
384
385 FreeRTOS_AddNetworkInterface( pxInterface );
386
387 return pxInterface;
388 }
389 /*-----------------------------------------------------------*/
390
391 #ifdef configNETWORK_INTERFACE_TYPE_TO_USE
392
393 /* In earlier versions of this network interface,
394 * `configNETWORK_INTERFACE_TO_USE` indicated the interface
395 * sequence number to be used. On some laptops with dynamic
396 * adapters, the numbering of interfaces changes all the time.
397 * The new macro 'configNETWORK_INTERFACE_TYPE_TO_USE' can be
398 * used to define the name of the interface to use, e.g. "Realtek"
399 * Note that a sort of strcasestr() is used to find a match between
400 * an interface name and e.g. "Realtek".
401 */
xDesiredAdapter(const char * pcDescription)402 static BaseType_t xDesiredAdapter( const char * pcDescription )
403 {
404 size_t uxIndex;
405 size_t uxLength;
406 size_t uxKeyLength = strlen( configNETWORK_INTERFACE_TYPE_TO_USE );
407 BaseType_t xMatchFound = pdFALSE;
408
409 if( ( pcDescription != NULL ) && ( pcDescription[ 0 ] != 0 ) )
410 {
411 uxLength = strlen( pcDescription );
412
413 if( uxKeyLength <= uxLength )
414 {
415 for( uxIndex = 0U; ( uxIndex <= uxLength - uxKeyLength ) && ( xMatchFound == 0 ); uxIndex++ )
416 {
417 if( strncasecmp( configNETWORK_INTERFACE_TYPE_TO_USE, &( pcDescription[ uxIndex ] ), uxKeyLength ) == 0 )
418 {
419 xMatchFound = pdTRUE;
420 break;
421 }
422 }
423 }
424 }
425
426 return xMatchFound;
427 }
428 #endif /* ifdef configNETWORK_INTERFACE_TYPE_TO_USE */
429 /*-----------------------------------------------------------*/
430
prvPrintAvailableNetworkInterfaces(void)431 static pcap_if_t * prvPrintAvailableNetworkInterfaces( void )
432 {
433 pcap_if_t * pxAllNetworkInterfaces = NULL, * xInterface;
434 int32_t lInterfaceNumber = 1;
435 char cBuffer[ 512 ];
436 static BaseType_t xInvalidInterfaceDetected = pdFALSE;
437
438 if( xInvalidInterfaceDetected == pdFALSE )
439 {
440 if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 )
441 {
442 printf( "Could not obtain a list of network interfaces\n%s\n", cErrorBuffer );
443 pxAllNetworkInterfaces = NULL;
444 }
445 else
446 {
447 printf( "\r\n\r\nThe following network interfaces are available:\r\n\r\n" );
448 }
449
450 if( pxAllNetworkInterfaces != NULL )
451 {
452 /* Print out the list of network interfaces. The first in the list
453 * is interface '1', not interface '0'. */
454 for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next )
455 {
456 /* The descriptions of the devices can be full of spaces, clean them
457 * a little. printf() can only be used here because the network is not
458 * up yet - so no other network tasks will be running. */
459 printf( "Interface %d - %s\n", lInterfaceNumber, prvRemoveSpaces( cBuffer, sizeof( cBuffer ), xInterface->name ) );
460 printf( " (%s)\n", prvRemoveSpaces( cBuffer, sizeof( cBuffer ), xInterface->description ? xInterface->description : "No description" ) );
461 printf( "\n" );
462 #ifdef configNETWORK_INTERFACE_TYPE_TO_USE
463 {
464 if( xInterface->description != NULL )
465 {
466 if( xDesiredAdapter( xInterface->description ) )
467 {
468 printf( "The description of adapter %d matches with '%s'\n", lInterfaceNumber, configNETWORK_INTERFACE_TYPE_TO_USE );
469 xConfigNetworkInterfaceToUse = lInterfaceNumber;
470 }
471 }
472 }
473 #endif /* ifdef configNETWORK_INTERFACE_TYPE_TO_USE */
474 lInterfaceNumber++;
475 }
476 }
477
478 if( lInterfaceNumber == 1 )
479 {
480 /* The interface number was never incremented, so the above for() loop
481 * did not execute meaning no interfaces were found. */
482 printf( " \nNo network interfaces were found.\n" );
483 pxAllNetworkInterfaces = NULL;
484 }
485
486 printf( "\r\nThe interface that will be opened is set by " );
487 printf( "\"configNETWORK_INTERFACE_TO_USE\", which\r\nshould be defined in FreeRTOSConfig.h\r\n" );
488
489 if( ( xConfigNetworkInterfaceToUse < 1L ) || ( xConfigNetworkInterfaceToUse >= lInterfaceNumber ) )
490 {
491 printf( "\r\nERROR: configNETWORK_INTERFACE_TO_USE is set to %d, which is an invalid value.\r\n", xConfigNetworkInterfaceToUse );
492 printf( "Please set configNETWORK_INTERFACE_TO_USE to one of the interface numbers listed above,\r\n" );
493 printf( "then re-compile and re-start the application. Only Ethernet (as opposed to WiFi)\r\n" );
494 printf( "interfaces are supported.\r\n\r\nHALTING\r\n\r\n\r\n" );
495 xInvalidInterfaceDetected = pdTRUE;
496
497 if( pxAllNetworkInterfaces != NULL )
498 {
499 /* Free the device list, as no devices are going to be opened. */
500 pcap_freealldevs( pxAllNetworkInterfaces );
501 pxAllNetworkInterfaces = NULL;
502 }
503 }
504 else
505 {
506 printf( "Attempting to open interface number %d.\n", xConfigNetworkInterfaceToUse );
507 }
508 }
509
510 return pxAllNetworkInterfaces;
511 }
512 /*-----------------------------------------------------------*/
513
prvOpenInterface(const char * pucName,const NetworkInterface_t * pxInterface)514 static int prvOpenInterface( const char * pucName,
515 const NetworkInterface_t * pxInterface )
516 {
517 static char pucInterfaceName[ 256 ];
518
519 if( pucName != NULL )
520 {
521 strncpy( pucInterfaceName, pucName, sizeof( pucInterfaceName ) );
522 }
523
524 pxOpenedInterfaceHandle = pcap_open( pucInterfaceName, /* The name of the selected interface. */
525 ipTOTAL_ETHERNET_FRAME_SIZE, /* The size of the packet to capture. */
526 PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscuous mode as the MAC and
527 * IP address is going to be "simulated", and
528 * not be the real MAC and IP address. This allows
529 * traffic to the simulated IP address to be routed
530 * to uIP, and traffic to the real IP address to be
531 * routed to the Windows TCP/IP stack. */
532 100,
533 NULL, /* No authentication is required as this is
534 * not a remote capture session. */
535 cErrorBuffer
536 );
537
538 if( pxOpenedInterfaceHandle == NULL )
539 {
540 printf( "\n%s is not supported by WinPcap and cannot be opened\n", pucInterfaceName );
541 return 1;
542 }
543 else
544 {
545 /* Configure the capture filter to allow blocking reads, and to filter
546 * out packets that are not of interest to this demo. */
547 prvConfigureCaptureBehaviour( pxInterface );
548 }
549
550 return 0;
551 }
552 /*-----------------------------------------------------------*/
553
prvOpenSelectedNetworkInterface(pcap_if_t * pxAllNetworkInterfaces,const NetworkInterface_t * pxInterface)554 static void prvOpenSelectedNetworkInterface( pcap_if_t * pxAllNetworkInterfaces,
555 const NetworkInterface_t * pxInterface )
556 {
557 pcap_if_t * pxPCAPInterface;
558 int32_t x;
559
560 /* Walk the list of devices until the selected device is located. */
561 pxPCAPInterface = pxAllNetworkInterfaces;
562
563 for( x = 0L; x < ( xConfigNetworkInterfaceToUse - 1L ); x++ )
564 {
565 pxPCAPInterface = pxPCAPInterface->next;
566 }
567
568 /* Open the selected interface. */
569 if( prvOpenInterface( pxPCAPInterface->name, pxInterface ) == 0 )
570 {
571 printf( "Successfully opened interface number %d.\n", x + 1 );
572 }
573 else
574 {
575 printf( "Failed to open interface number %d.\n", x + 1 );
576 }
577
578 /* The device list is no longer required. */
579 pcap_freealldevs( pxAllNetworkInterfaces );
580 }
581 /*-----------------------------------------------------------*/
582
prvConfigureCaptureBehaviour(const NetworkInterface_t * pxInterface)583 static void prvConfigureCaptureBehaviour( const NetworkInterface_t * pxInterface )
584 {
585 struct bpf_program xFilterCode;
586 uint32_t ulNetMask;
587 const uint8_t * pucMAC;
588 NetworkEndPoint_t * pxEndPoint;
589
590 /* Find the MAC address of the very first end-point. */
591 pxEndPoint = FreeRTOS_FirstEndPoint( pxInterface );
592
593 /* Make sure that at least one end-point is defined. */
594 configASSERT( pxEndPoint != NULL );
595
596 pucMAC = pxEndPoint->xMACAddress.ucBytes;
597
598 /* Set up a filter so only the packets of interest are passed to the IP
599 * stack. cErrorBuffer is used for convenience to create the string. Don't
600 * confuse this with an error message. */
601 snprintf( cErrorBuffer, sizeof( cErrorBuffer ), "broadcast or multicast or ether host %x:%x:%x:%x:%x:%x",
602 pucMAC[ 0 ], pucMAC[ 1 ], pucMAC[ 2 ], pucMAC[ 3 ], pucMAC[ 4 ], pucMAC[ 5 ] );
603
604 ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0;
605
606 if( pcap_compile( pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 )
607 {
608 printf( "\nThe packet filter string is invalid\n" );
609 }
610 else
611 {
612 if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 )
613 {
614 printf( "\nAn error occurred setting the packet filter.\n" );
615 }
616
617 /* When pcap_compile() succeeds, it allocates memory for the memory pointed to by the bpf_program struct
618 * parameter.pcap_freecode() will free that memory. */
619 pcap_freecode( &xFilterCode );
620 }
621
622 /* Create the buffers used to pass packets between the FreeRTOS simulator
623 * and the Win32 threads that are handling WinPCAP. */
624 prvCreateThreadSafeBuffers();
625
626 if( pvSendEvent == NULL )
627 {
628 /* Create event used to signal the Win32 WinPCAP Tx thread. */
629 pvSendEvent = CreateEvent( NULL, FALSE, TRUE, NULL );
630
631 /* Create the Win32 thread that handles WinPCAP Rx. */
632 vWinPcapRecvThreadHandle = CreateThread(
633 NULL, /* Pointer to thread security attributes. */
634 0, /* Initial thread stack size, in bytes. */
635 prvWinPcapRecvThread, /* Pointer to thread function. */
636 NULL, /* Argument for new thread. */
637 0, /* Creation flags. */
638 NULL );
639
640 /* Use the cores that are not used by the FreeRTOS tasks. */
641 SetThreadAffinityMask( vWinPcapRecvThreadHandle, ~0x01u );
642
643 /* Create the Win32 thread that handlers WinPCAP Tx. */
644 vWinPcapSendThreadHandle = CreateThread(
645 NULL, /* Pointer to thread security attributes. */
646 0, /* initial thread stack size, in bytes. */
647 prvWinPcapSendThread, /* Pointer to thread function. */
648 NULL, /* Argument for new thread. */
649 0, /* Creation flags. */
650 NULL );
651
652 /* Use the cores that are not used by the FreeRTOS tasks. */
653 SetThreadAffinityMask( vWinPcapSendThreadHandle, ~0x01u );
654
655 /* Create a task that simulates an interrupt in a real system. This will
656 * block waiting for packets, then send a message to the IP task when data
657 * is available. */
658 xTaskCreate( prvInterruptSimulatorTask, "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, configMAC_ISR_SIMULATOR_PRIORITY, NULL );
659 }
660 }
661 /*-----------------------------------------------------------*/
662
663 /* WinPCAP function. */
pcap_callback(u_char * user,const struct pcap_pkthdr * pkt_header,const u_char * pkt_data)664 void pcap_callback( u_char * user,
665 const struct pcap_pkthdr * pkt_header,
666 const u_char * pkt_data )
667 {
668 ( void ) user;
669
670 /* THIS IS CALLED FROM A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS
671 * OR TO PRINT OUT MESSAGES HERE. */
672
673 /* Pass data to the FreeRTOS simulator on a thread safe circular buffer. */
674 if( ( pkt_header->caplen <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) &&
675 ( uxStreamBufferGetSpace( xRecvBuffer ) >= ( ( ( size_t ) pkt_header->caplen ) + sizeof( *pkt_header ) ) ) )
676 {
677 /* The received packets will be written to a C source file,
678 * only if 'ipconfigUSE_DUMP_PACKETS' is defined.
679 * Otherwise, there is no action. */
680 iptraceDUMP_PACKET( ( const uint8_t * ) pkt_data, ( size_t ) pkt_header->caplen, pdTRUE );
681
682 /* NOTE. The prvStreamBufferAdd function is used here in place of
683 * uxStreamBufferAdd since the uxStreamBufferAdd call will suspend
684 * the FreeRTOS scheduler to atomically update the head and front
685 * of the stream buffer. Since xRecvBuffer is being used as a regular
686 * circular buffer (i.e. only the head and tail are needed), this call
687 * only updates the head of the buffer, removing the need to suspend
688 * the scheduler, and allowing this function to be safely called from
689 * a Windows thread. */
690 prvStreamBufferAdd( xRecvBuffer, ( const uint8_t * ) pkt_header, sizeof( *pkt_header ) );
691 prvStreamBufferAdd( xRecvBuffer, ( const uint8_t * ) pkt_data, ( size_t ) pkt_header->caplen );
692 }
693 }
694 /*-----------------------------------------------------------*/
695
prvWinPcapRecvThread(void * pvParam)696 DWORD WINAPI prvWinPcapRecvThread( void * pvParam )
697 {
698 ( void ) pvParam;
699
700 /* THIS IS A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS OR TO PRINT
701 * OUT MESSAGES HERE. */
702
703 for( ; ; )
704 {
705 pcap_dispatch( pxOpenedInterfaceHandle, 1, pcap_callback, ( u_char * ) "mydata" );
706 }
707 }
708 /*-----------------------------------------------------------*/
709
prvWinPcapSendThread(void * pvParam)710 DWORD WINAPI prvWinPcapSendThread( void * pvParam )
711 {
712 size_t xLength;
713 uint8_t ucBuffer[ ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ];
714 static char cErrorMessage[ 1024 ];
715 const DWORD xMaxMSToWait = 1000;
716
717 /* THIS IS A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS OR TO PRINT
718 * OUT MESSAGES HERE. */
719
720 /* Remove compiler warnings about unused parameters. */
721 ( void ) pvParam;
722
723 for( ; ; )
724 {
725 /* Wait until notified of something to send. */
726 WaitForSingleObject( pvSendEvent, xMaxMSToWait );
727
728 /* Is there more than the length value stored in the circular buffer
729 * used to pass data from the FreeRTOS simulator into this Win32 thread? */
730 while( uxStreamBufferGetSize( xSendBuffer ) > sizeof( xLength ) )
731 {
732 uxStreamBufferGet( xSendBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE );
733 uxStreamBufferGet( xSendBuffer, 0, ( uint8_t * ) ucBuffer, xLength, pdFALSE );
734
735 /* The packets sent will be written to a C source file,
736 * only if 'ipconfigUSE_DUMP_PACKETS' is defined.
737 * Otherwise, there is no action. */
738 iptraceDUMP_PACKET( ucBuffer, xLength, pdFALSE );
739
740 if( pcap_sendpacket( pxOpenedInterfaceHandle, ucBuffer, xLength ) != 0 )
741 {
742 ulWinPCAPSendFailures++;
743 }
744 }
745 }
746 }
747 /*-----------------------------------------------------------*/
748
xPacketBouncedBack(const uint8_t * pucBuffer)749 static BaseType_t xPacketBouncedBack( const uint8_t * pucBuffer )
750 {
751 static BaseType_t xHasWarned = pdFALSE;
752 EthernetHeader_t * pxEtherHeader;
753 NetworkEndPoint_t * pxEndPoint;
754 BaseType_t xResult = pdFALSE;
755
756 pxEtherHeader = ( EthernetHeader_t * ) pucBuffer;
757
758 /* Sometimes, packets are bounced back by the driver and we need not process them. Check
759 * whether this packet is one such packet. */
760 for( pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
761 pxEndPoint != NULL;
762 pxEndPoint = FreeRTOS_NextEndPoint( NULL, pxEndPoint ) )
763 {
764 if( memcmp( pxEndPoint->xMACAddress.ucBytes, pxEtherHeader->xSourceAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 )
765 {
766 if( xHasWarned == pdFALSE )
767 {
768 xHasWarned = pdTRUE;
769 FreeRTOS_printf( ( "Bounced back by WinPCAP interface: %02x:%02x:%02x:%02x:%02x:%02x\n",
770 pxEndPoint->xMACAddress.ucBytes[ 0 ],
771 pxEndPoint->xMACAddress.ucBytes[ 1 ],
772 pxEndPoint->xMACAddress.ucBytes[ 2 ],
773 pxEndPoint->xMACAddress.ucBytes[ 3 ],
774 pxEndPoint->xMACAddress.ucBytes[ 4 ],
775 pxEndPoint->xMACAddress.ucBytes[ 5 ] ) );
776 }
777
778 xResult = pdTRUE;
779 break;
780 }
781 }
782
783 return xResult;
784 }
785 /*-----------------------------------------------------------*/
786
prvInterruptSimulatorTask(void * pvParameters)787 static void prvInterruptSimulatorTask( void * pvParameters )
788 {
789 struct pcap_pkthdr xHeader;
790 static struct pcap_pkthdr * pxHeader;
791 const uint8_t * pucPacketData;
792 uint8_t ucRecvBuffer[ ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ];
793 NetworkBufferDescriptor_t * pxNetworkBuffer;
794 IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
795 eFrameProcessingResult_t eResult;
796
797 /* Remove compiler warnings about unused parameters. */
798 ( void ) pvParameters;
799
800 for( ; ; )
801 {
802 /* Does the circular buffer used to pass data from the Win32 thread that
803 * handles WinPCAP Rx into the FreeRTOS simulator contain another packet? */
804 if( uxStreamBufferGetSize( xRecvBuffer ) > sizeof( xHeader ) )
805 {
806 /* Get the next packet. */
807 uxStreamBufferGet( xRecvBuffer, 0, ( uint8_t * ) &xHeader, sizeof( xHeader ), pdFALSE );
808 uxStreamBufferGet( xRecvBuffer, 0, ( uint8_t * ) ucRecvBuffer, ( size_t ) xHeader.len, pdFALSE );
809 pucPacketData = ucRecvBuffer;
810 pxHeader = &xHeader;
811
812 iptraceNETWORK_INTERFACE_RECEIVE();
813
814 /* Check for minimal size. */
815 if( pxHeader->len >= sizeof( EthernetHeader_t ) )
816 {
817 eResult = ipCONSIDER_FRAME_FOR_PROCESSING( pucPacketData );
818 }
819 else
820 {
821 eResult = eReleaseBuffer;
822 }
823
824 if( eResult == eProcessBuffer )
825 {
826 /* Will the data fit into the frame buffer? */
827 if( pxHeader->len <= ipTOTAL_ETHERNET_FRAME_SIZE )
828 {
829 BaseType_t xBounced = xPacketBouncedBack( pucPacketData );
830
831 /* Obtain a buffer into which the data can be placed. This
832 * is only an interrupt simulator, not a real interrupt, so it
833 * is ok to call the task level function here, but note that
834 * some buffer implementations cannot be called from a real
835 * interrupt. */
836 if( xBounced == pdFALSE )
837 {
838 pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( pxHeader->len, 0 );
839 }
840 else
841 {
842 pxNetworkBuffer = NULL;
843 }
844
845 if( pxNetworkBuffer != NULL )
846 {
847 memcpy( pxNetworkBuffer->pucEthernetBuffer, pucPacketData, pxHeader->len );
848 pxNetworkBuffer->xDataLength = ( size_t ) pxHeader->len;
849
850 #if ( niDISRUPT_PACKETS == 1 )
851 {
852 pxNetworkBuffer = vRxFaultInjection( pxNetworkBuffer, pucPacketData );
853 }
854 #endif /* niDISRUPT_PACKETS */
855
856 if( pxNetworkBuffer != NULL )
857 {
858 xRxEvent.pvData = ( void * ) pxNetworkBuffer;
859
860 pxNetworkBuffer->pxInterface = pxMyInterface;
861 pxNetworkBuffer->pxEndPoint = FreeRTOS_MatchingEndpoint( pxMyInterface, pxNetworkBuffer->pucEthernetBuffer );
862
863 /* Just for now, make sure that there is a valid end-point. */
864 if( pxNetworkBuffer->pxEndPoint == NULL )
865 {
866 FreeRTOS_printf( ( "Network interface: dropped packet\n" ) );
867 vReleaseNetworkBufferAndDescriptor( BUFFER_FROM_WHERE_CALL( 153 ) pxNetworkBuffer );
868 }
869 else
870 {
871 /* Data was received and stored. Send a message to
872 * the IP task to let it know. */
873 if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )
874 {
875 /* The buffer could not be sent to the stack so
876 * must be released again. This is only an
877 * interrupt simulator, not a real interrupt, so it
878 * is ok to use the task level function here, but
879 * note no all buffer implementations will allow
880 * this function to be executed from a real
881 * interrupt. */
882 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
883 iptraceETHERNET_RX_EVENT_LOST();
884 }
885 }
886 }
887 else
888 {
889 /* The packet was already released or stored inside
890 * vRxFaultInjection(). Don't release it here. */
891 }
892 }
893 else
894 {
895 iptraceETHERNET_RX_EVENT_LOST();
896 }
897 }
898 else
899 {
900 /* Log that a packet was dropped because it would have
901 * overflowed the buffer, but there may be more buffers to
902 * process. */
903 }
904 }
905 }
906 else
907 {
908 /* There is no real way of simulating an interrupt. Make sure
909 * other tasks can run. */
910 vTaskDelay( configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY );
911 }
912 }
913 }
914 /*-----------------------------------------------------------*/
915
prvRemoveSpaces(char * pcBuffer,int aBuflen,const char * pcMessage)916 static const char * prvRemoveSpaces( char * pcBuffer,
917 int aBuflen,
918 const char * pcMessage )
919 {
920 char * pcTarget = pcBuffer;
921
922 /* Utility function used to format messages being printed only. */
923 while( ( *pcMessage != 0 ) && ( pcTarget < ( pcBuffer + aBuflen - 1 ) ) )
924 {
925 *( pcTarget++ ) = *pcMessage;
926
927 if( isspace( *pcMessage ) != pdFALSE )
928 {
929 while( isspace( *pcMessage ) != pdFALSE )
930 {
931 pcMessage++;
932 }
933 }
934 else
935 {
936 pcMessage++;
937 }
938 }
939
940 *pcTarget = '\0';
941
942 return pcBuffer;
943 }
944 /*-----------------------------------------------------------*/
945
946 #define BUFFER_SIZE ( ipTOTAL_ETHERNET_FRAME_SIZE + ipBUFFER_PADDING )
947 #define BUFFER_SIZE_ROUNDED_UP ( ( BUFFER_SIZE + 7 ) & ~0x07UL )
948
vNetworkInterfaceAllocateRAMToBuffers(NetworkBufferDescriptor_t pxNetworkBuffers[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS])949 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
950 {
951 static uint8_t * pucNetworkPacketBuffers = NULL;
952 size_t uxIndex;
953
954 if( pucNetworkPacketBuffers == NULL )
955 {
956 pucNetworkPacketBuffers = ( uint8_t * ) malloc( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * BUFFER_SIZE_ROUNDED_UP );
957 }
958
959 if( pucNetworkPacketBuffers == NULL )
960 {
961 FreeRTOS_printf( ( "Failed to allocate memory for pxNetworkBuffers" ) );
962 configASSERT( 0 );
963 }
964 else
965 {
966 for( uxIndex = 0; uxIndex < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; uxIndex++ )
967 {
968 size_t uxOffset = uxIndex * BUFFER_SIZE_ROUNDED_UP;
969 NetworkBufferDescriptor_t ** ppDescriptor;
970
971 /* At the beginning of each pbuff is a pointer to the relevant descriptor */
972 ppDescriptor = ( NetworkBufferDescriptor_t ** ) &( pucNetworkPacketBuffers[ uxOffset ] );
973
974 /* Set this pointer to the address of the correct descriptor */
975 *ppDescriptor = &( pxNetworkBuffers[ uxIndex ] );
976
977 /* pucEthernetBuffer is set to point ipBUFFER_PADDING bytes in from the
978 * beginning of the allocated buffer. */
979 pxNetworkBuffers[ uxIndex ].pucEthernetBuffer = &( pucNetworkPacketBuffers[ uxOffset + ipBUFFER_PADDING ] );
980 }
981 }
982 }
983