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