Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tcp_misc.c Source File

tcp_misc.c

Go to the documentation of this file.
00001 /**
00002  * @file tcp_misc.c
00003  * @brief Helper functions for TCP
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL TCP_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include "core/net.h"
00036 #include "core/socket.h"
00037 #include "core/tcp.h"
00038 #include "core/tcp_misc.h"
00039 #include "core/tcp_timer.h"
00040 #include "core/ip.h"
00041 #include "ipv4/ipv4.h"
00042 #include "ipv6/ipv6.h"
00043 #include "mibs/mib2_module.h"
00044 #include "date_time.h"
00045 #include "debug.h"
00046 
00047 //Check TCP/IP stack configuration
00048 #if (TCP_SUPPORT == ENABLED)
00049 
00050 
00051 /**
00052  * @brief Send a TCP segment
00053  * @param[in] socket Handle referencing a socket
00054  * @param[in] flags Value that contains bitwise OR of flags (see #TcpFlags enumeration)
00055  * @param[in] seqNum Sequence number
00056  * @param[in] ackNum Acknowledgment number
00057  * @param[in] length Length of the segment data
00058  * @param[in] addToQueue Add the segment to retransmission queue
00059  * @return Error code
00060  **/
00061 
00062 error_t tcpSendSegment(Socket *socket, uint8_t flags, uint32_t seqNum,
00063    uint32_t ackNum, size_t length, bool_t addToQueue)
00064 {
00065    error_t error;
00066    size_t offset;
00067    size_t totalLength;
00068    NetBuffer *buffer;
00069    TcpHeader *segment;
00070    TcpQueueItem *queueItem;
00071    IpPseudoHeader pseudoHeader;
00072 
00073    //Maximum segment size
00074    uint16_t mss = HTONS(socket->rmss);
00075 
00076    //Allocate a memory buffer to hold the TCP segment
00077    buffer = ipAllocBuffer(TCP_MAX_HEADER_LENGTH, &offset);
00078    //Failed to allocate memory?
00079    if(buffer == NULL)
00080       return ERROR_OUT_OF_MEMORY;
00081 
00082    //Point to the beginning of the TCP segment
00083    segment = netBufferAt(buffer, offset);
00084 
00085    //Format TCP header
00086    segment->srcPort = htons(socket->localPort);
00087    segment->destPort = htons(socket->remotePort);
00088    segment->seqNum = htonl(seqNum);
00089    segment->ackNum = (flags & TCP_FLAG_ACK) ? htonl(ackNum) : 0;
00090    segment->reserved1 = 0;
00091    segment->dataOffset = 5;
00092    segment->flags = flags;
00093    segment->reserved2 = 0;
00094    segment->window = htons(socket->rcvWnd);
00095    segment->checksum = 0;
00096    segment->urgentPointer = 0;
00097 
00098    //SYN flag set?
00099    if(flags & TCP_FLAG_SYN)
00100    {
00101       //Append MSS option
00102       tcpAddOption(segment, TCP_OPTION_MAX_SEGMENT_SIZE, &mss, sizeof(mss));
00103 
00104 #if (TCP_SACK_SUPPORT == ENABLED)
00105       //Append SACK Permitted option
00106       tcpAddOption(segment, TCP_OPTION_SACK_PERMITTED, NULL, 0);
00107 #endif
00108    }
00109 
00110    //Adjust the length of the multi-part buffer
00111    netBufferSetLength(buffer, offset + segment->dataOffset * 4);
00112 
00113    //Any data to send?
00114    if(length > 0)
00115    {
00116       //Copy data
00117       error = tcpReadTxBuffer(socket, seqNum, buffer, length);
00118       //Any error to report?
00119       if(error)
00120       {
00121          //Clean up side effects
00122          netBufferFree(buffer);
00123          //Exit immediately
00124          return error;
00125       }
00126    }
00127 
00128    //Calculate the length of the complete TCP segment
00129    totalLength = segment->dataOffset * 4 + length;
00130 
00131 #if (IPV4_SUPPORT == ENABLED)
00132    //Destination address is an IPv4 address?
00133    if(socket->remoteIpAddr.length == sizeof(Ipv4Addr))
00134    {
00135       //Format IPv4 pseudo header
00136       pseudoHeader.length = sizeof(Ipv4PseudoHeader);
00137       pseudoHeader.ipv4Data.srcAddr = socket->localIpAddr.ipv4Addr;
00138       pseudoHeader.ipv4Data.destAddr = socket->remoteIpAddr.ipv4Addr;
00139       pseudoHeader.ipv4Data.reserved = 0;
00140       pseudoHeader.ipv4Data.protocol = IPV4_PROTOCOL_TCP;
00141       pseudoHeader.ipv4Data.length = htons(totalLength);
00142 
00143       //Calculate TCP header checksum
00144       segment->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader.ipv4Data,
00145          sizeof(Ipv4PseudoHeader), buffer, offset, totalLength);
00146    }
00147    else
00148 #endif
00149 #if (IPV6_SUPPORT == ENABLED)
00150    //Destination address is an IPv6 address?
00151    if(socket->remoteIpAddr.length == sizeof(Ipv6Addr))
00152    {
00153       //Format IPv6 pseudo header
00154       pseudoHeader.length = sizeof(Ipv6PseudoHeader);
00155       pseudoHeader.ipv6Data.srcAddr = socket->localIpAddr.ipv6Addr;
00156       pseudoHeader.ipv6Data.destAddr = socket->remoteIpAddr.ipv6Addr;
00157       pseudoHeader.ipv6Data.length = htonl(totalLength);
00158       pseudoHeader.ipv6Data.reserved = 0;
00159       pseudoHeader.ipv6Data.nextHeader = IPV6_TCP_HEADER;
00160 
00161       //Calculate TCP header checksum
00162       segment->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader.ipv6Data,
00163          sizeof(Ipv6PseudoHeader), buffer, offset, totalLength);
00164    }
00165    else
00166 #endif
00167    //Destination address is not valid?
00168    {
00169       //Free previously allocated memory
00170       netBufferFree(buffer);
00171       //This should never occur...
00172       return ERROR_INVALID_ADDRESS;
00173    }
00174 
00175    //Add current segment to retransmission queue?
00176    if(addToQueue)
00177    {
00178       //Empty retransmission queue?
00179       if(!socket->retransmitQueue)
00180       {
00181          //Create a new item
00182          queueItem = memPoolAlloc(sizeof(TcpQueueItem));
00183          //Add the newly created item to the queue
00184          socket->retransmitQueue = queueItem;
00185       }
00186       else
00187       {
00188          //Point to the very first item
00189          queueItem = socket->retransmitQueue;
00190          //Reach the last item of the retransmission queue
00191          while(queueItem->next) queueItem = queueItem->next;
00192          //Create a new item
00193          queueItem->next = memPoolAlloc(sizeof(TcpQueueItem));
00194          //Point to the newly created item
00195          queueItem = queueItem->next;
00196       }
00197 
00198       //Failed to allocate memory?
00199       if(queueItem == NULL)
00200       {
00201          //Free previously allocated memory
00202          netBufferFree(buffer);
00203          //Return status
00204          return ERROR_OUT_OF_MEMORY;
00205       }
00206 
00207       //Retransmission mechanism requires additional information
00208       queueItem->next = NULL;
00209       queueItem->length = length;
00210       queueItem->sacked = FALSE;
00211       //Save TCP header
00212       memcpy(queueItem->header, segment, segment->dataOffset * 4);
00213       //Save pseudo header
00214       queueItem->pseudoHeader = pseudoHeader;
00215 
00216       //Take one RTT measurement at a time
00217       if(!socket->rttBusy)
00218       {
00219          //Save round-trip start time
00220          socket->rttStartTime = osGetSystemTime();
00221          //Record current sequence number
00222          socket->rttSeqNum = ntohl(segment->seqNum);
00223          //Wait for an acknowledgment that covers that sequence number...
00224          socket->rttBusy = TRUE;
00225 
00226 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
00227          //Reset the byte counter
00228          socket->n = 0;
00229 #endif
00230       }
00231 
00232       //Check whether the RTO timer is already running
00233       if(!tcpTimerRunning(&socket->retransmitTimer))
00234       {
00235          //If the timer is not running, start it running so that
00236          //it will expire after RTO seconds
00237          tcpTimerStart(&socket->retransmitTimer, socket->rto);
00238          //Reset retransmission counter
00239          socket->retransmitCount = 0;
00240       }
00241    }
00242 
00243    //Total number of segments sent
00244    MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpOutSegs, 1);
00245    MIB2_INC_COUNTER64(mib2Base.tcpGroup.tcpHCOutSegs, 1);
00246 
00247    //RST flag set?
00248    if(flags & TCP_FLAG_RST)
00249    {
00250       //Number of TCP segments sent containing the RST flag
00251       MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpOutRsts, 1);
00252    }
00253 
00254    //Debug message
00255    TRACE_DEBUG("%s: Sending TCP segment (%" PRIuSIZE " data bytes)...\r\n",
00256       formatSystemTime(osGetSystemTime(), NULL), length);
00257 
00258    //Dump TCP header contents for debugging purpose
00259    tcpDumpHeader(segment, length, socket->iss, socket->irs);
00260 
00261    //Send TCP segment
00262    error = ipSendDatagram(socket->interface, &pseudoHeader, buffer, offset, 0);
00263 
00264    //Free previously allocated memory
00265    netBufferFree(buffer);
00266    //Return error code
00267    return error;
00268 }
00269 
00270 
00271 /**
00272  * @brief Send a TCP reset in response to an invalid segment
00273  * @param[in] interface Underlying network interface
00274  * @param[in] pseudoHeader TCP pseudo header describing the incoming segment
00275  * @param[in] segment Incoming TCP segment
00276  * @param[in] length Length of the incoming segment data
00277  * @return Error code
00278  **/
00279 
00280 error_t tcpSendResetSegment(NetInterface *interface,
00281    IpPseudoHeader *pseudoHeader, TcpHeader *segment, size_t length)
00282 {
00283    error_t error;
00284    size_t offset;
00285    uint8_t flags;
00286    uint32_t seqNum;
00287    uint32_t ackNum;
00288    NetBuffer *buffer;
00289    TcpHeader *segment2;
00290    IpPseudoHeader pseudoHeader2;
00291 
00292    //Check whether the ACK bit is set
00293    if(segment->flags & TCP_FLAG_ACK)
00294    {
00295       //If the incoming segment has an ACK field, the reset takes
00296       //its sequence number from the ACK field of the segment
00297       flags = TCP_FLAG_RST;
00298       seqNum = segment->ackNum;
00299       ackNum = 0;
00300    }
00301    else
00302    {
00303       //Otherwise the reset has sequence number zero and the ACK field is set to
00304       //the sum of the sequence number and segment length of the incoming segment
00305       flags = TCP_FLAG_RST | TCP_FLAG_ACK;
00306       seqNum = 0;
00307       ackNum = segment->seqNum + length;
00308 
00309       //Advance the acknowledgment number over the SYN or the FIN
00310       if(segment->flags & TCP_FLAG_SYN)
00311          ackNum++;
00312       if(segment->flags & TCP_FLAG_FIN)
00313          ackNum++;
00314    }
00315 
00316    //Allocate a memory buffer to hold the reset segment
00317    buffer = ipAllocBuffer(sizeof(TcpHeader), &offset);
00318    //Failed to allocate memory?
00319    if(buffer == NULL)
00320       return ERROR_OUT_OF_MEMORY;
00321 
00322    //Point to the beginning of the TCP segment
00323    segment2 = netBufferAt(buffer, offset);
00324 
00325    //Format TCP header
00326    segment2->srcPort = htons(segment->destPort);
00327    segment2->destPort = htons(segment->srcPort);
00328    segment2->seqNum = htonl(seqNum);
00329    segment2->ackNum = htonl(ackNum);
00330    segment2->reserved1 = 0;
00331    segment2->dataOffset = 5;
00332    segment2->flags = flags;
00333    segment2->reserved2 = 0;
00334    segment2->window = 0;
00335    segment2->checksum = 0;
00336    segment2->urgentPointer = 0;
00337 
00338 #if (IPV4_SUPPORT == ENABLED)
00339    //Destination address is an IPv4 address?
00340    if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
00341    {
00342       //Format IPv4 pseudo header
00343       pseudoHeader2.length = sizeof(Ipv4PseudoHeader);
00344       pseudoHeader2.ipv4Data.srcAddr = pseudoHeader->ipv4Data.destAddr;
00345       pseudoHeader2.ipv4Data.destAddr = pseudoHeader->ipv4Data.srcAddr;
00346       pseudoHeader2.ipv4Data.reserved = 0;
00347       pseudoHeader2.ipv4Data.protocol = IPV4_PROTOCOL_TCP;
00348       pseudoHeader2.ipv4Data.length = HTONS(sizeof(TcpHeader));
00349 
00350       //Calculate TCP header checksum
00351       segment2->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader2.ipv4Data,
00352          sizeof(Ipv4PseudoHeader), buffer, offset, sizeof(TcpHeader));
00353    }
00354    else
00355 #endif
00356 #if (IPV6_SUPPORT == ENABLED)
00357    //Destination address is an IPv6 address?
00358    if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
00359    {
00360       //Format IPv6 pseudo header
00361       pseudoHeader2.length = sizeof(Ipv6PseudoHeader);
00362       pseudoHeader2.ipv6Data.srcAddr = pseudoHeader->ipv6Data.destAddr;
00363       pseudoHeader2.ipv6Data.destAddr = pseudoHeader->ipv6Data.srcAddr;
00364       pseudoHeader2.ipv6Data.length = HTONL(sizeof(TcpHeader));
00365       pseudoHeader2.ipv6Data.reserved = 0;
00366       pseudoHeader2.ipv6Data.nextHeader = IPV6_TCP_HEADER;
00367 
00368       //Calculate TCP header checksum
00369       segment2->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader2.ipv6Data,
00370          sizeof(Ipv6PseudoHeader), buffer, offset, sizeof(TcpHeader));
00371    }
00372    else
00373 #endif
00374    //Destination address is not valid?
00375    {
00376       //Free previously allocated memory
00377       netBufferFree(buffer);
00378       //This should never occur...
00379       return ERROR_INVALID_ADDRESS;
00380    }
00381 
00382    //Total number of segments sent
00383    MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpOutSegs, 1);
00384    MIB2_INC_COUNTER64(mib2Base.tcpGroup.tcpHCOutSegs, 1);
00385 
00386    //Number of TCP segments sent containing the RST flag
00387    MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpOutRsts, 1);
00388 
00389    //Debug message
00390    TRACE_DEBUG("%s: Sending TCP reset segment...\r\n",
00391       formatSystemTime(osGetSystemTime(), NULL));
00392    //Dump TCP header contents for debugging purpose
00393    tcpDumpHeader(segment2, length, 0, 0);
00394 
00395    //Send TCP segment
00396    error = ipSendDatagram(interface, &pseudoHeader2, buffer, offset, 0);
00397 
00398    //Free previously allocated memory
00399    netBufferFree(buffer);
00400    //Return error code
00401    return error;
00402 }
00403 
00404 
00405 /**
00406  * @brief Append an option to a TCP segment
00407  * @param[in] segment Pointer to the TCP header
00408  * @param[in] kind Option code
00409  * @param[in] value Option value
00410  * @param[in] length Length of the option value
00411  * @return Error code
00412  **/
00413 
00414 error_t tcpAddOption(TcpHeader *segment, uint8_t kind, const void *value, uint8_t length)
00415 {
00416    uint_t i;
00417    size_t paddingSize;
00418    TcpOption *option;
00419 
00420    //Length of the complete option field
00421    length += sizeof(TcpOption);
00422 
00423    //Make sure there is enough space to add the specified option
00424    if((segment->dataOffset * 4 + length) > TCP_MAX_HEADER_LENGTH)
00425       return ERROR_FAILURE;
00426 
00427    //Index of the first available byte
00428    i = segment->dataOffset * 4 - sizeof(TcpHeader);
00429 
00430    //Calculate the number of padding bytes
00431    paddingSize = (length % 4) ? 4 - (length % 4) : 0;
00432    //Write padding bytes
00433    while(paddingSize--)
00434       segment->options[i++] = TCP_OPTION_NOP;
00435 
00436    //Point to the current location
00437    option = (TcpOption *) (segment->options + i);
00438    //Write specified option
00439    option->kind = kind;
00440    option->length = length;
00441    memcpy(option->value, value, length - sizeof(TcpOption));
00442    //Adjust index value
00443    i += length;
00444 
00445    //Update TCP header length
00446    segment->dataOffset = (sizeof(TcpHeader) + i) / 4;
00447 
00448    //Option successfully added
00449    return NO_ERROR;
00450 }
00451 
00452 
00453 /**
00454  * @brief Find a specified option in a TCP segment
00455  * @param[in] segment Pointer to the TCP header
00456  * @param[in] kind Code of the option to find
00457  * @return If the specified option is found, a pointer to the corresponding
00458  *   option is returned. Otherwise NULL pointer is returned
00459  **/
00460 
00461 TcpOption *tcpGetOption(TcpHeader *segment, uint8_t kind)
00462 {
00463    size_t length;
00464    uint_t i;
00465    TcpOption *option;
00466 
00467    //Make sure the TCP header is valid
00468    if(segment->dataOffset < 5)
00469       return NULL;
00470 
00471    //Compute the length of the options field
00472    length = segment->dataOffset * 4 - sizeof(TcpHeader);
00473 
00474    //Point to the very first option
00475    i = 0;
00476 
00477    //Parse TCP options
00478    while(i < length)
00479    {
00480       //Point to the current option
00481       option = (TcpOption *) (segment->options + i);
00482 
00483       //NOP option detected?
00484       if(option->kind == TCP_OPTION_NOP)
00485       {
00486          i++;
00487          continue;
00488       }
00489       //END option detected?
00490       if(option->kind == TCP_OPTION_END)
00491          break;
00492       //Check option length
00493       if((i + 1) >= length || (i + option->length) > length)
00494          break;
00495 
00496       //Current option kind match the specified one?
00497       if(option->kind == kind)
00498          return option;
00499 
00500       //Jump to next the next option
00501       i += option->length;
00502    }
00503 
00504    //Specified option code not found
00505    return NULL;
00506 }
00507 
00508 
00509 /**
00510  * @brief Test the sequence number of an incoming segment
00511  * @param[in] socket Handle referencing the current socket
00512  * @param[in] segment Pointer to the TCP segment to check
00513  * @param[in] length Length of the segment data
00514  * @return NO_ERROR if the incoming segment is acceptable, ERROR_FAILURE otherwise
00515  **/
00516 
00517 error_t tcpCheckSequenceNumber(Socket *socket, TcpHeader *segment, size_t length)
00518 {
00519    //Acceptability test for an incoming segment
00520    bool_t acceptable = FALSE;
00521 
00522    //Case where both segment length and receive window are zero
00523    if(!length && !socket->rcvWnd)
00524    {
00525       //Make sure that SEG.SEQ = RCV.NXT
00526       if(segment->seqNum == socket->rcvNxt)
00527       {
00528          acceptable = TRUE;
00529       }
00530    }
00531    //Case where segment length is zero and receive window is non zero
00532    else if(!length && socket->rcvWnd)
00533    {
00534       //Make sure that RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND
00535       if(TCP_CMP_SEQ(segment->seqNum, socket->rcvNxt) >= 0 &&
00536          TCP_CMP_SEQ(segment->seqNum, socket->rcvNxt + socket->rcvWnd) < 0)
00537       {
00538          acceptable = TRUE;
00539       }
00540    }
00541    //Case where both segment length and receive window are non zero
00542    else if(length && socket->rcvWnd)
00543    {
00544       //Check whether RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND
00545       if(TCP_CMP_SEQ(segment->seqNum, socket->rcvNxt) >= 0 &&
00546          TCP_CMP_SEQ(segment->seqNum, socket->rcvNxt + socket->rcvWnd) < 0)
00547       {
00548          acceptable = TRUE;
00549       }
00550       //or RCV.NXT <= SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND
00551       else if(TCP_CMP_SEQ(segment->seqNum + length - 1, socket->rcvNxt) >= 0 &&
00552          TCP_CMP_SEQ(segment->seqNum + length - 1, socket->rcvNxt + socket->rcvWnd) < 0)
00553       {
00554          acceptable = TRUE;
00555       }
00556    }
00557 
00558    //Non acceptable sequence number?
00559    if(!acceptable)
00560    {
00561       //Debug message
00562       TRACE_WARNING("Sequence number is not acceptable!\r\n");
00563 
00564       //If an incoming segment is not acceptable, an acknowledgment
00565       //should be sent in reply (unless the RST bit is set)
00566       if(!(segment->flags & TCP_FLAG_RST))
00567          tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0, FALSE);
00568 
00569       //Return status code
00570       return ERROR_FAILURE;
00571    }
00572 
00573    //Sequence number is acceptable
00574    return NO_ERROR;
00575 }
00576 
00577 
00578 /**
00579  * @brief Check the SYN bit of an incoming segment
00580  * @param[in] socket Handle referencing the current socket
00581  * @param[in] segment Pointer to the TCP segment to check
00582  * @param[in] length Length of the segment data
00583  * @return ERROR_FAILURE if the SYN is in the window, NO_ERROR otherwise
00584  **/
00585 
00586 error_t tcpCheckSyn(Socket *socket, TcpHeader *segment, size_t length)
00587 {
00588    //Check the SYN bit
00589    if(segment->flags & TCP_FLAG_SYN)
00590    {
00591       //If this step is reached, the SYN is in the window.
00592       //It is an error and a reset shall be sent in response
00593       if(segment->flags & TCP_FLAG_ACK)
00594          tcpSendSegment(socket, TCP_FLAG_RST, segment->ackNum, 0, 0, FALSE);
00595       else
00596          tcpSendSegment(socket, TCP_FLAG_RST | TCP_FLAG_ACK, 0, segment->seqNum + length + 1, 0, FALSE);
00597 
00598       //Return immediately
00599       return ERROR_FAILURE;
00600    }
00601 
00602    //No error to report
00603    return NO_ERROR;
00604 }
00605 
00606 
00607 /**
00608  * @brief Test the ACK field of an incoming segment
00609  * @param[in] socket Handle referencing the current socket
00610  * @param[in] segment Pointer to the TCP segment to check
00611  * @param[in] length Length of the segment data
00612  * @return NO_ERROR if the acknowledgment is acceptable, ERROR_FAILURE otherwise
00613  **/
00614 
00615 error_t tcpCheckAck(Socket *socket, TcpHeader *segment, size_t length)
00616 {
00617    uint_t n;
00618    uint_t ownd;
00619    uint_t thresh;
00620    bool_t duplicateFlag;
00621    bool_t updateFlag;
00622 
00623    //If the ACK bit is off drop the segment and return
00624    if(!(segment->flags & TCP_FLAG_ACK))
00625       return ERROR_FAILURE;
00626 
00627    //Test the case where SEG.ACK < SND.UNA
00628    if(TCP_CMP_SEQ(segment->ackNum, socket->sndUna) < 0)
00629    {
00630       //An old duplicate ACK has been received
00631       return NO_ERROR;
00632    }
00633    //Test the case where SEG.ACK > SND.NXT
00634    else if(TCP_CMP_SEQ(segment->ackNum, socket->sndNxt) > 0)
00635    {
00636       //Send an ACK segment indicating the current send sequence number
00637       //and the acknowledgment number expected to be received
00638       tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0, FALSE);
00639 
00640       //The ACK segment acknowledges something not yet sent
00641       return ERROR_FAILURE;
00642    }
00643 
00644    //Check whether the ACK is a duplicate
00645    duplicateFlag = tcpIsDuplicateAck(socket, segment, length);
00646 
00647    //The send window should be updated
00648    tcpUpdateSendWindow(socket, segment);
00649 
00650    //The incoming ACK segment acknowledges new data?
00651    if(TCP_CMP_SEQ(segment->ackNum, socket->sndUna) > 0)
00652    {
00653 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
00654       //Compute the number of bytes acknowledged by the incoming ACK
00655       n = segment->ackNum - socket->sndUna;
00656 
00657       //Check whether the ACK segment acknowledges our SYN
00658       if(socket->sndUna == socket->iss)
00659          n--;
00660 
00661       //Total number of bytes acknowledged during the whole round-trip
00662       socket->n += n;
00663 #endif
00664       //Update SND.UNA pointer
00665       socket->sndUna = segment->ackNum;
00666 
00667       //Compute retransmission timeout
00668       updateFlag = tcpComputeRto(socket);
00669 
00670       //Any segments on the retransmission queue which are thereby
00671       //entirely acknowledged are removed
00672       tcpUpdateRetransmitQueue(socket);
00673 
00674 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
00675       //Check congestion state
00676       if(socket->congestState == TCP_CONGEST_STATE_RECOVERY)
00677       {
00678          //Invoke fast recovery (refer to RFC 6582)
00679          tcpFastRecovery(socket, segment, n);
00680       }
00681       else
00682       {
00683          //Reset duplicate ACK counter
00684          socket->dupAckCount = 0;
00685 
00686          //Check congestion state
00687          if(socket->congestState == TCP_CONGEST_STATE_LOSS_RECOVERY)
00688          {
00689             //Invoke fast loss recovery
00690             tcpFastLossRecovery(socket, segment);
00691          }
00692 
00693          //Slow start algorithm is used when cwnd is lower than ssthresh
00694          if(socket->cwnd < socket->ssthresh)
00695          {
00696             //During slow start, TCP increments cwnd by at most SMSS bytes
00697             //for each ACK received that cumulatively acknowledges new data
00698             socket->cwnd += MIN(n, socket->smss);
00699          }
00700          //Congestion avoidance algorithm is used when cwnd exceeds ssthres
00701          else
00702          {
00703             //Congestion window is updated once per RTT
00704             if(updateFlag)
00705             {
00706                //TCP must not increment cwnd by more than SMSS bytes
00707                socket->cwnd += MIN(socket->n, socket->smss);
00708             }
00709          }
00710       }
00711 
00712       //Limit the size of the congestion window
00713       socket->cwnd = MIN(socket->cwnd, socket->txBufferSize);
00714 #endif
00715    }
00716    //The incoming ACK segment does not acknowledge new data?
00717    else
00718    {
00719 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
00720       //Check whether the acknowledgment is a duplicate
00721       if(duplicateFlag)
00722       {
00723          //Increment duplicate ACK counter
00724          socket->dupAckCount++;
00725          //Debug message
00726          TRACE_INFO("TCP duplicate ACK #%u\r\n", socket->dupAckCount);
00727       }
00728       else
00729       {
00730          //Reset duplicate ACK counter
00731          socket->dupAckCount = 0;
00732       }
00733 
00734       //Check congestion state
00735       if(socket->congestState == TCP_CONGEST_STATE_IDLE)
00736       {
00737          //Use default duplicate ACK threshold
00738          thresh = TCP_FAST_RETRANSMIT_THRES;
00739          //Amount of data sent but not yet acknowledged
00740          ownd = socket->sndNxt - socket->sndUna;
00741 
00742          //Test if there is either no unsent data ready for transmission at
00743          //the sender, or the advertised receive window does not permit new
00744          //segments to be transmitted (refer to RFC 5827 section 3.1)
00745          if(socket->sndUser == 0 || socket->sndWnd <= (socket->sndNxt - socket->sndUna))
00746          {
00747             //Compute the duplicate ACK threshold used to trigger a
00748             //retransmission
00749             if(ownd <= (3 * socket->smss))
00750                thresh = 1;
00751             else if(ownd <= (4 * socket->smss))
00752                thresh = 2;
00753          }
00754 
00755          //Check the number of duplicate ACKs that have been received
00756          if(socket->dupAckCount >= thresh)
00757          {
00758             //The TCP sender first checks the value of recover to see if the
00759             //cumulative acknowledgment field covers more than recover
00760             if(TCP_CMP_SEQ(segment->ackNum, socket->recover + 1) > 0)
00761             {
00762                //Invoke Fast Retransmit (refer to RFC 6582)
00763                tcpFastRetransmit(socket);
00764             }
00765             else
00766             {
00767                //If not, the TCP does not enter fast retransmit and does not
00768                //reset ssthres...
00769             }
00770          }
00771       }
00772       else if(socket->congestState == TCP_CONGEST_STATE_RECOVERY)
00773       {
00774          //Duplicate ACK received?
00775          if(duplicateFlag)
00776          {
00777             //For each additional duplicate ACK received (after the third),
00778             //cwnd must be incremented by SMSS. This artificially inflates
00779             //the congestion window in order to reflect the additional
00780             //segment that has left the network
00781             socket->cwnd += socket->smss;
00782          }
00783       }
00784 
00785       //Limit the size of the congestion window
00786       socket->cwnd = MIN(socket->cwnd, socket->txBufferSize);
00787 #endif
00788    }
00789 
00790    //Update TX events
00791    tcpUpdateEvents(socket);
00792 
00793    //No error to report
00794    return NO_ERROR;
00795 }
00796 
00797 
00798 /**
00799  * @brief Test whether the incoming acknowledgment is a duplicate
00800  * @param[in] socket Handle referencing the current socket
00801  * @param[in] segment Pointer to the TCP segment to check
00802  * @param[in] length Length of the segment data
00803  * @return TRUE if the ACK is duplicate, else FALSE
00804  **/
00805 
00806 bool_t tcpIsDuplicateAck(Socket *socket, TcpHeader *segment, size_t length)
00807 {
00808    //An ACK is considered a duplicate when the following conditions are met
00809    bool_t flag = FALSE;
00810 
00811    //The receiver of the ACK has outstanding data
00812    if(socket->retransmitQueue != NULL)
00813    {
00814       //The incoming acknowledgment carries no data
00815       if(length == 0)
00816       {
00817          //the SYN and FIN bits are both off
00818          if(!(segment->flags & (TCP_FLAG_SYN | TCP_FLAG_FIN)))
00819          {
00820             //The acknowledgment number is equal to the greatest
00821             //acknowledgment received on the given connection
00822             if(segment->ackNum == socket->sndUna)
00823             {
00824                //The advertised window in the incoming acknowledgment equals the
00825                //advertised window in the last incoming acknowledgment
00826                if(segment->window == socket->sndWnd)
00827                {
00828                   //Duplicate ACK
00829                   flag = TRUE;
00830                }
00831             }
00832          }
00833       }
00834    }
00835 
00836    //Return TRUE if the acknowledgment is a duplicate
00837    return flag;
00838 }
00839 
00840 
00841 /**
00842  * @brief Fast retransmit procedure
00843  * @param[in] socket Handle referencing the current socket
00844  **/
00845 
00846 void tcpFastRetransmit(Socket *socket)
00847 {
00848 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
00849    uint_t flightSize;
00850 
00851    //Amount of data that has been sent but not yet acknowledged
00852    flightSize = socket->sndNxt - socket->sndUna;
00853    //After receiving 3 duplicate ACKs, ssthresh must be adjusted
00854    socket->ssthresh = MAX(flightSize / 2, 2 * socket->smss);
00855 
00856    //The value of recover is incremented to the value of the highest
00857    //sequence number transmitted by the TCP so far
00858    socket->recover = socket->sndNxt - 1;
00859 
00860    //Debug message
00861    TRACE_INFO("TCP fast retransmit...\r\n");
00862 
00863    //TCP performs a retransmission of what appears to be the missing segment,
00864    //without waiting for the retransmission timer to expire
00865    tcpRetransmitSegment(socket);
00866 
00867    //cwnd must set to ssthresh plus 3*SMSS. This artificially inflates the
00868    //congestion window by the number of segments (three) that have left
00869    //the network and which the receiver has buffered
00870    socket->cwnd = socket->ssthresh + TCP_FAST_RETRANSMIT_THRES * socket->smss;
00871 
00872    //Enter the fast recovery procedure
00873    socket->congestState = TCP_CONGEST_STATE_RECOVERY;
00874 #endif
00875 }
00876 
00877 
00878 /**
00879  * @brief Fast recovery procedure
00880  * @param[in] socket Handle referencing the current socket
00881  * @param[in] segment Pointer to the incoming TCP segment
00882  * @param[in] n Number of bytes acknowledged by the incoming ACK
00883  **/
00884 
00885 void tcpFastRecovery(Socket *socket, TcpHeader *segment, uint_t n)
00886 {
00887 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
00888    //Check whether this ACK acknowledges all of the data up to and
00889    //including recover
00890    if(TCP_CMP_SEQ(segment->ackNum, socket->recover) > 0)
00891    {
00892       //This is a full acknowledgment
00893       TRACE_INFO("TCP full acknowledgment\r\n");
00894 
00895       //Set cwnd to ssthresh
00896       socket->cwnd = socket->ssthresh;
00897       //Exit the fast recovery procedure
00898       socket->congestState = TCP_CONGEST_STATE_IDLE;
00899    }
00900    else
00901    {
00902       //If this ACK does not acknowledge all of the data up to and including
00903       //recover, then this is a partial ACK
00904       TRACE_INFO("TCP partial acknowledgment\r\n");
00905 
00906       //Retransmit the first unacknowledged segment
00907       tcpRetransmitSegment(socket);
00908 
00909       //Deflate the congestion window by the amount of new data acknowledged
00910       //by the cumulative acknowledgment field
00911       if(socket->cwnd > n)
00912          socket->cwnd -= n;
00913 
00914       //If the partial ACK acknowledges at least one SMSS of new data, then
00915       //add back SMSS bytes to the congestion window. This artificially
00916       //inflates the congestion window in order to reflect the additional
00917       //segment that has left the network
00918       if(n >= socket->smss)
00919          socket->cwnd += socket->smss;
00920 
00921       //Do not exit the fast recovery procedure...
00922       socket->congestState = TCP_CONGEST_STATE_RECOVERY;
00923    }
00924 #endif
00925 }
00926 
00927 
00928 /**
00929  * @brief Fast loss recovery procedure
00930  * @param[in] socket Handle referencing the current socket
00931  * @param[in] segment Pointer to the incoming TCP segment
00932  **/
00933 
00934 void tcpFastLossRecovery(Socket *socket, TcpHeader *segment)
00935 {
00936 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
00937    //Check whether this ACK acknowledges all of the data up to and
00938    //including recover
00939    if(TCP_CMP_SEQ(segment->ackNum, socket->recover) > 0)
00940    {
00941       //This is a full acknowledgment
00942       TRACE_INFO("TCP full acknowledgment\r\n");
00943 
00944       //Exit the fast loss recovery procedure
00945       socket->congestState = TCP_CONGEST_STATE_IDLE;
00946    }
00947    else
00948    {
00949       //If this ACK does not acknowledge all of the data up to and including
00950       //recover, then this is a partial ACK
00951       TRACE_INFO("TCP partial acknowledgment\r\n");
00952 
00953       //Retransmit the first unacknowledged segment
00954       tcpRetransmitSegment(socket);
00955 
00956       //Do not exit the fast loss recovery procedure...
00957       socket->congestState = TCP_CONGEST_STATE_LOSS_RECOVERY;
00958    }
00959 #endif
00960 }
00961 
00962 
00963 /**
00964  * @brief Process the segment text
00965  * @param[in] socket Handle referencing the current socket
00966  * @param[in] segment Pointer to the TCP header
00967  * @param[in] buffer Multi-part buffer containing the incoming TCP segment
00968  * @param[in] offset Offset to the first data byte
00969  * @param[in] length Length of the segment data
00970  **/
00971 
00972 void tcpProcessSegmentData(Socket *socket, TcpHeader *segment,
00973    const NetBuffer *buffer, size_t offset, size_t length)
00974 {
00975    uint32_t leftEdge;
00976    uint32_t rightEdge;
00977 
00978    //First sequence number occupied by the incoming segment
00979    leftEdge = segment->seqNum;
00980    //Sequence number immediately following the incoming segment
00981    rightEdge = segment->seqNum + length;
00982 
00983    //Check whether some data falls outside the receive window
00984    if(TCP_CMP_SEQ(leftEdge, socket->rcvNxt) < 0)
00985    {
00986       //Position of the first byte to be read
00987       offset += socket->rcvNxt - leftEdge;
00988       //Ignore the data that falls outside the receive window
00989       leftEdge = socket->rcvNxt;
00990    }
00991    if(TCP_CMP_SEQ(rightEdge, socket->rcvNxt + socket->rcvWnd) > 0)
00992    {
00993       //Ignore the data that falls outside the receive window
00994       rightEdge = socket->rcvNxt + socket->rcvWnd;
00995    }
00996 
00997    //Copy the incoming data to the receive buffer
00998    tcpWriteRxBuffer(socket, leftEdge, buffer, offset, rightEdge - leftEdge);
00999 
01000    //Update the list of non-contiguous blocks of data that
01001    //have been received and queued
01002    tcpUpdateSackBlocks(socket, &leftEdge, &rightEdge);
01003 
01004    //Check whether the segment was received out of order
01005    if(TCP_CMP_SEQ(leftEdge, socket->rcvNxt) > 0)
01006    {
01007       //Out of order data segments should be acknowledged
01008       //immediately, in order to accelerate loss recovery
01009       tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0, FALSE);
01010    }
01011    else
01012    {
01013       //Number of contiguous bytes that have been received
01014       length = rightEdge - leftEdge;
01015 
01016       //Next sequence number expected on incoming segments
01017       socket->rcvNxt += length;
01018       //Number of data available in the receive buffer
01019       socket->rcvUser += length;
01020       //Update the receive window
01021       socket->rcvWnd -= length;
01022 
01023       //Acknowledge the received data (delayed ACK not supported)
01024       tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0, FALSE);
01025       //Notify user task that data is available
01026       tcpUpdateEvents(socket);
01027    }
01028 }
01029 
01030 
01031 /**
01032  * @brief Delete TCB structure
01033  * @param[in] socket Handle referencing the socket
01034  **/
01035 
01036 void tcpDeleteControlBlock(Socket *socket)
01037 {
01038    //Delete retransmission queue
01039    tcpFlushRetransmitQueue(socket);
01040 
01041    //Delete SYN queue
01042    tcpFlushSynQueue(socket);
01043 
01044    //Release transmit buffer
01045    netBufferSetLength((NetBuffer *) &socket->txBuffer, 0);
01046 
01047    //Release receive buffer
01048    netBufferSetLength((NetBuffer *) &socket->rxBuffer, 0);
01049 }
01050 
01051 
01052 /**
01053  * @brief Remove acknowledged segments from retransmission queue
01054  * @param[in] socket Handle referencing the socket
01055  **/
01056 
01057 void tcpUpdateRetransmitQueue(Socket *socket)
01058 {
01059    size_t length;
01060    TcpQueueItem *prevQueueItem;
01061    TcpQueueItem *queueItem;
01062    TcpHeader *header;
01063 
01064    //Point to the first item of the retransmission queue
01065    prevQueueItem = NULL;
01066    queueItem = socket->retransmitQueue;
01067 
01068    //Loop through retransmission queue
01069    while(queueItem != NULL)
01070    {
01071       //Point to the TCP header
01072       header = (TcpHeader *) queueItem->header;
01073 
01074       //SYN segment?
01075       if(header->flags & TCP_FLAG_SYN)
01076          length = 1;
01077       //FIN segment?
01078       else if(header->flags & TCP_FLAG_FIN)
01079          length = queueItem->length + 1;
01080       //Segment containing data?
01081       else
01082          length = queueItem->length;
01083 
01084       //If an acknowledgment is received for a segment before its timer
01085       //expires, the segment is removed from the retransmission queue
01086       if(TCP_CMP_SEQ(socket->sndUna, ntohl(header->seqNum) + length) >= 0)
01087       {
01088          //First item of the queue?
01089          if(prevQueueItem == NULL)
01090          {
01091             //Remove the current item from the queue
01092             socket->retransmitQueue = queueItem->next;
01093             //The item can now be safely deleted
01094             memPoolFree(queueItem);
01095             //Point to the next item
01096             queueItem = socket->retransmitQueue;
01097          }
01098          else
01099          {
01100             //Remove the current item from the queue
01101             prevQueueItem->next = queueItem->next;
01102             //The item can now be safely deleted
01103             memPoolFree(queueItem);
01104             //Point to the next item
01105             queueItem = prevQueueItem->next;
01106          }
01107 
01108          //When an ACK is received that acknowledges new data, restart the
01109          //retransmission timer so that it will expire after RTO seconds
01110          tcpTimerStart(&socket->retransmitTimer, socket->rto);
01111          //Reset retransmission counter
01112          socket->retransmitCount = 0;
01113       }
01114       //No acknowledgment received for the current segment...
01115       else
01116       {
01117          //Point to the next item
01118          prevQueueItem = queueItem;
01119          queueItem = queueItem->next;
01120       }
01121    }
01122 
01123    //When all outstanding data has been acknowledged,
01124    //turn off the retransmission timer
01125    if(socket->retransmitQueue == NULL)
01126       tcpTimerStop(&socket->retransmitTimer);
01127 }
01128 
01129 
01130 /**
01131  * @brief Flush retransmission queue
01132  * @param[in] socket Handle referencing the socket
01133  **/
01134 
01135 void tcpFlushRetransmitQueue(Socket *socket)
01136 {
01137    //Point to the first item in the retransmission queue
01138    TcpQueueItem *queueItem = socket->retransmitQueue;
01139 
01140    //Loop through retransmission queue
01141    while(queueItem != NULL)
01142    {
01143       //Keep track of the next item in the queue
01144       TcpQueueItem *nextQueueItem = queueItem->next;
01145       //Free previously allocated memory
01146       memPoolFree(queueItem);
01147       //Point to the next item
01148       queueItem = nextQueueItem;
01149    }
01150 
01151    //The retransmission queue is now flushed
01152    socket->retransmitQueue = NULL;
01153 
01154    //Turn off the retransmission timer
01155    tcpTimerStop(&socket->retransmitTimer);
01156 }
01157 
01158 
01159 /**
01160  * @brief Flush SYN queue
01161  * @param[in] socket Handle referencing the socket
01162  **/
01163 
01164 void tcpFlushSynQueue(Socket *socket)
01165 {
01166    //Point to the first item in the SYN queue
01167    TcpSynQueueItem *queueItem = socket->synQueue;
01168 
01169    //Loop through SYN queue
01170    while(queueItem != NULL)
01171    {
01172       //Keep track of the next item in the queue
01173       TcpSynQueueItem *nextQueueItem = queueItem->next;
01174       //Free previously allocated memory
01175       memPoolFree(queueItem);
01176       //Point to the next item
01177       queueItem = nextQueueItem;
01178    }
01179 
01180    //SYN queue was successfully flushed
01181    socket->synQueue = NULL;
01182 }
01183 
01184 
01185 /**
01186  * @brief Update the list of non-contiguous blocks that have been received
01187  * @param[in] socket Handle referencing the socket
01188  * @param[in,out] leftEdge First sequence number occupied by the incoming data
01189  * @param[in,out] rightEdge Sequence number immediately following the incoming data
01190  **/
01191 
01192 void tcpUpdateSackBlocks(Socket *socket, uint32_t *leftEdge, uint32_t *rightEdge)
01193 {
01194    uint_t i = 0;
01195 
01196    //Loop through the blocks
01197    while(i < socket->sackBlockCount)
01198    {
01199       //Find each block that overlaps the specified one
01200       if(TCP_CMP_SEQ(*rightEdge, socket->sackBlock[i].leftEdge) >= 0 &&
01201          TCP_CMP_SEQ(*leftEdge, socket->sackBlock[i].rightEdge) <= 0)
01202       {
01203          //Merge blocks to form a contiguous one
01204          *leftEdge = MIN(*leftEdge, socket->sackBlock[i].leftEdge);
01205          *rightEdge = MAX(*rightEdge, socket->sackBlock[i].rightEdge);
01206 
01207          //Delete current block
01208          memmove(socket->sackBlock + i, socket->sackBlock + i + 1,
01209             (TCP_MAX_SACK_BLOCKS - i - 1) * sizeof(TcpSackBlock));
01210 
01211          //Decrement the number of non-contiguous blocks
01212          socket->sackBlockCount--;
01213       }
01214       else
01215       {
01216          //Point to the next block
01217          i++;
01218       }
01219    }
01220 
01221    //Check whether the incoming segment was received out of order
01222    if(TCP_CMP_SEQ(*leftEdge, socket->rcvNxt) > 0)
01223    {
01224       //Make room for the new non-contiguous block
01225       memmove(socket->sackBlock + 1, socket->sackBlock,
01226          (TCP_MAX_SACK_BLOCKS - 1) * sizeof(TcpSackBlock));
01227 
01228       //Insert the element in the list
01229       socket->sackBlock[0].leftEdge = *leftEdge;
01230       socket->sackBlock[0].rightEdge = *rightEdge;
01231 
01232       //Increment the number of non-contiguous blocks
01233       if(socket->sackBlockCount < TCP_MAX_SACK_BLOCKS)
01234          socket->sackBlockCount++;
01235    }
01236 }
01237 
01238 
01239 /**
01240  * @brief Update send window
01241  * @param[in] socket Handle referencing the socket
01242  * @param[in] segment Pointer to the incoming TCP segment
01243  **/
01244 
01245 void tcpUpdateSendWindow(Socket *socket, TcpHeader *segment)
01246 {
01247    //Case where neither the sequence nor the acknowledgment number is increased
01248    if(segment->seqNum == socket->sndWl1 && segment->ackNum == socket->sndWl2)
01249    {
01250       //TCP may ignore a window update with a smaller window than
01251       //previously offered if neither the sequence number nor the
01252       //acknowledgment number is increased (see RFC 1122 4.2.2.16)
01253       if(segment->window > socket->sndWnd)
01254       {
01255          //Update the send window and record the sequence number and
01256          //the acknowledgment number used to update SND.WND
01257          socket->sndWnd = segment->window;
01258          socket->sndWl1 = segment->seqNum;
01259          socket->sndWl2 = segment->ackNum;
01260 
01261          //Maximum send window it has seen so far on the connection
01262          socket->maxSndWnd = MAX(socket->maxSndWnd, segment->window);
01263       }
01264    }
01265    //Case where the sequence or the acknowledgment number is increased
01266    else if(TCP_CMP_SEQ(segment->seqNum, socket->sndWl1) >= 0 &&
01267       TCP_CMP_SEQ(segment->ackNum, socket->sndWl2) >= 0)
01268    {
01269       //The remote host advertises a zero window?
01270       if(!segment->window && socket->sndWnd)
01271       {
01272          //Start the persist timer
01273          socket->wndProbeCount = 0;
01274          socket->wndProbeInterval = TCP_DEFAULT_PROBE_INTERVAL;
01275          tcpTimerStart(&socket->persistTimer, socket->wndProbeInterval);
01276       }
01277 
01278       //Update the send window and record the sequence number and
01279       //the acknowledgment number used to update SND.WND
01280       socket->sndWnd = segment->window;
01281       socket->sndWl1 = segment->seqNum;
01282       socket->sndWl2 = segment->ackNum;
01283 
01284       //Maximum send window it has seen so far on the connection
01285       socket->maxSndWnd = MAX(socket->maxSndWnd, segment->window);
01286    }
01287 }
01288 
01289 
01290 /**
01291  * @brief Update receive window so as to avoid Silly Window Syndrome
01292  * @param[in] socket Handle referencing the socket
01293  **/
01294 
01295 void tcpUpdateReceiveWindow(Socket *socket)
01296 {
01297    uint16_t reduction;
01298 
01299    //Space available but not yet advertised
01300    reduction = socket->rxBufferSize - socket->rcvUser - socket->rcvWnd;
01301 
01302    //To avoid SWS, the receiver should not advertise small windows
01303    if((socket->rcvWnd + reduction) >= MIN(socket->rmss, socket->rxBufferSize / 2))
01304    {
01305       //Check whether a window update should be sent
01306       if(socket->rcvWnd < MIN(socket->rmss, socket->rxBufferSize / 2))
01307       {
01308          //Debug message
01309          TRACE_INFO("%s: TCP sending window update...\r\n",
01310             formatSystemTime(osGetSystemTime(), NULL));
01311 
01312          //Update the receive window
01313          socket->rcvWnd += reduction;
01314          //Send an ACK segment to advertise the new window size
01315          tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0, FALSE);
01316       }
01317       else
01318       {
01319          //The receive window can be updated
01320          socket->rcvWnd += reduction;
01321       }
01322    }
01323 }
01324 
01325 
01326 /**
01327  * @brief Compute retransmission timeout
01328  * @param[in] socket Handle referencing the socket
01329  * @return TRUE if the RTT measurement is complete, else FALSE
01330  **/
01331 
01332 bool_t tcpComputeRto(Socket *socket)
01333 {
01334    bool_t flag;
01335    systime_t r;
01336    systime_t delta;
01337 
01338    //Clear flag
01339    flag = FALSE;
01340 
01341    //TCP implementation takes one RTT measurement at a time
01342    if(socket->rttBusy)
01343    {
01344       //Ensure the incoming ACK number covers the expected sequence number
01345       if(TCP_CMP_SEQ(socket->sndUna, socket->rttSeqNum) > 0)
01346       {
01347          //Calculate round-time trip
01348          r = osGetSystemTime() - socket->rttStartTime;
01349 
01350          //First RTT measurement?
01351          if(!socket->srtt && !socket->rttvar)
01352          {
01353             //Initialize RTO calculation algorithm
01354             socket->srtt = r;
01355             socket->rttvar = r / 2;
01356          }
01357          else
01358          {
01359             //Calculate the difference between the measured value and the
01360             //current RTT estimator
01361             delta = (r > socket->srtt) ? (r - socket->srtt) : (socket->srtt - r);
01362 
01363             //Implement Van Jacobson's algorithm (as specified in RFC 6298 2.3)
01364             socket->rttvar = (3 * socket->rttvar + delta) / 4;
01365             socket->srtt = (7 * socket->srtt + r) / 8;
01366          }
01367 
01368          //Calculate the next retransmission timeout
01369          socket->rto = socket->srtt + 4 * socket->rttvar;
01370 
01371          //Whenever RTO is computed, if it is less than 1 second, then
01372          //the RTO should be rounded up to 1 second
01373          socket->rto = MAX(socket->rto, TCP_MIN_RTO);
01374          //A maximum value may be placed on RTO provided it is at least 60 seconds
01375          socket->rto = MIN(socket->rto, TCP_MAX_RTO);
01376 
01377          //Debug message
01378          TRACE_DEBUG("R=%" PRIu32 ", SRTT=%" PRIu32 ", RTTVAR=%" PRIu32 ", RTO=%" PRIu32 "\r\n",
01379             r, socket->srtt, socket->rttvar, socket->rto);
01380 
01381          //RTT measurement is complete
01382          socket->rttBusy = FALSE;
01383          //Set flag
01384          flag = TRUE;
01385       }
01386    }
01387 
01388    //Return TRUE if the RTT measurement is complete
01389    return flag;
01390 }
01391 
01392 
01393 /**
01394  * @brief TCP segment retransmission
01395  * @param[in] socket Handle referencing the socket
01396  * @return Error code
01397  **/
01398 
01399 error_t tcpRetransmitSegment(Socket *socket)
01400 {
01401    error_t error;
01402    size_t offset;
01403    size_t length;
01404    NetBuffer *buffer;
01405    TcpQueueItem *queueItem;
01406    TcpHeader *header;
01407 
01408    //Initialize error code
01409    error = NO_ERROR;
01410    //Total number of bytes that have been retransmitted
01411    length = 0;
01412 
01413    //Point to the retransmission queue
01414    queueItem = socket->retransmitQueue;
01415 
01416    //Any segment in the retransmission queue?
01417    while(queueItem != NULL)
01418    {
01419       //Total number of bytes that have been retransmitted
01420       length += queueItem->length;
01421 
01422       //The amount of data that can be sent cannot exceed the MSS
01423       if(length > socket->smss)
01424       {
01425          //We are done
01426          error = NO_ERROR;
01427          //Exit immediately
01428          break;
01429       }
01430 
01431       //Point to the TCP header
01432       header = (TcpHeader *) queueItem->header;
01433 
01434       //Allocate a memory buffer to hold the TCP segment
01435       buffer = ipAllocBuffer(0, &offset);
01436       //Failed to allocate memory?
01437       if(buffer == NULL)
01438       {
01439          //Report an error
01440          error = ERROR_OUT_OF_MEMORY;
01441          //Exit immediately
01442          break;
01443       }
01444 
01445       //Start of exception handling block
01446       do
01447       {
01448          //Copy TCP header
01449          error = netBufferAppend(buffer, header, header->dataOffset * 4);
01450          //Any error to report?
01451          if(error)
01452             break;
01453 
01454          //Copy data from send buffer
01455          error = tcpReadTxBuffer(socket, ntohl(header->seqNum), buffer, queueItem->length);
01456          //Any error to report?
01457          if(error)
01458             break;
01459 
01460          //Total number of segments retransmitted
01461          MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpRetransSegs, 1);
01462 
01463          //Dump TCP header contents for debugging purpose
01464          tcpDumpHeader(header, queueItem->length, socket->iss, socket->irs);
01465 
01466          //Retransmit the lost segment without waiting for the
01467          //retransmission timer to expire
01468          error = ipSendDatagram(socket->interface,
01469             &queueItem->pseudoHeader, buffer, offset, 0);
01470 
01471          //End of exception handling block
01472       } while(0);
01473 
01474       //Free previously allocated memory
01475       netBufferFree(buffer);
01476 
01477       //Any error to report?
01478       if(error)
01479       {
01480          //Exit immediately
01481          break;
01482       }
01483 
01484       //Point to the next segment in the queue
01485       queueItem = queueItem->next;
01486    }
01487 
01488    //Return status code
01489    return error;
01490 }
01491 
01492 
01493 /**
01494  * @brief Nagle algorithm implementation
01495  * @param[in] socket Handle referencing the socket
01496  * @param[in] flags Set of flags that influences the behavior of this function
01497  * @return Error code
01498  **/
01499 
01500 error_t tcpNagleAlgo(Socket *socket, uint_t flags)
01501 {
01502    error_t error;
01503    uint_t n;
01504    uint_t u;
01505 
01506    //The amount of data that can be sent at any given time is
01507    //limited by the receiver window and the congestion window
01508    n = MIN(socket->sndWnd, socket->txBufferSize);
01509 
01510 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
01511    //Check the congestion window
01512    n = MIN(n, socket->cwnd);
01513 #endif
01514 
01515    //Retrieve the size of the usable window
01516    u = n - (socket->sndNxt - socket->sndUna);
01517 
01518    //The remote host should not shrink its window. However, we
01519    //must be robust against window shrinking, which may cause
01520    //the usable window to become negative
01521    if((int_t) u < 0)
01522       return NO_ERROR;
01523 
01524    //The Nagle algorithm discourages sending tiny segments when
01525    //the data to be sent increases in small increments
01526    while(socket->sndUser > 0)
01527    {
01528       //Calculate the number of bytes to send at a time
01529       n = MIN(u, socket->sndUser);
01530       n = MIN(n, socket->smss);
01531 
01532       //Disable Nagle algorithm?
01533       if(flags & SOCKET_FLAG_NO_DELAY)
01534       {
01535          //All packets will be send no matter what size they have
01536          if(n > 0)
01537          {
01538             //Send TCP segment
01539             error = tcpSendSegment(socket, TCP_FLAG_PSH | TCP_FLAG_ACK,
01540                socket->sndNxt, socket->rcvNxt, n, TRUE);
01541             //Failed to send TCP segment?
01542             if(error)
01543                return error;
01544          }
01545          else
01546          {
01547             //We are done...
01548             break;
01549          }
01550       }
01551       else if(flags & SOCKET_FLAG_DELAY)
01552       {
01553          //Transmit data if a maximum-sized segment can be sent
01554          if(MIN(socket->sndUser, u) >= socket->smss)
01555          {
01556             //Send TCP segment
01557             error = tcpSendSegment(socket, TCP_FLAG_PSH | TCP_FLAG_ACK,
01558                socket->sndNxt, socket->rcvNxt, n, TRUE);
01559             //Failed to send TCP segment?
01560             if(error)
01561                return error;
01562          }
01563          else
01564          {
01565             //Prevent the sender from sending tiny segments...
01566             break;
01567          }
01568       }
01569       else
01570       {
01571          //Transmit data if a maximum-sized segment can be sent
01572          if(MIN(socket->sndUser, u) >= socket->smss)
01573          {
01574             //Send TCP segment
01575             error = tcpSendSegment(socket, TCP_FLAG_PSH | TCP_FLAG_ACK,
01576                socket->sndNxt, socket->rcvNxt, n, TRUE);
01577             //Failed to send TCP segment?
01578             if(error)
01579                return error;
01580          }
01581          //Or if all queued data can be sent now
01582          else if(socket->sndNxt == socket->sndUna && socket->sndUser <= u)
01583          {
01584             //Send TCP segment
01585             error = tcpSendSegment(socket, TCP_FLAG_PSH | TCP_FLAG_ACK,
01586                socket->sndNxt, socket->rcvNxt, n, TRUE);
01587             //Failed to send TCP segment?
01588             if(error)
01589                return error;
01590          }
01591          //Or if at least a fraction of the maximum window can be sent
01592          else if(MIN(socket->sndUser, u) >= (socket->maxSndWnd / 2))
01593          {
01594             //Send TCP segment
01595             error = tcpSendSegment(socket, TCP_FLAG_PSH | TCP_FLAG_ACK,
01596                socket->sndNxt, socket->rcvNxt, n, TRUE);
01597             //Failed to send TCP segment?
01598             if(error)
01599                return error;
01600          }
01601          else
01602          {
01603             //Prevent the sender from sending tiny segments...
01604             break;
01605          }
01606       }
01607 
01608       //Advance SND.NXT pointer
01609       socket->sndNxt += n;
01610       //Update the number of data buffered but not yet sent
01611       socket->sndUser -= n;
01612       //Update the size of the usable window
01613       u -= n;
01614    }
01615 
01616    //Check whether the transmitter can accept more data
01617    tcpUpdateEvents(socket);
01618 
01619    //No error to report
01620    return NO_ERROR;
01621 }
01622 
01623 
01624 /**
01625  * @brief Update TCP FSM current state
01626  * @param[in] socket Handle referencing the socket
01627  * @param[in] newState New TCP state to switch to
01628  **/
01629 
01630 void tcpChangeState(Socket *socket, TcpState newState)
01631 {
01632    //Enter CLOSED state?
01633    if(newState == TCP_STATE_CLOSED)
01634    {
01635       //Check previous state
01636       if(socket->state == TCP_STATE_LAST_ACK ||
01637          socket->state == TCP_STATE_TIME_WAIT)
01638       {
01639          //The connection has been closed properly
01640          socket->closedFlag = TRUE;
01641       }
01642       else
01643       {
01644          //The connection has been reset by the peer
01645          socket->resetFlag = TRUE;
01646       }
01647    }
01648 
01649    //Enter the desired state
01650    socket->state = newState;
01651    //Update TCP related events
01652    tcpUpdateEvents(socket);
01653 }
01654 
01655 
01656 /**
01657  * @brief Update TCP related events
01658  * @param[in] socket Handle referencing the socket
01659  **/
01660 
01661 void tcpUpdateEvents(Socket *socket)
01662 {
01663    //Clear event flags
01664    socket->eventFlags = 0;
01665 
01666    //Check current TCP state
01667    switch(socket->state)
01668    {
01669    //ESTABLISHED or FIN-WAIT-1 state?
01670    case TCP_STATE_ESTABLISHED:
01671    case TCP_STATE_FIN_WAIT_1:
01672       socket->eventFlags |= SOCKET_EVENT_CONNECTED;
01673       break;
01674    //FIN-WAIT-2 state?
01675    case TCP_STATE_FIN_WAIT_2:
01676       socket->eventFlags |= SOCKET_EVENT_CONNECTED;
01677       socket->eventFlags |= SOCKET_EVENT_TX_SHUTDOWN;
01678       break;
01679    //CLOSE-WAIT, LAST-ACK or CLOSING state?
01680    case TCP_STATE_CLOSE_WAIT:
01681    case TCP_STATE_LAST_ACK:
01682    case TCP_STATE_CLOSING:
01683       socket->eventFlags |= SOCKET_EVENT_CONNECTED;
01684       socket->eventFlags |= SOCKET_EVENT_RX_SHUTDOWN;
01685       break;
01686    //TIME-WAIT or CLOSED state?
01687    case TCP_STATE_TIME_WAIT:
01688    case TCP_STATE_CLOSED:
01689       socket->eventFlags |= SOCKET_EVENT_CLOSED;
01690       socket->eventFlags |= SOCKET_EVENT_TX_SHUTDOWN;
01691       socket->eventFlags |= SOCKET_EVENT_RX_SHUTDOWN;
01692       break;
01693    //Any other state
01694    default:
01695       break;
01696    }
01697 
01698    //Handle TX specific events
01699    if(socket->state == TCP_STATE_SYN_SENT ||
01700       socket->state == TCP_STATE_SYN_RECEIVED)
01701    {
01702       //Disallow write operations until the connection is established
01703       socket->eventFlags |= SOCKET_EVENT_TX_DONE;
01704       socket->eventFlags |= SOCKET_EVENT_TX_ACKED;
01705    }
01706    else if(socket->state == TCP_STATE_ESTABLISHED ||
01707       socket->state == TCP_STATE_CLOSE_WAIT)
01708    {
01709       //Check whether the send buffer is full or not
01710       if((socket->sndUser + socket->sndNxt - socket->sndUna) < socket->txBufferSize)
01711          socket->eventFlags |= SOCKET_EVENT_TX_READY;
01712 
01713       //Check whether all the data in the send buffer has been transmitted
01714       if(!socket->sndUser)
01715       {
01716          //All the pending data has been sent out
01717          socket->eventFlags |= SOCKET_EVENT_TX_DONE;
01718 
01719          //Check whether an acknowledgment has been received
01720          if(TCP_CMP_SEQ(socket->sndUna, socket->sndNxt) >= 0)
01721             socket->eventFlags |= SOCKET_EVENT_TX_ACKED;
01722       }
01723    }
01724    else if(socket->state != TCP_STATE_LISTEN)
01725    {
01726       //Unblock user task if the connection is being closed
01727       socket->eventFlags |= SOCKET_EVENT_TX_READY;
01728       socket->eventFlags |= SOCKET_EVENT_TX_DONE;
01729       socket->eventFlags |= SOCKET_EVENT_TX_ACKED;
01730    }
01731 
01732    //Handle RX specific events
01733    if(socket->state == TCP_STATE_ESTABLISHED ||
01734       socket->state == TCP_STATE_FIN_WAIT_1 ||
01735       socket->state == TCP_STATE_FIN_WAIT_2)
01736    {
01737       //Data is available for reading?
01738       if(socket->rcvUser > 0)
01739          socket->eventFlags |= SOCKET_EVENT_RX_READY;
01740    }
01741    else if(socket->state == TCP_STATE_LISTEN)
01742    {
01743       //If the socket is currently in the listen state, it will be marked
01744       //as readable if an incoming connection request has been received
01745       if(socket->synQueue)
01746          socket->eventFlags |= SOCKET_EVENT_RX_READY;
01747    }
01748    else if(socket->state != TCP_STATE_SYN_SENT &&
01749       socket->state != TCP_STATE_SYN_RECEIVED)
01750    {
01751       //Readability can also indicate that a request to close
01752       //the socket has been received from the peer
01753       socket->eventFlags |= SOCKET_EVENT_RX_READY;
01754    }
01755 
01756    //Check whether the socket is bound to a particular network interface
01757    if(socket->interface != NULL)
01758    {
01759       //Handle link up and link down events
01760       if(socket->interface->linkState)
01761          socket->eventFlags |= SOCKET_EVENT_LINK_UP;
01762       else
01763          socket->eventFlags |= SOCKET_EVENT_LINK_DOWN;
01764    }
01765 
01766    //Mask unused events
01767    socket->eventFlags &= socket->eventMask;
01768 
01769    //Any event to signal?
01770    if(socket->eventFlags)
01771    {
01772       //Unblock I/O operations currently in waiting state
01773       osSetEvent(&socket->event);
01774 
01775       //Set user event to signaled state if necessary
01776       if(socket->userEvent != NULL)
01777          osSetEvent(socket->userEvent);
01778    }
01779 }
01780 
01781 
01782 /**
01783  * @brief Wait for a particular TCP event
01784  * @param[in] socket Handle referencing the socket
01785  * @param[in] eventMask Logic OR of all the TCP events that will complete the wait
01786  * @param[in] timeout Maximum time to wait
01787  * @return Logic OR of all the TCP events that satisfied the wait
01788  **/
01789 
01790 uint_t tcpWaitForEvents(Socket *socket, uint_t eventMask, systime_t timeout)
01791 {
01792    //Sanity check
01793    if(socket == NULL)
01794       return 0;
01795 
01796    //Only one of the events listed here may complete the wait
01797    socket->eventMask = eventMask;
01798    //Update TCP related events
01799    tcpUpdateEvents(socket);
01800 
01801    //No event is signaled?
01802    if(!socket->eventFlags)
01803    {
01804       //Reset the event object
01805       osResetEvent(&socket->event);
01806 
01807       //Release exclusive access
01808       osReleaseMutex(&netMutex);
01809       //Wait until an event is triggered
01810       osWaitForEvent(&socket->event, timeout);
01811       //Get exclusive access
01812       osAcquireMutex(&netMutex);
01813    }
01814 
01815    //Return the list of TCP events that satisfied the wait
01816    return socket->eventFlags;
01817 }
01818 
01819 
01820 /**
01821  * @brief Copy incoming data to the send buffer
01822  * @param[in] socket Handle referencing the socket
01823  * @param[in] seqNum First sequence number occupied by the incoming data
01824  * @param[in] data Data to write
01825  * @param[in] length Number of data to write
01826  **/
01827 
01828 void tcpWriteTxBuffer(Socket *socket, uint32_t seqNum,
01829    const uint8_t *data, size_t length)
01830 {
01831    //Offset of the first byte to write in the circular buffer
01832    size_t offset = (seqNum - socket->iss - 1) % socket->txBufferSize;
01833 
01834    //Check whether the specified data crosses buffer boundaries
01835    if((offset + length) <= socket->txBufferSize)
01836    {
01837       //Copy the payload
01838       netBufferWrite((NetBuffer *) &socket->txBuffer,
01839          offset, data, length);
01840    }
01841    else
01842    {
01843       //Copy the first part of the payload
01844       netBufferWrite((NetBuffer *) &socket->txBuffer,
01845          offset, data, socket->txBufferSize - offset);
01846       //Wrap around to the beginning of the circular buffer
01847       netBufferWrite((NetBuffer *) &socket->txBuffer,
01848          0, data + socket->txBufferSize - offset, length - socket->txBufferSize + offset);
01849    }
01850 }
01851 
01852 
01853 /**
01854  * @brief Copy data from the send buffer
01855  * @param[in] socket Handle referencing the socket
01856  * @param[in] seqNum Sequence number of the first data to read
01857  * @param[out] buffer Pointer to the output buffer
01858  * @param[in] length Number of data to read
01859  * @return Error code
01860  **/
01861 
01862 error_t tcpReadTxBuffer(Socket *socket, uint32_t seqNum,
01863    NetBuffer *buffer, size_t length)
01864 {
01865    error_t error;
01866 
01867    //Offset of the first byte to read in the circular buffer
01868    size_t offset = (seqNum - socket->iss - 1) % socket->txBufferSize;
01869 
01870    //Check whether the specified data crosses buffer boundaries
01871    if((offset + length) <= socket->txBufferSize)
01872    {
01873       //Copy the payload
01874       error = netBufferConcat(buffer, (NetBuffer *) &socket->txBuffer,
01875          offset, length);
01876    }
01877    else
01878    {
01879       //Copy the first part of the payload
01880       error = netBufferConcat(buffer, (NetBuffer *) &socket->txBuffer,
01881          offset, socket->txBufferSize - offset);
01882 
01883       //Check status code
01884       if(!error)
01885       {
01886          //Wrap around to the beginning of the circular buffer
01887          error = netBufferConcat(buffer, (NetBuffer *) &socket->txBuffer,
01888             0, length - socket->txBufferSize + offset);
01889       }
01890    }
01891 
01892    //Return status code
01893    return error;
01894 }
01895 
01896 
01897 /**
01898  * @brief Copy incoming data to the receive buffer
01899  * @param[in] socket Handle referencing the socket
01900  * @param[in] seqNum First sequence number occupied by the incoming data
01901  * @param[in] data Multi-part buffer containing the incoming data
01902  * @param[in] dataOffset Offset to the first data byte
01903  * @param[in] length Number of data to write
01904  **/
01905 
01906 void tcpWriteRxBuffer(Socket *socket, uint32_t seqNum,
01907    const NetBuffer *data, size_t dataOffset, size_t length)
01908 {
01909    //Offset of the first byte to write in the circular buffer
01910    size_t offset = (seqNum - socket->irs - 1) % socket->rxBufferSize;
01911 
01912    //Check whether the specified data crosses buffer boundaries
01913    if((offset + length) <= socket->rxBufferSize)
01914    {
01915       //Copy the payload
01916       netBufferCopy((NetBuffer *) &socket->rxBuffer,
01917          offset, data, dataOffset, length);
01918    }
01919    else
01920    {
01921       //Copy the first part of the payload
01922       netBufferCopy((NetBuffer *) &socket->rxBuffer,
01923          offset, data, dataOffset, socket->rxBufferSize - offset);
01924       //Wrap around to the beginning of the circular buffer
01925       netBufferCopy((NetBuffer *) &socket->rxBuffer, 0, data,
01926          dataOffset + socket->rxBufferSize - offset, length - socket->rxBufferSize + offset);
01927    }
01928 }
01929 
01930 
01931 /**
01932  * @brief Copy data from the receive buffer
01933  * @param[in] socket Handle referencing the socket
01934  * @param[in] seqNum Sequence number of the first data to read
01935  * @param[out] data Pointer to the output buffer
01936  * @param[in] length Number of data to read
01937  **/
01938 
01939 void tcpReadRxBuffer(Socket *socket, uint32_t seqNum, uint8_t *data, size_t length)
01940 {
01941    //Offset of the first byte to read in the circular buffer
01942    size_t offset = (seqNum - socket->irs - 1) % socket->rxBufferSize;
01943 
01944    //Check whether the specified data crosses buffer boundaries
01945    if((offset + length) <= socket->rxBufferSize)
01946    {
01947       //Copy the payload
01948       netBufferRead(data, (NetBuffer *) &socket->rxBuffer,
01949          offset, length);
01950    }
01951    else
01952    {
01953       //Copy the first part of the payload
01954       netBufferRead(data, (NetBuffer *) &socket->rxBuffer,
01955          offset, socket->rxBufferSize - offset);
01956       //Wrap around to the beginning of the circular buffer
01957       netBufferRead(data + socket->rxBufferSize - offset, (NetBuffer *) &socket->rxBuffer,
01958          0, length - socket->rxBufferSize + offset);
01959    }
01960 }
01961 
01962 
01963 /**
01964  * @brief Dump TCP header for debugging purpose
01965  * @param[in] segment Pointer to the TCP header
01966  * @param[in] length Length of the segment data
01967  * @param[in] iss Initial send sequence number (needed to compute relative SEQ number)
01968  * @param[in] irs Initial receive sequence number (needed to compute relative ACK number)
01969  **/
01970 
01971 void tcpDumpHeader(const TcpHeader *segment, size_t length, uint32_t iss, uint32_t irs)
01972 {
01973    //Dump TCP header contents
01974    TRACE_DEBUG("%" PRIu16 " > %" PRIu16 ": %c%c%c%c%c%c seq=%" PRIu32 "(%" PRIu32 ")"
01975       "ack=%" PRIu32 "(%" PRIu32 ") win=%" PRIu16 " len=%" PRIuSIZE "\r\n",
01976       ntohs(segment->srcPort), ntohs(segment->destPort),
01977       (segment->flags & TCP_FLAG_FIN) ? 'F' : '-',
01978       (segment->flags & TCP_FLAG_SYN) ? 'S' : '-',
01979       (segment->flags & TCP_FLAG_RST) ? 'R' : '-',
01980       (segment->flags & TCP_FLAG_PSH) ? 'P' : '-',
01981       (segment->flags & TCP_FLAG_ACK) ? 'A' : '-',
01982       (segment->flags & TCP_FLAG_URG) ? 'U' : '-',
01983       ntohl(segment->seqNum), ntohl(segment->seqNum) - iss,
01984       ntohl(segment->ackNum), ntohl(segment->ackNum) - irs,
01985       ntohs(segment->window), length);
01986 }
01987 
01988 #endif
01989