xref: /FreeRTOS-Plus-TCP-v4.0.0/source/portable/NetworkInterface/WinPCap/NetworkInterface.c (revision 2d3f4daa567ffe71aeda2e0f6d0bc02850db0627)
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