1 /*
2 * FreeRTOS+TCP V3.1.0
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 MBuffNetDriverContext_t xDriverCtx = { 0 };
81
82 /**
83 * @brief Initialize the MessageBuffer backed network interface.
84 *
85 * @return BaseType_t pdTRUE on success
86 */
xNetworkInterfaceInitialise(void)87 BaseType_t xNetworkInterfaceInitialise( void )
88 {
89 BaseType_t xResult = pdTRUE;
90
91 if( xDriverCtx.xInterfaceState == pdFALSE )
92 {
93 xDriverCtx.xInterfaceState = pdFALSE;
94
95 #if defined( _WIN32 )
96 xDriverCtx.pvSendEvent = CreateEvent( NULL, FALSE, TRUE, NULL );
97 #else
98 xDriverCtx.pvSendEvent = ( void * ) event_create();
99 #endif
100
101 if( xDriverCtx.pvSendEvent == NULL )
102 {
103 xResult = pdFALSE;
104 }
105 else
106 {
107 vMBuffNetifBackendInit( &( xDriverCtx.xSendMsgBuffer ),
108 &( xDriverCtx.xRecvMsgBuffer ),
109 xDriverCtx.pvSendEvent,
110 &( xDriverCtx.pvBackendContext ) );
111
112 if( xDriverCtx.pvBackendContext == NULL )
113 {
114 xResult = pdFALSE;
115 #if defined( _WIN32 )
116 ( void ) CloseHandle( xDriverCtx.pvSendEvent );
117 #else
118 ( void ) event_delete( xDriverCtx.pvSendEvent );
119 #endif
120 }
121 }
122
123 if( xResult == pdTRUE )
124 {
125 xResult = xTaskCreate( vNetifReceiveTask, "NetRX",
126 configMINIMAL_STACK_SIZE, NULL,
127 tskIDLE_PRIORITY,
128 &( xDriverCtx.xRecvTask ) );
129 }
130
131 /* Cleanup on failure */
132 if( xResult != pdTRUE )
133 {
134 if( xDriverCtx.pvSendEvent != NULL )
135 {
136 #if defined( _WIN32 )
137 ( void ) CloseHandle( xDriverCtx.pvSendEvent );
138 #else
139 event_delete( xDriverCtx.pvSendEvent );
140 #endif
141 }
142
143 if( xDriverCtx.pvBackendContext != NULL )
144 {
145 vMBuffNetifBackendDeInit( xDriverCtx.pvBackendContext );
146 }
147 }
148
149 xDriverCtx.xInterfaceState = xResult;
150 }
151
152 return xResult;
153 }
154
155 /**
156 * @brief Deinitialize the message buffer backed network interface.
157 *
158 * @return BaseType_t pdTRUE
159 */
xNetworkInterfaceDeInitialise(void)160 BaseType_t xNetworkInterfaceDeInitialise( void )
161 {
162 #if defined( _WIN32 )
163 ( void ) CloseHandle( xDriverCtx.pvSendEvent );
164 #else
165 event_delete( xDriverCtx.pvSendEvent );
166 #endif
167
168 vTaskDelete( xDriverCtx.xRecvTask );
169
170 return pdTRUE;
171 }
172
173 /*!
174 * @brief FreeRTOS task which reads from xRecvMsgBuffer and passes new frames to FreeRTOS+TCP.
175 * @param [in] pvParameters not used
176 */
vNetifReceiveTask(void * pvParameters)177 static void vNetifReceiveTask( void * pvParameters )
178 {
179 NetworkBufferDescriptor_t * pxDescriptor = NULL;
180
181 ( void ) pvParameters;
182
183 for( ; ; )
184 {
185 size_t uxMessageLen;
186
187 while( pxDescriptor == NULL )
188 {
189 /* Wait for an MTU + header sized buffer */
190 pxDescriptor = pxGetNetworkBufferWithDescriptor( NETWORK_BUFFER_LEN, portMAX_DELAY );
191 configASSERT( pxDescriptor->xDataLength >= NETWORK_BUFFER_LEN );
192 }
193
194 /* Read an incoming frame */
195 uxMessageLen = xMessageBufferReceive( xDriverCtx.xRecvMsgBuffer,
196 pxDescriptor->pucEthernetBuffer,
197 pxDescriptor->xDataLength,
198 portMAX_DELAY );
199
200 if( uxMessageLen > 0 )
201 {
202 IPStackEvent_t xRxEvent;
203 eFrameProcessingResult_t xFrameProcess;
204
205 pxDescriptor->xDataLength = uxMessageLen;
206
207 /* eConsiderFrameForProcessing is interrupt safe */
208 xFrameProcess = ipCONSIDER_FRAME_FOR_PROCESSING( pxDescriptor->pucEthernetBuffer );
209
210 if( xFrameProcess != eProcessBuffer )
211 {
212 FreeRTOS_debug_printf( ( "Dropping RX frame of length: %lu. eConsiderFrameForProcessing returned %lu.\n",
213 uxMessageLen, xFrameProcess ) );
214 }
215
216 xRxEvent.eEventType = eNetworkRxEvent;
217 xRxEvent.pvData = ( void * ) pxDescriptor;
218
219 if( xSendEventStructToIPTask( &xRxEvent, 0U ) == pdTRUE )
220 {
221 iptraceNETWORK_INTERFACE_RECEIVE();
222
223 /* Clear pxDescriptor so that the task requests a new buffer */
224 pxDescriptor = NULL;
225 }
226 else
227 {
228 FreeRTOS_debug_printf( ( "Dropping TX frame of length: %lu. FreeRTOS+TCP event queue is full.\n",
229 pxDescriptor->xDataLength ) );
230 /* Drop the frame and reuse the descriptor for the next incomming frame */
231 iptraceETHERNET_RX_EVENT_LOST();
232 }
233 }
234 else
235 {
236 /*
237 * xMessageBufferReceive returned zero.
238 */
239 }
240 }
241 }
242
243 /*!
244 * @brief API call, called from reeRTOS_IP.c to send a network packet over the
245 * selected interface
246 * @return pdTRUE if successful else pdFALSE
247 */
xNetworkInterfaceOutput(NetworkBufferDescriptor_t * const pxNetworkBuffer,BaseType_t xReleaseAfterSend)248 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer,
249 BaseType_t xReleaseAfterSend )
250 {
251 BaseType_t xResult = pdFALSE;
252
253 configASSERT( pxNetworkBuffer != NULL );
254 configASSERT( pxNetworkBuffer->pucEthernetBuffer != NULL );
255 configASSERT( pxNetworkBuffer->xDataLength >= sizeof( EthernetHeader_t ) );
256
257 if( xDriverCtx.xInterfaceState == pdTRUE )
258 {
259 if( xMessageBufferSpacesAvailable( xDriverCtx.xSendMsgBuffer ) > pxNetworkBuffer->xDataLength + 4U )
260 {
261 size_t uxBytesSent;
262 uxBytesSent = xMessageBufferSend( xDriverCtx.xSendMsgBuffer,
263 pxNetworkBuffer->pucEthernetBuffer,
264 pxNetworkBuffer->xDataLength,
265 0U );
266 ( void ) uxBytesSent;
267 configASSERT( uxBytesSent == pxNetworkBuffer->xDataLength );
268 xResult = pdTRUE;
269 }
270 else
271 {
272 FreeRTOS_debug_printf( ( "Dropping TX frame of length: %lu. xSendMsgBuffer is full.\n",
273 pxNetworkBuffer->xDataLength ) );
274 }
275
276 iptraceNETWORK_INTERFACE_TRANSMIT();
277
278 if( xReleaseAfterSend != pdFALSE )
279 {
280 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
281 }
282
283 if( xResult == pdTRUE )
284 {
285 #if defined( _WIN32 )
286 SetEvent( xDriverCtx.pvSendEvent );
287 #else
288 event_signal( xDriverCtx.pvSendEvent );
289 #endif
290 }
291 }
292
293 return xResult;
294 }
295
296 #define BUFFER_SIZE ( ipTOTAL_ETHERNET_FRAME_SIZE + ipBUFFER_PADDING )
297 #define BUFFER_SIZE_ROUNDED_UP ( ( BUFFER_SIZE + 7 ) & ~0x07UL )
298
299 /*!
300 * @brief Allocate RAM for packet buffers and set the pucEthernetBuffer field for each descriptor.
301 * Called when the BufferAllocation1 scheme is used.
302 * @param [in,out] pxNetworkBuffers Pointer to an array of NetworkBufferDescriptor_t to populate.
303 */
vNetworkInterfaceAllocateRAMToBuffers(NetworkBufferDescriptor_t pxNetworkBuffers[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS])304 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
305 {
306 static uint8_t * pucNetworkPacketBuffers = NULL;
307 size_t uxIndex;
308
309 if( pucNetworkPacketBuffers == NULL )
310 {
311 pucNetworkPacketBuffers = ( uint8_t * ) malloc( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * BUFFER_SIZE_ROUNDED_UP );
312 }
313
314 if( pucNetworkPacketBuffers == NULL )
315 {
316 FreeRTOS_printf( ( "Failed to allocate memory for pxNetworkBuffers" ) );
317 configASSERT( 0 );
318 }
319 else
320 {
321 for( uxIndex = 0; uxIndex < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; uxIndex++ )
322 {
323 size_t uxOffset = uxIndex * BUFFER_SIZE_ROUNDED_UP;
324 NetworkBufferDescriptor_t ** ppDescriptor;
325
326 /* At the beginning of each pbuff is a pointer to the relevant descriptor */
327 ppDescriptor = ( NetworkBufferDescriptor_t ** ) &( pucNetworkPacketBuffers[ uxOffset ] );
328
329 /* Set this pointer to the address of the correct descriptor */
330 *ppDescriptor = &( pxNetworkBuffers[ uxIndex ] );
331
332 /* pucEthernetBuffer is set to point ipBUFFER_PADDING bytes in from the
333 * beginning of the allocated buffer. */
334 pxNetworkBuffers[ uxIndex ].pucEthernetBuffer = &( pucNetworkPacketBuffers[ uxOffset + ipBUFFER_PADDING ] );
335 }
336 }
337 }
338