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