Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
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
Generated on Tue Jul 12 2022 17:10:17 by
