2 * FreeRTOS+TCP 191100 experimental
\r
3 * Copyright (C) 2018 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.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
28 /******************************************************************************
\r
30 * See the following web page for essential buffer allocation scheme usage and
\r
31 * configuration details:
\r
32 * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html
\r
34 ******************************************************************************/
\r
36 /* THIS FILE SHOULD NOT BE USED IF THE PROJECT INCLUDES A MEMORY ALLOCATOR
\r
37 THAT WILL FRAGMENT THE HEAP MEMORY. For example, heap_2 must not be used,
\r
38 heap_4 can be used. */
\r
41 /* Standard includes. */
\r
44 /* FreeRTOS includes. */
\r
45 #include "FreeRTOS.h"
\r
49 /* FreeRTOS+TCP includes. */
\r
50 #include "FreeRTOS_IP.h"
\r
51 #include "FreeRTOS_UDP_IP.h"
\r
52 #include "FreeRTOS_IP_Private.h"
\r
53 #include "NetworkInterface.h"
\r
54 #include "NetworkBufferManagement.h"
\r
56 /* The obtained network buffer must be large enough to hold a packet that might
\r
57 replace the packet that was requested to be sent. */
\r
58 #if ipconfigUSE_TCP == 1
\r
59 #define baMINIMAL_BUFFER_SIZE sizeof( TCPPacket_t )
\r
61 #define baMINIMAL_BUFFER_SIZE sizeof( ARPPacket_t )
\r
62 #endif /* ipconfigUSE_TCP == 1 */
\r
64 /*_RB_ This is too complex not to have an explanation. */
\r
65 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
66 #define ASSERT_CONCAT_(a, b) a##b
\r
67 #define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
\r
68 #define STATIC_ASSERT(e) \
\r
69 ;enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }
\r
71 STATIC_ASSERT( ipconfigETHERNET_MINIMUM_PACKET_BYTES <= baMINIMAL_BUFFER_SIZE );
\r
74 /* A list of free (available) NetworkBufferDescriptor_t structures. */
\r
75 static List_t xFreeBuffersList;
\r
77 /* Some statistics about the use of buffers. */
\r
78 static size_t uxMinimumFreeNetworkBuffers;
\r
80 /* Declares the pool of NetworkBufferDescriptor_t structures that are available
\r
81 to the system. All the network buffers referenced from xFreeBuffersList exist
\r
82 in this array. The array is not accessed directly except during initialisation,
\r
83 when the xFreeBuffersList is filled (as all the buffers are free when the system
\r
85 static NetworkBufferDescriptor_t xNetworkBufferDescriptors[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ];
\r
87 /* This constant is defined as false to let FreeRTOS_TCP_IP.c know that the
\r
88 network buffers have a variable size: resizing may be necessary */
\r
89 const BaseType_t xBufferAllocFixedSize = pdFALSE;
\r
91 /* The semaphore used to obtain network buffers. */
\r
92 static SemaphoreHandle_t xNetworkBufferSemaphore = NULL;
\r
94 /*-----------------------------------------------------------*/
\r
96 BaseType_t xNetworkBuffersInitialise( void )
\r
98 BaseType_t xReturn, x;
\r
100 /* Only initialise the buffers and their associated kernel objects if they
\r
101 have not been initialised before. */
\r
102 if( xNetworkBufferSemaphore == NULL )
\r
104 xNetworkBufferSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS );
\r
105 configASSERT( xNetworkBufferSemaphore );
\r
107 if( xNetworkBufferSemaphore != NULL )
\r
109 #if ( configQUEUE_REGISTRY_SIZE > 0 )
\r
111 vQueueAddToRegistry( xNetworkBufferSemaphore, "NetBufSem" );
\r
113 #endif /* configQUEUE_REGISTRY_SIZE */
\r
115 /* If the trace recorder code is included name the semaphore for viewing
\r
116 in FreeRTOS+Trace. */
\r
117 #if( ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 )
\r
119 extern QueueHandle_t xNetworkEventQueue;
\r
120 vTraceSetQueueName( xNetworkEventQueue, "IPStackEvent" );
\r
121 vTraceSetQueueName( xNetworkBufferSemaphore, "NetworkBufferCount" );
\r
123 #endif /* ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 */
\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( xNetworkBufferSemaphore != NULL )
\r
215 if( ( xRequestedSizeBytes != 0u ) && ( xRequestedSizeBytes < ( size_t ) baMINIMAL_BUFFER_SIZE ) )
\r
217 /* ARP packets can replace application packets, so the storage must be
\r
218 at least large enough to hold an ARP. */
\r
219 xRequestedSizeBytes = baMINIMAL_BUFFER_SIZE;
\r
222 /* Add 2 bytes to xRequestedSizeBytes and round up xRequestedSizeBytes
\r
223 to the nearest multiple of N bytes, where N equals 'sizeof( size_t )'. */
\r
224 xRequestedSizeBytes += 2u;
\r
225 if( ( xRequestedSizeBytes & ( sizeof( size_t ) - 1u ) ) != 0u )
\r
227 xRequestedSizeBytes = ( xRequestedSizeBytes | ( sizeof( size_t ) - 1u ) ) + 1u;
\r
230 /* If there is a semaphore available, there is a network buffer available. */
\r
231 if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS )
\r
233 /* Protect the structure as it is accessed from tasks and interrupts. */
\r
234 taskENTER_CRITICAL();
\r
236 pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
\r
237 uxListRemove( &( pxReturn->xBufferListItem ) );
\r
239 taskEXIT_CRITICAL();
\r
241 /* Reading UBaseType_t, no critical section needed. */
\r
242 uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList );
\r
244 if( uxMinimumFreeNetworkBuffers > uxCount )
\r
246 uxMinimumFreeNetworkBuffers = uxCount;
\r
249 /* Allocate storage of exactly the requested size to the buffer. */
\r
250 configASSERT( pxReturn->pucEthernetBuffer == NULL );
\r
251 if( xRequestedSizeBytes > 0 )
\r
253 /* Extra space is obtained so a pointer to the network buffer can
\r
254 be stored at the beginning of the buffer. */
\r
255 pxReturn->pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xRequestedSizeBytes + ipBUFFER_PADDING );
\r
257 if( pxReturn->pucEthernetBuffer == NULL )
\r
259 /* The attempt to allocate storage for the buffer payload failed,
\r
260 so the network buffer structure cannot be used and must be
\r
262 vReleaseNetworkBufferAndDescriptor( pxReturn );
\r
267 /* Store a pointer to the network buffer structure in the
\r
268 buffer storage area, then move the buffer pointer on past the
\r
269 stored pointer so the pointer value is not overwritten by the
\r
270 application when the buffer is used. */
\r
271 *( ( NetworkBufferDescriptor_t ** ) ( pxReturn->pucEthernetBuffer ) ) = pxReturn;
\r
272 pxReturn->pucEthernetBuffer += ipBUFFER_PADDING;
\r
274 /* Store the actual size of the allocated buffer, which may be
\r
275 greater than the original requested size. */
\r
276 pxReturn->xDataLength = xRequestedSizeBytes;
\r
278 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
\r
280 /* make sure the buffer is not linked */
\r
281 pxReturn->pxNextBuffer = NULL;
\r
283 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
\r
288 /* A descriptor is being returned without an associated buffer being
\r
294 if( pxReturn == NULL )
\r
296 iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();
\r
300 iptraceNETWORK_BUFFER_OBTAINED( pxReturn );
\r
305 /*-----------------------------------------------------------*/
\r
307 void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
309 BaseType_t xListItemAlreadyInFreeList;
\r
311 /* Ensure the buffer is returned to the list of free buffers before the
\r
312 counting semaphore is 'given' to say a buffer is available. Release the
\r
313 storage allocated to the buffer payload. THIS FILE SHOULD NOT BE USED
\r
314 IF THE PROJECT INCLUDES A MEMORY ALLOCATOR THAT WILL FRAGMENT THE HEAP
\r
315 MEMORY. For example, heap_2 must not be used, heap_4 can be used. */
\r
316 vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer );
\r
317 pxNetworkBuffer->pucEthernetBuffer = NULL;
\r
319 taskENTER_CRITICAL();
\r
321 xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
\r
323 if( xListItemAlreadyInFreeList == pdFALSE )
\r
325 vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
\r
328 taskEXIT_CRITICAL();
\r
331 * Update the network state machine, unless the program fails to release its 'xNetworkBufferSemaphore'.
\r
332 * The program should only try to release its semaphore if 'xListItemAlreadyInFreeList' is false.
\r
334 if( xListItemAlreadyInFreeList == pdFALSE )
\r
336 if ( xSemaphoreGive( xNetworkBufferSemaphore ) == pdTRUE )
\r
338 iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
\r
343 iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
\r
346 /*-----------------------------------------------------------*/
\r
349 * Returns the number of free network buffers
\r
351 UBaseType_t uxGetNumberOfFreeNetworkBuffers( void )
\r
353 return listCURRENT_LIST_LENGTH( &xFreeBuffersList );
\r
355 /*-----------------------------------------------------------*/
\r
357 UBaseType_t uxGetMinimumFreeNetworkBuffers( void )
\r
359 return uxMinimumFreeNetworkBuffers;
\r
361 /*-----------------------------------------------------------*/
\r
363 NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, size_t xNewSizeBytes )
\r
365 size_t xOriginalLength;
\r
366 uint8_t *pucBuffer;
\r
368 xOriginalLength = pxNetworkBuffer->xDataLength + ipBUFFER_PADDING;
\r
369 xNewSizeBytes = xNewSizeBytes + ipBUFFER_PADDING;
\r
371 pucBuffer = pucGetNetworkBuffer( &( xNewSizeBytes ) );
\r
373 if( pucBuffer == NULL )
\r
375 /* In case the allocation fails, return NULL. */
\r
376 pxNetworkBuffer = NULL;
\r
380 pxNetworkBuffer->xDataLength = xNewSizeBytes;
\r
381 if( xNewSizeBytes > xOriginalLength )
\r
383 xNewSizeBytes = xOriginalLength;
\r
386 memcpy( pucBuffer - ipBUFFER_PADDING, pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING, xNewSizeBytes );
\r
387 vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer );
\r
388 pxNetworkBuffer->pucEthernetBuffer = pucBuffer;
\r
391 return pxNetworkBuffer;
\r