]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/ethernet/lwip-1.4.0/ports/win32/WinPCap/arch.c
Update to MIT licensed FreeRTOS V10.0.0 - see https://www.freertos.org/History.txt
[freertos] / FreeRTOS / Demo / Common / ethernet / lwip-1.4.0 / ports / win32 / WinPCap / arch.c
1 /*\r
2  * FreeRTOS Kernel V10.0.0\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software. If you wish to use our Amazon\r
14  * FreeRTOS name, please do so in a fair use way that does not cause confusion.\r
15  *\r
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22  *\r
23  * http://www.FreeRTOS.org\r
24  * http://aws.amazon.com/freertos\r
25  *\r
26  * 1 tab == 4 spaces!\r
27  */\r
28 \r
29 /* WinPCap includes. */\r
30 #include "pcap.h"\r
31 #include "remote-ext.h"\r
32 \r
33 /* uIP includes. */\r
34 #include "net/uip.h"\r
35 #include "net/uip_arp.h"\r
36 #include "net/clock-arch.h"\r
37 \r
38 /* FreeRTOS includes. */\r
39 #include "FreeRTOS.h"\r
40 #include "task.h"\r
41 #include "queue.h"\r
42 \r
43 /*\r
44  * Query the computer the simulation is being executed on to find the network\r
45  * interfaces it has installed.\r
46  */\r
47 static pcap_if_t * prvPrintAvailableNetworkInterfaces( void );\r
48 \r
49 /*\r
50  * Open the network interface.  The number of the interface to be opened is set\r
51  * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.\r
52  */\r
53 static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces );\r
54 \r
55 /*\r
56  * Configure the capture filter to allow blocking reads, and to filter out\r
57  * packets that are not of interest to this demo.\r
58  */\r
59 static void prvConfigureCaptureBehaviour( void );\r
60 \r
61 pcap_t *pxOpenedInterfaceHandle = NULL;\r
62 LARGE_INTEGER freq, sys_start_time;\r
63 \r
64 #define archNUM_BUFFERS 5\r
65 #define archNUM_BUFFER_POINTERS ( archNUM_BUFFERS - 1 )\r
66 \r
67 static void prvInterruptSimulator( void *pvParameters );\r
68 \r
69 static unsigned char ucEthernetBuffer[ archNUM_BUFFERS ][ UIP_CONF_BUFFER_SIZE ];\r
70 static unsigned char *pucEthernetBufferPointers[ archNUM_BUFFER_POINTERS ];\r
71 \r
72 static long lLengthOfDataInBuffer[ archNUM_BUFFER_POINTERS ] = { 0 };\r
73 static unsigned char ucNextBufferToFill = 0U, ucNextBufferToProcess = 0U;\r
74 \r
75 unsigned char *uip_buf = NULL;\r
76 char cErrorBuffer[PCAP_ERRBUF_SIZE];\r
77 \r
78 void vNetifTx( void )\r
79 {\r
80         pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len );\r
81         pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len );\r
82 }\r
83 /*-----------------------------------------------------------*/\r
84 \r
85 unsigned portBASE_TYPE uxNetifRx( void )\r
86 {\r
87 unsigned portBASE_TYPE xDataLen;\r
88 unsigned char *pucTemp;\r
89 \r
90         /* Check there is really data available. */\r
91         xDataLen = lLengthOfDataInBuffer[ ucNextBufferToProcess ];\r
92         if( xDataLen != 0L )\r
93         {\r
94 \r
95                 /* The buffer pointed to by uip_buf is going to change.  Remember which\r
96                 buffer uip_buf is currently pointing to. */\r
97                 pucTemp = uip_buf;\r
98 \r
99                 /* Point uip_buf at the next buffer that contains data. */\r
100                 uip_buf = pucEthernetBufferPointers[ ucNextBufferToProcess ];\r
101 \r
102                 /* The buffer pointed to by \r
103                 pucEthernetBufferPointeres[ ucNextBufferToProcess ] is now in use by\r
104                 uip_buf, but the buffer uip_buf was pointing to on entry to this\r
105                 function is free.  Set \r
106                 pucEthernetBufferPointeres[ ucNextBufferToProcess ] to the free \r
107                 buffer. */\r
108                 pucEthernetBufferPointers[ ucNextBufferToProcess ] = pucTemp;\r
109                 lLengthOfDataInBuffer[ ucNextBufferToProcess ] = 0L;\r
110 \r
111                 ucNextBufferToProcess++;\r
112                 if( ucNextBufferToProcess >= archNUM_BUFFER_POINTERS )\r
113                 {\r
114                         ucNextBufferToProcess = 0L;\r
115                 }\r
116         }\r
117 \r
118         return xDataLen;\r
119 }\r
120 /*-----------------------------------------------------------*/\r
121 \r
122 portBASE_TYPE xNetifInit( void )\r
123 {\r
124 portBASE_TYPE x;\r
125 pcap_if_t *pxAllNetworkInterfaces;\r
126 \r
127         /* Allocate a free buffer to each buffer pointer. */\r
128         for( x = 0; x < sizeof( pucEthernetBufferPointers ) / sizeof( unsigned char * ); x++ )\r
129         {\r
130                 pucEthernetBufferPointers[ x ] = &( ucEthernetBuffer[ x ][ 0 ] );\r
131         }\r
132 \r
133         /* Start with uip_buf pointing to a buffer that is not referenced from the\r
134         pucEthernetBufferPointers[] array. */\r
135         uip_buf = &( ucEthernetBuffer[ archNUM_BUFFERS - 1 ][ 0 ] );\r
136 \r
137         /* Query the computer the simulation is being executed on to find the \r
138         network interfaces it has installed. */\r
139         pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces();\r
140         \r
141         /* Open the network interface.  The number of the interface to be opened is \r
142         set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.\r
143         Calling this function will set the pxOpenedInterfaceHandle variable.  If,\r
144         after calling this function, pxOpenedInterfaceHandle is equal to NULL, then\r
145         the interface could not be opened. */\r
146         if( pxAllNetworkInterfaces != NULL )\r
147         {\r
148                 prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces );\r
149         }\r
150         \r
151 \r
152         return x;\r
153 }\r
154 /*-----------------------------------------------------------*/\r
155 \r
156 static pcap_if_t * prvPrintAvailableNetworkInterfaces( void )\r
157 {    \r
158 pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface;\r
159 long lInterfaceNumber = 1;\r
160 \r
161     if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 )\r
162     {\r
163         printf( "\r\nCould not obtain a list of network interfaces\r\n%s\r\n", cErrorBuffer );\r
164         pxAllNetworkInterfaces = NULL;\r
165     }\r
166 \r
167         if( pxAllNetworkInterfaces != NULL )\r
168         {\r
169                 /* Print out the list of network interfaces.  The first in the list\r
170                 is interface '1', not interface '0'. */\r
171                 for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next )\r
172                 {\r
173                         printf( "%d. %s", lInterfaceNumber, xInterface->name );\r
174                         \r
175                         if( xInterface->description != NULL )\r
176                         {\r
177                                 printf( " (%s)\r\n", xInterface->description );\r
178                         }\r
179                         else\r
180                         {\r
181                                 printf( " (No description available)\r\n") ;\r
182                         }\r
183                         \r
184                         lInterfaceNumber++;\r
185                 }\r
186         }\r
187 \r
188     if( lInterfaceNumber == 1 )\r
189     {\r
190                 /* The interface number was never incremented, so the above for() loop\r
191                 did not execute meaning no interfaces were found. */\r
192         printf( " \r\nNo network interfaces were found.\r\n" );\r
193         pxAllNetworkInterfaces = NULL;\r
194     }\r
195 \r
196         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
197         printf( "Attempting to open interface number %d.\r\n", configNETWORK_INTERFACE_TO_USE );\r
198         \r
199     if( ( configNETWORK_INTERFACE_TO_USE < 1L ) || ( configNETWORK_INTERFACE_TO_USE > lInterfaceNumber ) )\r
200     {\r
201         printf("\r\nconfigNETWORK_INTERFACE_TO_USE is not in the valid range.\r\n" );\r
202                 \r
203                 if( pxAllNetworkInterfaces != NULL )\r
204                 {\r
205                         /* Free the device list, as no devices are going to be opened. */\r
206                         pcap_freealldevs( pxAllNetworkInterfaces );\r
207                         pxAllNetworkInterfaces = NULL;\r
208                 }\r
209     }\r
210 \r
211         return pxAllNetworkInterfaces;\r
212 }\r
213 /*-----------------------------------------------------------*/\r
214 \r
215 static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces )\r
216 {\r
217 pcap_if_t *xInterface;\r
218 long x;\r
219 \r
220     /* Walk the list of devices until the selected device is located. */\r
221         xInterface = pxAllNetworkInterfaces;\r
222     for( x = 0L; x < ( configNETWORK_INTERFACE_TO_USE - 1L ); x++ )\r
223         {\r
224                 xInterface = xInterface->next;\r
225         }\r
226 \r
227     /* Open the selected interface. */\r
228         pxOpenedInterfaceHandle = pcap_open(    xInterface->name,               /* The name of the selected interface. */\r
229                                                                                         UIP_CONF_BUFFER_SIZE,           /* The size of the packet to capture. */\r
230                                                                                         PCAP_OPENFLAG_PROMISCUOUS,      /* Open in promiscious mode as the MAC and \r
231                                                                                                                                                 IP address is going to be "simulated", and \r
232                                                                                                                                                 not be the real MAC and IP address.  This allows\r
233                                                                                                                                                 trafic to the simulated IP address to be routed\r
234                                                                                                                                                 to uIP, and trafic to the real IP address to be\r
235                                                                                                                                                 routed to the Windows TCP/IP stack. */\r
236                                                                                         0xfffffffL,                     /* The read time out.  This is going to block\r
237                                                                                                                                                 until data is available. */\r
238                                                                                         NULL,                                   /* No authentication is required as this is\r
239                                                                                                                                                 not a remote capture session. */\r
240                                                                                         cErrorBuffer            \r
241                                                                            );\r
242                                                                            \r
243     if ( pxOpenedInterfaceHandle == NULL )\r
244     {\r
245         printf( "\r\n%s is not supported by WinPcap and cannot be opened\r\n", xInterface->name );\r
246     }\r
247         else\r
248         {\r
249                 /* Configure the capture filter to allow blocking reads, and to filter \r
250                 out packets that are not of interest to this demo. */\r
251                 prvConfigureCaptureBehaviour();\r
252         }\r
253 \r
254         /* The device list is no longer required. */\r
255         pcap_freealldevs( pxAllNetworkInterfaces );\r
256 }\r
257 /*-----------------------------------------------------------*/\r
258 \r
259 static void prvConfigureCaptureBehaviour( void )\r
260 {\r
261 struct bpf_program xFilterCode;\r
262 const long lMinBytesToCopy = 10L, lBlocking = 0L;\r
263 unsigned long ulNetMask;\r
264 \r
265         /* Unblock a read as soon as anything is received. */\r
266         pcap_setmintocopy( pxOpenedInterfaceHandle, lMinBytesToCopy );\r
267 \r
268         /* Allow blocking. */\r
269         pcap_setnonblock( pxOpenedInterfaceHandle, lBlocking, cErrorBuffer );\r
270 \r
271         /* Set up a filter so only the packets of interest are passed to the uIP\r
272         stack.  cErrorBuffer is used for convenience to create the string.  Don't\r
273         confuse this with an error message. */\r
274         sprintf( cErrorBuffer, "broadcast or multicast or host %d.%d.%d.%d", configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 );\r
275 \r
276         ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0;\r
277 \r
278         if( pcap_compile(pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 )\r
279     {\r
280         printf("\r\nThe packet filter string is invalid\r\n" );\r
281     }\r
282         else\r
283         {    \r
284                 if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 )\r
285                 {\r
286                         printf( "\r\nAn error occurred setting the packet filter.\r\n" );\r
287                 }\r
288         }\r
289 \r
290         /* Create a task that simulates an interrupt in a real system.  This will\r
291         block waiting for packets, then send a message to the uIP task when data\r
292         is available. */\r
293         xTaskCreate( prvInterruptSimulator, "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, ( configuIP_TASK_PRIORITY - 1 ), NULL );\r
294 }\r
295 /*-----------------------------------------------------------*/\r
296 \r
297 static void prvInterruptSimulator( void *pvParameters )\r
298 {\r
299 static struct pcap_pkthdr *pxHeader;\r
300 const unsigned char *pucPacketData;\r
301 extern QueueHandle_t xEMACEventQueue;\r
302 const unsigned long ulRxEvent = uipETHERNET_RX_EVENT;\r
303 long lResult;\r
304 \r
305         /* Just to kill the compiler warning. */\r
306         ( void ) pvParameters;\r
307 \r
308         for( ;; )\r
309         {\r
310                 /* Get the next packet. */\r
311                 lResult = pcap_next_ex( pxOpenedInterfaceHandle, &pxHeader, &pucPacketData );\r
312                 if( lResult )\r
313                 {\r
314                         /* Is the next buffer into which data should be placed free? */\r
315                         if( lLengthOfDataInBuffer[ ucNextBufferToFill ] == 0L )\r
316                         {\r
317                                 /* Copy the data from the captured packet into the buffer. */\r
318                                 memcpy( pucEthernetBufferPointers[ ucNextBufferToFill ], pucPacketData, pxHeader->len );\r
319 \r
320                                 /* Note the amount of data that was copied. */\r
321                                 lLengthOfDataInBuffer[ ucNextBufferToFill ] = pxHeader->len;\r
322 \r
323                                 /* Move onto the next buffer, wrapping around if necessary. */\r
324                                 ucNextBufferToFill++;\r
325                                 if( ucNextBufferToFill >= archNUM_BUFFER_POINTERS )\r
326                                 {\r
327                                         ucNextBufferToFill = 0U;\r
328                                 }\r
329 \r
330                                 /* Data was received and stored.  Send a message to the uIP task\r
331                                 to let it know. */\r
332                                 xQueueSendToBack( xEMACEventQueue, &ulRxEvent, portMAX_DELAY );\r
333                         }\r
334                 }\r
335         }\r
336 }\r
337 \r