]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/BufferAllocation_2.c
Update version number in readiness for V10.3.0 release. Sync SVN with reviewed releas...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / pic32mzef / BufferAllocation_2.c
1 /*
2  * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
3  * Authors include Hein Tibosch and Richard Barry
4  *
5  *******************************************************************************
6  ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
7  ***                                                                         ***
8  ***                                                                         ***
9  ***   FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP     ***
10  ***   demos have a dependency on FreeRTOS+FAT, which is only in the Labs    ***
11  ***   download):                                                            ***
12  ***                                                                         ***
13  ***   FreeRTOS+TCP is functional and has been used in commercial products   ***
14  ***   for some time.  Be aware however that we are still refining its       ***
15  ***   design, the source code does not yet quite conform to the strict      ***
16  ***   coding and style standards mandated by Real Time Engineers ltd., and  ***
17  ***   the documentation and testing is not necessarily complete.            ***
18  ***                                                                         ***
19  ***   PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE    ***
20  ***   URL: http://www.FreeRTOS.org/contact  Active early adopters may, at   ***
21  ***   the sole discretion of Real Time Engineers Ltd., be offered versions  ***
22  ***   under a license other than that described below.                      ***
23  ***                                                                         ***
24  ***                                                                         ***
25  ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
26  *******************************************************************************
27  *
28  * FreeRTOS+TCP can be used under two different free open source licenses.  The
29  * license that applies is dependent on the processor on which FreeRTOS+TCP is
30  * executed, as follows:
31  *
32  * If FreeRTOS+TCP is executed on one of the processors listed under the Special
33  * License Arrangements heading of the FreeRTOS+TCP license information web
34  * page, then it can be used under the terms of the FreeRTOS Open Source
35  * License.  If FreeRTOS+TCP is used on any other processor, then it can be used
36  * under the terms of the GNU General Public License V2.  Links to the relevant
37  * licenses follow:
38  *
39  * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
40  * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
41  * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
42  *
43  * FreeRTOS+TCP is distributed in the hope that it will be useful.  You cannot
44  * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
45  * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
46  * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
47  * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
48  * implied, expressed, or statutory.
49  *
50  * 1 tab == 4 spaces!
51  *
52  * http://www.FreeRTOS.org
53  * http://www.FreeRTOS.org/plus
54  * http://www.FreeRTOS.org/labs
55  *
56  */
57
58 /******************************************************************************
59 *
60 * See the following web page for essential buffer allocation scheme usage and
61 * configuration details:
62 * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html
63 *
64 ******************************************************************************/
65
66 /* THIS FILE SHOULD NOT BE USED IF THE PROJECT INCLUDES A MEMORY ALLOCATOR
67  * THAT WILL FRAGMENT THE HEAP MEMORY.  For example, heap_2 must not be used,
68  * heap_4 can be used. */
69
70 /* Standard includes. */
71 #include <stdint.h>
72
73 /* FreeRTOS includes. */
74 #include "FreeRTOS.h"
75 #include "task.h"
76 #include "semphr.h"
77
78 /* FreeRTOS+TCP includes. */
79 #include "FreeRTOS_IP.h"
80 #include "FreeRTOS_UDP_IP.h"
81 #include "FreeRTOS_IP_Private.h"
82 #include "NetworkInterface.h"
83 #include "NetworkBufferManagement.h"
84
85 #include "tcpip/tcpip.h"
86 #include "tcpip/src/tcpip_private.h"
87
88 #include "NetworkConfig.h"
89
90 /* The obtained network buffer must be large enough to hold a packet that might
91  * replace the packet that was requested to be sent. */
92 #if ipconfigUSE_TCP == 1
93     #define baMINIMAL_BUFFER_SIZE    sizeof( TCPPacket_t )
94 #else
95     #define baMINIMAL_BUFFER_SIZE    sizeof( ARPPacket_t )
96 #endif /* ipconfigUSE_TCP == 1 */
97
98 /*_RB_ This is too complex not to have an explanation. */
99 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
100     #define ASSERT_CONCAT_( a, b )    a ## b
101     #define ASSERT_CONCAT( a, b )     ASSERT_CONCAT_( a, b )
102     #define STATIC_ASSERT( e ) \
103     ; enum { ASSERT_CONCAT( assert_line_, __LINE__ ) = 1 / ( !!( e ) ) }
104
105     STATIC_ASSERT( ipconfigETHERNET_MINIMUM_PACKET_BYTES <= baMINIMAL_BUFFER_SIZE );
106 #endif
107
108 /* A list of free (available) NetworkBufferDescriptor_t structures. */
109 static List_t xFreeBuffersList;
110
111 /* Some statistics about the use of buffers. */
112 static size_t uxMinimumFreeNetworkBuffers;
113
114 /* Declares the pool of NetworkBufferDescriptor_t structures that are available
115  * to the system.  All the network buffers referenced from xFreeBuffersList exist
116  * in this array.  The array is not accessed directly except during initialisation,
117  * when the xFreeBuffersList is filled (as all the buffers are free when the system
118  * is booted). */
119 static NetworkBufferDescriptor_t xNetworkBufferDescriptors[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ];
120
121 /* This constant is defined as false to let FreeRTOS_TCP_IP.c know that the
122  * network buffers have a variable size: resizing may be necessary */
123 const BaseType_t xBufferAllocFixedSize = pdFALSE;
124
125 /* The semaphore used to obtain network buffers. */
126 static SemaphoreHandle_t xNetworkBufferSemaphore = NULL;
127
128 /*-----------------------------------------------------------*/
129
130 #ifdef PIC32_USE_ETHERNET
131
132     /* PIC32 specific stuff */
133     /* */
134
135     /* MAC packet acknowledgment, once MAC is done with it */
136         static bool PIC32_MacPacketAcknowledge( TCPIP_MAC_PACKET * pPkt,
137                                                 const void * param );
138
139     /* allocates a MAC packet that holds a data buffer that can be used by both: */
140     /*  - the FreeRTOSIP (NetworkBufferDescriptor_t->pucEthernetBuffer) */
141     /*  - the Harmony MAC driver: TCPIP_MAC_PACKET->pDSeg->segLoad */
142     /* from the beginning of the buffer: */
143     /*      - 4 bytes pointer to the network descriptor (FreeRTOS) */
144     /*      - 4 bytes pointer to the MAC packet (pic32_NetworkInterface.c) */
145     /*      - 2 bytes offset from the MAC packet (Harmony MAC driver: segLoadOffset) */
146     /* */
147     /* NOTE: segLoadLen should NOT include: */
148     /*          - the TCPIP_MAC_FRAME_OFFSET (== ipBUFFER_PADDING which should be == 10!) */
149     /*          - the sizeof(TCPIP_MAC_ETHERNET_HEADER) */
150     /*       These are added by the MAC packet allocation! */
151     /* */
152     static uint8_t * PIC32_PktAlloc( uint16_t pktLen,
153                                      uint16_t segLoadLen,
154                                      TCPIP_MAC_PACKET_ACK_FUNC ackF,
155                                      TCPIP_MAC_PACKET ** pPtrPkt )
156     {
157         uint8_t * pBuff = 0;
158
159         /* allocate standard packet */
160         TCPIP_MAC_PACKET * pPkt = TCPIP_PKT_PacketAlloc( pktLen, segLoadLen, 0 );
161
162         /* set the MAC packet pointer in the packet */
163         if( pPkt != 0 )
164         {
165             pBuff = pPkt->pDSeg->segLoad;
166             TCPIP_MAC_PACKET ** ppkt = ( TCPIP_MAC_PACKET ** ) ( pBuff - PIC32_BUFFER_PKT_PTR_OSSET );
167             configASSERT( ( ( uint32_t ) ppkt & ( sizeof( uint32_t ) - 1 ) ) == 0 );
168             *ppkt = pPkt; /* store the packet it comes from */
169             pPkt->ackFunc = ackF;
170             pPkt->ackParam = 0;
171         }
172
173         if( pPtrPkt != 0 )
174         {
175             *pPtrPkt = pPkt;
176         }
177
178         return pBuff;
179     }
180
181
182
183     /* standard PIC32 MAC allocation function for a MAC packet */
184     /* this packet saves room for the FreeRTOS network descriptor */
185     /* at the beginning of the data buffer */
186     /* see NetworkBufferAllocate */
187     /* Note: flags parameter is ignored since that's used in the Harmony stack only */
188     TCPIP_MAC_PACKET * PIC32_MacPacketAllocate( uint16_t pktLen,
189                                                 uint16_t segLoadLen,
190                                                 TCPIP_MAC_PACKET_FLAGS flags )
191     {
192         TCPIP_MAC_PACKET * pPkt;
193
194         PIC32_PktAlloc( pktLen, segLoadLen, 0, &pPkt );
195
196         return pPkt;
197     }
198
199     /* standard PIC32 MAC packet acknowledgment */
200     /* function called once MAC is done with it */
201     static bool PIC32_MacPacketAcknowledge( TCPIP_MAC_PACKET * pPkt,
202                                             const void * param )
203     {
204         configASSERT( ( pPkt != 0 ) );
205
206         TCPIP_PKT_PacketFree( pPkt );
207
208         return false;
209     }
210
211     /* associates the current MAC packet with a network descriptor */
212     /* mainly for RX packet */
213     void PIC32_MacAssociate( TCPIP_MAC_PACKET * pRxPkt,
214                              NetworkBufferDescriptor_t * pxBufferDescriptor,
215                              size_t pktLength )
216     {
217         uint8_t * pPktBuff = pRxPkt->pDSeg->segLoad;
218
219         pxBufferDescriptor->pucEthernetBuffer = pPktBuff;
220         pxBufferDescriptor->xDataLength = pktLength;
221
222         /* make sure this is a properly allocated packet */
223         TCPIP_MAC_PACKET ** ppkt = ( TCPIP_MAC_PACKET ** ) ( pPktBuff - PIC32_BUFFER_PKT_PTR_OSSET );
224         configASSERT( ( ( uint32_t ) ppkt & ( sizeof( uint32_t ) - 1 ) ) == 0 );
225
226         if( *ppkt != pRxPkt )
227         {
228             configASSERT( false );
229         }
230
231         /* set the proper descriptor info */
232         NetworkBufferDescriptor_t ** ppDcpt = ( NetworkBufferDescriptor_t ** ) ( pPktBuff - ipBUFFER_PADDING );
233         configASSERT( ( ( uint32_t ) ppDcpt & ( sizeof( uint32_t ) - 1 ) ) == 0 );
234         *ppDcpt = pxBufferDescriptor;
235     }
236
237     /* debug functionality */
238     void PIC32_MacPacketOrphan( TCPIP_MAC_PACKET * pPkt )
239     {
240         TCPIP_PKT_PacketFree( pPkt );
241         configASSERT( false );
242     }
243
244     /* FreeRTOS allocation functions */
245
246     /* allocates a buffer that can be used by both: */
247     /*  - the FreeRTOSIP (NetworkBufferDescriptor_t->pucEthernetBuffer) */
248     /*  - the Harmony MAC driver: TCPIP_MAC_PACKET */
249     /*  See PIC32_PktAlloc for details */
250     /* */
251     /* NOTE: reqLength should NOT include the ipBUFFER_PADDING (which should be == 10!) */
252     /*       or the sizeof(TCPIP_MAC_ETHERNET_HEADER) */
253     /*       These are added by the MAC packet allocation! */
254     /* */
255     uint8_t * NetworkBufferAllocate( size_t reqLength )
256     {
257         return PIC32_PktAlloc( sizeof( TCPIP_MAC_PACKET ), reqLength, PIC32_MacPacketAcknowledge, 0 );
258     }
259
260     /* deallocates a network buffer previously allocated */
261     /* with NetworkBufferAllocate */
262     void NetworkBufferFree( uint8_t * pNetworkBuffer )
263     {
264         if( pNetworkBuffer != 0 )
265         {
266             TCPIP_MAC_PACKET ** ppkt = ( TCPIP_MAC_PACKET ** ) ( pNetworkBuffer - PIC32_BUFFER_PKT_PTR_OSSET );
267             configASSERT( ( ( uint32_t ) ppkt & ( sizeof( uint32_t ) - 1 ) ) == 0 );
268             TCPIP_MAC_PACKET * pPkt = *ppkt;
269             configASSERT( ( pPkt != 0 ) );
270
271             if( pPkt->ackFunc != 0 )
272             {
273                 ( *pPkt->ackFunc )( pPkt, pPkt->ackParam );
274             }
275             else
276             { /* ??? */
277                 PIC32_MacPacketOrphan( pPkt );
278             }
279         }
280     }
281
282 #endif /* #ifdef PIC32_USE_ETHERNET */
283
284 /*-----------------------------------------------------------*/
285
286 BaseType_t xNetworkBuffersInitialise( void )
287 {
288     BaseType_t xReturn, x;
289
290     /* Only initialise the buffers and their associated kernel objects if they
291      * have not been initialised before. */
292     if( xNetworkBufferSemaphore == NULL )
293     {
294         xNetworkBufferSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS );
295         configASSERT( xNetworkBufferSemaphore );
296
297         if( xNetworkBufferSemaphore != NULL )
298         {
299             #if ( configQUEUE_REGISTRY_SIZE > 0 )
300                 {
301                     vQueueAddToRegistry( xNetworkBufferSemaphore, "NetBufSem" );
302                 }
303             #endif /* configQUEUE_REGISTRY_SIZE */
304
305             /* If the trace recorder code is included name the semaphore for viewing
306              * in FreeRTOS+Trace.  */
307             #if ( ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 )
308                 {
309                     extern QueueHandle_t xNetworkEventQueue;
310                     vTraceSetQueueName( xNetworkEventQueue, "IPStackEvent" );
311                     vTraceSetQueueName( xNetworkBufferSemaphore, "NetworkBufferCount" );
312                 }
313             #endif /*  ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 */
314
315             vListInitialise( &xFreeBuffersList );
316
317             /* Initialise all the network buffers.  No storage is allocated to
318              * the buffers yet. */
319             for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )
320             {
321                 /* Initialise and set the owner of the buffer list items. */
322                 xNetworkBufferDescriptors[ x ].pucEthernetBuffer = NULL;
323                 vListInitialiseItem( &( xNetworkBufferDescriptors[ x ].xBufferListItem ) );
324                 listSET_LIST_ITEM_OWNER( &( xNetworkBufferDescriptors[ x ].xBufferListItem ), &xNetworkBufferDescriptors[ x ] );
325
326                 /* Currently, all buffers are available for use. */
327                 vListInsert( &xFreeBuffersList, &( xNetworkBufferDescriptors[ x ].xBufferListItem ) );
328             }
329
330             uxMinimumFreeNetworkBuffers = ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;
331         }
332     }
333
334     if( xNetworkBufferSemaphore == NULL )
335     {
336         xReturn = pdFAIL;
337     }
338     else
339     {
340         xReturn = pdPASS;
341     }
342
343     return xReturn;
344 }
345 /*-----------------------------------------------------------*/
346
347 uint8_t * pucGetNetworkBuffer( size_t * pxRequestedSizeBytes )
348 {
349     uint8_t * pucEthernetBuffer;
350     size_t xSize = *pxRequestedSizeBytes;
351
352     if( xSize < baMINIMAL_BUFFER_SIZE )
353     {
354         /* Buffers must be at least large enough to hold a TCP-packet with
355          * headers, or an ARP packet, in case TCP is not included. */
356         xSize = baMINIMAL_BUFFER_SIZE;
357     }
358
359     /* Round up xSize to the nearest multiple of N bytes,
360      * where N equals 'sizeof( size_t )'. */
361     if( ( xSize & ( sizeof( size_t ) - 1u ) ) != 0u )
362     {
363         xSize = ( xSize | ( sizeof( size_t ) - 1u ) ) + 1u;
364     }
365
366     *pxRequestedSizeBytes = xSize;
367
368     /* Allocate a buffer large enough to store the requested Ethernet frame size
369      * and a pointer to a network buffer structure (hence the addition of
370      * ipBUFFER_PADDING bytes). */
371
372     #ifdef PIC32_USE_ETHERNET
373         pucEthernetBuffer = NetworkBufferAllocate( xSize - sizeof( TCPIP_MAC_ETHERNET_HEADER ) );
374     #else
375         pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xSize + ipBUFFER_PADDING );
376     #endif /* #ifdef PIC32_USE_ETHERNET */
377
378     configASSERT( pucEthernetBuffer );
379
380     if( pucEthernetBuffer != NULL )
381     {
382         /* Enough space is left at the start of the buffer to place a pointer to
383          * the network buffer structure that references this Ethernet buffer.
384          * Return a pointer to the start of the Ethernet buffer itself. */
385                 #ifndef PIC32_USE_ETHERNET
386                 pucEthernetBuffer += ipBUFFER_PADDING;
387                 #endif /* #ifndef PIC32_USE_ETHERNET */
388     }
389
390     return pucEthernetBuffer;
391 }
392 /*-----------------------------------------------------------*/
393
394 void vReleaseNetworkBuffer( uint8_t * pucEthernetBuffer )
395 {
396     /* There is space before the Ethernet buffer in which a pointer to the
397      * network buffer that references this Ethernet buffer is stored.  Remove the
398      * space before freeing the buffer. */
399     #ifdef PIC32_USE_ETHERNET
400         NetworkBufferFree( pucEthernetBuffer );
401     #else
402         if( pucEthernetBuffer != NULL )
403         {
404             pucEthernetBuffer -= ipBUFFER_PADDING;
405             vPortFree( ( void * ) pucEthernetBuffer );
406         }
407     #endif /* #ifdef PIC32_USE_ETHERNET */
408 }
409 /*-----------------------------------------------------------*/
410
411 NetworkBufferDescriptor_t * pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes,
412                                                               TickType_t xBlockTimeTicks )
413 {
414     NetworkBufferDescriptor_t * pxReturn = NULL;
415     size_t uxCount;
416
417     if( ( xRequestedSizeBytes != 0u ) && ( xRequestedSizeBytes < ( size_t ) baMINIMAL_BUFFER_SIZE ) )
418     {
419         /* ARP packets can replace application packets, so the storage must be
420          * at least large enough to hold an ARP. */
421         xRequestedSizeBytes = baMINIMAL_BUFFER_SIZE;
422     }
423
424         #ifdef PIC32_USE_ETHERNET
425         if( xRequestedSizeBytes != 0u )
426     {
427         #endif /* #ifdef PIC32_USE_ETHERNET */
428         xRequestedSizeBytes += 2u;
429
430         if( ( xRequestedSizeBytes & ( sizeof( size_t ) - 1u ) ) != 0u )
431         {
432                 xRequestedSizeBytes = ( xRequestedSizeBytes | ( sizeof( size_t ) - 1u ) ) + 1u;
433         }
434         #ifdef PIC32_USE_ETHERNET
435     }
436         #endif /* #ifdef PIC32_USE_ETHERNET */
437
438     /* If there is a semaphore available, there is a network buffer available. */
439     if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS )
440     {
441         /* Protect the structure as it is accessed from tasks and interrupts. */
442         taskENTER_CRITICAL();
443         {
444             pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
445             uxListRemove( &( pxReturn->xBufferListItem ) );
446         }
447         taskEXIT_CRITICAL();
448
449         /* Reading UBaseType_t, no critical section needed. */
450         uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList );
451
452         if( uxMinimumFreeNetworkBuffers > uxCount )
453         {
454             uxMinimumFreeNetworkBuffers = uxCount;
455         }
456
457         /* Allocate storage of exactly the requested size to the buffer. */
458         configASSERT( pxReturn->pucEthernetBuffer == NULL );
459
460         if( xRequestedSizeBytes > 0 )
461         {
462             /* Extra space is obtained so a pointer to the network buffer can
463              * be stored at the beginning of the buffer. */
464
465             #ifdef PIC32_USE_ETHERNET
466                 pxReturn->pucEthernetBuffer = NetworkBufferAllocate( xRequestedSizeBytes - sizeof( TCPIP_MAC_ETHERNET_HEADER ) );
467             #else
468                 pxReturn->pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xRequestedSizeBytes + ipBUFFER_PADDING );
469             #endif /* #ifdef PIC32_USE_ETHERNET */
470
471             if( pxReturn->pucEthernetBuffer == NULL )
472             {
473                 /* The attempt to allocate storage for the buffer payload failed,
474                  * so the network buffer structure cannot be used and must be
475                  * released. */
476                 vReleaseNetworkBufferAndDescriptor( pxReturn );
477                 pxReturn = NULL;
478             }
479             else
480             {
481                 /* Store a pointer to the network buffer structure in the
482                  * buffer storage area, then move the buffer pointer on past the
483                  * stored pointer so the pointer value is not overwritten by the
484                  * application when the buffer is used. */
485                 #ifdef PIC32_USE_ETHERNET
486                     *( ( NetworkBufferDescriptor_t ** ) ( pxReturn->pucEthernetBuffer - ipBUFFER_PADDING ) ) = pxReturn;
487                 #else
488                     *( ( NetworkBufferDescriptor_t ** ) ( pxReturn->pucEthernetBuffer ) ) = pxReturn;
489                     pxReturn->pucEthernetBuffer += ipBUFFER_PADDING;
490                 #endif /* #ifdef PIC32_USE_ETHERNET */
491
492                 /* Store the actual size of the allocated buffer, which may be
493                  * greater than the original requested size. */
494                 pxReturn->xDataLength = xRequestedSizeBytes;
495
496                 #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
497                     {
498                         /* make sure the buffer is not linked */
499                         pxReturn->pxNextBuffer = NULL;
500                     }
501                 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
502             }
503         }
504         else
505         {
506             /* A descriptor is being returned without an associated buffer being
507              * allocated. */
508         }
509     }
510
511     if( pxReturn == NULL )
512     {
513         iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();
514     }
515     else
516     {
517         iptraceNETWORK_BUFFER_OBTAINED( pxReturn );
518     }
519
520     return pxReturn;
521 }
522 /*-----------------------------------------------------------*/
523
524 void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer )
525 {
526     BaseType_t xListItemAlreadyInFreeList;
527
528     /* Ensure the buffer is returned to the list of free buffers before the
529     * counting semaphore is 'given' to say a buffer is available.  Release the
530     * storage allocated to the buffer payload.  THIS FILE SHOULD NOT BE USED
531     * IF THE PROJECT INCLUDES A MEMORY ALLOCATOR THAT WILL FRAGMENT THE HEAP
532     * MEMORY.  For example, heap_2 must not be used, heap_4 can be used. */
533     vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer );
534     pxNetworkBuffer->pucEthernetBuffer = NULL;
535
536     taskENTER_CRITICAL();
537     {
538         xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
539
540         if( xListItemAlreadyInFreeList == pdFALSE )
541         {
542             vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
543         }
544     }
545     taskEXIT_CRITICAL();
546
547     /*
548      * Update the network state machine, unless the program fails to release its 'xNetworkBufferSemaphore'.
549      * The program should only try to release its semaphore if 'xListItemAlreadyInFreeList' is false.
550      */
551     if( xListItemAlreadyInFreeList == pdFALSE )
552     {
553         if ( xSemaphoreGive( xNetworkBufferSemaphore ) == pdTRUE )
554         {
555             iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
556         }
557     }
558     else
559     {
560         iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
561     }
562 }
563 /*-----------------------------------------------------------*/
564
565 /*
566  * Returns the number of free network buffers
567  */
568 UBaseType_t uxGetNumberOfFreeNetworkBuffers( void )
569 {
570     return listCURRENT_LIST_LENGTH( &xFreeBuffersList );
571 }
572 /*-----------------------------------------------------------*/
573
574 UBaseType_t uxGetMinimumFreeNetworkBuffers( void )
575 {
576     return uxMinimumFreeNetworkBuffers;
577 }
578 /*-----------------------------------------------------------*/
579
580 NetworkBufferDescriptor_t * pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer,
581                                                                  size_t xNewSizeBytes )
582 {
583     size_t xOriginalLength;
584     uint8_t * pucBuffer;
585
586     #ifdef PIC32_USE_ETHERNET
587         xOriginalLength = pxNetworkBuffer->xDataLength;
588     #else
589         xOriginalLength = pxNetworkBuffer->xDataLength + ipBUFFER_PADDING;
590                 xNewSizeBytes = xNewSizeBytes + ipBUFFER_PADDING;
591     #endif /* #ifdef PIC32_USE_ETHERNET */
592         
593     pucBuffer = pucGetNetworkBuffer( &( xNewSizeBytes ) );
594
595     if( pucBuffer == NULL )
596     {
597         /* In case the allocation fails, return NULL. */
598         pxNetworkBuffer = NULL;
599     }
600     else
601     {
602         pxNetworkBuffer->xDataLength = xNewSizeBytes;
603         if( xNewSizeBytes > xOriginalLength )
604         {
605             xNewSizeBytes = xOriginalLength;
606         }
607
608         #ifdef PIC32_USE_ETHERNET
609             memcpy( pucBuffer, pxNetworkBuffer->pucEthernetBuffer, xNewSizeBytes );
610             *( ( NetworkBufferDescriptor_t ** ) ( pucBuffer - ipBUFFER_PADDING ) ) = pxNetworkBuffer;
611         #else
612             memcpy( pucBuffer - ipBUFFER_PADDING, pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING, xNewSizeBytes );
613         #endif /* #ifdef PIC32_USE_ETHERNET */
614
615         vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer );
616         pxNetworkBuffer->pucEthernetBuffer = pucBuffer;
617     }
618
619     return pxNetworkBuffer;
620 }