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 /* WinPCap includes. */
28 #include "pcap.h"
29 #include "remote-ext.h"
30 
31 /* uIP includes. */
32 #include "net/uip.h"
33 #include "net/uip_arp.h"
34 #include "net/clock-arch.h"
35 
36 /* FreeRTOS includes. */
37 #include "FreeRTOS.h"
38 #include "task.h"
39 #include "queue.h"
40 
41 /*
42  * Query the computer the simulation is being executed on to find the network
43  * interfaces it has installed.
44  */
45 static pcap_if_t * prvPrintAvailableNetworkInterfaces( void );
46 
47 /*
48  * Open the network interface.  The number of the interface to be opened is set
49  * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
50  */
51 static void prvOpenSelectedNetworkInterface( pcap_if_t * pxAllNetworkInterfaces );
52 
53 /*
54  * Configure the capture filter to allow blocking reads, and to filter out
55  * packets that are not of interest to this demo.
56  */
57 static void prvConfigureCaptureBehaviour( void );
58 
59 pcap_t * pxOpenedInterfaceHandle = NULL;
60 LARGE_INTEGER freq, sys_start_time;
61 
62 #define archNUM_BUFFERS            5
63 #define archNUM_BUFFER_POINTERS    ( archNUM_BUFFERS - 1 )
64 
65 static void prvInterruptSimulator( void * pvParameters );
66 
67 static unsigned char ucEthernetBuffer[ archNUM_BUFFERS ][ UIP_CONF_BUFFER_SIZE ];
68 static unsigned char * pucEthernetBufferPointers[ archNUM_BUFFER_POINTERS ];
69 
70 static long lLengthOfDataInBuffer[ archNUM_BUFFER_POINTERS ] = { 0 };
71 static unsigned char ucNextBufferToFill = 0U, ucNextBufferToProcess = 0U;
72 
73 unsigned char * uip_buf = NULL;
74 char cErrorBuffer[ PCAP_ERRBUF_SIZE ];
75 
vNetifTx(void)76 void vNetifTx( void )
77 {
78     pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len );
79     pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len );
80 }
81 /*-----------------------------------------------------------*/
82 
uxNetifRx(void)83 UBaseType_t uxNetifRx( void )
84 {
85     UBaseType_t xDataLen;
86     unsigned char * pucTemp;
87 
88     /* Check there is really data available. */
89     xDataLen = lLengthOfDataInBuffer[ ucNextBufferToProcess ];
90 
91     if( xDataLen != 0L )
92     {
93         /* The buffer pointed to by uip_buf is going to change.  Remember which
94          * buffer uip_buf is currently pointing to. */
95         pucTemp = uip_buf;
96 
97         /* Point uip_buf at the next buffer that contains data. */
98         uip_buf = pucEthernetBufferPointers[ ucNextBufferToProcess ];
99 
100         /* The buffer pointed to by
101          * pucEthernetBufferPointeres[ ucNextBufferToProcess ] is now in use by
102          * uip_buf, but the buffer uip_buf was pointing to on entry to this
103          * function is free.  Set
104          * pucEthernetBufferPointeres[ ucNextBufferToProcess ] to the free
105          * buffer. */
106         pucEthernetBufferPointers[ ucNextBufferToProcess ] = pucTemp;
107         lLengthOfDataInBuffer[ ucNextBufferToProcess ] = 0L;
108 
109         ucNextBufferToProcess++;
110 
111         if( ucNextBufferToProcess >= archNUM_BUFFER_POINTERS )
112         {
113             ucNextBufferToProcess = 0L;
114         }
115     }
116 
117     return xDataLen;
118 }
119 /*-----------------------------------------------------------*/
120 
xNetifInit(void)121 BaseType_t xNetifInit( void )
122 {
123     BaseType_t x;
124     pcap_if_t * pxAllNetworkInterfaces;
125 
126     /* Allocate a free buffer to each buffer pointer. */
127     for( x = 0; x < sizeof( pucEthernetBufferPointers ) / sizeof( unsigned char * ); x++ )
128     {
129         pucEthernetBufferPointers[ x ] = &( ucEthernetBuffer[ x ][ 0 ] );
130     }
131 
132     /* Start with uip_buf pointing to a buffer that is not referenced from the
133      * pucEthernetBufferPointers[] array. */
134     uip_buf = &( ucEthernetBuffer[ archNUM_BUFFERS - 1 ][ 0 ] );
135 
136     /* Query the computer the simulation is being executed on to find the
137      * network interfaces it has installed. */
138     pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces();
139 
140     /* Open the network interface.  The number of the interface to be opened is
141      * set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
142      * Calling this function will set the pxOpenedInterfaceHandle variable.  If,
143      * after calling this function, pxOpenedInterfaceHandle is equal to NULL, then
144      * the interface could not be opened. */
145     if( pxAllNetworkInterfaces != NULL )
146     {
147         prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces );
148     }
149 
150     return x;
151 }
152 /*-----------------------------------------------------------*/
153 
prvPrintAvailableNetworkInterfaces(void)154 static pcap_if_t * prvPrintAvailableNetworkInterfaces( void )
155 {
156     pcap_if_t * pxAllNetworkInterfaces = NULL, * xInterface;
157     long lInterfaceNumber = 1;
158 
159     if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 )
160     {
161         printf( "\r\nCould not obtain a list of network interfaces\r\n%s\r\n", cErrorBuffer );
162         pxAllNetworkInterfaces = NULL;
163     }
164 
165     if( pxAllNetworkInterfaces != NULL )
166     {
167         /* Print out the list of network interfaces.  The first in the list
168          * is interface '1', not interface '0'. */
169         for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next )
170         {
171             printf( "%d. %s", lInterfaceNumber, xInterface->name );
172 
173             if( xInterface->description != NULL )
174             {
175                 printf( " (%s)\r\n", xInterface->description );
176             }
177             else
178             {
179                 printf( " (No description available)\r\n" );
180             }
181 
182             lInterfaceNumber++;
183         }
184     }
185 
186     if( lInterfaceNumber == 1 )
187     {
188         /* The interface number was never incremented, so the above for() loop
189          * did not execute meaning no interfaces were found. */
190         printf( " \r\nNo network interfaces were found.\r\n" );
191         pxAllNetworkInterfaces = NULL;
192     }
193 
194     printf( "\r\nThe interface that will be opened is set by configNETWORK_INTERFACE_TO_USE which should be defined in FreeRTOSConfig.h\r\n" );
195     printf( "Attempting to open interface number %d.\r\n", configNETWORK_INTERFACE_TO_USE );
196 
197     if( ( configNETWORK_INTERFACE_TO_USE < 1L ) || ( configNETWORK_INTERFACE_TO_USE > lInterfaceNumber ) )
198     {
199         printf( "\r\nconfigNETWORK_INTERFACE_TO_USE is not in the valid range.\r\n" );
200 
201         if( pxAllNetworkInterfaces != NULL )
202         {
203             /* Free the device list, as no devices are going to be opened. */
204             pcap_freealldevs( pxAllNetworkInterfaces );
205             pxAllNetworkInterfaces = NULL;
206         }
207     }
208 
209     return pxAllNetworkInterfaces;
210 }
211 /*-----------------------------------------------------------*/
212 
prvOpenSelectedNetworkInterface(pcap_if_t * pxAllNetworkInterfaces)213 static void prvOpenSelectedNetworkInterface( pcap_if_t * pxAllNetworkInterfaces )
214 {
215     pcap_if_t * xInterface;
216     long x;
217 
218     /* Walk the list of devices until the selected device is located. */
219     xInterface = pxAllNetworkInterfaces;
220 
221     for( x = 0L; x < ( configNETWORK_INTERFACE_TO_USE - 1L ); x++ )
222     {
223         xInterface = xInterface->next;
224     }
225 
226     /* Open the selected interface. */
227     pxOpenedInterfaceHandle = pcap_open( xInterface->name,          /* The name of the selected interface. */
228                                          UIP_CONF_BUFFER_SIZE,      /* The size of the packet to capture. */
229                                          PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscuous mode as the MAC and
230                                                                      * IP address is going to be "simulated", and
231                                                                      * not be the real MAC and IP address.  This allows
232                                                                      * traffic to the simulated IP address to be routed
233                                                                      * to uIP, and traffic to the real IP address to be
234                                                                      * routed to the Windows TCP/IP stack. */
235                                          0xfffffffL,                /* The read time out.  This is going to block
236                                                                      * until data is available. */
237                                          NULL,                      /* No authentication is required as this is
238                                                                      * not a remote capture session. */
239                                          cErrorBuffer
240                                          );
241 
242     if( pxOpenedInterfaceHandle == NULL )
243     {
244         printf( "\r\n%s is not supported by WinPcap and cannot be opened\r\n", xInterface->name );
245     }
246     else
247     {
248         /* Configure the capture filter to allow blocking reads, and to filter
249          * out packets that are not of interest to this demo. */
250         prvConfigureCaptureBehaviour();
251     }
252 
253     /* The device list is no longer required. */
254     pcap_freealldevs( pxAllNetworkInterfaces );
255 }
256 /*-----------------------------------------------------------*/
257 
prvConfigureCaptureBehaviour(void)258 static void prvConfigureCaptureBehaviour( void )
259 {
260     struct bpf_program xFilterCode;
261     const long lMinBytesToCopy = 10L, lBlocking = 0L;
262     unsigned long ulNetMask;
263 
264     /* Unblock a read as soon as anything is received. */
265     pcap_setmintocopy( pxOpenedInterfaceHandle, lMinBytesToCopy );
266 
267     /* Allow blocking. */
268     pcap_setnonblock( pxOpenedInterfaceHandle, lBlocking, cErrorBuffer );
269 
270     /* Set up a filter so only the packets of interest are passed to the uIP
271      * stack.  cErrorBuffer is used for convenience to create the string.  Don't
272      * confuse this with an error message. */
273     sprintf( cErrorBuffer, "broadcast or multicast or host %d.%d.%d.%d", configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 );
274 
275     ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0;
276 
277     if( pcap_compile( pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 )
278     {
279         printf( "\r\nThe packet filter string is invalid\r\n" );
280     }
281     else
282     {
283         if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 )
284         {
285             printf( "\r\nAn error occurred setting the packet filter.\r\n" );
286         }
287     }
288 
289     /* Create a task that simulates an interrupt in a real system.  This will
290      * block waiting for packets, then send a message to the uIP task when data
291      * is available. */
292     xTaskCreate( prvInterruptSimulator, ( signed char * ) "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, ( ipconfigIP_TASK_PRIORITY - 1 ), NULL );
293 }
294 /*-----------------------------------------------------------*/
295 
prvInterruptSimulator(void * pvParameters)296 static void prvInterruptSimulator( void * pvParameters )
297 {
298     static struct pcap_pkthdr * pxHeader;
299     const unsigned char * pucPacketData;
300     extern QueueHandle_t xEMACEventQueue;
301     const unsigned long ulRxEvent = uipETHERNET_RX_EVENT;
302     long lResult;
303 
304     /* Just to kill the compiler warning. */
305     ( void ) pvParameters;
306 
307     for( ; ; )
308     {
309         /* Get the next packet. */
310         lResult = pcap_next_ex( pxOpenedInterfaceHandle, &pxHeader, &pucPacketData );
311 
312         if( lResult )
313         {
314             /* Is the next buffer into which data should be placed free? */
315             if( lLengthOfDataInBuffer[ ucNextBufferToFill ] == 0L )
316             {
317                 /* Copy the data from the captured packet into the buffer. */
318                 memcpy( pucEthernetBufferPointers[ ucNextBufferToFill ], pucPacketData, pxHeader->len );
319 
320                 /* Note the amount of data that was copied. */
321                 lLengthOfDataInBuffer[ ucNextBufferToFill ] = pxHeader->len;
322 
323                 /* Move onto the next buffer, wrapping around if necessary. */
324                 ucNextBufferToFill++;
325 
326                 if( ucNextBufferToFill >= archNUM_BUFFER_POINTERS )
327                 {
328                     ucNextBufferToFill = 0U;
329                 }
330 
331                 /* Data was received and stored.  Send a message to the uIP task
332                  * to let it know. */
333                 xQueueSendToBack( xEMACEventQueue, &ulRxEvent, portMAX_DELAY );
334             }
335         }
336     }
337 }
338