]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_Windows_Simulator/WinPCap/arch.c
Update FreeRTOS+ version number ready for version 9 release candidate 1.
[freertos] / FreeRTOS-Plus / Demo / FreeRTOS_Plus_UDP_and_CLI_Windows_Simulator / WinPCap / arch.c
1 /*\r
2     FreeRTOS V9.0.0rc1 - Copyright (C) 2016 Real Time Engineers Ltd.\r
3     All rights reserved\r
4 \r
5     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     This file is part of the FreeRTOS distribution.\r
8 \r
9     FreeRTOS is free software; you can redistribute it and/or modify it under\r
10     the terms of the GNU General Public License (version 2) as published by the\r
11     Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.\r
12 \r
13     ***************************************************************************\r
14     >>!   NOTE: The modification to the GPL is included to allow you to     !<<\r
15     >>!   distribute a combined work that includes FreeRTOS without being   !<<\r
16     >>!   obliged to provide the source code for proprietary components     !<<\r
17     >>!   outside of the FreeRTOS kernel.                                   !<<\r
18     ***************************************************************************\r
19 \r
20     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
21     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
22     FOR A PARTICULAR PURPOSE.  Full license text is available on the following\r
23     link: http://www.freertos.org/a00114.html\r
24 \r
25     ***************************************************************************\r
26      *                                                                       *\r
27      *    FreeRTOS provides completely free yet professionally developed,    *\r
28      *    robust, strictly quality controlled, supported, and cross          *\r
29      *    platform software that is more than just the market leader, it     *\r
30      *    is the industry's de facto standard.                               *\r
31      *                                                                       *\r
32      *    Help yourself get started quickly while simultaneously helping     *\r
33      *    to support the FreeRTOS project by purchasing a FreeRTOS           *\r
34      *    tutorial book, reference manual, or both:                          *\r
35      *    http://www.FreeRTOS.org/Documentation                              *\r
36      *                                                                       *\r
37     ***************************************************************************\r
38 \r
39     http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading\r
40     the FAQ page "My application does not run, what could be wrong?".  Have you\r
41     defined configASSERT()?\r
42 \r
43     http://www.FreeRTOS.org/support - In return for receiving this top quality\r
44     embedded software for free we request you assist our global community by\r
45     participating in the support forum.\r
46 \r
47     http://www.FreeRTOS.org/training - Investing in training allows your team to\r
48     be as productive as possible as early as possible.  Now you can receive\r
49     FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers\r
50     Ltd, and the world's leading authority on the world's leading RTOS.\r
51 \r
52     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
53     including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
54     compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
55 \r
56     http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.\r
57     Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.\r
58 \r
59     http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High\r
60     Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
61     licenses offer ticketed support, indemnification and commercial middleware.\r
62 \r
63     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
64     engineered and independently SIL3 certified version for use in safety and\r
65     mission critical applications that require provable dependability.\r
66 \r
67     1 tab == 4 spaces!\r
68 */\r
69 \r
70 /* WinPCap includes. */\r
71 #include "pcap.h"\r
72 #include "remote-ext.h"\r
73 \r
74 /* uIP includes. */\r
75 #include "net/uip.h"\r
76 #include "net/uip_arp.h"\r
77 #include "net/clock-arch.h"\r
78 \r
79 /* FreeRTOS includes. */\r
80 #include "FreeRTOS.h"\r
81 #include "task.h"\r
82 #include "queue.h"\r
83 \r
84 /*\r
85  * Query the computer the simulation is being executed on to find the network\r
86  * interfaces it has installed.\r
87  */\r
88 static pcap_if_t * prvPrintAvailableNetworkInterfaces( void );\r
89 \r
90 /*\r
91  * Open the network interface.  The number of the interface to be opened is set\r
92  * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.\r
93  */\r
94 static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces );\r
95 \r
96 /*\r
97  * Configure the capture filter to allow blocking reads, and to filter out\r
98  * packets that are not of interest to this demo.\r
99  */\r
100 static void prvConfigureCaptureBehaviour( void );\r
101 \r
102 pcap_t *pxOpenedInterfaceHandle = NULL;\r
103 LARGE_INTEGER freq, sys_start_time;\r
104 \r
105 #define archNUM_BUFFERS 5\r
106 #define archNUM_BUFFER_POINTERS ( archNUM_BUFFERS - 1 )\r
107 \r
108 static void prvInterruptSimulator( void *pvParameters );\r
109 \r
110 static unsigned char ucEthernetBuffer[ archNUM_BUFFERS ][ UIP_CONF_BUFFER_SIZE ];\r
111 static unsigned char *pucEthernetBufferPointers[ archNUM_BUFFER_POINTERS ];\r
112 \r
113 static long lLengthOfDataInBuffer[ archNUM_BUFFER_POINTERS ] = { 0 };\r
114 static unsigned char ucNextBufferToFill = 0U, ucNextBufferToProcess = 0U;\r
115 \r
116 unsigned char *uip_buf = NULL;\r
117 char cErrorBuffer[PCAP_ERRBUF_SIZE];\r
118 \r
119 void vNetifTx( void )\r
120 {\r
121         pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len );\r
122         pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len );\r
123 }\r
124 /*-----------------------------------------------------------*/\r
125 \r
126 UBaseType_t uxNetifRx( void )\r
127 {\r
128 UBaseType_t xDataLen;\r
129 unsigned char *pucTemp;\r
130 \r
131         /* Check there is really data available. */\r
132         xDataLen = lLengthOfDataInBuffer[ ucNextBufferToProcess ];\r
133         if( xDataLen != 0L )\r
134         {\r
135 \r
136                 /* The buffer pointed to by uip_buf is going to change.  Remember which\r
137                 buffer uip_buf is currently pointing to. */\r
138                 pucTemp = uip_buf;\r
139 \r
140                 /* Point uip_buf at the next buffer that contains data. */\r
141                 uip_buf = pucEthernetBufferPointers[ ucNextBufferToProcess ];\r
142 \r
143                 /* The buffer pointed to by \r
144                 pucEthernetBufferPointeres[ ucNextBufferToProcess ] is now in use by\r
145                 uip_buf, but the buffer uip_buf was pointing to on entry to this\r
146                 function is free.  Set \r
147                 pucEthernetBufferPointeres[ ucNextBufferToProcess ] to the free \r
148                 buffer. */\r
149                 pucEthernetBufferPointers[ ucNextBufferToProcess ] = pucTemp;\r
150                 lLengthOfDataInBuffer[ ucNextBufferToProcess ] = 0L;\r
151 \r
152                 ucNextBufferToProcess++;\r
153                 if( ucNextBufferToProcess >= archNUM_BUFFER_POINTERS )\r
154                 {\r
155                         ucNextBufferToProcess = 0L;\r
156                 }\r
157         }\r
158 \r
159         return xDataLen;\r
160 }\r
161 /*-----------------------------------------------------------*/\r
162 \r
163 BaseType_t xNetifInit( void )\r
164 {\r
165 BaseType_t x;\r
166 pcap_if_t *pxAllNetworkInterfaces;\r
167 \r
168         /* Allocate a free buffer to each buffer pointer. */\r
169         for( x = 0; x < sizeof( pucEthernetBufferPointers ) / sizeof( unsigned char * ); x++ )\r
170         {\r
171                 pucEthernetBufferPointers[ x ] = &( ucEthernetBuffer[ x ][ 0 ] );\r
172         }\r
173 \r
174         /* Start with uip_buf pointing to a buffer that is not referenced from the\r
175         pucEthernetBufferPointers[] array. */\r
176         uip_buf = &( ucEthernetBuffer[ archNUM_BUFFERS - 1 ][ 0 ] );\r
177 \r
178         /* Query the computer the simulation is being executed on to find the \r
179         network interfaces it has installed. */\r
180         pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces();\r
181         \r
182         /* Open the network interface.  The number of the interface to be opened is \r
183         set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.\r
184         Calling this function will set the pxOpenedInterfaceHandle variable.  If,\r
185         after calling this function, pxOpenedInterfaceHandle is equal to NULL, then\r
186         the interface could not be opened. */\r
187         if( pxAllNetworkInterfaces != NULL )\r
188         {\r
189                 prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces );\r
190         }\r
191         \r
192 \r
193         return x;\r
194 }\r
195 /*-----------------------------------------------------------*/\r
196 \r
197 static pcap_if_t * prvPrintAvailableNetworkInterfaces( void )\r
198 {    \r
199 pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface;\r
200 long lInterfaceNumber = 1;\r
201 \r
202     if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 )\r
203     {\r
204         printf( "\r\nCould not obtain a list of network interfaces\r\n%s\r\n", cErrorBuffer );\r
205         pxAllNetworkInterfaces = NULL;\r
206     }\r
207 \r
208         if( pxAllNetworkInterfaces != NULL )\r
209         {\r
210                 /* Print out the list of network interfaces.  The first in the list\r
211                 is interface '1', not interface '0'. */\r
212                 for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next )\r
213                 {\r
214                         printf( "%d. %s", lInterfaceNumber, xInterface->name );\r
215                         \r
216                         if( xInterface->description != NULL )\r
217                         {\r
218                                 printf( " (%s)\r\n", xInterface->description );\r
219                         }\r
220                         else\r
221                         {\r
222                                 printf( " (No description available)\r\n") ;\r
223                         }\r
224                         \r
225                         lInterfaceNumber++;\r
226                 }\r
227         }\r
228 \r
229     if( lInterfaceNumber == 1 )\r
230     {\r
231                 /* The interface number was never incremented, so the above for() loop\r
232                 did not execute meaning no interfaces were found. */\r
233         printf( " \r\nNo network interfaces were found.\r\n" );\r
234         pxAllNetworkInterfaces = NULL;\r
235     }\r
236 \r
237         printf( "\r\nThe interface that will be opened is set by configNETWORK_INTERFACE_TO_USE which should be defined in FreeRTOSConfig.h\r\n" );\r
238         printf( "Attempting to open interface number %d.\r\n", configNETWORK_INTERFACE_TO_USE );\r
239         \r
240     if( ( configNETWORK_INTERFACE_TO_USE < 1L ) || ( configNETWORK_INTERFACE_TO_USE > lInterfaceNumber ) )\r
241     {\r
242         printf("\r\nconfigNETWORK_INTERFACE_TO_USE is not in the valid range.\r\n" );\r
243                 \r
244                 if( pxAllNetworkInterfaces != NULL )\r
245                 {\r
246                         /* Free the device list, as no devices are going to be opened. */\r
247                         pcap_freealldevs( pxAllNetworkInterfaces );\r
248                         pxAllNetworkInterfaces = NULL;\r
249                 }\r
250     }\r
251 \r
252         return pxAllNetworkInterfaces;\r
253 }\r
254 /*-----------------------------------------------------------*/\r
255 \r
256 static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces )\r
257 {\r
258 pcap_if_t *xInterface;\r
259 long x;\r
260 \r
261     /* Walk the list of devices until the selected device is located. */\r
262         xInterface = pxAllNetworkInterfaces;\r
263     for( x = 0L; x < ( configNETWORK_INTERFACE_TO_USE - 1L ); x++ )\r
264         {\r
265                 xInterface = xInterface->next;\r
266         }\r
267 \r
268     /* Open the selected interface. */\r
269         pxOpenedInterfaceHandle = pcap_open(    xInterface->name,               /* The name of the selected interface. */\r
270                                                                                         UIP_CONF_BUFFER_SIZE,           /* The size of the packet to capture. */\r
271                                                                                         PCAP_OPENFLAG_PROMISCUOUS,      /* Open in promiscious mode as the MAC and \r
272                                                                                                                                                 IP address is going to be "simulated", and \r
273                                                                                                                                                 not be the real MAC and IP address.  This allows\r
274                                                                                                                                                 trafic to the simulated IP address to be routed\r
275                                                                                                                                                 to uIP, and trafic to the real IP address to be\r
276                                                                                                                                                 routed to the Windows TCP/IP stack. */\r
277                                                                                         0xfffffffL,                     /* The read time out.  This is going to block\r
278                                                                                                                                                 until data is available. */\r
279                                                                                         NULL,                                   /* No authentication is required as this is\r
280                                                                                                                                                 not a remote capture session. */\r
281                                                                                         cErrorBuffer            \r
282                                                                            );\r
283                                                                            \r
284     if ( pxOpenedInterfaceHandle == NULL )\r
285     {\r
286         printf( "\r\n%s is not supported by WinPcap and cannot be opened\r\n", xInterface->name );\r
287     }\r
288         else\r
289         {\r
290                 /* Configure the capture filter to allow blocking reads, and to filter \r
291                 out packets that are not of interest to this demo. */\r
292                 prvConfigureCaptureBehaviour();\r
293         }\r
294 \r
295         /* The device list is no longer required. */\r
296         pcap_freealldevs( pxAllNetworkInterfaces );\r
297 }\r
298 /*-----------------------------------------------------------*/\r
299 \r
300 static void prvConfigureCaptureBehaviour( void )\r
301 {\r
302 struct bpf_program xFilterCode;\r
303 const long lMinBytesToCopy = 10L, lBlocking = 0L;\r
304 unsigned long ulNetMask;\r
305 \r
306         /* Unblock a read as soon as anything is received. */\r
307         pcap_setmintocopy( pxOpenedInterfaceHandle, lMinBytesToCopy );\r
308 \r
309         /* Allow blocking. */\r
310         pcap_setnonblock( pxOpenedInterfaceHandle, lBlocking, cErrorBuffer );\r
311 \r
312         /* Set up a filter so only the packets of interest are passed to the uIP\r
313         stack.  cErrorBuffer is used for convenience to create the string.  Don't\r
314         confuse this with an error message. */\r
315         sprintf( cErrorBuffer, "broadcast or multicast or host %d.%d.%d.%d", configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 );\r
316 \r
317         ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0;\r
318 \r
319         if( pcap_compile(pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 )\r
320     {\r
321         printf("\r\nThe packet filter string is invalid\r\n" );\r
322     }\r
323         else\r
324         {    \r
325                 if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 )\r
326                 {\r
327                         printf( "\r\nAn error occurred setting the packet filter.\r\n" );\r
328                 }\r
329         }\r
330 \r
331         /* Create a task that simulates an interrupt in a real system.  This will\r
332         block waiting for packets, then send a message to the uIP task when data\r
333         is available. */\r
334         xTaskCreate( prvInterruptSimulator, "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, ( configuIP_TASK_PRIORITY - 1 ), NULL );\r
335 }\r
336 /*-----------------------------------------------------------*/\r
337 \r
338 static void prvInterruptSimulator( void *pvParameters )\r
339 {\r
340 static struct pcap_pkthdr *pxHeader;\r
341 const unsigned char *pucPacketData;\r
342 extern xQueueHandle xEMACEventQueue;\r
343 const unsigned long ulRxEvent = uipETHERNET_RX_EVENT;\r
344 long lResult;\r
345 \r
346         /* Just to kill the compiler warning. */\r
347         ( void ) pvParameters;\r
348 \r
349         for( ;; )\r
350         {\r
351                 /* Get the next packet. */\r
352                 lResult = pcap_next_ex( pxOpenedInterfaceHandle, &pxHeader, &pucPacketData );\r
353                 if( lResult )\r
354                 {\r
355                         /* Is the next buffer into which data should be placed free? */\r
356                         if( lLengthOfDataInBuffer[ ucNextBufferToFill ] == 0L )\r
357                         {\r
358                                 /* Copy the data from the captured packet into the buffer. */\r
359                                 memcpy( pucEthernetBufferPointers[ ucNextBufferToFill ], pucPacketData, pxHeader->len );\r
360 \r
361                                 /* Note the amount of data that was copied. */\r
362                                 lLengthOfDataInBuffer[ ucNextBufferToFill ] = pxHeader->len;\r
363 \r
364                                 /* Move onto the next buffer, wrapping around if necessary. */\r
365                                 ucNextBufferToFill++;\r
366                                 if( ucNextBufferToFill >= archNUM_BUFFER_POINTERS )\r
367                                 {\r
368                                         ucNextBufferToFill = 0U;\r
369                                 }\r
370 \r
371                                 /* Data was received and stored.  Send a message to the uIP task\r
372                                 to let it know. */\r
373                                 xQueueSendToBack( xEMACEventQueue, &ulRxEvent, portMAX_DELAY );\r
374                         }\r
375                 }\r
376         }\r
377 }\r
378 \r