2 * FreeRTOS+TCP V2.0.0
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\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
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
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
23 * http://www.FreeRTOS.org
\r
24 * http://aws.amazon.com/freertos
\r
26 * 1 tab == 4 spaces!
\r
29 /******************************************************************************
\r
31 * See the following web page for essential buffer allocation scheme usage and
\r
32 * configuration details:
\r
33 * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html
\r
35 ******************************************************************************/
\r
37 /* THIS FILE SHOULD NOT BE USED IF THE PROJECT INCLUDES A MEMORY ALLOCATOR
\r
38 THAT WILL FRAGMENT THE HEAP MEMORY. For example, heap_2 must not be used,
\r
39 heap_4 can be used. */
\r
42 /* Standard includes. */
\r
45 /* FreeRTOS includes. */
\r
46 #include "FreeRTOS.h"
\r
50 /* FreeRTOS+TCP includes. */
\r
51 #include "FreeRTOS_IP.h"
\r
52 #include "FreeRTOS_UDP_IP.h"
\r
53 #include "FreeRTOS_IP_Private.h"
\r
54 #include "NetworkInterface.h"
\r
55 #include "NetworkBufferManagement.h"
\r
57 /* The obtained network buffer must be large enough to hold a packet that might
\r
58 replace the packet that was requested to be sent. */
\r
59 #if ipconfigUSE_TCP == 1
\r
60 #define baMINIMAL_BUFFER_SIZE sizeof( TCPPacket_t )
\r
62 #define baMINIMAL_BUFFER_SIZE sizeof( ARPPacket_t )
\r
63 #endif /* ipconfigUSE_TCP == 1 */
\r
65 /*_RB_ This is too complex not to have an explanation. */
\r
66 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
67 #define ASSERT_CONCAT_(a, b) a##b
\r
68 #define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
\r
69 #define STATIC_ASSERT(e) \
\r
70 ;enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }
\r
72 STATIC_ASSERT( ipconfigETHERNET_MINIMUM_PACKET_BYTES <= baMINIMAL_BUFFER_SIZE );
\r
75 /* A list of free (available) NetworkBufferDescriptor_t structures. */
\r
76 static List_t xFreeBuffersList;
\r
78 /* Some statistics about the use of buffers. */
\r
79 static size_t uxMinimumFreeNetworkBuffers;
\r
81 /* Declares the pool of NetworkBufferDescriptor_t structures that are available
\r
82 to the system. All the network buffers referenced from xFreeBuffersList exist
\r
83 in this array. The array is not accessed directly except during initialisation,
\r
84 when the xFreeBuffersList is filled (as all the buffers are free when the system
\r
86 static NetworkBufferDescriptor_t xNetworkBufferDescriptors[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ];
\r
88 /* This constant is defined as false to let FreeRTOS_TCP_IP.c know that the
\r
89 network buffers have a variable size: resizing may be necessary */
\r
90 const BaseType_t xBufferAllocFixedSize = pdFALSE;
\r
92 /* The semaphore used to obtain network buffers. */
\r
93 static SemaphoreHandle_t xNetworkBufferSemaphore = NULL;
\r
95 /*-----------------------------------------------------------*/
\r
97 BaseType_t xNetworkBuffersInitialise( void )
\r
99 BaseType_t xReturn, x;
\r
101 /* Only initialise the buffers and their associated kernel objects if they
\r
102 have not been initialised before. */
\r
103 if( xNetworkBufferSemaphore == NULL )
\r
105 xNetworkBufferSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS );
\r
106 configASSERT( xNetworkBufferSemaphore );
\r
107 #if ( configQUEUE_REGISTRY_SIZE > 0 )
\r
109 vQueueAddToRegistry( xNetworkBufferSemaphore, "NetBufSem" );
\r
111 #endif /* configQUEUE_REGISTRY_SIZE */
\r
113 /* If the trace recorder code is included name the semaphore for viewing
\r
114 in FreeRTOS+Trace. */
\r
115 #if( ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 )
\r
117 extern QueueHandle_t xNetworkEventQueue;
\r
118 vTraceSetQueueName( xNetworkEventQueue, "IPStackEvent" );
\r
119 vTraceSetQueueName( xNetworkBufferSemaphore, "NetworkBufferCount" );
\r
121 #endif /* ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 */
\r
123 if( xNetworkBufferSemaphore != NULL )
\r
125 vListInitialise( &xFreeBuffersList );
\r
127 /* Initialise all the network buffers. No storage is allocated to
\r
128 the buffers yet. */
\r
129 for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )
\r
131 /* Initialise and set the owner of the buffer list items. */
\r
132 xNetworkBufferDescriptors[ x ].pucEthernetBuffer = NULL;
\r
133 vListInitialiseItem( &( xNetworkBufferDescriptors[ x ].xBufferListItem ) );
\r
134 listSET_LIST_ITEM_OWNER( &( xNetworkBufferDescriptors[ x ].xBufferListItem ), &xNetworkBufferDescriptors[ x ] );
\r
136 /* Currently, all buffers are available for use. */
\r
137 vListInsert( &xFreeBuffersList, &( xNetworkBufferDescriptors[ x ].xBufferListItem ) );
\r
140 uxMinimumFreeNetworkBuffers = ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;
\r
144 if( xNetworkBufferSemaphore == NULL )
\r
155 /*-----------------------------------------------------------*/
\r
157 uint8_t *pucGetNetworkBuffer( size_t *pxRequestedSizeBytes )
\r
159 uint8_t *pucEthernetBuffer;
\r
160 size_t xSize = *pxRequestedSizeBytes;
\r
162 if( xSize < baMINIMAL_BUFFER_SIZE )
\r
164 /* Buffers must be at least large enough to hold a TCP-packet with
\r
165 headers, or an ARP packet, in case TCP is not included. */
\r
166 xSize = baMINIMAL_BUFFER_SIZE;
\r
169 /* Round up xSize to the nearest multiple of N bytes,
\r
170 where N equals 'sizeof( size_t )'. */
\r
171 if( ( xSize & ( sizeof( size_t ) - 1u ) ) != 0u )
\r
173 xSize = ( xSize | ( sizeof( size_t ) - 1u ) ) + 1u;
\r
175 *pxRequestedSizeBytes = xSize;
\r
177 /* Allocate a buffer large enough to store the requested Ethernet frame size
\r
178 and a pointer to a network buffer structure (hence the addition of
\r
179 ipBUFFER_PADDING bytes). */
\r
180 pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xSize + ipBUFFER_PADDING );
\r
181 configASSERT( pucEthernetBuffer );
\r
183 if( pucEthernetBuffer != NULL )
\r
185 /* Enough space is left at the start of the buffer to place a pointer to
\r
186 the network buffer structure that references this Ethernet buffer.
\r
187 Return a pointer to the start of the Ethernet buffer itself. */
\r
188 pucEthernetBuffer += ipBUFFER_PADDING;
\r
191 return pucEthernetBuffer;
\r
193 /*-----------------------------------------------------------*/
\r
195 void vReleaseNetworkBuffer( uint8_t *pucEthernetBuffer )
\r
197 /* There is space before the Ethernet buffer in which a pointer to the
\r
198 network buffer that references this Ethernet buffer is stored. Remove the
\r
199 space before freeing the buffer. */
\r
200 if( pucEthernetBuffer != NULL )
\r
202 pucEthernetBuffer -= ipBUFFER_PADDING;
\r
203 vPortFree( ( void * ) pucEthernetBuffer );
\r
206 /*-----------------------------------------------------------*/
\r
208 NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )
\r
210 NetworkBufferDescriptor_t *pxReturn = NULL;
\r
213 if( ( xRequestedSizeBytes != 0u ) && ( xRequestedSizeBytes < ( size_t ) baMINIMAL_BUFFER_SIZE ) )
\r
215 /* ARP packets can replace application packets, so the storage must be
\r
216 at least large enough to hold an ARP. */
\r
217 xRequestedSizeBytes = baMINIMAL_BUFFER_SIZE;
\r
220 /* Add 2 bytes to xRequestedSizeBytes and round up xRequestedSizeBytes
\r
221 to the nearest multiple of N bytes, where N equals 'sizeof( size_t )'. */
\r
222 xRequestedSizeBytes += 2u;
\r
223 if( ( xRequestedSizeBytes & ( sizeof( size_t ) - 1u ) ) != 0u )
\r
225 xRequestedSizeBytes = ( xRequestedSizeBytes | ( sizeof( size_t ) - 1u ) ) + 1u;
\r
228 /* If there is a semaphore available, there is a network buffer available. */
\r
229 if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS )
\r
231 /* Protect the structure as it is accessed from tasks and interrupts. */
\r
232 taskENTER_CRITICAL();
\r
234 pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
\r
235 uxListRemove( &( pxReturn->xBufferListItem ) );
\r
237 taskEXIT_CRITICAL();
\r
239 /* Reading UBaseType_t, no critical section needed. */
\r
240 uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList );
\r
242 if( uxMinimumFreeNetworkBuffers > uxCount )
\r
244 uxMinimumFreeNetworkBuffers = uxCount;
\r
247 /* Allocate storage of exactly the requested size to the buffer. */
\r
248 configASSERT( pxReturn->pucEthernetBuffer == NULL );
\r
249 if( xRequestedSizeBytes > 0 )
\r
251 /* Extra space is obtained so a pointer to the network buffer can
\r
252 be stored at the beginning of the buffer. */
\r
253 pxReturn->pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xRequestedSizeBytes + ipBUFFER_PADDING );
\r
255 if( pxReturn->pucEthernetBuffer == NULL )
\r
257 /* The attempt to allocate storage for the buffer payload failed,
\r
258 so the network buffer structure cannot be used and must be
\r
260 vReleaseNetworkBufferAndDescriptor( pxReturn );
\r
265 /* Store a pointer to the network buffer structure in the
\r
266 buffer storage area, then move the buffer pointer on past the
\r
267 stored pointer so the pointer value is not overwritten by the
\r
268 application when the buffer is used. */
\r
269 *( ( NetworkBufferDescriptor_t ** ) ( pxReturn->pucEthernetBuffer ) ) = pxReturn;
\r
270 pxReturn->pucEthernetBuffer += ipBUFFER_PADDING;
\r
272 /* Store the actual size of the allocated buffer, which may be
\r
273 greater than the original requested size. */
\r
274 pxReturn->xDataLength = xRequestedSizeBytes;
\r
276 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
\r
278 /* make sure the buffer is not linked */
\r
279 pxReturn->pxNextBuffer = NULL;
\r
281 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
\r
286 /* A descriptor is being returned without an associated buffer being
\r
291 if( pxReturn == NULL )
\r
293 iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();
\r
297 iptraceNETWORK_BUFFER_OBTAINED( pxReturn );
\r
302 /*-----------------------------------------------------------*/
\r
304 void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
306 BaseType_t xListItemAlreadyInFreeList;
\r
308 /* Ensure the buffer is returned to the list of free buffers before the
\r
309 counting semaphore is 'given' to say a buffer is available. Release the
\r
310 storage allocated to the buffer payload. THIS FILE SHOULD NOT BE USED
\r
311 IF THE PROJECT INCLUDES A MEMORY ALLOCATOR THAT WILL FRAGMENT THE HEAP
\r
312 MEMORY. For example, heap_2 must not be used, heap_4 can be used. */
\r
313 vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer );
\r
314 pxNetworkBuffer->pucEthernetBuffer = NULL;
\r
316 taskENTER_CRITICAL();
\r
318 xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
\r
320 if( xListItemAlreadyInFreeList == pdFALSE )
\r
322 vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
\r
325 taskEXIT_CRITICAL();
\r
327 if( xListItemAlreadyInFreeList == pdFALSE )
\r
329 xSemaphoreGive( xNetworkBufferSemaphore );
\r
332 iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
\r
334 /*-----------------------------------------------------------*/
\r
337 * Returns the number of free network buffers
\r
339 UBaseType_t uxGetNumberOfFreeNetworkBuffers( void )
\r
341 return listCURRENT_LIST_LENGTH( &xFreeBuffersList );
\r
343 /*-----------------------------------------------------------*/
\r
345 UBaseType_t uxGetMinimumFreeNetworkBuffers( void )
\r
347 return uxMinimumFreeNetworkBuffers;
\r
349 /*-----------------------------------------------------------*/
\r
351 NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, size_t xNewSizeBytes )
\r
353 size_t xOriginalLength;
\r
354 uint8_t *pucBuffer;
\r
356 xOriginalLength = pxNetworkBuffer->xDataLength + ipBUFFER_PADDING;
\r
357 xNewSizeBytes = xNewSizeBytes + ipBUFFER_PADDING;
\r
359 pucBuffer = pucGetNetworkBuffer( &( xNewSizeBytes ) );
\r
361 if( pucBuffer == NULL )
\r
363 /* In case the allocation fails, return NULL. */
\r
364 pxNetworkBuffer = NULL;
\r
368 pxNetworkBuffer->xDataLength = xNewSizeBytes;
\r
369 if( xNewSizeBytes > xOriginalLength )
\r
371 xNewSizeBytes = xOriginalLength;
\r
374 memcpy( pucBuffer - ipBUFFER_PADDING, pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING, xNewSizeBytes );
\r
375 vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer );
\r
376 pxNetworkBuffer->pucEthernetBuffer = pucBuffer;
\r
379 return pxNetworkBuffer;
\r