Embed:
(wiki syntax)
Show/hide line numbers
tcp_fsm.c
Go to the documentation of this file.
00001 /** 00002 * @file tcp_fsm.c 00003 * @brief TCP finite state machine 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 * @section Description 00026 * 00027 * The TCP state machine progresses from one state to another in response to 00028 * events (user calls, incoming segments and timeouts). This file describes 00029 * the state transitions caused by incoming segments. Refer to the 00030 * following RFCs for complete details: 00031 * - RFC 793: Transmission Control Protocol 00032 * - RFC 1122: Requirements for Internet Hosts - Communication Layers 00033 * 00034 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00035 * @version 1.7.6 00036 **/ 00037 00038 //Switch to the appropriate trace level 00039 #define TRACE_LEVEL TCP_TRACE_LEVEL 00040 00041 //Dependencies 00042 #include <stdlib.h> 00043 #include <string.h> 00044 #include "core/net.h" 00045 #include "core/ip.h" 00046 #include "core/socket.h" 00047 #include "core/tcp.h" 00048 #include "core/tcp_fsm.h" 00049 #include "core/tcp_misc.h" 00050 #include "core/tcp_timer.h" 00051 #include "ipv4/ipv4.h" 00052 #include "ipv6/ipv6.h" 00053 #include "mibs/mib2_module.h" 00054 #include "date_time.h" 00055 #include "debug.h" 00056 00057 //Check TCP/IP stack configuration 00058 #if (TCP_SUPPORT == ENABLED) 00059 00060 00061 /** 00062 * @brief Incoming TCP segment processing 00063 * @param[in] interface Underlying network interface 00064 * @param[in] pseudoHeader TCP pseudo header 00065 * @param[in] buffer Multi-part buffer that holds the incoming TCP segment 00066 * @param[in] offset Offset to the first byte of the TCP header 00067 **/ 00068 00069 void tcpProcessSegment(NetInterface *interface, 00070 IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset) 00071 { 00072 uint_t i; 00073 size_t length; 00074 Socket *socket; 00075 Socket *passiveSocket; 00076 TcpHeader *segment; 00077 00078 //Total number of segments received, including those received in error 00079 MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpInSegs, 1); 00080 MIB2_INC_COUNTER64(mib2Base.tcpGroup.tcpHCInSegs, 1); 00081 00082 //A TCP implementation must silently discard an incoming 00083 //segment that is addressed to a broadcast or multicast 00084 //address (see RFC 1122 4.2.3.10) 00085 #if (IPV4_SUPPORT == ENABLED) 00086 if(pseudoHeader->length == sizeof(Ipv4PseudoHeader)) 00087 { 00088 //Ensure the destination address is not a broadcast address 00089 if(ipv4IsBroadcastAddr(interface, pseudoHeader->ipv4Data.destAddr)) 00090 return; 00091 //Ensure the destination address is not a multicast address 00092 if(ipv4IsMulticastAddr(pseudoHeader->ipv4Data.destAddr)) 00093 return; 00094 } 00095 else 00096 #endif 00097 #if (IPV6_SUPPORT == ENABLED) 00098 if(pseudoHeader->length == sizeof(Ipv6PseudoHeader)) 00099 { 00100 //Ensure the destination address is not a multicast address 00101 if(ipv6IsMulticastAddr(&pseudoHeader->ipv6Data.destAddr)) 00102 return; 00103 } 00104 else 00105 #endif 00106 { 00107 //This should never occur... 00108 return; 00109 } 00110 00111 //Retrieve the length of the TCP segment 00112 length = netBufferGetLength(buffer) - offset; 00113 00114 //Point to the TCP header 00115 segment = netBufferAt(buffer, offset); 00116 //Sanity check 00117 if(segment == NULL) 00118 return; 00119 00120 //Ensure the TCP header is valid 00121 if(length < sizeof(TcpHeader)) 00122 { 00123 //Debug message 00124 TRACE_WARNING("TCP segment length is invalid!\r\n"); 00125 //Total number of segments received in error 00126 MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpInErrs, 1); 00127 //Exit immediately 00128 return; 00129 } 00130 00131 //Check header length 00132 if(segment->dataOffset < 5 || ((size_t) segment->dataOffset * 4) > length) 00133 { 00134 //Debug message 00135 TRACE_WARNING("TCP header length is invalid!\r\n"); 00136 //Total number of segments received in error 00137 MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpInErrs, 1); 00138 //Exit immediately 00139 return; 00140 } 00141 00142 //Verify TCP checksum 00143 if(ipCalcUpperLayerChecksumEx(pseudoHeader->data, 00144 pseudoHeader->length, buffer, offset, length) != 0x0000) 00145 { 00146 //Debug message 00147 TRACE_WARNING("Wrong TCP header checksum!\r\n"); 00148 //Total number of segments received in error 00149 MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpInErrs, 1); 00150 //Exit immediately 00151 return; 00152 } 00153 00154 //No matching socket in the LISTEN state for the moment 00155 passiveSocket = NULL; 00156 00157 //Look through opened sockets 00158 for(i = 0; i < SOCKET_MAX_COUNT; i++) 00159 { 00160 //Point to the current socket 00161 socket = socketTable + i; 00162 00163 //TCP socket found? 00164 if(socket->type != SOCKET_TYPE_STREAM) 00165 continue; 00166 //Check whether the socket is bound to a particular interface 00167 if(socket->interface && socket->interface != interface) 00168 continue; 00169 //Check destination port number 00170 if(socket->localPort != ntohs(segment->destPort)) 00171 continue; 00172 00173 #if (IPV4_SUPPORT == ENABLED) 00174 //An IPv4 packet was received? 00175 if(pseudoHeader->length == sizeof(Ipv4PseudoHeader)) 00176 { 00177 //Destination IP address filtering 00178 if(socket->localIpAddr.length) 00179 { 00180 //An IPv4 address is expected 00181 if(socket->localIpAddr.length != sizeof(Ipv4Addr)) 00182 continue; 00183 //Filter out non-matching addresses 00184 if(socket->localIpAddr.ipv4Addr != pseudoHeader->ipv4Data.destAddr) 00185 continue; 00186 } 00187 //Source IP address filtering 00188 if(socket->remoteIpAddr.length) 00189 { 00190 //An IPv4 address is expected 00191 if(socket->remoteIpAddr.length != sizeof(Ipv4Addr)) 00192 continue; 00193 //Filter out non-matching addresses 00194 if(socket->remoteIpAddr.ipv4Addr != pseudoHeader->ipv4Data.srcAddr) 00195 continue; 00196 } 00197 } 00198 else 00199 #endif 00200 #if (IPV6_SUPPORT == ENABLED) 00201 //An IPv6 packet was received? 00202 if(pseudoHeader->length == sizeof(Ipv6PseudoHeader)) 00203 { 00204 //Destination IP address filtering 00205 if(socket->localIpAddr.length) 00206 { 00207 //An IPv6 address is expected 00208 if(socket->localIpAddr.length != sizeof(Ipv6Addr)) 00209 continue; 00210 //Filter out non-matching addresses 00211 if(!ipv6CompAddr(&socket->localIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.destAddr)) 00212 continue; 00213 } 00214 //Source IP address filtering 00215 if(socket->remoteIpAddr.length) 00216 { 00217 //An IPv6 address is expected 00218 if(socket->remoteIpAddr.length != sizeof(Ipv6Addr)) 00219 continue; 00220 //Filter out non-matching addresses 00221 if(!ipv6CompAddr(&socket->remoteIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.srcAddr)) 00222 continue; 00223 } 00224 } 00225 else 00226 #endif 00227 //An invalid packet was received? 00228 { 00229 //This should never occur... 00230 continue; 00231 } 00232 00233 //Keep track of the first matching socket in the LISTEN state 00234 if(socket->state == TCP_STATE_LISTEN && !passiveSocket) 00235 passiveSocket = socket; 00236 //Source port filtering 00237 if(socket->remotePort != ntohs(segment->srcPort)) 00238 continue; 00239 00240 //A matching socket has been found 00241 break; 00242 } 00243 00244 //If no matching socket has been found then try to 00245 //use the first matching socket in the LISTEN state 00246 if(i >= SOCKET_MAX_COUNT) socket = passiveSocket; 00247 00248 //Offset to the first data byte 00249 offset += segment->dataOffset * 4; 00250 //Calculate the length of the data 00251 length -= segment->dataOffset * 4; 00252 00253 //Debug message 00254 TRACE_DEBUG("%s: TCP segment received (%" PRIuSIZE " data bytes)...\r\n", 00255 formatSystemTime(osGetSystemTime(), NULL), length); 00256 00257 //Dump TCP header contents for debugging purpose 00258 if(socket == NULL) 00259 tcpDumpHeader(segment, length, 0, 0); 00260 else 00261 tcpDumpHeader(segment, length, socket->irs, socket->iss); 00262 00263 //Convert from network byte order to host byte order 00264 segment->srcPort = ntohs(segment->srcPort); 00265 segment->destPort = ntohs(segment->destPort); 00266 segment->seqNum = ntohl(segment->seqNum); 00267 segment->ackNum = ntohl(segment->ackNum); 00268 segment->window = ntohs(segment->window); 00269 segment->urgentPointer = ntohs(segment->urgentPointer); 00270 00271 //Specified port is unreachable? 00272 if(socket == NULL) 00273 { 00274 //An incoming segment not containing a RST causes 00275 //a reset to be sent in response 00276 if(!(segment->flags & TCP_FLAG_RST)) 00277 tcpSendResetSegment(interface, pseudoHeader, segment, length); 00278 00279 //Return immediately 00280 return; 00281 } 00282 00283 //Check current state 00284 switch(socket->state) 00285 { 00286 //Process CLOSED state 00287 case TCP_STATE_CLOSED: 00288 //This is the default state that each connection starts in before 00289 //the process of establishing it begins 00290 tcpStateClosed(interface, pseudoHeader, segment, length); 00291 break; 00292 //Process LISTEN state 00293 case TCP_STATE_LISTEN: 00294 //A device (normally a server) is waiting to receive a synchronize (SYN) 00295 //message from a client. It has not yet sent its own SYN message 00296 tcpStateListen(socket, interface, pseudoHeader, segment, length); 00297 break; 00298 //Process SYN_SENT state 00299 case TCP_STATE_SYN_SENT: 00300 //The device (normally a client) has sent a synchronize (SYN) message and 00301 //is waiting for a matching SYN from the other device (usually a server) 00302 tcpStateSynSent(socket, segment, length); 00303 break; 00304 //Process SYN_RECEIVED state 00305 case TCP_STATE_SYN_RECEIVED: 00306 //The device has both received a SYN from its partner and sent its own SYN. 00307 //It is now waiting for an ACK to its SYN to finish connection setup 00308 tcpStateSynReceived(socket, segment, buffer, offset, length); 00309 break; 00310 //Process ESTABLISHED state 00311 case TCP_STATE_ESTABLISHED: 00312 //Data can be exchanged freely once both devices in the connection enter 00313 //this state. This will continue until the connection is closed 00314 tcpStateEstablished(socket, segment, buffer, offset, length); 00315 break; 00316 //Process CLOSE_WAIT state 00317 case TCP_STATE_CLOSE_WAIT: 00318 //The device has received a close request (FIN) from the other device. It 00319 //must now wait for the application to acknowledge this request and 00320 //generate a matching request 00321 tcpStateCloseWait(socket, segment, length); 00322 break; 00323 //Process LAST_ACK state 00324 case TCP_STATE_LAST_ACK: 00325 //A device that has already received a close request and acknowledged it, 00326 //has sent its own FIN and is waiting for an ACK to this request 00327 tcpStateLastAck(socket, segment, length); 00328 break; 00329 //Process FIN_WAIT_1 state 00330 case TCP_STATE_FIN_WAIT_1: 00331 //A device in this state is waiting for an ACK for a FIN it has sent, or 00332 //is waiting for a connection termination request from the other device 00333 tcpStateFinWait1(socket, segment, buffer, offset, length); 00334 break; 00335 //Process FIN_WAIT_2 state 00336 case TCP_STATE_FIN_WAIT_2: 00337 //A device in this state has received an ACK for its request to terminate the 00338 //connection and is now waiting for a matching FIN from the other device 00339 tcpStateFinWait2(socket, segment, buffer, offset, length); 00340 break; 00341 //Process CLOSING state 00342 case TCP_STATE_CLOSING: 00343 //The device has received a FIN from the other device and sent an ACK for 00344 //it, but not yet received an ACK for its own FIN message 00345 tcpStateClosing(socket, segment, length); 00346 break; 00347 //Process TIME_WAIT state 00348 case TCP_STATE_TIME_WAIT: 00349 //The device has now received a FIN from the other device and acknowledged 00350 //it, and sent its own FIN and received an ACK for it. We are done, except 00351 //for waiting to ensure the ACK is received and prevent potential overlap 00352 //with new connections 00353 tcpStateTimeWait(socket, segment, length); 00354 break; 00355 //Invalid state... 00356 default: 00357 //Back to the CLOSED state 00358 tcpChangeState(socket, TCP_STATE_CLOSED); 00359 //Silently discard incoming packet 00360 break; 00361 } 00362 } 00363 00364 00365 /** 00366 * @brief CLOSED state 00367 * 00368 * This is the default state that each connection starts in before 00369 * the process of establishing it begins 00370 * 00371 * @param[in] interface Underlying network interface 00372 * @param[in] pseudoHeader TCP pseudo header 00373 * @param[in] segment Incoming TCP segment 00374 * @param[in] length Length of the segment data 00375 **/ 00376 00377 void tcpStateClosed(NetInterface *interface, 00378 IpPseudoHeader *pseudoHeader, TcpHeader *segment, size_t length) 00379 { 00380 //Debug message 00381 TRACE_DEBUG("TCP FSM: CLOSED state\r\n"); 00382 00383 //An incoming segment not containing a RST causes 00384 //a reset to be sent in response 00385 if(!(segment->flags & TCP_FLAG_RST)) 00386 tcpSendResetSegment(interface, pseudoHeader, segment, length); 00387 } 00388 00389 00390 /** 00391 * @brief LISTEN state 00392 * 00393 * A device (normally a server) is waiting to receive a synchronize (SYN) 00394 * message from a client. It has not yet sent its own SYN message 00395 * 00396 * @param[in] socket Handle referencing the current socket 00397 * @param[in] interface Underlying network interface 00398 * @param[in] pseudoHeader TCP pseudo header 00399 * @param[in] segment Incoming TCP segment 00400 * @param[in] length Length of the segment data 00401 **/ 00402 00403 void tcpStateListen(Socket *socket, NetInterface *interface, 00404 IpPseudoHeader *pseudoHeader, TcpHeader *segment, size_t length) 00405 { 00406 uint_t i; 00407 TcpOption *option; 00408 TcpSynQueueItem *queueItem; 00409 00410 //Debug message 00411 TRACE_DEBUG("TCP FSM: LISTEN state\r\n"); 00412 00413 //An incoming RST should be ignored 00414 if(segment->flags & TCP_FLAG_RST) 00415 return; 00416 00417 //Any acknowledgment is bad if it arrives on a connection 00418 //still in the LISTEN state 00419 if(segment->flags & TCP_FLAG_ACK) 00420 { 00421 //A reset segment should be formed for any arriving ACK-bearing segment 00422 tcpSendResetSegment(interface, pseudoHeader, segment, length); 00423 //Return immediately 00424 return; 00425 } 00426 00427 //Check the SYN bit 00428 if(segment->flags & TCP_FLAG_SYN) 00429 { 00430 //The SYN queue is empty? 00431 if(!socket->synQueue) 00432 { 00433 //Allocate memory to save incoming data 00434 queueItem = memPoolAlloc(sizeof(TcpSynQueueItem)); 00435 //Add the newly created item to the queue 00436 socket->synQueue = queueItem; 00437 } 00438 else 00439 { 00440 //Point to the very first item 00441 queueItem = socket->synQueue; 00442 00443 //Reach the last item in the receive queue 00444 for(i = 1; queueItem->next; i++) 00445 queueItem = queueItem->next; 00446 00447 //Make sure the receive queue is not full 00448 if(i >= socket->synQueueSize) 00449 return; 00450 00451 //Allocate memory to save incoming data 00452 queueItem->next = memPoolAlloc(sizeof(TcpSynQueueItem)); 00453 //Point to the newly created item 00454 queueItem = queueItem->next; 00455 } 00456 00457 //Failed to allocate memory? 00458 if(queueItem == NULL) 00459 return; 00460 00461 #if (IPV4_SUPPORT == ENABLED) 00462 //IPv4 is currently used? 00463 if(pseudoHeader->length == sizeof(Ipv4PseudoHeader)) 00464 { 00465 //Save the source IPv4 address 00466 queueItem->srcAddr.length = sizeof(Ipv4Addr); 00467 queueItem->srcAddr.ipv4Addr = pseudoHeader->ipv4Data.srcAddr; 00468 //Save the destination IPv4 address 00469 queueItem->destAddr.length = sizeof(Ipv4Addr); 00470 queueItem->destAddr.ipv4Addr = pseudoHeader->ipv4Data.destAddr; 00471 } 00472 else 00473 #endif 00474 #if (IPV6_SUPPORT == ENABLED) 00475 //IPv6 is currently used? 00476 if(pseudoHeader->length == sizeof(Ipv6PseudoHeader)) 00477 { 00478 //Save the source IPv6 address 00479 queueItem->srcAddr.length = sizeof(Ipv6Addr); 00480 queueItem->srcAddr.ipv6Addr = pseudoHeader->ipv6Data.srcAddr; 00481 //Save the destination IPv6 address 00482 queueItem->destAddr.length = sizeof(Ipv6Addr); 00483 queueItem->destAddr.ipv6Addr = pseudoHeader->ipv6Data.destAddr; 00484 } 00485 else 00486 #endif 00487 //Invalid pseudo header? 00488 { 00489 //This should never occur... 00490 return; 00491 } 00492 00493 //Initialize next field 00494 queueItem->next = NULL; 00495 //Underlying network interface 00496 queueItem->interface = interface; 00497 //Save the port number of the client 00498 queueItem->srcPort = segment->srcPort; 00499 //Save the initial sequence number 00500 queueItem->isn = segment->seqNum; 00501 //Default MSS value 00502 queueItem->mss = MIN(TCP_DEFAULT_MSS, TCP_MAX_MSS); 00503 00504 //Get the maximum segment size 00505 option = tcpGetOption(segment, TCP_OPTION_MAX_SEGMENT_SIZE); 00506 //Specified option found? 00507 if(option != NULL && option->length == 4) 00508 { 00509 //Retrieve MSS value 00510 memcpy(&queueItem->mss, option->value, 2); 00511 //Convert from network byte order to host byte order 00512 queueItem->mss = ntohs(queueItem->mss); 00513 00514 //Debug message 00515 TRACE_DEBUG("Remote host MSS = %" PRIu16 "\r\n", queueItem->mss); 00516 00517 //Make sure that the MSS advertised by the peer is acceptable 00518 queueItem->mss = MIN(queueItem->mss, TCP_MAX_MSS); 00519 queueItem->mss = MAX(queueItem->mss, TCP_MIN_MSS); 00520 } 00521 00522 //Notify user that a connection request is pending 00523 tcpUpdateEvents(socket); 00524 00525 //The rest of the processing described in RFC 793 will be done 00526 //asynchronously when socketAccept() function is called 00527 } 00528 } 00529 00530 00531 /** 00532 * @brief SYN-SENT state 00533 * 00534 * The device (normally a client) has sent a synchronize (SYN) message and 00535 * is waiting for a matching SYN from the other device (usually a server) 00536 * 00537 * @param[in] socket Handle referencing the current socket 00538 * @param[in] segment Incoming TCP segment 00539 * @param[in] length Length of the segment data 00540 **/ 00541 00542 void tcpStateSynSent(Socket *socket, TcpHeader *segment, size_t length) 00543 { 00544 TcpOption *option; 00545 00546 //Debug message 00547 TRACE_DEBUG("TCP FSM: SYN-SENT state\r\n"); 00548 00549 //Check the ACK bit 00550 if(segment->flags & TCP_FLAG_ACK) 00551 { 00552 //Make sure the acknowledgment number is valid 00553 if(segment->ackNum != socket->sndNxt) 00554 { 00555 //Send a reset segment unless the RST bit is set 00556 if(!(segment->flags & TCP_FLAG_RST)) 00557 tcpSendSegment(socket, TCP_FLAG_RST, segment->ackNum, 0, 0, FALSE); 00558 00559 //Drop the segment and return 00560 return; 00561 } 00562 } 00563 00564 //Check the RST bit 00565 if(segment->flags & TCP_FLAG_RST) 00566 { 00567 //Make sure the ACK is acceptable 00568 if(segment->flags & TCP_FLAG_ACK) 00569 { 00570 //Enter CLOSED state 00571 tcpChangeState(socket, TCP_STATE_CLOSED); 00572 00573 //Number of times TCP connections have made a direct transition to the 00574 //CLOSED state from either the SYN-SENT state or the SYN-RECEIVED state 00575 MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpAttemptFails, 1); 00576 } 00577 00578 //Drop the segment and return 00579 return; 00580 } 00581 00582 //Check the SYN bit 00583 if(segment->flags & TCP_FLAG_SYN) 00584 { 00585 //Save initial receive sequence number 00586 socket->irs = segment->seqNum; 00587 //Initialize RCV.NXT pointer 00588 socket->rcvNxt = segment->seqNum + 1; 00589 00590 //If there is an ACK, SND.UNA should be advanced to equal SEG.ACK 00591 if(segment->flags & TCP_FLAG_ACK) 00592 socket->sndUna = segment->ackNum; 00593 00594 //Compute retransmission timeout 00595 tcpComputeRto(socket); 00596 00597 //Any segments on the retransmission queue which are thereby 00598 //acknowledged should be removed 00599 tcpUpdateRetransmitQueue(socket); 00600 00601 //Get the maximum segment size 00602 option = tcpGetOption(segment, TCP_OPTION_MAX_SEGMENT_SIZE); 00603 00604 //Specified option found? 00605 if(option != NULL && option->length == 4) 00606 { 00607 //Retrieve MSS value 00608 memcpy(&socket->smss, option->value, 2); 00609 //Convert from network byte order to host byte order 00610 socket->smss = ntohs(socket->smss); 00611 00612 //Debug message 00613 TRACE_DEBUG("Remote host MSS = %" PRIu16 "\r\n", socket->smss); 00614 00615 //Make sure that the MSS advertised by the peer is acceptable 00616 socket->smss = MIN(socket->smss, TCP_MAX_MSS); 00617 socket->smss = MAX(socket->smss, TCP_MIN_MSS); 00618 } 00619 00620 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED) 00621 //Initial congestion window 00622 socket->cwnd = MIN(TCP_INITIAL_WINDOW * socket->smss, socket->txBufferSize); 00623 #endif 00624 00625 //Check whether our SYN has been acknowledged (SND.UNA > ISS) 00626 if(TCP_CMP_SEQ(socket->sndUna, socket->iss) > 0) 00627 { 00628 //Update the send window before entering ESTABLISHED state (see RFC 1122 4.2.2.20) 00629 socket->sndWnd = segment->window; 00630 socket->sndWl1 = segment->seqNum; 00631 socket->sndWl2 = segment->ackNum; 00632 00633 //Maximum send window it has seen so far on the connection 00634 socket->maxSndWnd = segment->window; 00635 00636 //Form an ACK segment and send it 00637 tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0, FALSE); 00638 //Switch to the ESTABLISHED state 00639 tcpChangeState(socket, TCP_STATE_ESTABLISHED); 00640 } 00641 else 00642 { 00643 //Form an SYN ACK segment and send it 00644 tcpSendSegment(socket, TCP_FLAG_SYN | TCP_FLAG_ACK, socket->iss, socket->rcvNxt, 0, TRUE); 00645 //Enter SYN-RECEIVED state 00646 tcpChangeState(socket, TCP_STATE_SYN_RECEIVED); 00647 } 00648 } 00649 } 00650 00651 00652 /** 00653 * @brief SYN-RECEIVED state 00654 * 00655 * The device has both received a SYN from its partner and sent its own SYN. 00656 * It is now waiting for an ACK to its SYN to finish connection setup 00657 * 00658 * @param[in] socket Handle referencing the current socket 00659 * @param[in] segment Incoming TCP segment 00660 * @param[in] buffer Multi-part buffer containing the incoming TCP segment 00661 * @param[in] offset Offset to the first data byte 00662 * @param[in] length Length of the segment data 00663 **/ 00664 00665 void tcpStateSynReceived(Socket *socket, TcpHeader *segment, 00666 const NetBuffer *buffer, size_t offset, size_t length) 00667 { 00668 //Debug message 00669 TRACE_DEBUG("TCP FSM: SYN-RECEIVED state\r\n"); 00670 00671 //First check sequence number 00672 if(tcpCheckSequenceNumber(socket, segment, length)) 00673 return; 00674 00675 //Check the RST bit 00676 if(segment->flags & TCP_FLAG_RST) 00677 { 00678 //Return to CLOSED state 00679 tcpChangeState(socket, TCP_STATE_CLOSED); 00680 00681 //Number of times TCP connections have made a direct transition to the 00682 //CLOSED state from either the SYN-SENT state or the SYN-RECEIVED state 00683 MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpAttemptFails, 1); 00684 00685 //Return immediately 00686 return; 00687 } 00688 00689 //Check the SYN bit 00690 if(tcpCheckSyn(socket, segment, length)) 00691 return; 00692 00693 //If the ACK bit is off drop the segment and return 00694 if(!(segment->flags & TCP_FLAG_ACK)) 00695 return; 00696 00697 //Make sure the acknowledgment number is valid 00698 if(segment->ackNum != socket->sndNxt) 00699 { 00700 //If the segment acknowledgment is not acceptable, form a reset 00701 //segment and send it 00702 tcpSendSegment(socket, TCP_FLAG_RST, segment->ackNum, 0, 0, FALSE); 00703 00704 //Drop the segment and return 00705 return; 00706 } 00707 00708 //Update the send window before entering ESTABLISHED state (see RFC 1122 4.2.2.20) 00709 socket->sndWnd = segment->window; 00710 socket->sndWl1 = segment->seqNum; 00711 socket->sndWl2 = segment->ackNum; 00712 00713 //Maximum send window it has seen so far on the connection 00714 socket->maxSndWnd = segment->window; 00715 00716 //Enter ESTABLISHED state 00717 tcpChangeState(socket, TCP_STATE_ESTABLISHED); 00718 //And continue processing... 00719 tcpStateEstablished(socket, segment, buffer, offset, length); 00720 } 00721 00722 00723 /** 00724 * @brief ESTABLISHED state 00725 * 00726 * Data can be exchanged freely once both devices in the connection enter 00727 * this state. This will continue until the connection is closed 00728 * 00729 * @param[in] socket Handle referencing the current socket 00730 * @param[in] segment Incoming TCP segment 00731 * @param[in] buffer Multi-part buffer containing the incoming TCP segment 00732 * @param[in] offset Offset to the first data byte 00733 * @param[in] length Length of the segment data 00734 **/ 00735 00736 void tcpStateEstablished(Socket *socket, TcpHeader *segment, 00737 const NetBuffer *buffer, size_t offset, size_t length) 00738 { 00739 uint_t flags = 0; 00740 00741 //Debug message 00742 TRACE_DEBUG("TCP FSM: ESTABLISHED state\r\n"); 00743 00744 //First check sequence number 00745 if(tcpCheckSequenceNumber(socket, segment, length)) 00746 return; 00747 00748 //Check the RST bit 00749 if(segment->flags & TCP_FLAG_RST) 00750 { 00751 //Switch to the CLOSED state 00752 tcpChangeState(socket, TCP_STATE_CLOSED); 00753 00754 //Number of times TCP connections have made a direct transition to the 00755 //CLOSED state from either the ESTABLISHED state or the CLOSE-WAIT state 00756 MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpEstabResets, 1); 00757 00758 //Return immediately 00759 return; 00760 } 00761 00762 //Check the SYN bit 00763 if(tcpCheckSyn(socket, segment, length)) 00764 return; 00765 //Check the ACK field 00766 if(tcpCheckAck(socket, segment, length)) 00767 return; 00768 //Process the segment text 00769 if(length > 0) 00770 tcpProcessSegmentData(socket, segment, buffer, offset, length); 00771 00772 //Check the FIN bit 00773 if(segment->flags & TCP_FLAG_FIN) 00774 { 00775 //The FIN can only be acknowledged if all the segment data 00776 //has been successfully transferred to the receive buffer 00777 if(socket->rcvNxt == (segment->seqNum + length)) 00778 { 00779 //Advance RCV.NXT over the FIN 00780 socket->rcvNxt++; 00781 //Send an acknowledgment for the FIN 00782 tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0, FALSE); 00783 //Switch to the CLOSE-WAIT state 00784 tcpChangeState(socket, TCP_STATE_CLOSE_WAIT); 00785 } 00786 } 00787 00788 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED) 00789 //Duplicate AK received? 00790 if(socket->dupAckCount > 0) 00791 flags = SOCKET_FLAG_NO_DELAY; 00792 #endif 00793 00794 //The Nagle algorithm should be implemented to coalesce 00795 //short segments (refer to RFC 1122 4.2.3.4) 00796 tcpNagleAlgo(socket, flags); 00797 } 00798 00799 00800 /** 00801 * @brief CLOSE-WAIT state 00802 * 00803 * The device has received a close request (FIN) from the other device. It 00804 * must now wait for the application to acknowledge this request and 00805 * generate a matching request 00806 * 00807 * @param[in] socket Handle referencing the current socket 00808 * @param[in] segment Incoming TCP segment 00809 * @param[in] length Length of the segment data 00810 **/ 00811 00812 void tcpStateCloseWait(Socket *socket, TcpHeader *segment, size_t length) 00813 { 00814 uint_t flags = 0; 00815 00816 //Debug message 00817 TRACE_DEBUG("TCP FSM: CLOSE-WAIT state\r\n"); 00818 00819 //First check sequence number 00820 if(tcpCheckSequenceNumber(socket, segment, length)) 00821 return; 00822 00823 //Check the RST bit 00824 if(segment->flags & TCP_FLAG_RST) 00825 { 00826 //Switch to the CLOSED state 00827 tcpChangeState(socket, TCP_STATE_CLOSED); 00828 00829 //Number of times TCP connections have made a direct transition to the 00830 //CLOSED state from either the ESTABLISHED state or the CLOSE-WAIT state 00831 MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpEstabResets, 1); 00832 00833 //Return immediately 00834 return; 00835 } 00836 00837 //Check the SYN bit 00838 if(tcpCheckSyn(socket, segment, length)) 00839 return; 00840 //Check the ACK field 00841 if(tcpCheckAck(socket, segment, length)) 00842 return; 00843 00844 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED) 00845 //Duplicate AK received? 00846 if(socket->dupAckCount > 0) 00847 flags = SOCKET_FLAG_NO_DELAY; 00848 #endif 00849 00850 //The Nagle algorithm should be implemented to coalesce 00851 //short segments (refer to RFC 1122 4.2.3.4) 00852 tcpNagleAlgo(socket, flags); 00853 } 00854 00855 00856 /** 00857 * @brief LAST-ACK state 00858 * 00859 * A device that has already received a close request and acknowledged it, 00860 * has sent its own FIN and is waiting for an ACK to this request 00861 * 00862 * @param[in] socket Handle referencing the current socket 00863 * @param[in] segment Incoming TCP segment 00864 * @param[in] length Length of the segment data 00865 **/ 00866 00867 void tcpStateLastAck(Socket *socket, TcpHeader *segment, size_t length) 00868 { 00869 //Debug message 00870 TRACE_DEBUG("TCP FSM: LAST-ACK state\r\n"); 00871 00872 //First check sequence number 00873 if(tcpCheckSequenceNumber(socket, segment, length)) 00874 return; 00875 00876 //Check the RST bit 00877 if(segment->flags & TCP_FLAG_RST) 00878 { 00879 //Enter CLOSED state 00880 tcpChangeState(socket, TCP_STATE_CLOSED); 00881 //Return immediately 00882 return; 00883 } 00884 00885 //Check the SYN bit 00886 if(tcpCheckSyn(socket, segment, length)) 00887 return; 00888 //If the ACK bit is off drop the segment and return 00889 if(!(segment->flags & TCP_FLAG_ACK)) 00890 return; 00891 00892 //The only thing that can arrive in this state is an 00893 //acknowledgment of our FIN 00894 if(segment->ackNum == socket->sndNxt) 00895 { 00896 //Enter CLOSED state 00897 tcpChangeState(socket, TCP_STATE_CLOSED); 00898 } 00899 } 00900 00901 00902 /** 00903 * @brief FIN-WAIT-1 state 00904 * 00905 * A device in this state is waiting for an ACK for a FIN it has sent, or 00906 * is waiting for a connection termination request from the other device 00907 * 00908 * @param[in] socket Handle referencing the current socket 00909 * @param[in] segment Incoming TCP segment 00910 * @param[in] buffer Multi-part buffer containing the incoming TCP segment 00911 * @param[in] offset Offset to the first data byte 00912 * @param[in] length Length of the segment data 00913 **/ 00914 00915 void tcpStateFinWait1(Socket *socket, TcpHeader *segment, 00916 const NetBuffer *buffer, size_t offset, size_t length) 00917 { 00918 //Debug message 00919 TRACE_DEBUG("TCP FSM: FIN-WAIT-1 state\r\n"); 00920 00921 //First check sequence number 00922 if(tcpCheckSequenceNumber(socket, segment, length)) 00923 return; 00924 00925 //Check the RST bit 00926 if(segment->flags & TCP_FLAG_RST) 00927 { 00928 //Switch to the CLOSED state 00929 tcpChangeState(socket, TCP_STATE_CLOSED); 00930 //Return immediately 00931 return; 00932 } 00933 00934 //Check the SYN bit 00935 if(tcpCheckSyn(socket, segment, length)) 00936 return; 00937 //Check the ACK field 00938 if(tcpCheckAck(socket, segment, length)) 00939 return; 00940 00941 //Check whether our FIN is now acknowledged 00942 if(segment->ackNum == socket->sndNxt) 00943 { 00944 //Start the FIN-WAIT-2 timer to prevent the connection 00945 //from staying in the FIN-WAIT-2 state forever 00946 tcpTimerStart(&socket->finWait2Timer, TCP_FIN_WAIT_2_TIMER); 00947 //enter FIN-WAIT-2 and continue processing in that state 00948 tcpChangeState(socket, TCP_STATE_FIN_WAIT_2); 00949 } 00950 00951 //Process the segment text 00952 if(length > 0) 00953 tcpProcessSegmentData(socket, segment, buffer, offset, length); 00954 00955 //Check the FIN bit 00956 if(segment->flags & TCP_FLAG_FIN) 00957 { 00958 //The FIN can only be acknowledged if all the segment data 00959 //has been successfully transferred to the receive buffer 00960 if(socket->rcvNxt == (segment->seqNum + length)) 00961 { 00962 //Advance RCV.NXT over the FIN 00963 socket->rcvNxt++; 00964 //Send an acknowledgment for the FIN 00965 tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0, FALSE); 00966 00967 //Check if our FIN has been acknowledged 00968 if(segment->ackNum == socket->sndNxt) 00969 { 00970 //Release previously allocated resources 00971 tcpDeleteControlBlock(socket); 00972 //Start the 2MSL timer 00973 tcpTimerStart(&socket->timeWaitTimer, TCP_2MSL_TIMER); 00974 //Switch to the TIME-WAIT state 00975 tcpChangeState(socket, TCP_STATE_TIME_WAIT); 00976 } 00977 else 00978 { 00979 //If our FIN has not been acknowledged, then enter CLOSING state 00980 tcpChangeState(socket, TCP_STATE_CLOSING); 00981 } 00982 } 00983 } 00984 } 00985 00986 00987 /** 00988 * @brief FIN-WAIT-2 state 00989 * 00990 * A device in this state has received an ACK for its request to terminate the 00991 * connection and is now waiting for a matching FIN from the other device 00992 * 00993 * @param[in] socket Handle referencing the current socket 00994 * @param[in] segment Incoming TCP segment 00995 * @param[in] buffer Multi-part buffer containing the incoming TCP segment 00996 * @param[in] offset Offset to the first data byte 00997 * @param[in] length Length of the segment data 00998 **/ 00999 01000 void tcpStateFinWait2(Socket *socket, TcpHeader *segment, 01001 const NetBuffer *buffer, size_t offset, size_t length) 01002 { 01003 //Debug message 01004 TRACE_DEBUG("TCP FSM: FIN-WAIT-2 state\r\n"); 01005 01006 //First check sequence number 01007 if(tcpCheckSequenceNumber(socket, segment, length)) 01008 return; 01009 01010 //Check the RST bit 01011 if(segment->flags & TCP_FLAG_RST) 01012 { 01013 //Switch to the CLOSED state 01014 tcpChangeState(socket, TCP_STATE_CLOSED); 01015 //Return immediately 01016 return; 01017 } 01018 01019 //Check the SYN bit 01020 if(tcpCheckSyn(socket, segment, length)) 01021 return; 01022 //Check the ACK field 01023 if(tcpCheckAck(socket, segment, length)) 01024 return; 01025 //Process the segment text 01026 if(length > 0) 01027 tcpProcessSegmentData(socket, segment, buffer, offset, length); 01028 01029 //Check the FIN bit 01030 if(segment->flags & TCP_FLAG_FIN) 01031 { 01032 //The FIN can only be acknowledged if all the segment data 01033 //has been successfully transferred to the receive buffer 01034 if(socket->rcvNxt == (segment->seqNum + length)) 01035 { 01036 //Advance RCV.NXT over the FIN 01037 socket->rcvNxt++; 01038 //Send an acknowledgment for the FIN 01039 tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0, FALSE); 01040 01041 //Release previously allocated resources 01042 tcpDeleteControlBlock(socket); 01043 //Start the 2MSL timer 01044 tcpTimerStart(&socket->timeWaitTimer, TCP_2MSL_TIMER); 01045 //Switch to the TIME_WAIT state 01046 tcpChangeState(socket, TCP_STATE_TIME_WAIT); 01047 } 01048 } 01049 } 01050 01051 01052 /** 01053 * @brief CLOSING state 01054 * 01055 * The device has received a FIN from the other device and sent an ACK for 01056 * it, but not yet received an ACK for its own FIN message 01057 * 01058 * @param[in] socket Handle referencing the current socket 01059 * @param[in] segment Incoming TCP segment 01060 * @param[in] length Length of the segment data 01061 **/ 01062 01063 void tcpStateClosing(Socket *socket, TcpHeader *segment, size_t length) 01064 { 01065 //Debug message 01066 TRACE_DEBUG("TCP FSM: CLOSING state\r\n"); 01067 01068 //First check sequence number 01069 if(tcpCheckSequenceNumber(socket, segment, length)) 01070 return; 01071 01072 //Check the RST bit 01073 if(segment->flags & TCP_FLAG_RST) 01074 { 01075 //Enter CLOSED state 01076 tcpChangeState(socket, TCP_STATE_CLOSED); 01077 //Return immediately 01078 return; 01079 } 01080 01081 //Check the SYN bit 01082 if(tcpCheckSyn(socket, segment, length)) 01083 return; 01084 //Check the ACK field 01085 if(tcpCheckAck(socket, segment, length)) 01086 return; 01087 01088 //If the ACK acknowledges our FIN then enter the TIME-WAIT 01089 //state, otherwise ignore the segment 01090 if(segment->ackNum == socket->sndNxt) 01091 { 01092 //Release previously allocated resources 01093 tcpDeleteControlBlock(socket); 01094 //Start the 2MSL timer 01095 tcpTimerStart(&socket->timeWaitTimer, TCP_2MSL_TIMER); 01096 //Switch to the TIME-WAIT state 01097 tcpChangeState(socket, TCP_STATE_TIME_WAIT); 01098 } 01099 } 01100 01101 01102 /** 01103 * @brief TIME-WAIT state 01104 * 01105 * The device has now received a FIN from the other device and acknowledged 01106 * it, and sent its own FIN and received an ACK for it. We are done, except 01107 * for waiting to ensure the ACK is received and prevent potential overlap 01108 * with new connections 01109 * 01110 * @param[in] socket Handle referencing the current socket 01111 * @param[in] segment Incoming TCP segment 01112 * @param[in] length Length of the segment data 01113 **/ 01114 01115 void tcpStateTimeWait(Socket *socket, TcpHeader *segment, size_t length) 01116 { 01117 //Debug message 01118 TRACE_DEBUG("TCP FSM: TIME-WAIT state\r\n"); 01119 01120 //First check sequence number 01121 if(tcpCheckSequenceNumber(socket, segment, length)) 01122 return; 01123 01124 //Check the RST bit 01125 if(segment->flags & TCP_FLAG_RST) 01126 { 01127 //Enter CLOSED state 01128 tcpChangeState(socket, TCP_STATE_CLOSED); 01129 01130 //Dispose the socket if the user does not have the ownership anymore 01131 if(!socket->ownedFlag) 01132 { 01133 //Delete the TCB 01134 tcpDeleteControlBlock(socket); 01135 //Mark the socket as closed 01136 socket->type = SOCKET_TYPE_UNUSED; 01137 } 01138 01139 //Return immediately 01140 return; 01141 } 01142 01143 //Check the SYN bit 01144 if(tcpCheckSyn(socket, segment, length)) 01145 return; 01146 //If the ACK bit is off drop the segment and return 01147 if(!(segment->flags & TCP_FLAG_ACK)) 01148 return; 01149 01150 //The only thing that can arrive in this state is a retransmission 01151 //of the remote FIN. Acknowledge it and restart the 2 MSL timeout 01152 if(segment->flags & TCP_FLAG_FIN) 01153 { 01154 //Send an acknowledgment for the FIN 01155 tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0, FALSE); 01156 //Restart the 2MSL timer 01157 tcpTimerStart(&socket->timeWaitTimer, TCP_2MSL_TIMER); 01158 } 01159 } 01160 01161 #endif 01162
Generated on Tue Jul 12 2022 17:10:17 by
