diff options
Diffstat (limited to 'lib/lufa/Demos/Device/ClassDriver/RNDISEthernet/Lib/TCP.c')
-rw-r--r-- | lib/lufa/Demos/Device/ClassDriver/RNDISEthernet/Lib/TCP.c | 632 |
1 files changed, 0 insertions, 632 deletions
diff --git a/lib/lufa/Demos/Device/ClassDriver/RNDISEthernet/Lib/TCP.c b/lib/lufa/Demos/Device/ClassDriver/RNDISEthernet/Lib/TCP.c deleted file mode 100644 index dcc527aa97..0000000000 --- a/lib/lufa/Demos/Device/ClassDriver/RNDISEthernet/Lib/TCP.c +++ /dev/null @@ -1,632 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2017. - - dean [at] fourwalledcubicle [dot] com - www.lufa-lib.org -*/ - -/* - Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com) - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that the copyright notice and this - permission notice and warranty disclaimer appear in supporting - documentation, and that the name of the author not be used in - advertising or publicity pertaining to distribution of the - software without specific, written prior permission. - - The author disclaims all warranties with regard to this - software, including all implied warranties of merchantability - and fitness. In no event shall the author be liable for any - special, indirect or consequential damages or any damages - whatsoever resulting from loss of use, data or profits, whether - in an action of contract, negligence or other tortious action, - arising out of or in connection with the use or performance of - this software. -*/ - -/** \file - * - * Transmission Control Protocol (TCP) packet handling routines. This protocol handles the reliable in-order transmission - * and reception of packets to and from devices on a network, to "ports" on the device. It is used in situations where data - * delivery must be reliable and correct, e.g. HTTP, TELNET and most other non-streaming protocols. - */ - -#define INCLUDE_FROM_TCP_C -#include "TCP.h" - -/** Port state table array. This contains the current status of TCP ports in the device. To save on space, only open ports are - * stored - closed ports may be overwritten at any time, and the system will assume any ports not present in the array are closed. This - * allows for MAX_OPEN_TCP_PORTS to be less than the number of ports used by the application if desired. - */ -TCP_PortState_t PortStateTable[MAX_OPEN_TCP_PORTS]; - -/** Connection state table array. This contains the current status of TCP connections in the device. To save on space, only active - * (non-closed) connections are stored - closed connections may be overwritten at any time, and the system will assume any connections - * not present in the array are closed. - */ -TCP_ConnectionState_t ConnectionStateTable[MAX_TCP_CONNECTIONS]; - - -/** Task to handle the calling of each registered application's callback function, to process and generate TCP packets at the application - * level. If an application produces a response, this task constructs the appropriate Ethernet frame and places it into the Ethernet OUT - * buffer for later transmission. - */ -void TCP_TCPTask(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo, - Ethernet_Frame_Info_t* const FrameOUT) -{ - /* Run each application in sequence, to process incoming and generate outgoing packets */ - for (uint8_t CSTableEntry = 0; CSTableEntry < MAX_TCP_CONNECTIONS; CSTableEntry++) - { - /* Find the corresponding port entry in the port table */ - for (uint8_t PTableEntry = 0; PTableEntry < MAX_OPEN_TCP_PORTS; PTableEntry++) - { - /* Run the application handler for the port */ - if ((PortStateTable[PTableEntry].Port == ConnectionStateTable[CSTableEntry].Port) && - (PortStateTable[PTableEntry].State == TCP_Port_Open)) - { - PortStateTable[PTableEntry].ApplicationHandler(&ConnectionStateTable[CSTableEntry], - &ConnectionStateTable[CSTableEntry].Info.Buffer); - } - } - } - - /* Bail out early if there is already a frame waiting to be sent in the Ethernet OUT buffer */ - if (FrameOUT->FrameLength) - return; - - /* Send response packets from each application as the TCP packet buffers are filled by the applications */ - for (uint8_t CSTableEntry = 0; CSTableEntry < MAX_TCP_CONNECTIONS; CSTableEntry++) - { - /* For each completely received packet, pass it along to the listening application */ - if ((ConnectionStateTable[CSTableEntry].Info.Buffer.Direction == TCP_PACKETDIR_OUT) && - (ConnectionStateTable[CSTableEntry].Info.Buffer.Ready)) - { - Ethernet_Frame_Header_t* FrameOUTHeader = (Ethernet_Frame_Header_t*)&FrameOUT->FrameData; - IP_Header_t* IPHeaderOUT = (IP_Header_t*)&FrameOUT->FrameData[sizeof(Ethernet_Frame_Header_t)]; - TCP_Header_t* TCPHeaderOUT = (TCP_Header_t*)&FrameOUT->FrameData[sizeof(Ethernet_Frame_Header_t) + - sizeof(IP_Header_t)]; - void* TCPDataOUT = &FrameOUT->FrameData[sizeof(Ethernet_Frame_Header_t) + - sizeof(IP_Header_t) + - sizeof(TCP_Header_t)]; - - uint16_t PacketSize = ConnectionStateTable[CSTableEntry].Info.Buffer.Length; - - /* Fill out the TCP data */ - TCPHeaderOUT->SourcePort = ConnectionStateTable[CSTableEntry].Port; - TCPHeaderOUT->DestinationPort = ConnectionStateTable[CSTableEntry].RemotePort; - TCPHeaderOUT->SequenceNumber = SwapEndian_32(ConnectionStateTable[CSTableEntry].Info.SequenceNumberOut); - TCPHeaderOUT->AcknowledgmentNumber = SwapEndian_32(ConnectionStateTable[CSTableEntry].Info.SequenceNumberIn); - TCPHeaderOUT->DataOffset = (sizeof(TCP_Header_t) / sizeof(uint32_t)); - TCPHeaderOUT->WindowSize = SwapEndian_16(TCP_WINDOW_SIZE); - - TCPHeaderOUT->Flags = TCP_FLAG_ACK; - TCPHeaderOUT->UrgentPointer = 0; - TCPHeaderOUT->Checksum = 0; - TCPHeaderOUT->Reserved = 0; - - memcpy(TCPDataOUT, ConnectionStateTable[CSTableEntry].Info.Buffer.Data, PacketSize); - - ConnectionStateTable[CSTableEntry].Info.SequenceNumberOut += PacketSize; - - TCPHeaderOUT->Checksum = TCP_Checksum16(TCPHeaderOUT, &ServerIPAddress, - &ConnectionStateTable[CSTableEntry].RemoteAddress, - (sizeof(TCP_Header_t) + PacketSize)); - - PacketSize += sizeof(TCP_Header_t); - - /* Fill out the response IP header */ - IPHeaderOUT->TotalLength = SwapEndian_16(sizeof(IP_Header_t) + PacketSize); - IPHeaderOUT->TypeOfService = 0; - IPHeaderOUT->HeaderLength = (sizeof(IP_Header_t) / sizeof(uint32_t)); - IPHeaderOUT->Version = 4; - IPHeaderOUT->Flags = 0; - IPHeaderOUT->FragmentOffset = 0; - IPHeaderOUT->Identification = 0; - IPHeaderOUT->HeaderChecksum = 0; - IPHeaderOUT->Protocol = PROTOCOL_TCP; - IPHeaderOUT->TTL = DEFAULT_TTL; - IPHeaderOUT->SourceAddress = ServerIPAddress; - IPHeaderOUT->DestinationAddress = ConnectionStateTable[CSTableEntry].RemoteAddress; - - IPHeaderOUT->HeaderChecksum = Ethernet_Checksum16(IPHeaderOUT, sizeof(IP_Header_t)); - - PacketSize += sizeof(IP_Header_t); - - /* Fill out the response Ethernet frame header */ - FrameOUTHeader->Source = ServerMACAddress; - FrameOUTHeader->Destination = (MAC_Address_t){{0x02, 0x00, 0x02, 0x00, 0x02, 0x00}}; - FrameOUTHeader->EtherType = SwapEndian_16(ETHERTYPE_IPV4); - - PacketSize += sizeof(Ethernet_Frame_Header_t); - - /* Set the response length in the buffer and indicate that a response is ready to be sent */ - FrameOUT->FrameLength = PacketSize; - - ConnectionStateTable[CSTableEntry].Info.Buffer.Ready = false; - - break; - } - } -} - -/** Initializes the TCP protocol handler, clearing the port and connection state tables. This must be called before TCP packets are - * processed. - */ -void TCP_Init(void) -{ - /* Initialize the port state table with all CLOSED entries */ - for (uint8_t PTableEntry = 0; PTableEntry < MAX_OPEN_TCP_PORTS; PTableEntry++) - PortStateTable[PTableEntry].State = TCP_Port_Closed; - - /* Initialize the connection table with all CLOSED entries */ - for (uint8_t CSTableEntry = 0; CSTableEntry < MAX_TCP_CONNECTIONS; CSTableEntry++) - ConnectionStateTable[CSTableEntry].State = TCP_Connection_Closed; -} - -/** Sets the state and callback handler of the given port, specified in big endian to the given state. - * - * \param[in] Port Port whose state and callback function to set, specified in big endian - * \param[in] State New state of the port, a value from the \ref TCP_PortStates_t enum - * \param[in] Handler Application callback handler for the port - * - * \return Boolean \c true if the port state was set, \c false otherwise (no more space in the port state table) - */ -bool TCP_SetPortState(const uint16_t Port, - const uint8_t State, - void (*Handler)(TCP_ConnectionState_t*, TCP_ConnectionBuffer_t*)) -{ - /* Note, Port number should be specified in BIG endian to simplify network code */ - - /* Check to see if the port entry is already in the port state table */ - for (uint8_t PTableEntry = 0; PTableEntry < MAX_OPEN_TCP_PORTS; PTableEntry++) - { - /* Find existing entry for the port in the table, update it if found */ - if (PortStateTable[PTableEntry].Port == Port) - { - PortStateTable[PTableEntry].State = State; - PortStateTable[PTableEntry].ApplicationHandler = Handler; - return true; - } - } - - /* Check if trying to open the port -- if so we need to find an unused (closed) entry and replace it */ - if (State == TCP_Port_Open) - { - for (uint8_t PTableEntry = 0; PTableEntry < MAX_OPEN_TCP_PORTS; PTableEntry++) - { - /* Find a closed port entry in the table, change it to the given port and state */ - if (PortStateTable[PTableEntry].State == TCP_Port_Closed) - { - PortStateTable[PTableEntry].Port = Port; - PortStateTable[PTableEntry].State = State; - PortStateTable[PTableEntry].ApplicationHandler = Handler; - return true; - } - } - - /* Port not in table and no room to add it, return failure */ - return false; - } - else - { - /* Port not in table but trying to close it, so operation successful */ - return true; - } -} - -/** Retrieves the current state of a given TCP port, specified in big endian. - * - * \param[in] Port TCP port whose state is to be retrieved, given in big-endian - * - * \return A value from the \ref TCP_PortStates_t enum - */ -uint8_t TCP_GetPortState(const uint16_t Port) -{ - /* Note, Port number should be specified in BIG endian to simplify network code */ - - for (uint8_t PTableEntry = 0; PTableEntry < MAX_OPEN_TCP_PORTS; PTableEntry++) - { - /* Find existing entry for the port in the table, return the port status if found */ - if (PortStateTable[PTableEntry].Port == Port) - return PortStateTable[PTableEntry].State; - } - - /* Port not in table, assume closed */ - return TCP_Port_Closed; -} - -/** Sets the connection state of the given port, remote address and remote port to the given TCP connection state. If the - * connection exists in the connection state table it is updated, otherwise it is created if possible. - * - * \param[in] Port TCP port of the connection on the device, specified in big endian - * \param[in] RemoteAddress Remote protocol IP address of the connected device - * \param[in] RemotePort TCP port of the remote device in the connection, specified in big endian - * \param[in] State TCP connection state, a value from the \ref TCP_ConnectionStates_t enum - * - * \return Boolean \c true if the connection was updated or created, \c false otherwise (no more space in the connection state table) - */ -bool TCP_SetConnectionState(const uint16_t Port, - const IP_Address_t* RemoteAddress, - const uint16_t RemotePort, - const uint8_t State) -{ - /* Note, Port number should be specified in BIG endian to simplify network code */ - - for (uint8_t CSTableEntry = 0; CSTableEntry < MAX_TCP_CONNECTIONS; CSTableEntry++) - { - /* Find port entry in the table */ - if ((ConnectionStateTable[CSTableEntry].Port == Port) && - IP_COMPARE(&ConnectionStateTable[CSTableEntry].RemoteAddress, RemoteAddress) && - ConnectionStateTable[CSTableEntry].RemotePort == RemotePort) - { - ConnectionStateTable[CSTableEntry].State = State; - return true; - } - } - - for (uint8_t CSTableEntry = 0; CSTableEntry < MAX_TCP_CONNECTIONS; CSTableEntry++) - { - /* Find empty entry in the table */ - if (ConnectionStateTable[CSTableEntry].State == TCP_Connection_Closed) - { - ConnectionStateTable[CSTableEntry].Port = Port; - ConnectionStateTable[CSTableEntry].RemoteAddress = *RemoteAddress; - ConnectionStateTable[CSTableEntry].RemotePort = RemotePort; - ConnectionStateTable[CSTableEntry].State = State; - return true; - } - } - - return false; -} - -/** Retrieves the current state of a given TCP connection to a host. - * - * \param[in] Port TCP port on the device in the connection, specified in big endian - * \param[in] RemoteAddress Remote protocol IP address of the connected host - * \param[in] RemotePort Remote TCP port of the connected host, specified in big endian - * - * \return A value from the \ref TCP_ConnectionStates_t enum - */ -uint8_t TCP_GetConnectionState(const uint16_t Port, - const IP_Address_t* RemoteAddress, - const uint16_t RemotePort) -{ - /* Note, Port number should be specified in BIG endian to simplify network code */ - - for (uint8_t CSTableEntry = 0; CSTableEntry < MAX_TCP_CONNECTIONS; CSTableEntry++) - { - /* Find port entry in the table */ - if ((ConnectionStateTable[CSTableEntry].Port == Port) && - IP_COMPARE(&ConnectionStateTable[CSTableEntry].RemoteAddress, RemoteAddress) && - ConnectionStateTable[CSTableEntry].RemotePort == RemotePort) - - { - return ConnectionStateTable[CSTableEntry].State; - } - } - - return TCP_Connection_Closed; -} - -/** Retrieves the connection info structure of a given connection to a host. - * - * \param[in] Port TCP port on the device in the connection, specified in big endian - * \param[in] RemoteAddress Remote protocol IP address of the connected host - * \param[in] RemotePort Remote TCP port of the connected host, specified in big endian - * - * \return ConnectionInfo structure of the connection if found, NULL otherwise - */ -TCP_ConnectionInfo_t* TCP_GetConnectionInfo(const uint16_t Port, - const IP_Address_t* RemoteAddress, - const uint16_t RemotePort) -{ - /* Note, Port number should be specified in BIG endian to simplify network code */ - - for (uint8_t CSTableEntry = 0; CSTableEntry < MAX_TCP_CONNECTIONS; CSTableEntry++) - { - /* Find port entry in the table */ - if ((ConnectionStateTable[CSTableEntry].Port == Port) && - IP_COMPARE(&ConnectionStateTable[CSTableEntry].RemoteAddress, RemoteAddress) && - ConnectionStateTable[CSTableEntry].RemotePort == RemotePort) - { - return &ConnectionStateTable[CSTableEntry].Info; - } - } - - return NULL; -} - -/** Processes a TCP packet inside an Ethernet frame, and writes the appropriate response - * to the output Ethernet frame if one is created by a application handler. - * - * \param[in] IPHeaderInStart Pointer to the start of the incoming packet's IP header - * \param[in] TCPHeaderInStart Pointer to the start of the incoming packet's TCP header - * \param[out] TCPHeaderOutStart Pointer to the start of the outgoing packet's TCP header - * - * \return The number of bytes written to the out Ethernet frame if any, NO_RESPONSE if no - * response was generated, NO_PROCESS if the packet processing was deferred until the - * next Ethernet packet handler iteration - */ -int16_t TCP_ProcessTCPPacket(void* IPHeaderInStart, - void* TCPHeaderInStart, - void* TCPHeaderOutStart) -{ - IP_Header_t* IPHeaderIN = (IP_Header_t*)IPHeaderInStart; - TCP_Header_t* TCPHeaderIN = (TCP_Header_t*)TCPHeaderInStart; - TCP_Header_t* TCPHeaderOUT = (TCP_Header_t*)TCPHeaderOutStart; - - TCP_ConnectionInfo_t* ConnectionInfo; - - DecodeTCPHeader(TCPHeaderInStart); - - bool PacketResponse = false; - - /* Check if the destination port is open and allows incoming connections */ - if (TCP_GetPortState(TCPHeaderIN->DestinationPort) == TCP_Port_Open) - { - /* Detect SYN from host to start a connection */ - if (TCPHeaderIN->Flags & TCP_FLAG_SYN) - TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, TCPHeaderIN->SourcePort, TCP_Connection_Listen); - - /* Detect RST from host to abort existing connection */ - if (TCPHeaderIN->Flags & TCP_FLAG_RST) - { - if (TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, - TCPHeaderIN->SourcePort, TCP_Connection_Closed)) - { - TCPHeaderOUT->Flags = (TCP_FLAG_RST | TCP_FLAG_ACK); - PacketResponse = true; - } - } - else - { - /* Process the incoming TCP packet based on the current connection state for the sender and port */ - switch (TCP_GetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, TCPHeaderIN->SourcePort)) - { - case TCP_Connection_Listen: - if (TCPHeaderIN->Flags == TCP_FLAG_SYN) - { - /* SYN connection starts a connection with a peer */ - if (TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, - TCPHeaderIN->SourcePort, TCP_Connection_SYNReceived)) - { - TCPHeaderOUT->Flags = (TCP_FLAG_SYN | TCP_FLAG_ACK); - - ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, TCPHeaderIN->SourcePort); - - ConnectionInfo->SequenceNumberIn = (SwapEndian_32(TCPHeaderIN->SequenceNumber) + 1); - ConnectionInfo->SequenceNumberOut = 0; - ConnectionInfo->Buffer.InUse = false; - } - else - { - TCPHeaderOUT->Flags = TCP_FLAG_RST; - } - - PacketResponse = true; - } - - break; - case TCP_Connection_SYNReceived: - if (TCPHeaderIN->Flags == TCP_FLAG_ACK) - { - /* ACK during the connection process completes the connection to a peer */ - - TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, - TCPHeaderIN->SourcePort, TCP_Connection_Established); - - ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, - TCPHeaderIN->SourcePort); - - ConnectionInfo->SequenceNumberOut++; - } - - break; - case TCP_Connection_Established: - if (TCPHeaderIN->Flags == (TCP_FLAG_FIN | TCP_FLAG_ACK)) - { - /* FIN ACK when connected to a peer starts the finalization process */ - - TCPHeaderOUT->Flags = (TCP_FLAG_FIN | TCP_FLAG_ACK); - PacketResponse = true; - - TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, - TCPHeaderIN->SourcePort, TCP_Connection_CloseWait); - - ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, - TCPHeaderIN->SourcePort); - - ConnectionInfo->SequenceNumberIn++; - ConnectionInfo->SequenceNumberOut++; - } - else if ((TCPHeaderIN->Flags == TCP_FLAG_ACK) || (TCPHeaderIN->Flags == (TCP_FLAG_ACK | TCP_FLAG_PSH))) - { - ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, - TCPHeaderIN->SourcePort); - - /* Check if the buffer is currently in use either by a buffered data to send, or receive */ - if ((ConnectionInfo->Buffer.InUse == false) && (ConnectionInfo->Buffer.Ready == false)) - { - ConnectionInfo->Buffer.Direction = TCP_PACKETDIR_IN; - ConnectionInfo->Buffer.InUse = true; - ConnectionInfo->Buffer.Length = 0; - } - - /* Check if the buffer has been claimed by us to read in data from the peer */ - if ((ConnectionInfo->Buffer.Direction == TCP_PACKETDIR_IN) && - (ConnectionInfo->Buffer.Length != TCP_WINDOW_SIZE)) - { - uint16_t IPOffset = (IPHeaderIN->HeaderLength * sizeof(uint32_t)); - uint16_t TCPOffset = (TCPHeaderIN->DataOffset * sizeof(uint32_t)); - uint16_t DataLength = (SwapEndian_16(IPHeaderIN->TotalLength) - IPOffset - TCPOffset); - - /* Copy the packet data into the buffer */ - memcpy(&ConnectionInfo->Buffer.Data[ConnectionInfo->Buffer.Length], - &((uint8_t*)TCPHeaderInStart)[TCPOffset], - DataLength); - - ConnectionInfo->SequenceNumberIn += DataLength; - ConnectionInfo->Buffer.Length += DataLength; - - /* Check if the buffer is full or if the PSH flag is set, if so indicate buffer ready */ - if ((!(TCP_WINDOW_SIZE - ConnectionInfo->Buffer.Length)) || (TCPHeaderIN->Flags & TCP_FLAG_PSH)) - { - ConnectionInfo->Buffer.InUse = false; - ConnectionInfo->Buffer.Ready = true; - - TCPHeaderOUT->Flags = TCP_FLAG_ACK; - PacketResponse = true; - } - } - else - { - /* Buffer is currently in use by the application, defer processing of the incoming packet */ - return NO_PROCESS; - } - } - - break; - case TCP_Connection_Closing: - ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, - TCPHeaderIN->SourcePort); - - TCPHeaderOUT->Flags = (TCP_FLAG_ACK | TCP_FLAG_FIN); - PacketResponse = true; - - ConnectionInfo->Buffer.InUse = false; - - TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, - TCPHeaderIN->SourcePort, TCP_Connection_FINWait1); - - break; - case TCP_Connection_FINWait1: - if (TCPHeaderIN->Flags == (TCP_FLAG_FIN | TCP_FLAG_ACK)) - { - ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, - TCPHeaderIN->SourcePort); - - TCPHeaderOUT->Flags = TCP_FLAG_ACK; - PacketResponse = true; - - ConnectionInfo->SequenceNumberIn++; - ConnectionInfo->SequenceNumberOut++; - - TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, - TCPHeaderIN->SourcePort, TCP_Connection_Closed); - } - else if (TCPHeaderIN->Flags == TCP_FLAG_ACK) - { - TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, - TCPHeaderIN->SourcePort, TCP_Connection_FINWait2); - } - - break; - case TCP_Connection_FINWait2: - if (TCPHeaderIN->Flags == (TCP_FLAG_FIN | TCP_FLAG_ACK)) - { - ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, - TCPHeaderIN->SourcePort); - - TCPHeaderOUT->Flags = TCP_FLAG_ACK; - PacketResponse = true; - - ConnectionInfo->SequenceNumberIn++; - ConnectionInfo->SequenceNumberOut++; - - TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, - TCPHeaderIN->SourcePort, TCP_Connection_Closed); - } - - break; - case TCP_Connection_CloseWait: - if (TCPHeaderIN->Flags == TCP_FLAG_ACK) - { - TCP_SetConnectionState(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, - TCPHeaderIN->SourcePort, TCP_Connection_Closed); - } - - break; - } - } - } - else - { - /* Port is not open, indicate via a RST/ACK response to the sender */ - TCPHeaderOUT->Flags = (TCP_FLAG_RST | TCP_FLAG_ACK); - PacketResponse = true; - } - - /* Check if we need to respond to the sent packet */ - if (PacketResponse) - { - ConnectionInfo = TCP_GetConnectionInfo(TCPHeaderIN->DestinationPort, &IPHeaderIN->SourceAddress, - TCPHeaderIN->SourcePort); - - TCPHeaderOUT->SourcePort = TCPHeaderIN->DestinationPort; - TCPHeaderOUT->DestinationPort = TCPHeaderIN->SourcePort; - TCPHeaderOUT->SequenceNumber = SwapEndian_32(ConnectionInfo->SequenceNumberOut); - TCPHeaderOUT->AcknowledgmentNumber = SwapEndian_32(ConnectionInfo->SequenceNumberIn); - TCPHeaderOUT->DataOffset = (sizeof(TCP_Header_t) / sizeof(uint32_t)); - - if (!(ConnectionInfo->Buffer.InUse)) - TCPHeaderOUT->WindowSize = SwapEndian_16(TCP_WINDOW_SIZE); - else - TCPHeaderOUT->WindowSize = SwapEndian_16(TCP_WINDOW_SIZE - ConnectionInfo->Buffer.Length); - - TCPHeaderOUT->UrgentPointer = 0; - TCPHeaderOUT->Checksum = 0; - TCPHeaderOUT->Reserved = 0; - - TCPHeaderOUT->Checksum = TCP_Checksum16(TCPHeaderOUT, &IPHeaderIN->DestinationAddress, - &IPHeaderIN->SourceAddress, sizeof(TCP_Header_t)); - - return sizeof(TCP_Header_t); - } - - return NO_RESPONSE; -} - -/** Calculates the appropriate TCP checksum, consisting of the addition of the one's compliment of each word, - * complimented. - * - * \param[in] TCPHeaderOutStart Pointer to the start of the packet's outgoing TCP header - * \param[in] SourceAddress Source protocol IP address of the outgoing IP header - * \param[in] DestinationAddress Destination protocol IP address of the outgoing IP header - * \param[in] TCPOutSize Size in bytes of the TCP data header and payload - * - * \return A 16-bit TCP checksum value - */ -static uint16_t TCP_Checksum16(void* TCPHeaderOutStart, - const IP_Address_t* SourceAddress, - const IP_Address_t* DestinationAddress, - uint16_t TCPOutSize) -{ - uint32_t Checksum = 0; - - /* TCP/IP checksums are the addition of the one's compliment of each word including the IP pseudo-header, - complimented */ - - Checksum += ((uint16_t*)SourceAddress)[0]; - Checksum += ((uint16_t*)SourceAddress)[1]; - Checksum += ((uint16_t*)DestinationAddress)[0]; - Checksum += ((uint16_t*)DestinationAddress)[1]; - Checksum += SwapEndian_16(PROTOCOL_TCP); - Checksum += SwapEndian_16(TCPOutSize); - - for (uint16_t CurrWord = 0; CurrWord < (TCPOutSize >> 1); CurrWord++) - Checksum += ((uint16_t*)TCPHeaderOutStart)[CurrWord]; - - if (TCPOutSize & 0x01) - Checksum += (((uint16_t*)TCPHeaderOutStart)[TCPOutSize >> 1] & 0x00FF); - - while (Checksum & 0xFFFF0000) - Checksum = ((Checksum & 0xFFFF) + (Checksum >> 16)); - - return ~Checksum; -} - |