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