3      Copyright (C) Dean Camera, 2009. 
   5   dean [at] fourwalledcubicle [dot] com 
   6       www.fourwalledcubicle.com 
  10   Copyright 2009  Dean Camera (dean [at] fourwalledcubicle [dot] com) 
  12   Permission to use, copy, modify, and distribute this software 
  13   and its documentation for any purpose and without fee is hereby 
  14   granted, provided that the above copyright notice appear in all 
  15   copies and that both that the copyright notice and this 
  16   permission notice and warranty disclaimer appear in supporting 
  17   documentation, and that the name of the author not be used in 
  18   advertising or publicity pertaining to distribution of the 
  19   software without specific, written prior permission. 
  21   The author disclaim all warranties with regard to this 
  22   software, including all implied warranties of merchantability 
  23   and fitness.  In no event shall the author be liable for any 
  24   special, indirect or consequential damages or any damages 
  25   whatsoever resulting from loss of use, data or profits, whether 
  26   in an action of contract, negligence or other tortious action, 
  27   arising out of or in connection with the use or performance of 
  33  *  Transmission Control Protocol (TCP) packet handling routines. This protocol handles the reliable in-order transmission 
  34  *  and reception of packets to and from devices on a network, to "ports" on the device. It is used in situations where data 
  35  *  delivery must be reliable and correct, e.g. HTTP, TELNET and most other non-streaming protocols. 
  38 #define  INCLUDE_FROM_TCP_C 
  41 /** Port state table array. This contains the current status of TCP ports in the device. To save on space, only open ports are 
  42  *  stored - closed ports may be overwritten at any time, and the system will assume any ports not present in the array are closed. This 
  43  *  allows for MAX_OPEN_TCP_PORTS to be less than the number of ports used by the application if desired. 
  45 TCP_PortState_t        PortStateTable
[MAX_OPEN_TCP_PORTS
]; 
  47 /** Connection state table array. This contains the current status of TCP connections in the device. To save on space, only active 
  48  *  (non-closed) connections are stored - closed connections may be overwritten at any time, and the system will assume any connections 
  49  *  not present in the array are closed. 
  51 TCP_ConnectionState_t  ConnectionStateTable
[MAX_TCP_CONNECTIONS
]; 
  54 /** Task to handle the calling of each registered application's callback function, to process and generate TCP packets at the application 
  55  *  level. If an application produces a response, this task constructs the appropriate Ethernet frame and places it into the Ethernet OUT 
  56  *  buffer for later transmission. 
  58 void TCP_TCPTask(USB_ClassInfo_RNDIS_Device_t
* RNDISInterfaceInfo
) 
  60         /* Run each application in sequence, to process incoming and generate outgoing packets */ 
  61         for (uint8_t CSTableEntry 
= 0; CSTableEntry 
< MAX_TCP_CONNECTIONS
; CSTableEntry
++) 
  63                 /* Find the corresponding port entry in the port table */ 
  64                 for (uint8_t PTableEntry 
= 0; PTableEntry 
< MAX_OPEN_TCP_PORTS
; PTableEntry
++) 
  66                         /* Run the application handler for the port */ 
  67                         if ((PortStateTable
[PTableEntry
].Port  
== ConnectionStateTable
[CSTableEntry
].Port
) &&  
  68                             (PortStateTable
[PTableEntry
].State 
== TCP_Port_Open
)) 
  70                                 PortStateTable
[PTableEntry
].ApplicationHandler(&ConnectionStateTable
[CSTableEntry
], 
  71                                                                                &ConnectionStateTable
[CSTableEntry
].Info
.Buffer
); 
  76         /* Get pointer to the output frame info struct for convenience */ 
  77         Ethernet_Frame_Info_t
* FrameOUT 
= (Ethernet_Frame_Info_t
*)&RNDISInterfaceInfo
->State
.FrameOUT
; 
  79         /* Bail out early if there is already a frame waiting to be sent in the Ethernet OUT buffer */ 
  80         if (FrameOUT
->FrameInBuffer
) 
  83         /* Send response packets from each application as the TCP packet buffers are filled by the applications */ 
  84         for (uint8_t CSTableEntry 
= 0; CSTableEntry 
< MAX_TCP_CONNECTIONS
; CSTableEntry
++) 
  86                 /* For each completely received packet, pass it along to the listening application */ 
  87                 if ((ConnectionStateTable
[CSTableEntry
].Info
.Buffer
.Direction 
== TCP_PACKETDIR_OUT
) && 
  88                     (ConnectionStateTable
[CSTableEntry
].Info
.Buffer
.Ready
)) 
  90                         Ethernet_Frame_Header_t
