| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515 |
- /*
- * FreeRTOS+TCP V2.3.2 LTS Patch 1
- * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * http://aws.amazon.com/freertos
- * http://www.FreeRTOS.org
- */
- /**
- * @file FreeRTOS_TCP_WIN.c
- * @brief Module which handles the TCP windowing schemes for FreeRTOS+TCP. Many
- * functions have two versions - one for FreeRTOS+TCP (full) and one for
- * FreeRTOS+TCP (lite).
- *
- * In this module all ports and IP addresses and sequence numbers are
- * being stored in host byte-order.
- */
- /* Standard includes. */
- #include <stdint.h>
- /* FreeRTOS includes. */
- #include "FreeRTOS.h"
- #include "task.h"
- /* FreeRTOS+TCP includes. */
- #include "FreeRTOS_UDP_IP.h"
- #include "FreeRTOS_IP.h"
- #include "FreeRTOS_Sockets.h"
- #include "FreeRTOS_IP_Private.h"
- #ifndef FREERTOS_DEFAULT_IP_CONFIG_H
- #error "FreeRTOSIPConfigDefaults.h not included."
- #endif
- #if ( ipconfigUSE_TCP == 1 )
- /* Constants used for Smoothed Round Trip Time (SRTT). */
- #define winSRTT_INCREMENT_NEW 2 /**< New increment for the smoothed RTT. */
- #define winSRTT_INCREMENT_CURRENT 6 /**< Current increment for the smoothed RTT. */
- #define winSRTT_DECREMENT_NEW 1 /**< New decrement for the smoothed RTT. */
- #define winSRTT_DECREMENT_CURRENT 7 /**< Current decrement for the smoothed RTT. */
- #define winSRTT_CAP_mS 50 /**< Cap in milliseconds. */
- /**
- * @brief Utility function to cast pointer of a type to pointer of type TCPSegment_t.
- *
- * @return The casted pointer.
- */
- static portINLINE ipDECL_CAST_PTR_FUNC_FOR_TYPE( TCPSegment_t )
- {
- return ( TCPSegment_t * ) pvArgument;
- }
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /** @brief Create a new Rx window. */
- #define xTCPWindowRxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdTRUE )
- /** @brief Create a new Tx window. */
- #define xTCPWindowTxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdFALSE )
- /** @brief The code to send a single Selective ACK (SACK):
- * NOP (0x01), NOP (0x01), SACK (0x05), LEN (0x0a),
- * followed by a lower and a higher sequence number,
- * where LEN is 2 + 2*4 = 10 bytes. */
- #if ( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN )
- #define OPTION_CODE_SINGLE_SACK ( 0x0101050aUL )
- #else
- #define OPTION_CODE_SINGLE_SACK ( 0x0a050101UL )
- #endif
- /** @brief Normal retransmission:
- * A packet will be retransmitted after a Retransmit Time-Out (RTO).
- * Fast retransmission:
- * When 3 packets with a higher sequence number have been acknowledged
- * by the peer, it is very unlikely a current packet will ever arrive.
- * It will be retransmitted far before the RTO.
- */
- #define DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ( 3U )
- /** @brief If there have been several retransmissions (4), decrease the
- * size of the transmission window to at most 2 times MSS.
- */
- #define MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW ( 4U )
- #endif /* configUSE_TCP_WIN */
- /*-----------------------------------------------------------*/
- void vListInsertGeneric( List_t * const pxList,
- ListItem_t * const pxNewListItem,
- MiniListItem_t * const pxWhere );
- /*
- * All TCP sockets share a pool of segment descriptors (TCPSegment_t)
- * Available descriptors are stored in the 'xSegmentList'
- * When a socket owns a descriptor, it will either be stored in
- * 'xTxSegments' or 'xRxSegments'
- * As soon as a package has been confirmed, the descriptor will be returned
- * to the segment pool
- */
- #if ( ipconfigUSE_TCP_WIN == 1 )
- static BaseType_t prvCreateSectors( void );
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*
- * Find a segment with a given sequence number in the list of received
- * segments: 'pxWindow->xRxSegments'.
- */
- #if ( ipconfigUSE_TCP_WIN == 1 )
- static TCPSegment_t * xTCPWindowRxFind( const TCPWindow_t * pxWindow,
- uint32_t ulSequenceNumber );
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*
- * Allocate a new segment
- * The socket will borrow all segments from a common pool: 'xSegmentList',
- * which is a list of 'TCPSegment_t'
- */
- #if ( ipconfigUSE_TCP_WIN == 1 )
- static TCPSegment_t * xTCPWindowNew( TCPWindow_t * pxWindow,
- uint32_t ulSequenceNumber,
- int32_t lCount,
- BaseType_t xIsForRx );
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*
- * Detaches and returns the head of a queue
- */
- #if ( ipconfigUSE_TCP_WIN == 1 )
- static TCPSegment_t * xTCPWindowGetHead( const List_t * pxList );
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*
- * Returns the head of a queue but it won't be detached
- */
- #if ( ipconfigUSE_TCP_WIN == 1 )
- static TCPSegment_t * xTCPWindowPeekHead( const List_t * pxList );
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*
- * Free entry pxSegment because it's not used anymore
- * The ownership will be passed back to the segment pool
- */
- #if ( ipconfigUSE_TCP_WIN == 1 )
- static void vTCPWindowFree( TCPSegment_t * pxSegment );
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*
- * A segment has been received with sequence number 'ulSequenceNumber', where
- * 'ulCurrentSequenceNumber == ulSequenceNumber', which means that exactly this
- * segment was expected. xTCPWindowRxConfirm() will check if there is already
- * another segment with a sequence number between (ulSequenceNumber) and
- * (ulSequenceNumber+xLength). Normally none will be found, because the next Rx
- * segment should have a sequence number equal to '(ulSequenceNumber+xLength)'.
- */
- #if ( ipconfigUSE_TCP_WIN == 1 )
- static TCPSegment_t * xTCPWindowRxConfirm( const TCPWindow_t * pxWindow,
- uint32_t ulSequenceNumber,
- uint32_t ulLength );
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*
- * FreeRTOS+TCP stores data in circular buffers. Calculate the next position to
- * store.
- */
- #if ( ipconfigUSE_TCP_WIN == 1 )
- static int32_t lTCPIncrementTxPosition( int32_t lPosition,
- int32_t lMax,
- int32_t lCount );
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*
- * This function will look if there is new transmission data. It will return
- * true if there is data to be sent.
- */
- #if ( ipconfigUSE_TCP_WIN == 1 )
- static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t const * pxWindow,
- uint32_t ulWindowSize );
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*
- * An acknowledge was received. See if some outstanding data may be removed
- * from the transmission queue(s).
- */
- #if ( ipconfigUSE_TCP_WIN == 1 )
- static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t * pxWindow,
- uint32_t ulFirst,
- uint32_t ulLast );
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*
- * A higher Tx block has been acknowledged. Now iterate through the xWaitQueue
- * to find a possible condition for a FAST retransmission.
- */
- #if ( ipconfigUSE_TCP_WIN == 1 )
- static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t * pxWindow,
- uint32_t ulFirst );
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- /**< TCP segment pool. */
- #if ( ipconfigUSE_TCP_WIN == 1 )
- static TCPSegment_t * xTCPSegments = NULL;
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /**< List of free TCP segments. */
- #if ( ipconfigUSE_TCP_WIN == 1 )
- _static List_t xSegmentList;
- #endif
- /** @brief Logging verbosity level. */
- BaseType_t xTCPWindowLoggingLevel = 0;
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /* Some 32-bit arithmetic: comparing sequence numbers */
- static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a,
- uint32_t b );
- /**
- * @brief Check if a <= b.
- *
- * @param[in] a: The value on the left-hand side.
- * @param[in] b: The value on the right-hand side.
- *
- * @return pdTRUE when "( b - a ) < 0x80000000". Else, pdFALSE.
- */
- static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a,
- uint32_t b )
- {
- BaseType_t xResult;
- /* Test if a <= b
- * Return true if the unsigned subtraction of (b-a) doesn't generate an
- * arithmetic overflow. */
- if( ( ( b - a ) & 0x80000000UL ) == 0UL )
- {
- xResult = pdTRUE;
- }
- else
- {
- xResult = pdFALSE;
- }
- return xResult;
- }
- #endif /* ipconfigUSE_TCP_WIN */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- static portINLINE BaseType_t xSequenceLessThan( uint32_t a,
- uint32_t b );
- /**
- * @brief Check if a < b.
- *
- * @param[in] a: The value on the left-hand side.
- * @param[in] b: The value on the right-hand side.
- *
- * @return pdTRUE when "( b - ( a + 1 ) ) < 0x80000000", else pdFALSE.
- */
- static portINLINE BaseType_t xSequenceLessThan( uint32_t a,
- uint32_t b )
- {
- BaseType_t xResult;
- /* Test if a < b */
- if( ( ( b - ( a + 1UL ) ) & 0x80000000UL ) == 0UL )
- {
- xResult = pdTRUE;
- }
- else
- {
- xResult = pdFALSE;
- }
- return xResult;
- }
- #endif /* ipconfigUSE_TCP_WIN */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a,
- uint32_t b );
- /**
- * @brief Check if a > b.
- *
- * @param[in] a: The value on the left-hand side.
- * @param[in] b: The value on the right-hand side.
- *
- * @return pdTRUE when "( a - b ) < 0x80000000", else pdFALSE.
- */
- static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a,
- uint32_t b )
- {
- BaseType_t xResult;
- /* Test if a > b */
- if( ( ( a - ( b + 1UL ) ) & 0x80000000UL ) == 0UL )
- {
- xResult = pdTRUE;
- }
- else
- {
- xResult = pdFALSE;
- }
- return xResult;
- }
- #endif /* ipconfigUSE_TCP_WIN */
- /*-----------------------------------------------------------*/
- static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a,
- uint32_t b );
- /**
- * @brief Test if a>=b. This function is required since the sequence numbers can roll over.
- *
- * @param[in] a: The first sequence number.
- * @param[in] b: The second sequence number.
- *
- * @return pdTRUE if a>=b, else pdFALSE.
- */
- static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a,
- uint32_t b )
- {
- BaseType_t xResult;
- /* Test if a >= b */
- if( ( ( a - b ) & 0x80000000UL ) == 0UL )
- {
- xResult = pdTRUE;
- }
- else
- {
- xResult = pdFALSE;
- }
- return xResult;
- }
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- static portINLINE void vListInsertFifo( List_t * const pxList,
- ListItem_t * const pxNewListItem );
- /**
- * @brief Insert the given item in the list in FIFO manner.
- *
- * @param[in] pxList: The list in which the item is to inserted.
- * @param[in] pxNewListItem: The item to be inserted.
- */
- static portINLINE void vListInsertFifo( List_t * const pxList,
- ListItem_t * const pxNewListItem )
- {
- vListInsertGeneric( pxList, pxNewListItem, &pxList->xListEnd );
- }
- #endif
- /*-----------------------------------------------------------*/
- static portINLINE void vTCPTimerSet( TCPTimer_t * pxTimer );
- /**
- * @brief Set the timer's "born" time.
- *
- * @param[in] pxTimer: The TCP timer.
- */
- static portINLINE void vTCPTimerSet( TCPTimer_t * pxTimer )
- {
- pxTimer->ulBorn = xTaskGetTickCount();
- }
- /*-----------------------------------------------------------*/
- static portINLINE uint32_t ulTimerGetAge( const TCPTimer_t * pxTimer );
- /**
- * @brief Get the timer age in milliseconds.
- *
- * @param[in] pxTimer: The timer whose age is to be fetched.
- *
- * @return The time in milliseconds since the timer was born.
- */
- static portINLINE uint32_t ulTimerGetAge( const TCPTimer_t * pxTimer )
- {
- return( ( xTaskGetTickCount() - ( ( TickType_t ) pxTimer->ulBorn ) ) * portTICK_PERIOD_MS );
- }
- /*-----------------------------------------------------------*/
- /**
- * @brief Insert a new list item into a list.
- *
- * @param[in] pxList: The list in which the item is to be inserted.
- * @param[in] pxNewListItem: The item to be inserted.
- * @param[in] pxWhere: Where should the item be inserted.
- */
- void vListInsertGeneric( List_t * const pxList,
- ListItem_t * const pxNewListItem,
- MiniListItem_t * const pxWhere )
- {
- /* Insert a new list item into pxList, it does not sort the list,
- * but it puts the item just before xListEnd, so it will be the last item
- * returned by listGET_HEAD_ENTRY() */
- pxNewListItem->pxNext = ( struct xLIST_ITEM * configLIST_VOLATILE ) pxWhere;
- pxNewListItem->pxPrevious = pxWhere->pxPrevious;
- pxWhere->pxPrevious->pxNext = pxNewListItem;
- pxWhere->pxPrevious = pxNewListItem;
- /* Remember which list the item is in. */
- listLIST_ITEM_CONTAINER( pxNewListItem ) = ( struct xLIST * configLIST_VOLATILE ) pxList;
- ( pxList->uxNumberOfItems )++;
- }
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Creates a pool of 'ipconfigTCP_WIN_SEG_COUNT' sector buffers. Should be called once only.
- *
- * @return When the allocation was successful: pdPASS, otherwise pdFAIL.
- */
- static BaseType_t prvCreateSectors( void )
- {
- BaseType_t xIndex, xReturn;
- /* Allocate space for 'xTCPSegments' and store them in 'xSegmentList'. */
- vListInitialise( &xSegmentList );
- xTCPSegments = ipCAST_PTR_TO_TYPE_PTR( TCPSegment_t, pvPortMallocLarge( ( size_t ) ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ) );
- if( xTCPSegments == NULL )
- {
- FreeRTOS_debug_printf( ( "prvCreateSectors: malloc %u failed\n",
- ( unsigned ) ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ) );
- xReturn = pdFAIL;
- }
- else
- {
- /* Clear the allocated space. */
- ( void ) memset( xTCPSegments, 0, ( size_t ) ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );
- for( xIndex = 0; xIndex < ipconfigTCP_WIN_SEG_COUNT; xIndex++ )
- {
- /* Could call vListInitialiseItem here but all data has been
- * nulled already. Set the owner to a segment descriptor. */
- listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xSegmentItem ), ( void * ) &( xTCPSegments[ xIndex ] ) );
- listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xQueueItem ), ( void * ) &( xTCPSegments[ xIndex ] ) );
- /* And add it to the pool of available segments */
- vListInsertFifo( &xSegmentList, &( xTCPSegments[ xIndex ].xSegmentItem ) );
- }
- xReturn = pdPASS;
- }
- return xReturn;
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Find a segment with a given sequence number in the list of received segments.
- *
- * @param[in] pxWindow: The descriptor of the TCP sliding windows.
- * @param[in] ulSequenceNumber: the sequence number to look-up
- *
- * @return The address of the segment descriptor found, or NULL when not found.
- */
- static TCPSegment_t * xTCPWindowRxFind( const TCPWindow_t * pxWindow,
- uint32_t ulSequenceNumber )
- {
- const ListItem_t * pxIterator;
- const ListItem_t * pxEnd;
- TCPSegment_t * pxSegment, * pxReturn = NULL;
- /* Find a segment with a given sequence number in the list of received
- * segments. */
- pxEnd = listGET_END_MARKER( &pxWindow->xRxSegments );
- for( pxIterator = listGET_NEXT( pxEnd );
- pxIterator != pxEnd;
- pxIterator = listGET_NEXT( pxIterator ) )
- {
- pxSegment = ipCAST_PTR_TO_TYPE_PTR( TCPSegment_t, listGET_LIST_ITEM_OWNER( pxIterator ) );
- if( pxSegment->ulSequenceNumber == ulSequenceNumber )
- {
- pxReturn = pxSegment;
- break;
- }
- }
- return pxReturn;
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Allocate a new segment object, either for transmission or reception.
- *
- * @param[in] pxWindow: The descriptor of the TCP sliding windows.
- * @param[in] ulSequenceNumber: The sequence number.
- * @param[in] lCount: The number of bytes stored in this segment.
- * @param[in] xIsForRx: True when this is a reception segment.
- *
- * @return Allocate and initialise a segment descriptor, or NULL when none was available.
- */
- static TCPSegment_t * xTCPWindowNew( TCPWindow_t * pxWindow,
- uint32_t ulSequenceNumber,
- int32_t lCount,
- BaseType_t xIsForRx )
- {
- TCPSegment_t * pxSegment;
- ListItem_t * pxItem;
- /* Allocate a new segment. The socket will borrow all segments from a
- * common pool: 'xSegmentList', which is a list of 'TCPSegment_t' */
- if( listLIST_IS_EMPTY( &xSegmentList ) != pdFALSE )
- {
- /* If the TCP-stack runs out of segments, you might consider
- * increasing 'ipconfigTCP_WIN_SEG_COUNT'. */
- FreeRTOS_debug_printf( ( "xTCPWindow%cxNew: Error: all segments occupied\n", ( xIsForRx != 0 ) ? 'R' : 'T' ) );
- pxSegment = NULL;
- }
- else
- {
- /* Pop the item at the head of the list. Semaphore protection is
- * not required as only the IP task will call these functions. */
- pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( &xSegmentList );
- pxSegment = ipCAST_PTR_TO_TYPE_PTR( TCPSegment_t, listGET_LIST_ITEM_OWNER( pxItem ) );
- configASSERT( pxItem != NULL );
- configASSERT( pxSegment != NULL );
- /* Remove the item from xSegmentList. */
- ( void ) uxListRemove( pxItem );
- /* Add it to either the connections' Rx or Tx queue. */
- if( xIsForRx != 0 )
- {
- vListInsertFifo( &pxWindow->xRxSegments, pxItem );
- }
- else
- {
- vListInsertFifo( &pxWindow->xTxSegments, pxItem );
- }
- /* And set the segment's timer to zero */
- vTCPTimerSet( &pxSegment->xTransmitTimer );
- pxSegment->u.ulFlags = 0;
- pxSegment->u.bits.bIsForRx = ( xIsForRx != 0 ) ? 1U : 0U;
- pxSegment->lMaxLength = lCount;
- pxSegment->lDataLength = lCount;
- pxSegment->ulSequenceNumber = ulSequenceNumber;
- #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
- {
- static UBaseType_t xLowestLength = ipconfigTCP_WIN_SEG_COUNT;
- UBaseType_t xLength = listCURRENT_LIST_LENGTH( &xSegmentList );
- if( xLowestLength > xLength )
- {
- xLowestLength = xLength;
- }
- }
- #endif /* ipconfigHAS_DEBUG_PRINTF */
- }
- return pxSegment;
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief See if the peer has more packets for this node, before allowing to shut down the connection.
- *
- * @param[in] pxWindow: The descriptor of the TCP sliding windows.
- *
- * @return pdTRUE if the connection can be closed. Else, pdFALSE.
- */
- BaseType_t xTCPWindowRxEmpty( const TCPWindow_t * pxWindow )
- {
- BaseType_t xReturn;
- /* When the peer has a close request (FIN flag), the driver will check
- * if there are missing packets in the Rx-queue. It will accept the
- * closure of the connection if both conditions are true:
- * - the Rx-queue is empty
- * - the highest Rx sequence number has been ACK'ed */
- if( listLIST_IS_EMPTY( ( &pxWindow->xRxSegments ) ) == pdFALSE )
- {
- /* Rx data has been stored while earlier packets were missing. */
- xReturn = pdFALSE;
- }
- else if( xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber ) != pdFALSE )
- {
- /* No Rx packets are being stored and the highest sequence number
- * that has been received has been ACKed. */
- xReturn = pdTRUE;
- }
- else
- {
- FreeRTOS_debug_printf( ( "xTCPWindowRxEmpty: cur %lu highest %lu (empty)\n",
- ( pxWindow->rx.ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
- ( pxWindow->rx.ulHighestSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ) ) );
- xReturn = pdFALSE;
- }
- return xReturn;
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Remove the head item of a list (generic function).
- *
- * @param[in] pxList: The list of segment descriptors.
- *
- * @return The address of the segment descriptor, or NULL when not found.
- */
- static TCPSegment_t * xTCPWindowGetHead( const List_t * pxList )
- {
- TCPSegment_t * pxSegment;
- ListItem_t * pxItem;
- /* Detaches and returns the head of a queue. */
- if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
- {
- pxSegment = NULL;
- }
- else
- {
- pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
- pxSegment = ipCAST_PTR_TO_TYPE_PTR( TCPSegment_t, listGET_LIST_ITEM_OWNER( pxItem ) );
- ( void ) uxListRemove( pxItem );
- }
- return pxSegment;
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Return the head item of a list (generic function).
- *
- * @param[in] pxList: The list of segment descriptors.
- *
- * @return The address of the segment descriptor, or NULL when the list is empty.
- */
- static TCPSegment_t * xTCPWindowPeekHead( const List_t * pxList )
- {
- const ListItem_t * pxItem;
- TCPSegment_t * pxReturn;
- /* Returns the head of a queue but it won't be detached. */
- if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
- {
- pxReturn = NULL;
- }
- else
- {
- pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
- pxReturn = ipCAST_PTR_TO_TYPE_PTR( TCPSegment_t, listGET_LIST_ITEM_OWNER( pxItem ) );
- }
- return pxReturn;
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Release a segment object, return it to the list of available segment holders.
- *
- * @param[in] pxSegment: The segment descriptor that must be freed.
- */
- static void vTCPWindowFree( TCPSegment_t * pxSegment )
- {
- /* Free entry pxSegment because it's not used any more. The ownership
- * will be passed back to the segment pool.
- *
- * Unlink it from one of the queues, if any. */
- if( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL )
- {
- ( void ) uxListRemove( &( pxSegment->xQueueItem ) );
- }
- pxSegment->ulSequenceNumber = 0UL;
- pxSegment->lDataLength = 0L;
- pxSegment->u.ulFlags = 0UL;
- /* Take it out of xRxSegments/xTxSegments */
- if( listLIST_ITEM_CONTAINER( &( pxSegment->xSegmentItem ) ) != NULL )
- {
- ( void ) uxListRemove( &( pxSegment->xSegmentItem ) );
- }
- /* Return it to xSegmentList */
- vListInsertFifo( &xSegmentList, &( pxSegment->xSegmentItem ) );
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Return all segment descriptor to the poll of descriptors, before deleting a socket.
- *
- * @param[in] pxWindow: The descriptor of the TCP sliding windows.
- */
- void vTCPWindowDestroy( TCPWindow_t const * pxWindow )
- {
- const List_t * pxSegments;
- BaseType_t xRound;
- TCPSegment_t * pxSegment;
- /* Destroy a window. A TCP window doesn't serve any more. Return all
- * owned segments to the pool. In order to save code, it will make 2 rounds,
- * one to remove the segments from xRxSegments, and a second round to clear
- * xTxSegments*/
- for( xRound = 0; xRound < 2; xRound++ )
- {
- if( xRound != 0 )
- {
- pxSegments = &( pxWindow->xRxSegments );
- }
- else
- {
- pxSegments = &( pxWindow->xTxSegments );
- }
- if( listLIST_IS_INITIALISED( pxSegments ) )
- {
- while( listCURRENT_LIST_LENGTH( pxSegments ) > 0U )
- {
- pxSegment = ipCAST_PTR_TO_TYPE_PTR( TCPSegment_t, listGET_OWNER_OF_HEAD_ENTRY( pxSegments ) );
- vTCPWindowFree( pxSegment );
- }
- }
- }
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- /**
- * @brief Create a window for TCP.
- *
- * @param[in] pxWindow: The window to be created.
- * @param[in] ulRxWindowLength: The length of the receive window.
- * @param[in] ulTxWindowLength: The length of the transmit window.
- * @param[in] ulAckNumber: The first ACK number.
- * @param[in] ulSequenceNumber: The first sequence number.
- * @param[in] ulMSS: The MSS of the connection.
- */
- void vTCPWindowCreate( TCPWindow_t * pxWindow,
- uint32_t ulRxWindowLength,
- uint32_t ulTxWindowLength,
- uint32_t ulAckNumber,
- uint32_t ulSequenceNumber,
- uint32_t ulMSS )
- {
- /* Create and initialize a window. */
- #if ( ipconfigUSE_TCP_WIN == 1 )
- {
- if( xTCPSegments == NULL )
- {
- ( void ) prvCreateSectors();
- }
- vListInitialise( &( pxWindow->xTxSegments ) );
- vListInitialise( &( pxWindow->xRxSegments ) );
- vListInitialise( &( pxWindow->xPriorityQueue ) ); /* Priority queue: segments which must be sent immediately */
- vListInitialise( &( pxWindow->xTxQueue ) ); /* Transmit queue: segments queued for transmission */
- vListInitialise( &( pxWindow->xWaitQueue ) ); /* Waiting queue: outstanding segments */
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- if( xTCPWindowLoggingLevel != 0 )
- {
- FreeRTOS_debug_printf( ( "vTCPWindowCreate: for WinLen = Rx/Tx: %lu/%lu\n",
- ulRxWindowLength, ulTxWindowLength ) );
- }
- pxWindow->xSize.ulRxWindowLength = ulRxWindowLength;
- pxWindow->xSize.ulTxWindowLength = ulTxWindowLength;
- vTCPWindowInit( pxWindow, ulAckNumber, ulSequenceNumber, ulMSS );
- }
- /*-----------------------------------------------------------*/
- /**
- * @brief Initialise a TCP window.
- *
- * @param[in] pxWindow: The window to be initialised.
- * @param[in] ulAckNumber: The number of the first ACK.
- * @param[in] ulSequenceNumber: The first sequence number.
- * @param[in] ulMSS: The MSS of the connection.
- */
- void vTCPWindowInit( TCPWindow_t * pxWindow,
- uint32_t ulAckNumber,
- uint32_t ulSequenceNumber,
- uint32_t ulMSS )
- {
- const int32_t l500ms = 500;
- pxWindow->u.ulFlags = 0UL;
- pxWindow->u.bits.bHasInit = pdTRUE_UNSIGNED;
- if( ulMSS != 0UL )
- {
- if( pxWindow->usMSSInit != 0U )
- {
- pxWindow->usMSSInit = ( uint16_t ) ulMSS;
- }
- if( ( ulMSS < ( uint32_t ) pxWindow->usMSS ) || ( pxWindow->usMSS == 0U ) )
- {
- pxWindow->xSize.ulRxWindowLength = ( pxWindow->xSize.ulRxWindowLength / ulMSS ) * ulMSS;
- pxWindow->usMSS = ( uint16_t ) ulMSS;
- }
- }
- #if ( ipconfigUSE_TCP_WIN == 0 )
- {
- pxWindow->xTxSegment.lMaxLength = ( int32_t ) pxWindow->usMSS;
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*Start with a timeout of 2 * 500 ms (1 sec). */
- pxWindow->lSRTT = l500ms;
- /* Just for logging, to print relative sequence numbers. */
- pxWindow->rx.ulFirstSequenceNumber = ulAckNumber;
- /* The segment asked for in the next transmission. */
- pxWindow->rx.ulCurrentSequenceNumber = ulAckNumber;
- /* The right-hand side of the receive window. */
- pxWindow->rx.ulHighestSequenceNumber = ulAckNumber;
- pxWindow->tx.ulFirstSequenceNumber = ulSequenceNumber;
- /* The segment asked for in next transmission. */
- pxWindow->tx.ulCurrentSequenceNumber = ulSequenceNumber;
- /* The sequence number given to the next outgoing byte to be added is
- * maintained by lTCPWindowTxAdd(). */
- pxWindow->ulNextTxSequenceNumber = ulSequenceNumber;
- /* The right-hand side of the transmit window. */
- pxWindow->tx.ulHighestSequenceNumber = ulSequenceNumber;
- pxWindow->ulOurSequenceNumber = ulSequenceNumber;
- }
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Free the space occupied by the pool of segment descriptors, normally never used
- */
- void vTCPSegmentCleanup( void )
- {
- /* Free and clear the TCP segments pointer. This function should only be called
- * once FreeRTOS+TCP will no longer be used. No thread-safety is provided for this
- * function. */
- if( xTCPSegments != NULL )
- {
- vPortFreeLarge( xTCPSegments );
- xTCPSegments = NULL;
- }
- }
- #endif /* ipconfgiUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- /*=============================================================================
- *
- * ###### # #
- * # # # #
- * # # # #
- * # # ####
- * ###### ##
- * # ## ####
- * # # # #
- * # # # #
- * ### ## # #
- * Rx functions
- *
- *=============================================================================*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief A expected segment has been received, see if there is overlap with earlier segments.
- *
- * @param[in] pxWindow: The descriptor of the TCP sliding windows.
- * @param[in] ulSequenceNumber: The sequence number of the segment that was received.
- * @param[in] ulLength: The number of bytes that were received.
- *
- * @return The first segment descriptor involved, or NULL when no matching descriptor was found.
- */
- static TCPSegment_t * xTCPWindowRxConfirm( const TCPWindow_t * pxWindow,
- uint32_t ulSequenceNumber,
- uint32_t ulLength )
- {
- TCPSegment_t * pxBest = NULL;
- const ListItem_t * pxIterator;
- uint32_t ulNextSequenceNumber = ulSequenceNumber + ulLength;
- const ListItem_t * pxEnd = listGET_END_MARKER( &pxWindow->xRxSegments );
- TCPSegment_t * pxSegment;
- /* A segment has been received with sequence number 'ulSequenceNumber',
- * where 'ulCurrentSequenceNumber == ulSequenceNumber', which means that
- * exactly this segment was expected. xTCPWindowRxConfirm() will check if
- * there is already another segment with a sequence number between (ulSequenceNumber)
- * and (ulSequenceNumber+ulLength). Normally none will be found, because
- * the next RX segment should have a sequence number equal to
- * '(ulSequenceNumber+ulLength)'. */
- /* Iterate through all RX segments that are stored: */
- for( pxIterator = listGET_NEXT( pxEnd );
- pxIterator != pxEnd;
- pxIterator = listGET_NEXT( pxIterator ) )
- {
- pxSegment = ipCAST_PTR_TO_TYPE_PTR( TCPSegment_t, listGET_LIST_ITEM_OWNER( pxIterator ) );
- /* And see if there is a segment for which:
- * 'ulSequenceNumber' <= 'pxSegment->ulSequenceNumber' < 'ulNextSequenceNumber'
- * If there are more matching segments, the one with the lowest sequence number
- * shall be taken */
- if( ( xSequenceGreaterThanOrEqual( pxSegment->ulSequenceNumber, ulSequenceNumber ) != 0 ) &&
- ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulNextSequenceNumber ) != 0 ) )
- {
- if( ( pxBest == NULL ) || ( xSequenceLessThan( pxSegment->ulSequenceNumber, pxBest->ulSequenceNumber ) != 0 ) )
- {
- pxBest = pxSegment;
- }
- }
- }
- if( ( pxBest != NULL ) &&
- ( ( pxBest->ulSequenceNumber != ulSequenceNumber ) || ( pxBest->lDataLength != ( int32_t ) ulLength ) ) )
- {
- FreeRTOS_debug_printf( ( "xTCPWindowRxConfirm[%u]: search %lu (+%ld=%lu) found %lu (+%ld=%lu)\n",
- pxWindow->usPeerPortNumber,
- ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
- ulLength,
- ulSequenceNumber + ulLength - pxWindow->rx.ulFirstSequenceNumber,
- pxBest->ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
- pxBest->lDataLength,
- pxBest->ulSequenceNumber + ( ( uint32_t ) pxBest->lDataLength ) - pxWindow->rx.ulFirstSequenceNumber ) );
- }
- return pxBest;
- }
- #endif /* ipconfgiUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Check what to do with a new incoming packet: store or ignore.
- *
- * @param[in] pxWindow: The descriptor of the TCP sliding windows.
- * @param[in] ulSequenceNumber: The sequence number of the packet received.
- * @param[in] ulLength: The number of bytes received.
- * @param[in] ulSpace: The available space in the RX stream buffer.
- *
- * @return 0 or positive value indicating the offset at which the packet is to
- * be stored, -1 if the packet is to be ignored.
- */
- int32_t lTCPWindowRxCheck( TCPWindow_t * pxWindow,
- uint32_t ulSequenceNumber,
- uint32_t ulLength,
- uint32_t ulSpace )
- {
- uint32_t ulCurrentSequenceNumber, ulLast, ulSavedSequenceNumber, ulIntermediateResult = 0;
- int32_t lReturn, lDistance;
- TCPSegment_t * pxFound;
- /* If lTCPWindowRxCheck( ) returns == 0, the packet will be passed
- * directly to user (segment is expected). If it returns a positive
- * number, an earlier packet is missing, but this packet may be stored.
- * If negative, the packet has already been stored, or it is out-of-order,
- * or there is not enough space.
- *
- * As a side-effect, pxWindow->ulUserDataLength will get set to non-zero,
- * if more Rx data may be passed to the user after this packet. */
- ulCurrentSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber;
- /* For Selective Ack (SACK), used when out-of-sequence data come in. */
- pxWindow->ucOptionLength = 0U;
- /* Non-zero if TCP-windows contains data which must be popped. */
- pxWindow->ulUserDataLength = 0UL;
- if( ulCurrentSequenceNumber == ulSequenceNumber )
- {
- /* This is the packet with the lowest sequence number we're waiting
- * for. It can be passed directly to the rx stream. */
- if( ulLength > ulSpace )
- {
- FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu bytes, due to lack of space (%lu)\n", ulLength, ulSpace ) );
- lReturn = -1;
- }
- else
- {
- ulCurrentSequenceNumber += ulLength;
- if( listCURRENT_LIST_LENGTH( &( pxWindow->xRxSegments ) ) != 0U )
- {
- ulSavedSequenceNumber = ulCurrentSequenceNumber;
- /* Clean up all sequence received between ulSequenceNumber and ulSequenceNumber + ulLength since they are duplicated.
- * If the server is forced to retransmit packets several time in a row it might send a batch of concatenated packet for speed.
- * So we cannot rely on the packets between ulSequenceNumber and ulSequenceNumber + ulLength to be sequential and it is better to just
- * clean them out. */
- do
- {
- pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength );
- if( pxFound != NULL )
- {
- /* Remove it because it will be passed to user directly. */
- vTCPWindowFree( pxFound );
- }
- } while( pxFound != NULL );
- /* Check for following segments that are already in the
- * queue and increment ulCurrentSequenceNumber. */
- for( ; ; )
- {
- pxFound = xTCPWindowRxFind( pxWindow, ulCurrentSequenceNumber );
- if( pxFound == NULL )
- {
- break;
- }
- ulCurrentSequenceNumber += ( uint32_t ) pxFound->lDataLength;
- /* As all packet below this one have been passed to the
- * user it can be discarded. */
- vTCPWindowFree( pxFound );
- }
- if( ulSavedSequenceNumber != ulCurrentSequenceNumber )
- {
- /* After the current data-package, there is more data
- * to be popped. */
- pxWindow->ulUserDataLength = ulCurrentSequenceNumber - ulSavedSequenceNumber;
- if( xTCPWindowLoggingLevel >= 1 )
- {
- FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: retran %lu (Found %lu bytes at %lu cnt %ld)\n",
- pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
- ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
- pxWindow->ulUserDataLength,
- ulSavedSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
- listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
- }
- }
- }
- pxWindow->rx.ulCurrentSequenceNumber = ulCurrentSequenceNumber;
- /* Packet was expected, may be passed directly to the socket
- * buffer or application. Store the packet at offset 0. */
- lReturn = 0;
- }
- }
- else if( ulCurrentSequenceNumber == ( ulSequenceNumber + 1UL ) )
- {
- /* Looks like a TCP keep-alive message. Do not accept/store Rx data
- * ulUserDataLength = 0. Not packet out-of-sync. Just reply to it. */
- lReturn = -1;
- }
- else
- {
- /* The packet is not the one expected. See if it falls within the Rx
- * window so it can be stored. */
- /* An "out-of-sequence" segment was received, must have missed one.
- * Prepare a SACK (Selective ACK). */
- ulLast = ulSequenceNumber + ulLength;
- ulIntermediateResult = ulLast - ulCurrentSequenceNumber;
- /* The cast from unsigned long to signed long is on purpose. */
- lDistance = ( int32_t ) ulIntermediateResult;
- if( lDistance <= 0 )
- {
- /* An earlier has been received, must be a retransmission of a
- * packet that has been accepted already. No need to send out a
- * Selective ACK (SACK). */
- lReturn = -1;
- }
- else if( lDistance > ( int32_t ) ulSpace )
- {
- /* The new segment is ahead of rx.ulCurrentSequenceNumber. The
- * sequence number of this packet is too far ahead, ignore it. */
- FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu+%lu bytes, due to lack of space (%lu)\n", lDistance, ulLength, ulSpace ) );
- lReturn = -1;
- }
- else
- {
- /* See if there is more data in a contiguous block to make the
- * SACK describe a longer range of data. */
- /* TODO: SACK's may also be delayed for a short period
- * This is useful because subsequent packets will be SACK'd with
- * single one message
- */
- for( ; ; )
- {
- pxFound = xTCPWindowRxFind( pxWindow, ulLast );
- if( pxFound == NULL )
- {
- break;
- }
- ulLast += ( uint32_t ) pxFound->lDataLength;
- }
- if( xTCPWindowLoggingLevel >= 1 )
- {
- FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: seqnr %u exp %u (dist %d) SACK to %u\n",
- ( int ) pxWindow->usPeerPortNumber,
- ( int ) pxWindow->usOurPortNumber,
- ( unsigned ) ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
- ( unsigned ) ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
- ( unsigned ) ( ulSequenceNumber - ulCurrentSequenceNumber ), /* want this signed */
- ( unsigned ) ( ulLast - pxWindow->rx.ulFirstSequenceNumber ) ) );
- }
- /* Now prepare the SACK message.
- * Code OPTION_CODE_SINGLE_SACK already in network byte order. */
- pxWindow->ulOptionsData[ 0 ] = OPTION_CODE_SINGLE_SACK;
- /* First sequence number that we received. */
- pxWindow->ulOptionsData[ 1 ] = FreeRTOS_htonl( ulSequenceNumber );
- /* Last + 1 */
- pxWindow->ulOptionsData[ 2 ] = FreeRTOS_htonl( ulLast );
- /* Which make 12 (3*4) option bytes. */
- pxWindow->ucOptionLength = ( uint8_t ) ( 3U * sizeof( pxWindow->ulOptionsData[ 0 ] ) );
- pxFound = xTCPWindowRxFind( pxWindow, ulSequenceNumber );
- if( pxFound != NULL )
- {
- /* This out-of-sequence packet has been received for a
- * second time. It is already stored but do send a SACK
- * again. */
- lReturn = -1;
- }
- else
- {
- pxFound = xTCPWindowRxNew( pxWindow, ulSequenceNumber, ( int32_t ) ulLength );
- if( pxFound == NULL )
- {
- /* Can not send a SACK, because the segment cannot be
- * stored. */
- pxWindow->ucOptionLength = 0U;
- /* Needs to be stored but there is no segment
- * available. */
- lReturn = -1;
- }
- else
- {
- if( xTCPWindowLoggingLevel != 0 )
- {
- FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%u,%u]: seqnr %lu (cnt %lu)\n",
- pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber, ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
- listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
- FreeRTOS_flush_logging();
- }
- /* Return a positive value. The packet may be accepted
- * and stored but an earlier packet is still missing. */
- ulIntermediateResult = ulSequenceNumber - ulCurrentSequenceNumber;
- lReturn = ( int32_t ) ulIntermediateResult;
- }
- }
- }
- }
- return lReturn;
- }
- #endif /* ipconfgiUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- /*=============================================================================
- *
- * ######### # #
- * # # # # #
- * # # #
- * # ####
- * # ##
- * # ####
- * # # #
- * # # #
- * ##### # #
- *
- * Tx functions
- *
- *=============================================================================*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Increment the position in a circular buffer of size 'lMax'.
- *
- * @param[in] lPosition: The current index in the buffer.
- * @param[in] lMax: The total number of items in this buffer.
- * @param[in] lCount: The number of bytes that must be advanced.
- *
- * @return The new incremented position, or "( lPosition + lCount ) % lMax".
- */
- static int32_t lTCPIncrementTxPosition( int32_t lPosition,
- int32_t lMax,
- int32_t lCount )
- {
- int32_t lReturn;
- /* +TCP stores data in circular buffers. Calculate the next position to
- * store. */
- lReturn = lPosition + lCount;
- if( lReturn >= lMax )
- {
- lReturn -= lMax;
- }
- return lReturn;
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Will add data to be transmitted to the front of the segment fifo.
- *
- * @param[in] pxWindow: The descriptor of the TCP sliding windows.
- * @param[in] ulLength: The number of bytes that will be sent.
- * @param[in] lPosition: The index in the TX stream buffer.
- * @param[in] lMax: The size of the ( circular ) TX stream buffer.
- *
- * @return The number of bytes added to the sliding window for transmission.
- *
- */
- int32_t lTCPWindowTxAdd( TCPWindow_t * pxWindow,
- uint32_t ulLength,
- int32_t lPosition,
- int32_t lMax )
- {
- int32_t lBytesLeft = ( int32_t ) ulLength, lToWrite;
- int32_t lDone = 0;
- int32_t lBufferIndex = lPosition;
- TCPSegment_t * pxSegment = pxWindow->pxHeadSegment;
- /* Puts a message in the Tx-window (after buffer size has been
- * verified). */
- if( pxSegment != NULL )
- {
- if( pxSegment->lDataLength < pxSegment->lMaxLength )
- {
- if( ( pxSegment->u.bits.bOutstanding == pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength != 0 ) )
- {
- /* Adding data to a segment that was already in the TX queue. It
- * will be filled-up to a maximum of MSS (maximum segment size). */
- lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength - pxSegment->lDataLength );
- pxSegment->lDataLength += lToWrite;
- if( pxSegment->lDataLength >= pxSegment->lMaxLength )
- {
- /* This segment is full, don't add more bytes. */
- pxWindow->pxHeadSegment = NULL;
- }
- lBytesLeft -= lToWrite;
- /* ulNextTxSequenceNumber is the sequence number of the next byte to
- * be stored for transmission. */
- pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
- /* Increased the return value. */
- lDone += lToWrite;
- /* Some detailed logging, for those who're interested. */
- if( ( xTCPWindowLoggingLevel >= 2 ) && ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) )
- {
- FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Add %4lu bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
- ulLength,
- pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
- pxSegment->lDataLength,
- pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
- pxSegment->lStreamPos ) );
- FreeRTOS_flush_logging();
- }
- /* Calculate the next position in the circular data buffer, knowing
- * its maximum length 'lMax'. */
- lBufferIndex = lTCPIncrementTxPosition( lBufferIndex, lMax, lToWrite );
- }
- }
- }
- while( lBytesLeft > 0 )
- {
- /* The current transmission segment is full, create new segments as
- * needed. */
- pxSegment = xTCPWindowTxNew( pxWindow, pxWindow->ulNextTxSequenceNumber, ( int32_t ) pxWindow->usMSS );
- if( pxSegment != NULL )
- {
- /* Store as many as needed, but no more than the maximum
- * (MSS). */
- lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength );
- pxSegment->lDataLength = lToWrite;
- pxSegment->lStreamPos = lBufferIndex;
- lBytesLeft -= lToWrite;
- lBufferIndex = lTCPIncrementTxPosition( lBufferIndex, lMax, lToWrite );
- pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
- lDone += lToWrite;
- /* Link this segment in the Tx-Queue. */
- vListInsertFifo( &( pxWindow->xTxQueue ), &( pxSegment->xQueueItem ) );
- /* Let 'pxHeadSegment' point to this segment if there is still
- * space. */
- if( pxSegment->lDataLength < pxSegment->lMaxLength )
- {
- pxWindow->pxHeadSegment = pxSegment;
- }
- else
- {
- pxWindow->pxHeadSegment = NULL;
- }
- if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) )
- {
- if( ( xTCPWindowLoggingLevel >= 3 ) ||
- ( ( xTCPWindowLoggingLevel >= 2 ) && ( pxWindow->pxHeadSegment != NULL ) ) )
- {
- FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: New %4ld bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
- ulLength,
- pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
- pxSegment->lDataLength,
- pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
- pxSegment->lStreamPos ) );
- FreeRTOS_flush_logging();
- }
- }
- }
- else
- {
- /* A sever situation: running out of segments for transmission.
- * No more data can be sent at the moment. */
- if( lDone != 0 )
- {
- FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Sorry all buffers full (cancel %ld bytes)\n", lBytesLeft ) );
- }
- break;
- }
- }
- return lDone;
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Returns true if there are no more outstanding TX segments.
- *
- * @param[in] pxWindow: The descriptor of the TCP sliding windows.
- *
- * @return pdTRUE if there are no more outstanding Tx segments, else pdFALSE.
- */
- BaseType_t xTCPWindowTxDone( const TCPWindow_t * pxWindow )
- {
- return listLIST_IS_EMPTY( ( &pxWindow->xTxSegments ) );
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Find out if the peer is able to receive more data.
- *
- * @param[in] pxWindow: The descriptor of the TCP sliding windows.
- * @param[in] ulWindowSize: The number of bytes in this segment.
- *
- * @return True if the peer has space in it window to receive more data.
- */
- static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t const * pxWindow,
- uint32_t ulWindowSize )
- {
- uint32_t ulTxOutstanding;
- BaseType_t xHasSpace;
- const TCPSegment_t * pxSegment;
- uint32_t ulNettSize;
- /* This function will look if there is new transmission data. It will
- * return true if there is data to be sent. */
- pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
- if( pxSegment == NULL )
- {
- xHasSpace = pdFALSE;
- }
- else
- {
- /* How much data is outstanding, i.e. how much data has been sent
- * but not yet acknowledged ? */
- if( pxWindow->tx.ulHighestSequenceNumber >= pxWindow->tx.ulCurrentSequenceNumber )
- {
- ulTxOutstanding = pxWindow->tx.ulHighestSequenceNumber - pxWindow->tx.ulCurrentSequenceNumber;
- }
- else
- {
- ulTxOutstanding = 0UL;
- }
- /* Subtract this from the peer's space. */
- ulNettSize = ulWindowSize - FreeRTOS_min_uint32( ulWindowSize, ulTxOutstanding );
- /* See if the next segment may be sent. */
- if( ulNettSize >= ( uint32_t ) pxSegment->lDataLength )
- {
- xHasSpace = pdTRUE;
- }
- else
- {
- xHasSpace = pdFALSE;
- }
- /* If 'xHasSpace', it looks like the peer has at least space for 1
- * more new segment of size MSS. xSize.ulTxWindowLength is the self-imposed
- * limitation of the transmission window (in case of many resends it
- * may be decreased). */
- if( ( ulTxOutstanding != 0UL ) && ( pxWindow->xSize.ulTxWindowLength < ( ulTxOutstanding + ( ( uint32_t ) pxSegment->lDataLength ) ) ) )
- {
- xHasSpace = pdFALSE;
- }
- }
- return xHasSpace;
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Returns true if there is TX data that can be sent right now.
- *
- * @param[in] pxWindow: The descriptor of the TCP sliding windows.
- * @param[in] ulWindowSize: The current size of the sliding RX window of the peer.
- * @param[out] pulDelay: The delay before the packet may be sent.
- *
- * @return pdTRUE if there is Tx data that can be sent, else pdFALSE.
- */
- BaseType_t xTCPWindowTxHasData( TCPWindow_t const * pxWindow,
- uint32_t ulWindowSize,
- TickType_t * pulDelay )
- {
- TCPSegment_t const * pxSegment;
- BaseType_t xReturn;
- TickType_t ulAge, ulMaxAge;
- *pulDelay = 0U;
- if( listLIST_IS_EMPTY( &pxWindow->xPriorityQueue ) == pdFALSE )
- {
- /* No need to look at retransmissions or new transmission as long as
- * there are priority segments. *pulDelay equals zero, meaning it must
- * be sent out immediately. */
- xReturn = pdTRUE;
- }
- else
- {
- pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
- if( pxSegment != NULL )
- {
- /* There is an outstanding segment, see if it is time to resend
- * it. */
- ulAge = ulTimerGetAge( &pxSegment->xTransmitTimer );
- /* After a packet has been sent for the first time, it will wait
- * '1 * lSRTT' ms for an ACK. A second time it will wait '2 * lSRTT' ms,
- * each time doubling the time-out */
- ulMaxAge = ( 1UL << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
- if( ulMaxAge > ulAge )
- {
- /* A segment must be sent after this amount of msecs */
- *pulDelay = ulMaxAge - ulAge;
- }
- xReturn = pdTRUE;
- }
- else
- {
- /* No priority segment, no outstanding data, see if there is new
- * transmission data. */
- pxSegment = xTCPWindowPeekHead( &pxWindow->xTxQueue );
- /* See if it fits in the peer's reception window. */
- if( pxSegment == NULL )
- {
- xReturn = pdFALSE;
- }
- else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
- {
- /* Too many outstanding messages. */
- xReturn = pdFALSE;
- }
- else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
- {
- /* 'bSendFullSize' is a special optimisation. If true, the
- * driver will only sent completely filled packets (of MSS
- * bytes). */
- xReturn = pdFALSE;
- }
- else
- {
- xReturn = pdTRUE;
- }
- }
- }
- return xReturn;
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Get data that can be transmitted right now.
- *
- * @param[in] pxWindow: The descriptor of the TCP sliding windows.
- * @param[in] ulWindowSize: The current size of the sliding RX window of the peer.
- * @param[out] plPosition: The index within the TX stream buffer of the first byte to be sent.
- *
- * @return The amount of data in bytes that can be transmitted right now.
- */
- uint32_t ulTCPWindowTxGet( TCPWindow_t * pxWindow,
- uint32_t ulWindowSize,
- int32_t * plPosition )
- {
- TCPSegment_t * pxSegment;
- uint32_t ulMaxTime;
- uint32_t ulReturn = ~0UL;
- /* Fetches data to be sent-out now.
- *
- * Priority messages: segments with a resend need no check current sliding
- * window size. */
- pxSegment = xTCPWindowGetHead( &( pxWindow->xPriorityQueue ) );
- pxWindow->ulOurSequenceNumber = pxWindow->tx.ulHighestSequenceNumber;
- if( pxSegment == NULL )
- {
- /* Waiting messages: outstanding messages with a running timer
- * neither check peer's reception window size because these packets
- * have been sent earlier. */
- pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
- if( pxSegment != NULL )
- {
- /* Do check the timing. */
- ulMaxTime = ( 1UL << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
- if( ulTimerGetAge( &pxSegment->xTransmitTimer ) > ulMaxTime )
- {
- /* A normal (non-fast) retransmission. Move it from the
- * head of the waiting queue. */
- pxSegment = xTCPWindowGetHead( &( pxWindow->xWaitQueue ) );
- pxSegment->u.bits.ucDupAckCount = ( uint8_t ) pdFALSE_UNSIGNED;
- /* Some detailed logging. */
- if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) ) )
- {
- FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: WaitQueue %ld bytes for sequence number %lu (%lX)\n",
- pxWindow->usPeerPortNumber,
- pxWindow->usOurPortNumber,
- pxSegment->lDataLength,
- pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
- pxSegment->ulSequenceNumber ) );
- FreeRTOS_flush_logging();
- }
- }
- else
- {
- pxSegment = NULL;
- }
- }
- if( pxSegment == NULL )
- {
- /* New messages: sent-out for the first time. Check current
- * sliding window size of peer. */
- pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
- if( pxSegment == NULL )
- {
- /* No segments queued. */
- ulReturn = 0UL;
- }
- else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
- {
- /* A segment has been queued but the driver waits until it
- * has a full size of MSS. */
- ulReturn = 0;
- }
- else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
- {
- /* Peer has no more space at this moment. */
- ulReturn = 0;
- }
- else
- {
- /* Move it out of the Tx queue. */
- pxSegment = xTCPWindowGetHead( &( pxWindow->xTxQueue ) );
- /* Don't let pxHeadSegment point to this segment any more,
- * so no more data will be added. */
- if( pxWindow->pxHeadSegment == pxSegment )
- {
- pxWindow->pxHeadSegment = NULL;
- }
- /* pxWindow->tx.highest registers the highest sequence
- * number in our transmission window. */
- pxWindow->tx.ulHighestSequenceNumber = pxSegment->ulSequenceNumber + ( ( uint32_t ) pxSegment->lDataLength );
- /* ...and more detailed logging */
- if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) ) )
- {
- FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: XmitQueue %ld bytes for sequence number %lu (ws %lu)\n",
- pxWindow->usPeerPortNumber,
- pxWindow->usOurPortNumber,
- pxSegment->lDataLength,
- pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
- ulWindowSize ) );
- FreeRTOS_flush_logging();
- }
- }
- }
- }
- else
- {
- /* There is a priority segment. It doesn't need any checking for
- * space or timeouts. */
- if( xTCPWindowLoggingLevel != 0 )
- {
- FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: PrioQueue %ld bytes for sequence number %lu (ws %lu)\n",
- pxWindow->usPeerPortNumber,
- pxWindow->usOurPortNumber,
- pxSegment->lDataLength,
- pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
- ulWindowSize ) );
- FreeRTOS_flush_logging();
- }
- }
- /* See if it has already been determined to return 0. */
- if( ulReturn != 0UL )
- {
- /* pxSegment is not NULL when ulReturn != 0UL. */
- configASSERT( pxSegment != NULL );
- configASSERT( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) == NULL );
- /* Now that the segment will be transmitted, add it to the tail of
- * the waiting queue. */
- vListInsertFifo( &pxWindow->xWaitQueue, &pxSegment->xQueueItem );
- /* And mark it as outstanding. */
- pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
- /* Administer the transmit count, needed for fast
- * retransmissions. */
- ( pxSegment->u.bits.ucTransmitCount )++;
- /* If there have been several retransmissions (4), decrease the
- * size of the transmission window to at most 2 times MSS. */
- if( pxSegment->u.bits.ucTransmitCount == MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW )
- {
- if( pxWindow->xSize.ulTxWindowLength > ( 2U * ( ( uint32_t ) pxWindow->usMSS ) ) )
- {
- FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u - %d]: Change Tx window: %lu -> %u\n",
- pxWindow->usPeerPortNumber,
- pxWindow->usOurPortNumber,
- pxWindow->xSize.ulTxWindowLength,
- 2U * pxWindow->usMSS ) );
- pxWindow->xSize.ulTxWindowLength = ( 2UL * pxWindow->usMSS );
- }
- }
- /* Clear the transmit timer. */
- vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
- pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
- /* Inform the caller where to find the data within the queue. */
- *plPosition = pxSegment->lStreamPos;
- /* And return the length of the data segment */
- ulReturn = ( uint32_t ) pxSegment->lDataLength;
- }
- return ulReturn;
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief An acknowledgement or a selective ACK (SACK) was received. See if some outstanding data
- * may be removed from the transmission queue(s). All TX segments for which
- * ( ( ulSequenceNumber >= ulFirst ) && ( ulSequenceNumber < ulLast ) in a contiguous block.
- * Note that the segments are stored in xTxSegments in a strict sequential order.
- *
- * @param[in] pxWindow: The TCP-window object of the current connection.
- * @param[in] ulFirst: The sequence number of the first byte that was acknowledged.
- * @param[in] ulLast: The sequence number of the last byte ( minus one ) that was acknowledged.
- *
- * @return number of bytes that the tail of txStream may be advanced.
- */
- static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t * pxWindow,
- uint32_t ulFirst,
- uint32_t ulLast )
- {
- uint32_t ulBytesConfirmed = 0U;
- uint32_t ulSequenceNumber = ulFirst, ulDataLength;
- const ListItem_t * pxIterator;
- const ListItem_t * pxEnd = listGET_END_MARKER( &pxWindow->xTxSegments );
- BaseType_t xDoUnlink;
- TCPSegment_t * pxSegment;
- /* An acknowledgement or a selective ACK (SACK) was received. See if some outstanding data
- * may be removed from the transmission queue(s).
- * All TX segments for which
- * ( ( ulSequenceNumber >= ulFirst ) && ( ulSequenceNumber < ulLast ) in a
- * contiguous block. Note that the segments are stored in xTxSegments in a
- * strict sequential order. */
- /* SRTT[i] = (1-a) * SRTT[i-1] + a * RTT
- *
- * 0 < a < 1; usually a = 1/8
- *
- * RTO = 2 * SRTT
- *
- * where:
- * RTT is Round Trip Time
- * SRTT is Smoothed RTT
- * RTO is Retransmit timeout
- *
- * A Smoothed RTT will increase quickly, but it is conservative when
- * becoming smaller. */
- pxIterator = listGET_NEXT( pxEnd );
- while( ( pxIterator != pxEnd ) && ( xSequenceLessThan( ulSequenceNumber, ulLast ) != 0 ) )
- {
- xDoUnlink = pdFALSE;
- pxSegment = ipCAST_PTR_TO_TYPE_PTR( TCPSegment_t, listGET_LIST_ITEM_OWNER( pxIterator ) );
- /* Move to the next item because the current item might get
- * removed. */
- pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
- /* Continue if this segment does not fall within the ACK'd range. */
- if( xSequenceGreaterThan( ulSequenceNumber, pxSegment->ulSequenceNumber ) != pdFALSE )
- {
- continue;
- }
- /* Is it ready? */
- if( ulSequenceNumber != pxSegment->ulSequenceNumber )
- {
- /* coverity[break_stmt] : Break statement terminating the loop */
- break;
- }
- ulDataLength = ( uint32_t ) pxSegment->lDataLength;
- if( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED )
- {
- if( xSequenceGreaterThan( pxSegment->ulSequenceNumber + ( uint32_t ) ulDataLength, ulLast ) != pdFALSE )
- {
- /* What happens? Only part of this segment was accepted,
- * probably due to WND limits
- *
- * AAAAAAA BBBBBBB << acked
- * aaaaaaa aaaa << sent */
- #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
- {
- uint32_t ulFirstSeq = pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber;
- FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck[%u.%u]: %lu - %lu Partial sequence number %lu - %lu\n",
- pxWindow->usPeerPortNumber,
- pxWindow->usOurPortNumber,
- ulFirstSeq - pxWindow->tx.ulFirstSequenceNumber,
- ulLast - pxWindow->tx.ulFirstSequenceNumber,
- ulFirstSeq, ulFirstSeq + ulDataLength ) );
- }
- #endif /* ipconfigHAS_DEBUG_PRINTF */
- break;
- }
- /* This segment is fully ACK'd, set the flag. */
- pxSegment->u.bits.bAcked = pdTRUE;
- /* Calculate the RTT only if the segment was sent-out for the
- * first time and if this is the last ACK'd segment in a range. */
- if( ( pxSegment->u.bits.ucTransmitCount == 1U ) && ( ( pxSegment->ulSequenceNumber + ulDataLength ) == ulLast ) )
- {
- int32_t mS = ( int32_t ) ulTimerGetAge( &( pxSegment->xTransmitTimer ) );
- if( pxWindow->lSRTT >= mS )
- {
- /* RTT becomes smaller: adapt slowly. */
- pxWindow->lSRTT = ( ( winSRTT_DECREMENT_NEW * mS ) + ( winSRTT_DECREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_DECREMENT_NEW + winSRTT_DECREMENT_CURRENT );
- }
- else
- {
- /* RTT becomes larger: adapt quicker */
- pxWindow->lSRTT = ( ( winSRTT_INCREMENT_NEW * mS ) + ( winSRTT_INCREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_INCREMENT_NEW + winSRTT_INCREMENT_CURRENT );
- }
- /* Cap to the minimum of 50ms. */
- if( pxWindow->lSRTT < winSRTT_CAP_mS )
- {
- pxWindow->lSRTT = winSRTT_CAP_mS;
- }
- }
- /* Unlink it from the 3 queues, but do not destroy it (yet). */
- xDoUnlink = pdTRUE;
- }
- /* pxSegment->u.bits.bAcked is now true. Is it located at the left
- * side of the transmission queue? If so, it may be freed. */
- if( ulSequenceNumber == pxWindow->tx.ulCurrentSequenceNumber )
- {
- if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) ) )
- {
- FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck: %lu - %lu Ready sequence number %lu\n",
- ulFirst - pxWindow->tx.ulFirstSequenceNumber,
- ulLast - pxWindow->tx.ulFirstSequenceNumber,
- pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
- }
- /* Increase the left-hand value of the transmission window. */
- pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
- /* This function will return the number of bytes that the tail
- * of txStream may be advanced. */
- ulBytesConfirmed += ulDataLength;
- /* All segments below tx.ulCurrentSequenceNumber may be freed. */
- vTCPWindowFree( pxSegment );
- /* No need to unlink it any more. */
- xDoUnlink = pdFALSE;
- }
- if( ( xDoUnlink != pdFALSE ) && ( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL ) )
- {
- /* Remove item from its queues. */
- ( void ) uxListRemove( &pxSegment->xQueueItem );
- }
- ulSequenceNumber += ulDataLength;
- }
- return ulBytesConfirmed;
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief See if there are segments that need a fast retransmission.
- *
- * @param[in] pxWindow: The descriptor of the TCP sliding windows.
- * @param[in] ulFirst: The sequence number of the first segment that must be checked.
- *
- * @return The number of segments that need a fast retransmission.
- */
- static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t * pxWindow,
- uint32_t ulFirst )
- {
- const ListItem_t * pxIterator;
- const ListItem_t * pxEnd;
- TCPSegment_t * pxSegment;
- uint32_t ulCount = 0UL;
- /* A higher Tx block has been acknowledged. Now iterate through the
- * xWaitQueue to find a possible condition for a FAST retransmission. */
- pxEnd = listGET_END_MARKER( &( pxWindow->xWaitQueue ) );
- pxIterator = listGET_NEXT( pxEnd );
- while( pxIterator != pxEnd )
- {
- /* Get the owner, which is a TCP segment. */
- pxSegment = ipCAST_PTR_TO_TYPE_PTR( TCPSegment_t, listGET_LIST_ITEM_OWNER( pxIterator ) );
- /* Hop to the next item before the current gets unlinked. */
- pxIterator = listGET_NEXT( pxIterator );
- /* Fast retransmission:
- * When 3 packets with a higher sequence number have been acknowledged
- * by the peer, it is very unlikely a current packet will ever arrive.
- * It will be retransmitted far before the RTO. */
- if( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED )
- {
- if( xSequenceLessThan( pxSegment->ulSequenceNumber, ulFirst ) != pdFALSE )
- {
- pxSegment->u.bits.ucDupAckCount++;
- if( pxSegment->u.bits.ucDupAckCount == DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT )
- {
- pxSegment->u.bits.ucTransmitCount = ( uint8_t ) pdFALSE;
- /* Not clearing 'ucDupAckCount' yet as more SACK's might come in
- * which might lead to a second fast rexmit. */
- if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) ) )
- {
- FreeRTOS_debug_printf( ( "prvTCPWindowFastRetransmit: Requeue sequence number %lu < %lu\n",
- pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
- ulFirst - pxWindow->tx.ulFirstSequenceNumber ) );
- FreeRTOS_flush_logging();
- }
- /* Remove it from xWaitQueue. */
- ( void ) uxListRemove( &pxSegment->xQueueItem );
- /* Add this segment to the priority queue so it gets
- * retransmitted immediately. */
- vListInsertFifo( &( pxWindow->xPriorityQueue ), &( pxSegment->xQueueItem ) );
- ulCount++;
- }
- }
- }
- }
- return ulCount;
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Receive a normal ACK.
- *
- * @param[in] pxWindow: Window in which a data is receive.
- * @param[in] ulSequenceNumber: The sequence number of the ACK.
- *
- * @return The location where the packet should be added.
- */
- uint32_t ulTCPWindowTxAck( TCPWindow_t * pxWindow,
- uint32_t ulSequenceNumber )
- {
- uint32_t ulFirstSequence, ulReturn;
- /* Receive a normal ACK. */
- ulFirstSequence = pxWindow->tx.ulCurrentSequenceNumber;
- if( xSequenceLessThanOrEqual( ulSequenceNumber, ulFirstSequence ) != pdFALSE )
- {
- ulReturn = 0UL;
- }
- else
- {
- ulReturn = prvTCPWindowTxCheckAck( pxWindow, ulFirstSequence, ulSequenceNumber );
- }
- return ulReturn;
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 1 )
- /**
- * @brief Receive a SACK option.
- *
- * @param[in] pxWindow: Window in which the data is received.
- * @param[in] ulFirst: Index of starting position of options.
- * @param[in] ulLast: Index of end position of the options.
- *
- * @return returns the number of bytes which have been acked starting from
- * the head position.
- */
- uint32_t ulTCPWindowTxSack( TCPWindow_t * pxWindow,
- uint32_t ulFirst,
- uint32_t ulLast )
- {
- uint32_t ulAckCount;
- uint32_t ulCurrentSequenceNumber = pxWindow->tx.ulCurrentSequenceNumber;
- /* Receive a SACK option. */
- ulAckCount = prvTCPWindowTxCheckAck( pxWindow, ulFirst, ulLast );
- ( void ) prvTCPWindowFastRetransmit( pxWindow, ulFirst );
- if( ( xTCPWindowLoggingLevel >= 1 ) && ( xSequenceGreaterThan( ulFirst, ulCurrentSequenceNumber ) != pdFALSE ) )
- {
- FreeRTOS_debug_printf( ( "ulTCPWindowTxSack[%u,%u]: from %lu to %lu (ack = %lu)\n",
- pxWindow->usPeerPortNumber,
- pxWindow->usOurPortNumber,
- ulFirst - pxWindow->tx.ulFirstSequenceNumber,
- ulLast - pxWindow->tx.ulFirstSequenceNumber,
- pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
- FreeRTOS_flush_logging();
- }
- return ulAckCount;
- }
- #endif /* ipconfigUSE_TCP_WIN == 1 */
- /*-----------------------------------------------------------*/
- /*
- ##### # ##### #### ######
- # # # # # # # # # # #
- # # # # # #
- # ### ##### # # # # # #
- # # # # # # # # #####
- # # # # # # #### # # #
- # # # # # # # # # #
- # # # # #### # # # #
- #### ##### # # # #### #### ####
- #
- ###
- */
- #if ( ipconfigUSE_TCP_WIN == 0 )
- /**
- * @brief Data was received at 'ulSequenceNumber'. See if it was expected
- * and if there is enough space to store the new data.
- *
- * @param[in] pxWindow: The window to be checked.
- * @param[in] ulSequenceNumber: Sequence number of the data received.
- * @param[in] ulLength: Length of the data received.
- * @param[in] ulSpace: Space in the buffer.
- *
- * @return A 0 is returned if there is enough space and the sequence number is correct,
- * if not then a -1 is returned.
- *
- * @note if true may be passed directly to user (segment expected and window is empty).
- * But pxWindow->ackno should always be used to set "BUF->ackno".
- */
- int32_t lTCPWindowRxCheck( TCPWindow_t * pxWindow,
- uint32_t ulSequenceNumber,
- uint32_t ulLength,
- uint32_t ulSpace )
- {
- int32_t iReturn;
- /* Data was received at 'ulSequenceNumber'. See if it was expected
- * and if there is enough space to store the new data. */
- if( ( pxWindow->rx.ulCurrentSequenceNumber != ulSequenceNumber ) || ( ulSpace < ulLength ) )
- {
- iReturn = -1;
- }
- else
- {
- pxWindow->rx.ulCurrentSequenceNumber += ( uint32_t ) ulLength;
- iReturn = 0;
- }
- return iReturn;
- }
- #endif /* ipconfigUSE_TCP_WIN == 0 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 0 )
- /**
- * @brief Add data to the Tx Window.
- *
- * @param[in] pxWindow: The window to which the data is to be added.
- * @param[in] ulLength: The length of the data to be added.
- * @param[in] lPosition: Position in the stream.
- * @param[in] lMax: Size of the Tx stream.
- *
- * @return The data actually added.
- */
- int32_t lTCPWindowTxAdd( TCPWindow_t * pxWindow,
- uint32_t ulLength,
- int32_t lPosition,
- int32_t lMax )
- {
- TCPSegment_t * pxSegment = &( pxWindow->xTxSegment );
- int32_t lResult;
- /* Data is being scheduled for transmission. */
- /* lMax would indicate the size of the txStream. */
- ( void ) lMax;
- /* This is tiny TCP: there is only 1 segment for outgoing data.
- * As long as 'lDataLength' is unequal to zero, the segment is still occupied. */
- if( pxSegment->lDataLength > 0 )
- {
- lResult = 0L;
- }
- else
- {
- if( ulLength > ( uint32_t ) pxSegment->lMaxLength )
- {
- if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
- {
- FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: can only store %ld / %ld bytes\n", ulLength, pxSegment->lMaxLength ) );
- }
- ulLength = ( uint32_t ) pxSegment->lMaxLength;
- }
- if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
- {
- FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: SeqNr %ld (%ld) Len %ld\n",
- pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
- pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
- ulLength ) );
- }
- /* The sequence number of the first byte in this packet. */
- pxSegment->ulSequenceNumber = pxWindow->ulNextTxSequenceNumber;
- pxSegment->lDataLength = ( int32_t ) ulLength;
- pxSegment->lStreamPos = lPosition;
- pxSegment->u.ulFlags = 0UL;
- vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
- /* Increase the sequence number of the next data to be stored for
- * transmission. */
- pxWindow->ulNextTxSequenceNumber += ulLength;
- lResult = ( int32_t ) ulLength;
- }
- return lResult;
- }
- #endif /* ipconfigUSE_TCP_WIN == 0 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 0 )
- /**
- * @brief Fetches data to be sent.
- *
- * @param[in] pxWindow: The window for the connection.
- * @param[in] ulWindowSize: The size of the window.
- * @param[out] plPosition: plPosition will point to a location with the circular data buffer: txStream.
- *
- * @return return the amount of data which may be sent along with the position in the txStream.
- */
- uint32_t ulTCPWindowTxGet( TCPWindow_t * pxWindow,
- uint32_t ulWindowSize,
- int32_t * plPosition )
- {
- TCPSegment_t * pxSegment = &( pxWindow->xTxSegment );
- uint32_t ulLength = ( uint32_t ) pxSegment->lDataLength;
- uint32_t ulMaxTime;
- if( ulLength != 0UL )
- {
- /* _HT_ Still under investigation */
- ( void ) ulWindowSize;
- if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
- {
- /* As 'ucTransmitCount' has a minimum of 1, take 2 * RTT */
- ulMaxTime = ( ( uint32_t ) 1U << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
- if( ulTimerGetAge( &( pxSegment->xTransmitTimer ) ) < ulMaxTime )
- {
- ulLength = 0UL;
- }
- }
- if( ulLength != 0UL )
- {
- pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
- pxSegment->u.bits.ucTransmitCount++;
- vTCPTimerSet( &pxSegment->xTransmitTimer );
- pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
- *plPosition = pxSegment->lStreamPos;
- }
- }
- return ulLength;
- }
- #endif /* ipconfigUSE_TCP_WIN == 0 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 0 )
- /**
- * @brief Has the transmission completed.
- *
- * @param[in] pxWindow: The window whose transmission window is to be checked.
- *
- * @return If there is no outstanding data then pdTRUE is returned,
- * else pdFALSE.
- */
- BaseType_t xTCPWindowTxDone( const TCPWindow_t * pxWindow )
- {
- BaseType_t xReturn;
- /* Has the outstanding data been sent because user wants to shutdown? */
- if( pxWindow->xTxSegment.lDataLength == 0 )
- {
- xReturn = pdTRUE;
- }
- else
- {
- xReturn = pdFALSE;
- }
- return xReturn;
- }
- #endif /* ipconfigUSE_TCP_WIN == 0 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 0 )
- static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t const * pxWindow,
- uint32_t ulWindowSize );
- /**
- * @brief Check if the window has space for one message.
- *
- * @param[in] pxWindow: The window to be checked.
- * @param[in] ulWindowSize: Size of the window.
- *
- * @return pdTRUE if the window has space, pdFALSE otherwise.
- */
- static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t const * pxWindow,
- uint32_t ulWindowSize )
- {
- BaseType_t xReturn;
- if( ulWindowSize >= pxWindow->usMSSInit )
- {
- xReturn = pdTRUE;
- }
- else
- {
- xReturn = pdFALSE;
- }
- return xReturn;
- }
- #endif /* ipconfigUSE_TCP_WIN == 0 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 0 )
- /**
- * @brief Check data to be sent and calculate the time period the process may sleep.
- *
- * @param[in] pxWindow: The window to be checked.
- * @param[in] ulWindowSize: Size of the window.
- * @param[out] pulDelay: The time period (in ticks) that the process may sleep.
- *
- * @return pdTRUE if the process should sleep or pdFALSE.
- */
- BaseType_t xTCPWindowTxHasData( TCPWindow_t const * pxWindow,
- uint32_t ulWindowSize,
- TickType_t * pulDelay )
- {
- TCPSegment_t const * pxSegment = &( pxWindow->xTxSegment );
- BaseType_t xReturn;
- TickType_t ulAge, ulMaxAge;
- /* Check data to be sent. */
- *pulDelay = ( TickType_t ) 0;
- if( pxSegment->lDataLength == 0 )
- {
- /* Got nothing to send right now. */
- xReturn = pdFALSE;
- }
- else
- {
- if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
- {
- ulAge = ulTimerGetAge( &pxSegment->xTransmitTimer );
- ulMaxAge = ( ( TickType_t ) 1U << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
- if( ulMaxAge > ulAge )
- {
- *pulDelay = ulMaxAge - ulAge;
- }
- xReturn = pdTRUE;
- }
- else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
- {
- /* Too many outstanding messages. */
- xReturn = pdFALSE;
- }
- else
- {
- xReturn = pdTRUE;
- }
- }
- return xReturn;
- }
- #endif /* ipconfigUSE_TCP_WIN == 0 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 0 )
- /**
- * @brief Receive a normal ACK.
- *
- * @param[in] pxWindow: The window for this particular connection.
- * @param[in] ulSequenceNumber: The sequence number of the packet.
- *
- * @return Number of bytes to send.
- */
- uint32_t ulTCPWindowTxAck( TCPWindow_t * pxWindow,
- uint32_t ulSequenceNumber )
- {
- TCPSegment_t * pxSegment = &( pxWindow->xTxSegment );
- uint32_t ulDataLength = ( uint32_t ) pxSegment->lDataLength;
- /* Receive a normal ACK */
- if( ulDataLength != 0UL )
- {
- if( ulSequenceNumber < ( pxWindow->tx.ulCurrentSequenceNumber + ulDataLength ) )
- {
- if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE )
- {
- FreeRTOS_debug_printf( ( "win_tx_ack: acked %ld expc %ld len %ld\n",
- ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
- pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
- ulDataLength ) );
- }
- /* Nothing to send right now. */
- ulDataLength = 0UL;
- }
- else
- {
- pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
- if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
- {
- FreeRTOS_debug_printf( ( "win_tx_ack: acked seqnr %ld len %ld\n",
- ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
- ulDataLength ) );
- }
- pxSegment->lDataLength = 0;
- }
- }
- return ulDataLength;
- }
- #endif /* ipconfigUSE_TCP_WIN == 0 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 0 )
- /**
- * @brief This function will be called as soon as a FIN is received to check
- * whether all transmit queues are empty or not.
- *
- * @param[in] pxWindow: The window to be checked.
- *
- * @return It will return true if there are no 'open' reception segments.
- */
- BaseType_t xTCPWindowRxEmpty( const TCPWindow_t * pxWindow )
- {
- /* Return true if 'ulCurrentSequenceNumber >= ulHighestSequenceNumber'
- * 'ulCurrentSequenceNumber' is the highest sequence number stored,
- * 'ulHighestSequenceNumber' is the highest sequence number seen. */
- return xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber );
- }
- #endif /* ipconfigUSE_TCP_WIN == 0 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP_WIN == 0 )
- /**
- * @brief Destroy a window.
- *
- * @param[in] pxWindow: Pointer to the window to be destroyed.
- *
- * @return Always returns a NULL.
- */
- void vTCPWindowDestroy( const TCPWindow_t * pxWindow )
- {
- /* As in tiny TCP there are no shared segments descriptors, there is
- * nothing to release. */
- ( void ) pxWindow;
- }
- #endif /* ipconfigUSE_TCP_WIN == 0 */
- /*-----------------------------------------------------------*/
- #endif /* ipconfigUSE_TCP == 1 */
|