2 * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
\r
3 * Authors include Hein Tibosch and Richard Barry
\r
5 *******************************************************************************
\r
6 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
9 *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
\r
10 *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
\r
13 *** FreeRTOS+TCP is functional and has been used in commercial products ***
\r
14 *** for some time. Be aware however that we are still refining its ***
\r
15 *** design, the source code does not yet quite conform to the strict ***
\r
16 *** coding and style standards mandated by Real Time Engineers ltd., and ***
\r
17 *** the documentation and testing is not necessarily complete. ***
\r
19 *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
\r
20 *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
\r
21 *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
\r
22 *** under a license other than that described below. ***
\r
25 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
26 *******************************************************************************
\r
28 * FreeRTOS+TCP can be used under two different free open source licenses. The
\r
29 * license that applies is dependent on the processor on which FreeRTOS+TCP is
\r
30 * executed, as follows:
\r
32 * If FreeRTOS+TCP is executed on one of the processors listed under the Special
\r
33 * License Arrangements heading of the FreeRTOS+TCP license information web
\r
34 * page, then it can be used under the terms of the FreeRTOS Open Source
\r
35 * License. If FreeRTOS+TCP is used on any other processor, then it can be used
\r
36 * under the terms of the GNU General Public License V2. Links to the relevant
\r
39 * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
\r
40 * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
\r
41 * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
\r
43 * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
\r
44 * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
\r
45 * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
\r
46 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
47 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
48 * implied, expressed, or statutory.
\r
50 * 1 tab == 4 spaces!
\r
52 * http://www.FreeRTOS.org
\r
53 * http://www.FreeRTOS.org/plus
\r
54 * http://www.FreeRTOS.org/labs
\r
58 /******************************************************************************
\r
60 * See the following web page for essential buffer allocation scheme usage and
\r
61 * configuration details:
\r
62 * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html
\r
64 ******************************************************************************/
\r
66 /* THIS FILE SHOULD NOT BE USED IF THE PROJECT INCLUDES A MEMORY ALLOCATOR
\r
67 THAT WILL FRAGMENT THE HEAP MEMORY. For example, heap_2 must not be used,
\r
68 heap_4 can be used. */
\r
71 /* Standard includes. */
\r
74 /* FreeRTOS includes. */
\r
75 #include "FreeRTOS.h"
\r
79 /* FreeRTOS+TCP includes. */
\r
80 #include "FreeRTOS_IP.h"
\r
81 #include "FreeRTOS_UDP_IP.h"
\r
82 #include "FreeRTOS_IP_Private.h"
\r
83 #include "NetworkInterface.h"
\r
84 #include "NetworkBufferManagement.h"
\r
86 /* The obtained network buffer must be large enough to hold a packet that might
\r
87 replace the packet that was requested to be sent. */
\r
88 #if ipconfigUSE_TCP == 1
\r
89 #define baMINIMAL_BUFFER_SIZE sizeof( TCPPacket_t )
\r
91 #define baMINIMAL_BUFFER_SIZE sizeof( ARPPacket_t )
\r
92 #endif /* ipconfigUSE_TCP == 1 */
\r
94 /*_RB_ This is too complex not to have an explanation. */
\r
95 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
96 #define ASSERT_CONCAT_(a, b) a##b
\r
97 #define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
\r
98 #define STATIC_ASSERT(e) \
\r
99 ;enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }
\r
101 STATIC_ASSERT( ipconfigETHERNET_MINIMUM_PACKET_BYTES <= baMINIMAL_BUFFER_SIZE );
\r
104 /* A list of free (available) NetworkBufferDescriptor_t structures. */
\r
105 static List_t xFreeBuffersList;
\r
107 /* Some statistics about the use of buffers. */
\r
108 static size_t uxMinimumFreeNetworkBuffers;
\r
110 /* Declares the pool of NetworkBufferDescriptor_t structures that are available
\r
111 to the system. All the network buffers referenced from xFreeBuffersList exist
\r
112 in this array. The array is not accessed directly except during initialisation,
\r
113 when the xFreeBuffersList is filled (as all the buffers are free when the system
\r
115 static NetworkBufferDescriptor_t xNetworkBufferDescriptors[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ];
\r
117 /* This constant is defined as false to let FreeRTOS_TCP_IP.c know that the
\r
118 network buffers have a variable size: resizing may be necessary */
\r
119 const BaseType_t xBufferAllocFixedSize = pdFALSE;
\r
121 /* The semaphore used to obtain network buffers. */
\r
122 static SemaphoreHandle_t xNetworkBufferSemaphore = NULL;
\r
124 /*-----------------------------------------------------------*/
\r
126 BaseType_t xNetworkBuffersInitialise( void )
\r
128 BaseType_t xReturn, x;
\r
130 /* Only initialise the buffers and their associated kernel objects if they
\r
131 have not been initialised before. */
\r
132 if( xNetworkBufferSemaphore == NULL )
\r
134 xNetworkBufferSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS );
\r
135 configASSERT( xNetworkBufferSemaphore );
\r
136 #if ( configQUEUE_REGISTRY_SIZE > 0 )
\r
138 vQueueAddToRegistry( xNetworkBufferSemaphore, "NetBufSem" );
\r
140 #endif /* configQUEUE_REGISTRY_SIZE */
\r
142 /* If the trace recorder code is included name the semaphore for viewing
\r
143 in FreeRTOS+Trace. */
\r
144 #if( ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 )
\r
146 extern QueueHandle_t xNetworkEventQueue;
\r
147 vTraceSetQueueName( xNetworkEventQueue, "IPStackEvent" );
\r
148 vTraceSetQueueName( xNetworkBufferSemaphore, "NetworkBufferCount" );
\r
150 #endif /* ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 */
\r
152 if( xNetworkBufferSemaphore != NULL )
\r
154 vListInitialise( &xFreeBuffersList );
\r
156 /* Initialise all the network buffers. No storage is allocated to
\r
157 the buffers yet. */
\r
158 for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )
\r
160 /* Initialise and set the owner of the buffer list items. */
\r
161 xNetworkBufferDescriptors[ x ].pucEthernetBuffer = NULL;
\r
162 vListInitialiseItem( &( xNetworkBufferDescriptors[ x ].xBufferListItem ) );
\r
163 listSET_LIST_ITEM_OWNER( &( xNetworkBufferDescriptors[ x ].xBufferListItem ), &xNetworkBufferDescriptors[ x ] );
\r
165 /* Currently, all buffers are available for use. */
\r
166 vListInsert( &xFreeBuffersList, &( xNetworkBufferDescriptors[ x ].xBufferListItem ) );
\r
169 uxMinimumFreeNetworkBuffers = ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;
\r
173 if( xNetworkBufferSemaphore == NULL )
\r
184 /*-----------------------------------------------------------*/
\r
186 uint8_t *pucGetNetworkBuffer( size_t *pxRequestedSizeBytes )
\r
188 uint8_t *pucEthernetBuffer;
\r
189 size_t xSize = *pxRequestedSizeBytes;
\r
191 if( xSize < baMINIMAL_BUFFER_SIZE )
\r
193 /* Buffers must be at least large enough to hold a TCP-packet with
\r
194 headers, or an ARP packet, in case TCP is not included. */
\r
195 xSize = baMINIMAL_BUFFER_SIZE;
\r
198 /* Round up xSize to the nearest multiple of N bytes,
\r
199 where N equals 'sizeof( size_t )'. */
\r
200 if( ( xSize & ( sizeof( size_t ) - 1u ) ) != 0u )
\r
202 xSize = ( xSize | ( sizeof( size_t ) - 1u ) ) + 1u;
\r
204 *pxRequestedSizeBytes = xSize;
\r
206 /* Allocate a buffer large enough to store the requested Ethernet frame size
\r
207 and a pointer to a network buffer structure (hence the addition of
\r
208 ipBUFFER_PADDING bytes). */
\r
209 pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xSize + ipBUFFER_PADDING );
\r
210 configASSERT( pucEthernetBuffer );
\r
212 if( pucEthernetBuffer != NULL )
\r
214 /* Enough space is left at the start of the buffer to place a pointer to
\r
215 the network buffer structure that references this Ethernet buffer.
\r
216 Return a pointer to the start of the Ethernet buffer itself. */
\r
217 pucEthernetBuffer += ipBUFFER_PADDING;
\r
220 return pucEthernetBuffer;
\r
222 /*-----------------------------------------------------------*/
\r
224 void vReleaseNetworkBuffer( uint8_t *pucEthernetBuffer )
\r
226 /* There is space before the Ethernet buffer in which a pointer to the
\r
227 network buffer that references this Ethernet buffer is stored. Remove the
\r
228 space before freeing the buffer. */
\r
229 if( pucEthernetBuffer != NULL )
\r
231 pucEthernetBuffer -= ipBUFFER_PADDING;
\r
232 vPortFree( ( void * ) pucEthernetBuffer );
\r
235 /*-----------------------------------------------------------*/
\r
237 NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )
\r
239 NetworkBufferDescriptor_t *pxReturn = NULL;
\r
242 if( ( xRequestedSizeBytes != 0u ) && ( xRequestedSizeBytes < ( size_t ) baMINIMAL_BUFFER_SIZE ) )
\r
244 /* ARP packets can replace application packets, so the storage must be
\r
245 at least large enough to hold an ARP. */
\r
246 xRequestedSizeBytes = baMINIMAL_BUFFER_SIZE;
\r
249 /* Add 2 bytes to xRequestedSizeBytes and round up xRequestedSizeBytes
\r
250 to the nearest multiple of N bytes, where N equals 'sizeof( size_t )'. */
\r
251 xRequestedSizeBytes += 2u;
\r
252 if( ( xRequestedSizeBytes & ( sizeof( size_t ) - 1u ) ) != 0u )
\r
254 xRequestedSizeBytes = ( xRequestedSizeBytes | ( sizeof( size_t ) - 1u ) ) + 1u;
\r
257 /* If there is a semaphore available, there is a network buffer available. */
\r
258 if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS )
\r
260 /* Protect the structure as it is accessed from tasks and interrupts. */
\r
261 taskENTER_CRITICAL();
\r
263 pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
\r
264 uxListRemove( &( pxReturn->xBufferListItem ) );
\r
266 taskEXIT_CRITICAL();
\r
268 /* Reading UBaseType_t, no critical section needed. */
\r
269 uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList );
\r
271 if( uxMinimumFreeNetworkBuffers > uxCount )
\r
273 uxMinimumFreeNetworkBuffers = uxCount;
\r
276 /* Allocate storage of exactly the requested size to the buffer. */
\r
277 configASSERT( pxReturn->pucEthernetBuffer == NULL );
\r
278 if( xRequestedSizeBytes > 0 )
\r
280 /* Extra space is obtained so a pointer to the network buffer can
\r
281 be stored at the beginning of the buffer. */
\r
282 pxReturn->pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xRequestedSizeBytes + ipBUFFER_PADDING );
\r
284 if( pxReturn->pucEthernetBuffer == NULL )
\r
286 /* The attempt to allocate storage for the buffer payload failed,
\r
287 so the network buffer structure cannot be used and must be
\r
289 vReleaseNetworkBufferAndDescriptor( pxReturn );
\r
294 /* Store a pointer to the network buffer structure in the
\r
295 buffer storage area, then move the buffer pointer on past the
\r
296 stored pointer so the pointer value is not overwritten by the
\r
297 application when the buffer is used. */
\r
298 *( ( NetworkBufferDescriptor_t ** ) ( pxReturn->pucEthernetBuffer ) ) = pxReturn;
\r
299 pxReturn->pucEthernetBuffer += ipBUFFER_PADDING;
\r
301 /* Store the actual size of the allocated buffer, which may be
\r
302 greater than the original requested size. */
\r
303 pxReturn->xDataLength = xRequestedSizeBytes;
\r
305 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
\r
307 /* make sure the buffer is not linked */
\r
308 pxReturn->pxNextBuffer = NULL;
\r
310 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
\r
315 /* A descriptor is being returned without an associated buffer being
\r
320 if( pxReturn == NULL )
\r
322 iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();
\r
326 iptraceNETWORK_BUFFER_OBTAINED( pxReturn );
\r
331 /*-----------------------------------------------------------*/
\r
333 void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
335 BaseType_t xListItemAlreadyInFreeList;
\r
337 /* Ensure the buffer is returned to the list of free buffers before the
\r
338 counting semaphore is 'given' to say a buffer is available. Release the
\r
339 storage allocated to the buffer payload. THIS FILE SHOULD NOT BE USED
\r
340 IF THE PROJECT INCLUDES A MEMORY ALLOCATOR THAT WILL FRAGMENT THE HEAP
\r
341 MEMORY. For example, heap_2 must not be used, heap_4 can be used. */
\r
342 vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer );
\r
343 pxNetworkBuffer->pucEthernetBuffer = NULL;
\r
345 taskENTER_CRITICAL();
\r
347 xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
\r
349 if( xListItemAlreadyInFreeList == pdFALSE )
\r
351 vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
\r
354 taskEXIT_CRITICAL();
\r
356 if( xListItemAlreadyInFreeList == pdFALSE )
\r
358 xSemaphoreGive( xNetworkBufferSemaphore );
\r
361 iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
\r
363 /*-----------------------------------------------------------*/
\r
366 * Returns the number of free network buffers
\r
368 UBaseType_t uxGetNumberOfFreeNetworkBuffers( void )
\r
370 return listCURRENT_LIST_LENGTH( &xFreeBuffersList );
\r
372 /*-----------------------------------------------------------*/
\r
374 UBaseType_t uxGetMinimumFreeNetworkBuffers( void )
\r
376 return uxMinimumFreeNetworkBuffers;
\r
378 /*-----------------------------------------------------------*/
\r
380 NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, size_t xNewSizeBytes )
\r
382 size_t xOriginalLength;
\r
383 uint8_t *pucBuffer;
\r
385 xOriginalLength = pxNetworkBuffer->xDataLength + ipBUFFER_PADDING;
\r
386 xNewSizeBytes = xNewSizeBytes + ipBUFFER_PADDING;
\r
388 pucBuffer = pucGetNetworkBuffer( &( xNewSizeBytes ) );
\r
390 if( pucBuffer == NULL )
\r
392 /* In case the allocation fails, return NULL. */
\r
393 pxNetworkBuffer = NULL;
\r
397 pxNetworkBuffer->xDataLength = xNewSizeBytes;
\r
398 if( xNewSizeBytes > xOriginalLength )
\r
400 xNewSizeBytes = xOriginalLength;
\r
403 memcpy( pucBuffer - ipBUFFER_PADDING, pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING, xNewSizeBytes );
\r
404 vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer );
\r
405 pxNetworkBuffer->pucEthernetBuffer = pucBuffer;
\r
408 return pxNetworkBuffer;
\r