* FrameOUTHeader 
= (Ethernet_Frame_Header_t
*)&FrameOUT
->FrameData
; 
  91                         IP_Header_t
*             IPHeaderOUT    
= (IP_Header_t
*)&FrameOUT
->FrameData
[sizeof(Ethernet_Frame_Header_t
)]; 
  92                         TCP_Header_t
*            TCPHeaderOUT   
= (TCP_Header_t
*)&FrameOUT
->FrameData
[sizeof(Ethernet_Frame_Header_t
) + 
  94                         void*                    TCPDataOUT     
= &FrameOUT
->FrameData
[sizeof(Ethernet_Frame_Header_t
) + 
  96                                                                                        sizeof(TCP_Header_t
)]; 
  98                         uint16_t PacketSize 
= ConnectionStateTable
[CSTableEntry
].Info
.Buffer
.Length
; 
 100                         /* Fill out the TCP data */ 
 101                         TCPHeaderOUT
->SourcePort           
= ConnectionStateTable
[CSTableEntry
].Port
; 
 102                         TCPHeaderOUT
->DestinationPort      
= ConnectionStateTable
[CSTableEntry
].RemotePort
; 
 103                         TCPHeaderOUT
->SequenceNumber       
= SwapEndian_32(ConnectionStateTable
[CSTableEntry
].Info
.SequenceNumberOut
); 
 104                         TCPHeaderOUT
->AcknowledgmentNumber 
= SwapEndian_32(ConnectionStateTable
[CSTableEntry
].Info
.SequenceNumberIn
); 
 105                         TCPHeaderOUT
->DataOffset           
= (sizeof(TCP_Header_t
) / sizeof(uint32_t)); 
 106                         TCPHeaderOUT
->WindowSize           
= SwapEndian_16(TCP_WINDOW_SIZE
); 
 108                         TCPHeaderOUT
->Flags                
= TCP_FLAG_ACK
; 
 109                         TCPHeaderOUT
->UrgentPointer        
= 0; 
 110                         TCPHeaderOUT
->Checksum             
= 0; 
 111                         TCPHeaderOUT
->Reserved             
= 0; 
 113                         memcpy(TCPDataOUT
, ConnectionStateTable
[CSTableEntry
].Info
.Buffer
.Data
, PacketSize
); 
 115                         ConnectionStateTable
[CSTableEntry
].Info
.SequenceNumberOut 
+= PacketSize
; 
 117                         TCPHeaderOUT
->Checksum             
= TCP_Checksum16(TCPHeaderOUT
, ServerIPAddress
, 
 118                                                                             ConnectionStateTable
[CSTableEntry
].RemoteAddress
, 
 119                                                                             (sizeof(TCP_Header_t
) + PacketSize
)); 
 121                         PacketSize 
+= sizeof(TCP_Header_t
); 
 123                         /* Fill out the response IP header */ 
 124                         IPHeaderOUT
->TotalLength        
= SwapEndian_16(sizeof(IP_Header_t
) + PacketSize
); 
 125                         IPHeaderOUT
->TypeOfService      
= 0; 
 126                         IPHeaderOUT
->HeaderLength       
= (sizeof(IP_Header_t
) / sizeof(uint32_t)); 
 127                         IPHeaderOUT
->Version            
= 4; 
 128                         IPHeaderOUT
->Flags              
= 0; 
 129                         IPHeaderOUT
->FragmentOffset     
= 0; 
 130                         IPHeaderOUT
->Identification     
= 0; 
 131                         IPHeaderOUT
->HeaderChecksum     
= 0; 
 132                         IPHeaderOUT
->Protocol           
= PROTOCOL_TCP
; 
 133                         IPHeaderOUT
->TTL                
= DEFAULT_TTL
; 
 134                         IPHeaderOUT
->SourceAddress      
= ServerIPAddress
; 
 135                         IPHeaderOUT
->DestinationAddress 
= ConnectionStateTable
[CSTableEntry
].RemoteAddress
; 
 137                         IPHeaderOUT
->HeaderChecksum     
= Ethernet_Checksum16(IPHeaderOUT
, sizeof(IP_Header_t
)); 
 139                         PacketSize 
+= sizeof(IP_Header_t
); 
 141                         /* Fill out the response Ethernet frame header */ 
 142                         FrameOUTHeader
->Source          
= ServerMACAddress
; 
 143                         FrameOUTHeader
->Destination     
= (MAC_Address_t
){{0x02, 0x00, 0x02, 0x00, 0x02, 0x00}}; 
 144                         FrameOUTHeader
->EtherType       
= SwapEndian_16(ETHERTYPE_IPV4
); 
 146                         PacketSize 
+= sizeof(Ethernet_Frame_Header_t
); 
 148                         /* Set the response length in the buffer and indicate that a response is ready to be sent */ 
 149                         FrameOUT
->FrameLength           
= PacketSize
; 
 150                         FrameOUT
->FrameInBuffer         
= true; 
 152                         ConnectionStateTable
[CSTableEntry
].Info
.Buffer
.Ready 
= false; 
 159 /** Initializes the TCP protocol handler, clearing the port and connection state tables. This must be called before TCP packets are 
 164         /* Initialize the port state table with all CLOSED entries */ 
 165         for (uint8_t PTableEntry 
= 0; PTableEntry 
< MAX_OPEN_TCP_PORTS
; PTableEntry
++) 
 166           PortStateTable
[PTableEntry
].State 
= TCP_Port_Closed
; 
 168         /* Initialize the connection table with all CLOSED entries */ 
 169         for (uint8_t CSTableEntry 
= 0; CSTableEntry 
< MAX_TCP_CONNECTIONS
; CSTableEntry
++) 
 170           ConnectionStateTable
[CSTableEntry
].State 
= TCP_Connection_Closed
; 
 173 /** Sets the state and callback handler of the given port, specified in big endian to the given state. 
 175  *  \param[in] Port     Port whose state and callback function to set, specified in big endian 
 176  *  \param[in] State    New state of the port, a value from the TCP_PortStates_t enum 
 177  *  \param[in] Handler  Application callback handler for the port 
 179  *  \return Boolean true if the port state was set, false otherwise (no more space in the port state table) 
 181 bool TCP_SetPortState(uint16_t Port
, uint8_t State
, void (*Handler
)(TCP_ConnectionState_t
*, TCP_ConnectionBuffer_t
*)) 
 183         /* Note, Port number should be specified in BIG endian to simplify network code */ 
 185         /* Check to see if the port entry is already in the port state table */ 
 186         for (uint8_t PTableEntry 
= 0; PTableEntry 
< MAX_TCP_CONNECTIONS
; PTableEntry
++) 
 188                 /* Find existing entry for the port in the table, update it if found */ 
 189                 if (PortStateTable
[PTableEntry
].Port 
== Port
) 
 191                         PortStateTable
[PTableEntry
].State 
= State
; 
 192                         PortStateTable
[PTableEntry
].ApplicationHandler 
= Handler
; 
 197         /* Check if trying to open the port -- if so we need to find an unused (closed) entry and replace it */ 
 198         if (State 
== TCP_Port_Open
) 
 200                 for (uint8_t PTableEntry 
= 0; PTableEntry 
< MAX_TCP_CONNECTIONS
; PTableEntry
++) 
 202                         /* Find a closed port entry in the table, change it to the given port and state */ 
 203                         if (PortStateTable
[PTableEntry
].State 
== TCP_Port_Closed
) 
 205                                 PortStateTable
[PTableEntry
].Port  
= Port
; 
 206                                 PortStateTable
[PTableEntry
].State 
= State
; 
 207                                 PortStateTable
[PTableEntry
].ApplicationHandler 
= Handler
; 
 212                 /* Port not in table and no room to add it, return failure */ 
 217                 /* Port not in table but trying to close it, so operation successful */ 
 222 /** Retrieves the current state of a given TCP port, specified in big endian. 
 224  *  \param[in] Port  TCP port whose state is to be retrieved, given in big-endian 
 226  *  \return A value from the TCP_PortStates_t enum 
 228 uint8_t TCP_GetPortState(uint16_t Port
) 
 230         /* Note, Port number should be specified in BIG endian to simplify network code */ 
 232         for (uint8_t PTableEntry 
= 0; PTableEntry 
< MAX_TCP_CONNECTIONS
; PTableEntry
++) 
 234                 /* Find existing entry for the port in the table, return the port status if found */ 
 235                 if (PortStateTable
[PTableEntry
].Port 
== Port
) 
 236                   return PortStateTable
[PTableEntry
].State
; 
 239         /* Port not in table, assume closed */ 
 240         return TCP_Port_Closed
; 
 243 /** Sets the connection state of the given port, remote address and remote port to the given TCP connection state. If the 
 244  *  connection exists in the connection state table it is updated, otherwise it is created if possible. 
 246  *  \param[in] Port           TCP port of the connection on the device, specified in big endian 
 247  *  \param[in] RemoteAddress  Remote protocol IP address of the connected device 
 248  *  \param[in] RemotePort     TCP port of the remote device in the connection, specified in big endian 
 249  *  \param[in] State          TCP connection state, a value from the TCP_ConnectionStates_t enum 
 251  *  \return Boolean true if the connection was updated or created, false otherwise (no more space in the connection state table) 
 253 bool TCP_SetConnectionState(uint16_t Port
, IP_Address_t RemoteAddress
, uint16_t RemotePort
, uint8_t State
) 
 255         /* Note, Port number should be specified in BIG endian to simplify network code */ 
 257         for (uint8_t CSTableEntry 
= 0; CSTableEntry 
< MAX_TCP_CONNECTIONS
; CSTableEntry
++) 
 259                 /* Find port entry in the table */ 
 260                 if ((ConnectionStateTable
[CSTableEntry
].Port 
== Port
) && 
 261                      IP_COMPARE(&ConnectionStateTable
[CSTableEntry
].RemoteAddress
, &RemoteAddress
) && 
 262                          ConnectionStateTable
[CSTableEntry
].RemotePort 
== RemotePort
) 
 264                         ConnectionStateTable
[CSTableEntry
].State 
= State
; 
 269         for (uint8_t CSTableEntry 
= 0; CSTableEntry 
< MAX_TCP_CONNECTIONS
; CSTableEntry
++) 
 271                 /* Find empty entry in the table */ 
 272                 if (ConnectionStateTable
[CSTableEntry
].State 
== TCP_Connection_Closed
) 
 274                         ConnectionStateTable
[CSTableEntry
].Port          
= Port
; 
 275                         ConnectionStateTable
[CSTableEntry
].RemoteAddress 
= RemoteAddress
;                        
 276                         ConnectionStateTable
[CSTableEntry
].RemotePort    
= RemotePort
; 
 277                         ConnectionStateTable
[CSTableEntry
].State         
= State
; 
 285 /** Retrieves the current state of a given TCP connection to a host. 
 287  *  \param[in] Port           TCP port on the device in the connection, specified in big endian 
 288  *  \param[in] RemoteAddress  Remote protocol IP address of the connected host 
 289  *  \param[in] RemotePort     Remote TCP port of the connected host, specified in big endian 
 291  *  \return A value from the TCP_ConnectionStates_t enum 
 293 uint8_t TCP_GetConnectionState(uint16_t Port
, IP_Address_t RemoteAddress
, uint16_t RemotePort
) 
 295         /* Note, Port number should be specified in BIG endian to simplify network code */ 
 297         for (uint8_t CSTableEntry 
= 0; CSTableEntry 
< MAX_TCP_CONNECTIONS
; CSTableEntry
++) 
 299                 /* Find port entry in the table */ 
 300                 if ((ConnectionStateTable
[CSTableEntry
].Port 
== Port
) && 
 301                      IP_COMPARE(&ConnectionStateTable
[CSTableEntry
].RemoteAddress
, &RemoteAddress
) && 
 302                          ConnectionStateTable
[CSTableEntry
].RemotePort 
== RemotePort
) 
 305                         return ConnectionStateTable
[CSTableEntry
].State
; 
 309         return TCP_Connection_Closed
; 
 312 /** Retrieves the connection info structure of a given connection to a host. 
 314  *  \param[in] Port           TCP port on the device in the connection, specified in big endian 
 315  *  \param[in] RemoteAddress  Remote protocol IP address of the connected host 
 316  *  \param[in] RemotePort     Remote TCP port of the connected host, specified in big endian 
 318  *  \return ConnectionInfo structure of the connection if found, NULL otherwise 
 320 TCP_ConnectionInfo_t
* TCP_GetConnectionInfo(uint16_t Port
, IP_Address_t RemoteAddress
, uint16_t RemotePort
) 
 322         /* Note, Port number should be specified in BIG endian to simplify network code */ 
 324         for (uint8_t CSTableEntry 
= 0; CSTableEntry 
< MAX_TCP_CONNECTIONS
; CSTableEntry
++) 
 326                 /* Find port entry in the table */ 
 327                 if ((ConnectionStateTable
[CSTableEntry
].Port 
== Port
) && 
 328                      IP_COMPARE(&ConnectionStateTable
[CSTableEntry
].RemoteAddress
, &RemoteAddress
) && 
 329                          ConnectionStateTable
[CSTableEntry
].RemotePort 
== RemotePort
) 
 331                         return &ConnectionStateTable
[CSTableEntry
].Info
; 
 338 /** Processes a TCP packet inside an Ethernet frame, and writes the appropriate response 
 339  *  to the output Ethernet frame if one is created by a application handler. 
 341  *  \param[in] IPHeaderInStart     Pointer to the start of the incoming packet's IP header 
 342  *  \param[in] TCPHeaderInStart    Pointer to the start of the incoming packet's TCP header 
 343  *  \param[out] TCPHeaderOutStart  Pointer to the start of the outgoing packet's TCP header 
 345  *  \return The number of bytes written to the out Ethernet frame if any, NO_RESPONSE if no 
 346  *           response was generated, NO_PROCESS if the packet processing was deferred until the 
 347  *           next Ethernet packet handler iteration 
 349 int16_t TCP_ProcessTCPPacket(void* IPHeaderInStart
, void* TCPHeaderInStart
, void* TCPHeaderOutStart
) 
 351         IP_Header_t
*  IPHeaderIN   
= (IP_Header_t
*)IPHeaderInStart
; 
 352         TCP_Header_t
* TCPHeaderIN  
= (TCP_Header_t
*)TCPHeaderInStart
; 
 353         TCP_Header_t
* TCPHeaderOUT 
= (TCP_Header_t
*)TCPHeaderOutStart
; 
 355         TCP_ConnectionInfo_t
* ConnectionInfo
; 
 357         DecodeTCPHeader(TCPHeaderInStart
); 
 359         bool PacketResponse 
= false; 
 361         /* Check if the destination port is open and allows incoming connections */ 
 362         if (TCP_GetPortState(TCPHeaderIN
->DestinationPort
) == TCP_Port_Open
) 
 364                 /* Detect SYN from host to start a connection */ 
 365                 if (TCPHeaderIN
->Flags 
& TCP_FLAG_SYN
) 
 366                   TCP_SetConnectionState(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, TCPHeaderIN
->SourcePort
, TCP_Connection_Listen
); 
 368                 /* Detect RST from host to abort existing connection */ 
 369                 if (TCPHeaderIN
->Flags 
& TCP_FLAG_RST
) 
 371                         if (TCP_SetConnectionState(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, 
 372                                                    TCPHeaderIN
->SourcePort
, TCP_Connection_Closed
)) 
 374                                 TCPHeaderOUT
->Flags 
= (TCP_FLAG_RST 
| TCP_FLAG_ACK
);                             
 375                                 PacketResponse 
= true;                   
 380                         /* Process the incoming TCP packet based on the current connection state for the sender and port */ 
 381                         switch (TCP_GetConnectionState(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, TCPHeaderIN
->SourcePort
)) 
 383                                 case TCP_Connection_Listen
: 
 384                                         if (TCPHeaderIN
->Flags 
== TCP_FLAG_SYN
) 
 386                                                 /* SYN connection starts a connection with a peer */ 
 387                                                 if (TCP_SetConnectionState(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, 
 388                                                                            TCPHeaderIN
->SourcePort
, TCP_Connection_SYNReceived
)) 
 390                                                         TCPHeaderOUT
->Flags 
= (TCP_FLAG_SYN 
| TCP_FLAG_ACK
);                                             
 392                                                         ConnectionInfo 
= TCP_GetConnectionInfo(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, TCPHeaderIN
->SourcePort
); 
 394                                                         ConnectionInfo
->SequenceNumberIn  
= (SwapEndian_32(TCPHeaderIN
->SequenceNumber
) + 1); 
 395                                                         ConnectionInfo
->SequenceNumberOut 
= 0; 
 396                                                         ConnectionInfo
->Buffer
.InUse      
= false; 
 400                                                         TCPHeaderOUT
->Flags 
= TCP_FLAG_RST
; 
 403                                                 PacketResponse      
= true; 
 407                                 case TCP_Connection_SYNReceived
: 
 408                                         if (TCPHeaderIN
->Flags 
== TCP_FLAG_ACK
) 
 410                                                 /* ACK during the connection process completes the connection to a peer */ 
 412                                                 TCP_SetConnectionState(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, 
 413                                                                                            TCPHeaderIN
->SourcePort
, TCP_Connection_Established
); 
 415                                                 ConnectionInfo 
= TCP_GetConnectionInfo(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, 
 416                                                                                                                            TCPHeaderIN
->SourcePort
); 
 418                                                 ConnectionInfo
->SequenceNumberOut
++; 
 422                                 case TCP_Connection_Established
: 
 423                                         if (TCPHeaderIN
->Flags 
== (TCP_FLAG_FIN 
| TCP_FLAG_ACK
)) 
 425                                                 /* FIN ACK when connected to a peer starts the finalization process */ 
 427                                                 TCPHeaderOUT
->Flags 
= (TCP_FLAG_FIN 
| TCP_FLAG_ACK
);                             
 428                                                 PacketResponse      
= true; 
 430                                                 TCP_SetConnectionState(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, 
 431                                                                                            TCPHeaderIN
->SourcePort
, TCP_Connection_CloseWait
); 
 433                                                 ConnectionInfo 
= TCP_GetConnectionInfo(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, 
 434                                                                                                                            TCPHeaderIN
->SourcePort
); 
 436                                                 ConnectionInfo
->SequenceNumberIn
++; 
 437                                                 ConnectionInfo
->SequenceNumberOut
++; 
 439                                         else if ((TCPHeaderIN
->Flags 
== TCP_FLAG_ACK
) || (TCPHeaderIN
->Flags 
== (TCP_FLAG_ACK 
| TCP_FLAG_PSH
))) 
 441                                                 ConnectionInfo 
= TCP_GetConnectionInfo(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, 
 442                                                                                                                            TCPHeaderIN
->SourcePort
); 
 444                                                 /* Check if the buffer is currently in use either by a buffered data to send, or receive */              
 445                                                 if ((ConnectionInfo
->Buffer
.InUse 
== false) && (ConnectionInfo
->Buffer
.Ready 
== false)) 
 447                                                         ConnectionInfo
->Buffer
.Direction 
= TCP_PACKETDIR_IN
; 
 448                                                         ConnectionInfo
->Buffer
.InUse     
= true; 
 449                                                         ConnectionInfo
->Buffer
.Length    
= 0; 
 452                                                 /* Check if the buffer has been claimed by us to read in data from the peer */ 
 453                                                 if ((ConnectionInfo
->Buffer
.Direction 
== TCP_PACKETDIR_IN
) && 
 454                                                         (ConnectionInfo
->Buffer
.Length 
!= TCP_WINDOW_SIZE
)) 
 456                                                         uint16_t IPOffset   
= (IPHeaderIN
->HeaderLength 
* sizeof(uint32_t)); 
 457                                                         uint16_t TCPOffset  
= (TCPHeaderIN
->DataOffset 
* sizeof(uint32_t)); 
 458                                                         uint16_t DataLength 
= (SwapEndian_16(IPHeaderIN
->TotalLength
) - IPOffset 
- TCPOffset
); 
 460                                                         /* Copy the packet data into the buffer */ 
 461                                                         memcpy(&ConnectionInfo
->Buffer
.Data
[ConnectionInfo
->Buffer
.Length
], 
 462                                                                    &((uint8_t*)TCPHeaderInStart
)[TCPOffset
], 
 465                                                         ConnectionInfo
->SequenceNumberIn 
+= DataLength
; 
 466                                                         ConnectionInfo
->Buffer
.Length    
+= DataLength
; 
 468                                                         /* Check if the buffer is full or if the PSH flag is set, if so indicate buffer ready */ 
 469                                                         if ((!(TCP_WINDOW_SIZE 
- ConnectionInfo
->Buffer
.Length
)) || (TCPHeaderIN
->Flags 
& TCP_FLAG_PSH
)) 
 471                                                                 ConnectionInfo
->Buffer
.InUse 
= false; 
 472                                                                 ConnectionInfo
->Buffer
.Ready 
= true; 
 474                                                                 TCPHeaderOUT
->Flags 
= TCP_FLAG_ACK
; 
 475                                                                 PacketResponse      
= true; 
 480                                                         /* Buffer is currently in use by the application, defer processing of the incoming packet */ 
 486                                 case TCP_Connection_Closing
: 
 487                                                 ConnectionInfo 
= TCP_GetConnectionInfo(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, 
 488                                                                                                                            TCPHeaderIN
->SourcePort
); 
 490                                                 TCPHeaderOUT
->Flags 
= (TCP_FLAG_ACK 
| TCP_FLAG_FIN
); 
 491                                                 PacketResponse      
= true; 
 493                                                 ConnectionInfo
->Buffer
.InUse 
= false; 
 495                                                 TCP_SetConnectionState(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, 
 496                                                                                            TCPHeaderIN
->SourcePort
, TCP_Connection_FINWait1
); 
 499                                 case TCP_Connection_FINWait1
: 
 500                                         if (TCPHeaderIN
->Flags 
== (TCP_FLAG_FIN 
| TCP_FLAG_ACK
)) 
 502                                                 ConnectionInfo 
= TCP_GetConnectionInfo(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, 
 503                                                                                                                            TCPHeaderIN
->SourcePort
); 
 505                                                 TCPHeaderOUT
->Flags 
= TCP_FLAG_ACK
; 
 506                                                 PacketResponse      
= true; 
 508                                                 ConnectionInfo
->SequenceNumberIn
++; 
 509                                                 ConnectionInfo
->SequenceNumberOut
++; 
 511                                                 TCP_SetConnectionState(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, 
 512                                                                                            TCPHeaderIN
->SourcePort
, TCP_Connection_Closed
); 
 514                                         else if (TCPHeaderIN
->Flags 
== TCP_FLAG_ACK
) 
 516                                                 TCP_SetConnectionState(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, 
 517                                                                                            TCPHeaderIN
->SourcePort
, TCP_Connection_FINWait2
); 
 521                                 case TCP_Connection_FINWait2
: 
 522                                         if (TCPHeaderIN
->Flags 
== (TCP_FLAG_FIN 
| TCP_FLAG_ACK
)) 
 524                                                 ConnectionInfo 
= TCP_GetConnectionInfo(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, 
 525                                                                                                                            TCPHeaderIN
->SourcePort
); 
 527                                                 TCPHeaderOUT
->Flags 
= TCP_FLAG_ACK
; 
 528                                                 PacketResponse      
= true; 
 530                                                 ConnectionInfo
->SequenceNumberIn
++; 
 531                                                 ConnectionInfo
->SequenceNumberOut
++; 
 533                                                 TCP_SetConnectionState(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, 
 534                                                                                            TCPHeaderIN
->SourcePort
, TCP_Connection_Closed
); 
 538                                 case TCP_Connection_CloseWait
: 
 539                                         if (TCPHeaderIN
->Flags 
== TCP_FLAG_ACK
) 
 541                                                 TCP_SetConnectionState(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, 
 542                                                                                            TCPHeaderIN
->SourcePort
, TCP_Connection_Closed
); 
 551                 /* Port is not open, indicate via a RST/ACK response to the sender */ 
 552                 TCPHeaderOUT
->Flags 
= (TCP_FLAG_RST 
| TCP_FLAG_ACK
);                             
 553                 PacketResponse      
= true; 
 556         /* Check if we need to respond to the sent packet */ 
 559                 ConnectionInfo 
= TCP_GetConnectionInfo(TCPHeaderIN
->DestinationPort
, IPHeaderIN
->SourceAddress
, 
 560                                                        TCPHeaderIN
->SourcePort
); 
 562                 TCPHeaderOUT
->SourcePort           
= TCPHeaderIN
->DestinationPort
; 
 563                 TCPHeaderOUT
->DestinationPort      
= TCPHeaderIN
->SourcePort
; 
 564                 TCPHeaderOUT
->SequenceNumber       
= SwapEndian_32(ConnectionInfo
->SequenceNumberOut
); 
 565                 TCPHeaderOUT
->AcknowledgmentNumber 
= SwapEndian_32(ConnectionInfo
->SequenceNumberIn
); 
 566                 TCPHeaderOUT
->DataOffset           
= (sizeof(TCP_Header_t
) / sizeof(uint32_t)); 
 568                 if (!(ConnectionInfo
->Buffer
.InUse
)) 
 569                   TCPHeaderOUT
->WindowSize         
= SwapEndian_16(TCP_WINDOW_SIZE
); 
 571                   TCPHeaderOUT
->WindowSize         
= SwapEndian_16(TCP_WINDOW_SIZE 
- ConnectionInfo
->Buffer
.Length
); 
 573                 TCPHeaderOUT
->UrgentPointer        
= 0; 
 574                 TCPHeaderOUT
->Checksum             
= 0; 
 575                 TCPHeaderOUT
->Reserved             
= 0; 
 577                 TCPHeaderOUT
->Checksum             
= TCP_Checksum16(TCPHeaderOUT
, IPHeaderIN
->DestinationAddress
, 
 578                                                                     IPHeaderIN
->SourceAddress
, sizeof(TCP_Header_t
));                                    
 580                 return sizeof(TCP_Header_t
);     
 586 /** Calculates the appropriate TCP checksum, consisting of the addition of the one's compliment of each word, 
 589  *  \param[in] TCPHeaderOutStart   Pointer to the start of the packet's outgoing TCP header 
 590  *  \param[in] SourceAddress       Source protocol IP address of the outgoing IP header 
 591  *  \param[in] DestinationAddress  Destination protocol IP address of the outgoing IP header 
 592  *  \param[in] TCPOutSize          Size in bytes of the TCP data header and payload 
 594  *  \return A 16-bit TCP checksum value 
 596 static uint16_t TCP_Checksum16(void* TCPHeaderOutStart
, IP_Address_t SourceAddress
, 
 597                                IP_Address_t DestinationAddress
, uint16_t TCPOutSize
) 
 599         uint32_t Checksum 
= 0; 
 601         /* TCP/IP checksums are the addition of the one's compliment of each word including the IP pseudo-header, 
 604         Checksum 
+= ((uint16_t*)&SourceAddress
)[0]; 
 605         Checksum 
+= ((uint16_t*)&SourceAddress
)[1]; 
 606         Checksum 
+= ((uint16_t*)&DestinationAddress
)[0]; 
 607         Checksum 
+= ((uint16_t*)&DestinationAddress
)[1]; 
 608         Checksum 
+= SwapEndian_16(PROTOCOL_TCP
); 
 609         Checksum 
+= SwapEndian_16(TCPOutSize
); 
 611         for (uint8_t CurrWord 
= 0; CurrWord 
< (TCPOutSize 
>> 1); CurrWord
++) 
 612           Checksum 
+= ((uint16_t*)TCPHeaderOutStart
)[CurrWord
]; 
 614         if (TCPOutSize 
& 0x01) 
 615           Checksum 
+= (((uint16_t*)TCPHeaderOutStart
)[TCPOutSize 
>> 1] & 0x00FF); 
 617         while (Checksum 
& 0xFFFF0000) 
 618           Checksum 
= ((Checksum 
& 0xFFFF) + (Checksum 
>> 16));