1 /*
2 * FreeRTOS+TCP <DEVELOPMENT BRANCH>
3 * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * http://aws.amazon.com/freertos
25 * http://www.FreeRTOS.org
26 */
27
28 #include <stdlib.h>
29
30 /* FreeRTOS includes. */
31 #include "FreeRTOS.h"
32 #include "list.h"
33 #include "task.h"
34 #include "message_buffer.h"
35
36 #if !defined( _WIN32 )
37 #include "wait_for_event.h"
38 #endif
39
40 /* FreeRTOS+TCP includes. */
41 #include "FreeRTOS_IP.h"
42
43 /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
44 * driver will filter incoming packets and only pass the stack those packets it
45 * considers need processing. */
46 #if ( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )
47 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
48 #else
49 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
50 #endif
51
52 #if ipconfigNETWORK_MTU < 1500U
53 #error ipconfigNETWORK_MTU must be at least 1500
54 #endif
55
56 #define NETWORK_BUFFER_LEN ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER )
57
58 #define xSEND_BUFFER_SIZE ( 32U * NETWORK_BUFFER_LEN )
59 #define xRECV_BUFFER_SIZE ( 32U * NETWORK_BUFFER_LEN )
60
61 typedef struct
62 {
63 BaseType_t xInterfaceState;
64 MessageBufferHandle_t xSendMsgBuffer;
65 MessageBufferHandle_t xRecvMsgBuffer;
66 TaskHandle_t xRecvTask;
67 void * pvSendEvent;
68 void * pvBackendContext;
69 } MBuffNetDriverContext_t;
70
71 extern void vMBuffNetifBackendInit( MessageBufferHandle_t * pxSendMsgBuffer,
72 MessageBufferHandle_t * pxRecvMsgBuffer,
73 void * pvSendEvent,
74 void ** ppvBackendContext );
75
76 extern void vMBuffNetifBackendDeInit( void * pvBackendContext );
77
78 static void vNetifReceiveTask( void * pvParameters );
79
80 /**
81 * @brief Initialize the MessageBuffer backed network interface.
82 *
83 * @return BaseType_t pdTRUE on success
84 */
xNetworkInterfaceInitialise(NetworkInterface_t * pxNetif)85 static BaseType_t xNetworkInterfaceInitialise( NetworkInterface_t * pxNetif )
86 {
87 BaseType_t xResult = pdTRUE;
88
89 pxNetif->pvArgument = pvPortMalloc( sizeof( MBuffNetDriverContext_t ) );
90
91 if( pxNetif->pvArgument == NULL )
92 {
93 FreeRTOS_printf( ( "Failed to allocate memory for pxNetif->pvArgument" ) );
94 configASSERT( 0 );
95 }
96
97 MBuffNetDriverContext_t * pxDriverCtx = ( MBuffNetDriverContext_t * ) pxNetif->pvArgument;
98
99 if( pxDriverCtx->xInterfaceState == pdFALSE )
100 {
101 pxDriverCtx->xInterfaceState = pdFALSE;
102
103 #if defined( _WIN32 )
104 pxDriverCtx->pvSendEvent = CreateEvent( NULL, FALSE, TRUE, NULL );
105 #else
106 pxDriverCtx->pvSendEvent = ( void * ) event_create();
107 #endif
108
109 if( pxDriverCtx->pvSendEvent == NULL )
110 {
111 xResult = pdFALSE;
112 }
113 else
114 {
115 vMBuffNetifBackendInit( &( pxDriverCtx->xSendMsgBuffer ),
116 &( pxDriverCtx->xRecvMsgBuffer ),
117 pxDriverCtx->pvSendEvent,
118 &( pxDriverCtx->pvBackendContext ) );
119
120 if( pxDriverCtx->pvBackendContext == NULL )
121 {
122 xResult = pdFALSE;
123 #if defined( _WIN32 )
124 ( void ) CloseHandle( pxDriverCtx->pvSendEvent );
125 #else
126 ( void ) event_delete( pxDriverCtx->pvSendEvent );
127 #endif
128 }
129 }
130
131 static BaseType_t xReceiveTaskCreated = pdFALSE;
132
133 if( ( xResult == pdTRUE ) && ( xReceiveTaskCreated == pdFALSE ) )
134 {
135 xResult = xTaskCreate( vNetifReceiveTask, "NetRX",
136 configMINIMAL_STACK_SIZE,
137 pxNetif,
138 tskIDLE_PRIORITY,
139 &( pxDriverCtx->xRecvTask ) );
140
141 if( xResult == pdPASS )
142 {
143 xReceiveTaskCreated = pdTRUE;
144 }
145 }
146
147 /* Cleanup on failure */
148 if( xResult != pdTRUE )
149 {
150 if( pxDriverCtx->pvSendEvent != NULL )
151 {
152 #if defined( _WIN32 )
153 ( void ) CloseHandle( pxDriverCtx->pvSendEvent );
154 #else
155 event_delete( pxDriverCtx->pvSendEvent );
156 #endif
157 }
158
159 if( pxDriverCtx->pvBackendContext != NULL )
160 {
161 vMBuffNetifBackendDeInit( pxDriverCtx->pvBackendContext );
162 }
163 }
164
165 pxDriverCtx->xInterfaceState = xResult;
166 }
167
168 return xResult;
169 }
170
171 /**
172 * @brief Deinitialize the message buffer backed network interface.
173 *
174 * @return BaseType_t pdTRUE
175 */
xNetworkInterfaceDeInitialise(NetworkInterface_t * pxNetif)176 BaseType_t xNetworkInterfaceDeInitialise( NetworkInterface_t * pxNetif )
177 {
178 MBuffNetDriverContext_t * pxDriverCtx = ( MBuffNetDriverContext_t * ) pxNetif->pvArgument;
179
180 #if defined( _WIN32 )
181 ( void ) CloseHandle( pxDriverCtx->pvSendEvent );
182 #else
183 event_delete( pxDriverCtx->pvSendEvent );
184 #endif
185
186 vTaskDelete( pxDriverCtx->xRecvTask );
187
188 vMBuffNetifBackendDeInit( pxDriverCtx->pvBackendContext );
189
190 vPortFree( pxNetif->pvArgument );
191
192 return pdTRUE;
193 }
194
195 /*!
196 * @brief FreeRTOS task which reads from xRecvMsgBuffer and passes new frames to FreeRTOS+TCP.
197 * @param [in] pvParameters not used
198 */
vNetifReceiveTask(void * pvParameters)199 static void vNetifReceiveTask( void * pvParameters )
200 {
201 NetworkBufferDescriptor_t * pxDescriptor = NULL;
202 NetworkInterface_t * pxNetif = ( NetworkInterface_t * ) pvParameters;
203
204 MBuffNetDriverContext_t * pxDriverCtx = ( MBuffNetDriverContext_t * ) pxNetif->pvArgument;
205
206 for( ; ; )
207 {
208 size_t uxMessageLen;
209
210 while( pxDescriptor == NULL )
211 {
212 /* Wait for an MTU + header sized buffer */
213 pxDescriptor = pxGetNetworkBufferWithDescriptor( NETWORK_BUFFER_LEN, portMAX_DELAY );
214 configASSERT( pxDescriptor->xDataLength >= NETWORK_BUFFER_LEN );
215 }
216
217 /* Read an incoming frame */
218 uxMessageLen = xMessageBufferReceive( pxDriverCtx->xRecvMsgBuffer,
219 pxDescriptor->pucEthernetBuffer,
220 pxDescriptor->xDataLength,
221 portMAX_DELAY );
222
223 if( uxMessageLen > 0 )
224 {
225 IPStackEvent_t xRxEvent;
226 eFrameProcessingResult_t xFrameProcess;
227
228 pxDescriptor->xDataLength = uxMessageLen;
229
230 /* eConsiderFrameForProcessing is interrupt safe */
231 xFrameProcess = ipCONSIDER_FRAME_FOR_PROCESSING( pxDescriptor->pucEthernetBuffer );
232
233 if( xFrameProcess != eProcessBuffer )
234 {
235 FreeRTOS_debug_printf( ( "Dropping RX frame of length: %lu. eConsiderFrameForProcessing returned %lu.\n",
236 uxMessageLen, xFrameProcess ) );
237 }
238
239 pxDescriptor->pxInterface = pxNetif;
240 pxDescriptor->pxEndPoint = FreeRTOS_MatchingEndpoint( pxNetif, pxDescriptor->pucEthernetBuffer );
241
242 xRxEvent.eEventType = eNetworkRxEvent;
243 xRxEvent.pvData = ( void * ) pxDescriptor;
244
245 if( xSendEventStructToIPTask( &xRxEvent, 0U ) == pdTRUE )
246 {
247 iptraceNETWORK_INTERFACE_RECEIVE();
248
249 /* Clear pxDescriptor so that the task requests a new buffer */
250 pxDescriptor = NULL;
251 }
252 else
253 {
254 FreeRTOS_debug_printf( ( "Dropping TX frame of length: %lu. FreeRTOS+TCP event queue is full.\n",
255 pxDescriptor->xDataLength ) );
256 /* Drop the frame and reuse the descriptor for the next incomming frame */
257 iptraceETHERNET_RX_EVENT_LOST();
258 }
259 }
260 else
261 {
262 /*
263 * xMessageBufferReceive returned zero.
264 */
265 }
266 }
267 }
268
269 /*!
270 * @brief API call, called from FreeRTOS_IP.c to send a network packet over the
271 * selected interface
272 * @return pdTRUE if successful else pdFALSE
273 */
xNetworkInterfaceOutput(NetworkInterface_t * pxNetif,NetworkBufferDescriptor_t * const pxNetworkBuffer,BaseType_t xReleaseAfterSend)274 static BaseType_t xNetworkInterfaceOutput( NetworkInterface_t * pxNetif,
275 NetworkBufferDescriptor_t * const pxNetworkBuffer,
276 BaseType_t xReleaseAfterSend )
277 {
278 BaseType_t xResult = pdFALSE;
279
280 MBuffNetDriverContext_t * pxDriverCtx = ( MBuffNetDriverContext_t * ) pxNetif->pvArgument;
281
282 FreeRTOS_debug_printf( ( "xNetworkInterfaceOutput: %p:%p\n", pxNetworkBuffer, pxNetworkBuffer->pucEthernetBuffer ) );
283
284 if( pxDriverCtx->xInterfaceState == pdTRUE )
285 {
286 configASSERT( pxNetworkBuffer != NULL );
287 configASSERT( pxNetworkBuffer->pucEthernetBuffer != NULL );
288 configASSERT( pxNetworkBuffer->xDataLength >= sizeof( EthernetHeader_t ) );
289
290 if( xMessageBufferSpacesAvailable( pxDriverCtx->xSendMsgBuffer ) > pxNetworkBuffer->xDataLength + 4U )
291 {
292 size_t uxBytesSent;
293 uxBytesSent = xMessageBufferSend( pxDriverCtx->xSendMsgBuffer,
294 pxNetworkBuffer->pucEthernetBuffer,
295 pxNetworkBuffer->xDataLength,
296 0U );
297 ( void ) uxBytesSent;
298 configASSERT( uxBytesSent == pxNetworkBuffer->xDataLength );
299 xResult = pdTRUE;
300 }
301 else
302 {
303 FreeRTOS_debug_printf( ( "Dropping TX frame of length: %lu. xSendMsgBuffer is full.\n",
304 pxNetworkBuffer->xDataLength ) );
305 }
306
307 iptraceNETWORK_INTERFACE_TRANSMIT();
308
309 if( xReleaseAfterSend != pdFALSE )
310 {
311 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
312 }
313
314 if( xResult == pdTRUE )
315 {
316 #if defined( _WIN32 )
317 SetEvent( pxDriverCtx->pvSendEvent );
318 #else
319 event_signal( pxDriverCtx->pvSendEvent );
320 #endif
321 }
322 }
323
324 return xResult;
325 }
326
327 #define BUFFER_SIZE ( ipTOTAL_ETHERNET_FRAME_SIZE + ipBUFFER_PADDING )
328 #define BUFFER_SIZE_ROUNDED_UP ( ( BUFFER_SIZE + 7 ) & ~0x07UL )
329
330 /*!
331 * @brief Allocate RAM for packet buffers and set the pucEthernetBuffer field for each descriptor.
332 * Called when the BufferAllocation1 scheme is used.
333 * @param [in,out] pxNetworkBuffers Pointer to an array of NetworkBufferDescriptor_t to populate.
334 */
vNetworkInterfaceAllocateRAMToBuffers(NetworkBufferDescriptor_t pxNetworkBuffers[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS])335 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
336 {
337 static uint8_t * pucNetworkPacketBuffers = NULL;
338 size_t uxIndex;
339
340 if( pucNetworkPacketBuffers == NULL )
341 {
342 pucNetworkPacketBuffers = ( uint8_t * ) malloc( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * BUFFER_SIZE_ROUNDED_UP );
343 }
344
345 if( pucNetworkPacketBuffers == NULL )
346 {
347 FreeRTOS_printf( ( "Failed to allocate memory for pxNetworkBuffers" ) );
348 configASSERT( 0 );
349 }
350 else
351 {
352 for( uxIndex = 0; uxIndex < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; uxIndex++ )
353 {
354 size_t uxOffset = uxIndex * BUFFER_SIZE_ROUNDED_UP;
355 NetworkBufferDescriptor_t ** ppDescriptor;
356
357 /* At the beginning of each pbuff is a pointer to the relevant descriptor */
358 ppDescriptor = ( NetworkBufferDescriptor_t ** ) &( pucNetworkPacketBuffers[ uxOffset ] );
359
360 /* Set this pointer to the address of the correct descriptor */
361 *ppDescriptor = &( pxNetworkBuffers[ uxIndex ] );
362
363 /* pucEthernetBuffer is set to point ipBUFFER_PADDING bytes in from the
364 * beginning of the allocated buffer. */
365 pxNetworkBuffers[ uxIndex ].pucEthernetBuffer = &( pucNetworkPacketBuffers[ uxOffset + ipBUFFER_PADDING ] );
366 }
367 }
368 }
369
xGetPhyLinkStatus(NetworkInterface_t * pxNetif)370 BaseType_t xGetPhyLinkStatus( NetworkInterface_t * pxNetif )
371 {
372 BaseType_t xResult = pdFALSE;
373
374 MBuffNetDriverContext_t * pxDriverCtx = ( MBuffNetDriverContext_t * ) pxNetif->pvArgument;
375
376 if( pxDriverCtx->xInterfaceState == pdTRUE )
377 {
378 xResult = pdTRUE;
379 }
380
381 return xResult;
382 }
383
pxLibslirp_FillInterfaceDescriptor(BaseType_t xEMACIndex,NetworkInterface_t * pxInterface)384 NetworkInterface_t * pxLibslirp_FillInterfaceDescriptor( BaseType_t xEMACIndex,
385 NetworkInterface_t * pxInterface )
386 {
387 configASSERT( pxInterface != NULL );
388 static char pcName[ 17 ];
389
390 snprintf( pcName, sizeof( pcName ), "eth%ld", xEMACIndex );
391
392 memset( pxInterface, 0, sizeof( NetworkInterface_t ) );
393
394 pxInterface->pcName = pcName; /* Just for logging, debugging. */
395 pxInterface->pvArgument = ( void * ) xEMACIndex; /* Has only meaning for the driver functions. */
396 pxInterface->pfInitialise = xNetworkInterfaceInitialise;
397 pxInterface->pfOutput = xNetworkInterfaceOutput;
398 pxInterface->pfGetPhyLinkStatus = xGetPhyLinkStatus;
399
400 FreeRTOS_AddNetworkInterface( pxInterface );
401
402 return pxInterface;
403 }
404